Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 27 Jan 2008 07:01:20 +0000 (23:01 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 27 Jan 2008 07:01:20 +0000 (23:01 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] DFS build fixes
  [CIFS] DFS support: provide shrinkable mounts
  [CIFS] Do not log path names in lookup errors
  [CIFS] DFS support patchset: Added mountdata
  [CIFS] Forgot to add two new files from previous commit
  [CIFS] DNS name resolution helper upcall for cifs
  [CIFS] fix checkpatch warnings in fs/cifs/inode.c
  [CIFS] hold ses sem on tcp session reconnect during mount
  [CIFS] Allow setting mode via cifs acl
  [CIFS]  fix unicode string alignment in SPNEGO setup
  [CIFS] cifs_partialpagewrite() cleanup
  [CIFS]  use krb5 session key from first SMB session after a NegProt
  [CIFS] redo existing session setup if needed in cifs_mount
  [CIFS] Only dump SPNEGO key if CONFIG_CIFS_DEBUG2 is set
  [CIFS] fix SetEA failure to some Samba versions

1637 files changed:
Documentation/DocBook/Makefile
Documentation/DocBook/s390-drivers.tmpl
Documentation/DocBook/scsi.tmpl [new file with mode: 0644]
Documentation/DocBook/videobook.tmpl
Documentation/RCU/RTFP.txt
Documentation/RCU/rcu.txt
Documentation/RCU/torture.txt
Documentation/cpu-hotplug.txt
Documentation/crypto/api-intro.txt
Documentation/dontdiff
Documentation/dvb/bt8xx.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ocfs2.txt
Documentation/ide.txt
Documentation/ioctl-number.txt
Documentation/kernel-parameters.txt
Documentation/kobject.txt
Documentation/local_ops.txt
Documentation/m68k/kernel-options.txt
Documentation/networking/driver.txt
Documentation/networking/wavelan.txt
Documentation/nfsroot.txt
Documentation/pnp.txt
Documentation/s390/CommonIO
Documentation/s390/cds.txt
Documentation/scsi/00-INDEX
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/scsi/aacraid.txt
Documentation/scsi/hptiop.txt
Documentation/scsi/ncr53c7xx.txt [deleted file]
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.ivtv
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/CARDLIST.usbvision
Documentation/video4linux/extract_xc3028.pl [new file with mode: 0644]
Documentation/video4linux/sn9c102.txt
Documentation/vm/slabinfo.c
Documentation/vm/slub.txt
Documentation/watchdog/watchdog-api.txt
Documentation/zh_CN/CodingStyle [new file with mode: 0644]
Documentation/zh_CN/HOWTO
Documentation/zh_CN/SubmittingDrivers [new file with mode: 0644]
Documentation/zh_CN/SubmittingPatches [new file with mode: 0644]
Documentation/zh_CN/oops-tracing.txt [new file with mode: 0644]
Documentation/zh_CN/sparse.txt [new file with mode: 0644]
Documentation/zh_CN/stable_kernel_rules.txt [new file with mode: 0644]
Documentation/zh_CN/volatile-considered-harmful.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/.gitignore [new file with mode: 0644]
arch/alpha/math-emu/math.c
arch/arm/Kconfig
arch/arm/Kconfig.instrumentation [new file with mode: 0644]
arch/arm/kernel/time.c
arch/arm/mach-at91/board-ek.c
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/sleep.S
arch/arm/mach-s3c2410/s3c2410.c
arch/arm/mach-s3c2412/s3c2412.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2443/s3c2443.c
arch/arm/mach-sa1100/irq.c
arch/arm/oprofile/common.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/s3c244x.c
arch/arm/vfp/vfp.h
arch/arm/vfp/vfpdouble.c
arch/avr32/Kconfig
arch/avr32/Kconfig.debug
arch/avr32/Makefile
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/Kconfig
arch/avr32/boards/atstk1000/Makefile
arch/avr32/boards/atstk1000/atstk1000.h
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/boards/atstk1000/atstk1003.c [new file with mode: 0644]
arch/avr32/boards/atstk1000/atstk1004.c [new file with mode: 0644]
arch/avr32/boards/atstk1000/setup.c
arch/avr32/configs/atngw100_defconfig
arch/avr32/configs/atstk1002_defconfig
arch/avr32/configs/atstk1003_defconfig [new file with mode: 0644]
arch/avr32/configs/atstk1004_defconfig [new file with mode: 0644]
arch/avr32/kernel/Makefile
arch/avr32/kernel/cpu.c
arch/avr32/kernel/irq.c
arch/avr32/kernel/kprobes.c
arch/avr32/kernel/nmi_debug.c [new file with mode: 0644]
arch/avr32/kernel/ocd.c [new file with mode: 0644]
arch/avr32/kernel/process.c
arch/avr32/kernel/ptrace.c
arch/avr32/kernel/signal.c
arch/avr32/kernel/time.c
arch/avr32/kernel/traps.c
arch/avr32/mach-at32ap/Kconfig
arch/avr32/mach-at32ap/Makefile
arch/avr32/mach-at32ap/at32ap7000.c [deleted file]
arch/avr32/mach-at32ap/at32ap700x.c [new file with mode: 0644]
arch/avr32/mach-at32ap/extint.c
arch/avr32/mm/dma-coherent.c
arch/avr32/mm/tlb.c
arch/avr32/oprofile/Makefile [new file with mode: 0644]
arch/avr32/oprofile/op_model_avr32.c [new file with mode: 0644]
arch/blackfin/Kconfig
arch/cris/arch-v10/drivers/ds1302.c
arch/cris/arch-v10/kernel/io_interface_mux.c
arch/cris/arch-v10/kernel/signal.c
arch/cris/arch-v10/kernel/time.c
arch/cris/arch-v10/vmlinux.lds.S
arch/cris/arch-v32/drivers/iop_fw_load.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/time.c
arch/ia64/kernel/topology.c
arch/ia64/kernel/unaligned.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/kernel/xp_nofault.S
arch/mips/Kconfig
arch/mips/au1000/common/pci.c
arch/mips/cobalt/console.c
arch/mips/kernel/head.S
arch/mips/kernel/i8259.c
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/setup.c
arch/mips/kernel/time.c
arch/mips/lasat/image/Makefile
arch/mips/mips-boards/generic/memory.c
arch/mips/mips-boards/generic/reset.c
arch/mips/mips-boards/malta/malta_setup.c
arch/mips/mm/dma-default.c
arch/mips/pci/fixup-cobalt.c
arch/mips/pci/ops-au1000.c
arch/mips/pci/ops-mace.c
arch/mips/pci/pci-ip32.c
arch/mips/philips/pnx8550/common/time.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sgi-ip32/ip32-platform.c
arch/mips/tx4938/toshiba_rbtx4938/setup.c
arch/powerpc/boot/flatdevtree_env.h
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/mm/slb.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/power.c
arch/powerpc/platforms/pseries/rtasd.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/ppc/kernel/ppc_htab.c
arch/ppc/syslib/ipic.c
arch/ppc/syslib/open_pic.c
arch/ppc/syslib/open_pic2.c
arch/s390/Kconfig
arch/s390/crypto/Kconfig [deleted file]
arch/s390/crypto/aes_s390.c
arch/s390/crypto/prng.c
arch/s390/hypfs/inode.c
arch/s390/kernel/Makefile
arch/s390/kernel/early.c
arch/s390/kernel/head64.S
arch/s390/kernel/ipl.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/kernel/traps.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/lib/spinlock.c
arch/s390/mm/extmem.c
arch/s390/mm/vmem.c
arch/sh/drivers/dma/dma-sysfs.c
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/time.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/time.c
arch/sparc64/kernel/ktlb.S
arch/sparc64/kernel/pci_fire.c
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/pci_schizo.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/sun4v_tlb_miss.S
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/vio.c
arch/x86/crypto/Makefile
arch/x86/crypto/aes-i586-asm_32.S
arch/x86/crypto/aes-x86_64-asm_64.S
arch/x86/crypto/aes_32.c [deleted file]
arch/x86/crypto/aes_64.c [deleted file]
arch/x86/crypto/aes_glue.c [new file with mode: 0644]
arch/x86/crypto/salsa20-i586-asm_32.S [new file with mode: 0644]
arch/x86/crypto/salsa20-x86_64-asm_64.S [new file with mode: 0644]
arch/x86/crypto/salsa20_glue.c [new file with mode: 0644]
arch/x86/crypto/twofish_32.c [deleted file]
arch/x86/crypto/twofish_64.c [deleted file]
arch/x86/crypto/twofish_glue.c [new file with mode: 0644]
arch/x86/kernel/apic_32.c
arch/x86/kernel/apic_64.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce_64.c
arch/x86/kernel/cpu/mcheck/mce_amd_64.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_32.S
arch/x86/kernel/hpet.c
arch/x86/kernel/i8237.c
arch/x86/kernel/i8259_32.c
arch/x86/kernel/i8259_64.c
arch/x86/kernel/io_apic_32.c
arch/x86/kernel/io_apic_64.c
arch/x86/kernel/mfgpt_32.c
arch/x86/kernel/microcode.c
arch/x86/kernel/msr.c
arch/x86/kernel/nmi_32.c
arch/x86/kernel/nmi_64.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/signal_32.c
arch/x86/kernel/signal_64.c
arch/x86/kernel/smpboot_64.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/traps_32.c
arch/x86/kernel/traps_64.c
arch/x86/mm/init_32.c
arch/x86/oprofile/nmi_int.c
arch/x86/xen/enlighten.c
block/blktrace.c
block/bsg.c
block/elevator.c
block/genhd.c
block/ll_rw_blk.c
crypto/Kconfig
crypto/Makefile
crypto/ablkcipher.c
crypto/aead.c
crypto/aes_generic.c
crypto/algapi.c
crypto/api.c
crypto/authenc.c
crypto/blkcipher.c
crypto/camellia.c
crypto/cast6.c
crypto/cbc.c
crypto/ccm.c [new file with mode: 0644]
crypto/chainiv.c [new file with mode: 0644]
crypto/cryptd.c
crypto/crypto_null.c
crypto/ctr.c [new file with mode: 0644]
crypto/des_generic.c
crypto/digest.c
crypto/eseqiv.c [new file with mode: 0644]
crypto/gcm.c [new file with mode: 0644]
crypto/hmac.c
crypto/internal.h
crypto/lzo.c [new file with mode: 0644]
crypto/pcbc.c
crypto/salsa20_generic.c [new file with mode: 0644]
crypto/scatterwalk.c
crypto/scatterwalk.h [deleted file]
crypto/seqiv.c [new file with mode: 0644]
crypto/sha256_generic.c
crypto/tcrypt.c
crypto/tcrypt.h
crypto/twofish_common.c
crypto/xcbc.c
drivers/acpi/Kconfig
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/blacklist.c
drivers/acpi/bus.c
drivers/acpi/ec.c
drivers/acpi/events/evregion.c
drivers/acpi/fan.c
drivers/acpi/osl.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_throttling.c
drivers/acpi/sbs.c
drivers/acpi/scan.c
drivers/acpi/system.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_acpi.c
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_icside.c
drivers/ata/pata_it821x.c
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_legacy.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_ninja32.c [new file with mode: 0644]
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_qdi.c
drivers/ata/pata_scc.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_via.c
drivers/ata/pata_winbond.c
drivers/ata/pdc_adma.c
drivers/ata/sata_fsl.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_promise.h
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sil24.c
drivers/ata/sata_sx4.c
drivers/atm/idt77105.c
drivers/atm/nicstar.c
drivers/atm/suni.c
drivers/base/Makefile
drivers/base/attribute_container.c
drivers/base/base.h
drivers/base/bus.c
drivers/base/class.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/driver.c
drivers/base/firmware.c
drivers/base/hypervisor.c
drivers/base/init.c
drivers/base/memory.c
drivers/base/module.c [new file with mode: 0644]
drivers/base/node.c
drivers/base/platform.c
drivers/base/power/Makefile
drivers/base/power/main.c
drivers/base/power/power.h
drivers/base/power/shutdown.c [deleted file]
drivers/base/sys.c
drivers/block/aoe/aoeblk.c
drivers/block/aoe/aoechr.c
drivers/block/cciss.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/paride/pg.c
drivers/block/paride/pt.c
drivers/block/pktcdvd.c
drivers/bluetooth/hci_ll.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/intel-agp.c
drivers/char/drm/drm_pciids.h
drivers/char/hvc_console.c
drivers/char/hvcs.c
drivers/char/hw_random/amd-rng.c
drivers/char/hw_random/core.c
drivers/char/hw_random/geode-rng.c
drivers/char/hw_random/intel-rng.c
drivers/char/hw_random/omap-rng.c
drivers/char/hw_random/pasemi-rng.c
drivers/char/hw_random/via-rng.c
drivers/char/nozomi.c [new file with mode: 0644]
drivers/char/tpm/tpm.c
drivers/char/tty_ioctl.c
drivers/connector/cn_queue.c
drivers/connector/connector.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpuidle/sysfs.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/geode-aes.c
drivers/crypto/geode-aes.h
drivers/crypto/hifn_795x.c [new file with mode: 0644]
drivers/crypto/padlock-aes.c
drivers/dma/dmaengine.c
drivers/edac/edac_device_sysfs.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_module.c
drivers/edac/edac_pci_sysfs.c
drivers/firewire/fw-sbp2.c
drivers/firmware/dmi-id.c
drivers/firmware/dmi_scan.c
drivers/firmware/edd.c
drivers/firmware/efivars.c
drivers/hwmon/it87.c
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-sibyte.c
drivers/i2c/chips/isp1301_omap.c
drivers/i2c/i2c-dev.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/arm/Makefile
drivers/ide/arm/bast-ide.c
drivers/ide/arm/icside.c
drivers/ide/arm/ide_arm.c
drivers/ide/arm/rapide.c
drivers/ide/cris/Makefile
drivers/ide/cris/ide-cris.c
drivers/ide/h8300/Makefile [new file with mode: 0644]
drivers/ide/h8300/ide-h8300.c
drivers/ide/ide-acpi.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-floppy.c
drivers/ide/ide-generic.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-pnp.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-scan-pci.c [new file with mode: 0644]
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide.c
drivers/ide/legacy/Makefile
drivers/ide/legacy/ali14xx.c
drivers/ide/legacy/buddha.c
drivers/ide/legacy/dtc2278.c
drivers/ide/legacy/falconide.c
drivers/ide/legacy/gayle.c
drivers/ide/legacy/ht6560b.c
drivers/ide/legacy/ide-cs.c
drivers/ide/legacy/ide_platform.c
drivers/ide/legacy/macide.c
drivers/ide/legacy/q40ide.c
drivers/ide/legacy/qd65xx.c
drivers/ide/legacy/umc8672.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/mips/swarm.c
drivers/ide/pci/Makefile
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd640.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5520.c
drivers/ide/pci/cs5530.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/cy82c693.c
drivers/ide/pci/delkin_cb.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/triflex.c
drivers/ide/pci/trm290.c
drivers/ide/pci/via82cxxx.c
drivers/ide/ppc/Makefile [new file with mode: 0644]
drivers/ide/ppc/mpc8xx.c
drivers/ide/ppc/pmac.c
drivers/ide/setup-pci.c
drivers/ieee1394/nodemgr.c
drivers/ieee1394/sbp2.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/fmr_pool.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/mad_priv.h
drivers/infiniband/core/mad_rmpp.c
drivers/infiniband/core/multicast.c
drivers/infiniband/core/smi.h
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucm.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/hw/cxgb3/cxio_hal.c
drivers/infiniband/hw/cxgb3/cxio_wr.h
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/cxgb3/iwch_mem.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb3/iwch_qp.c
drivers/infiniband/hw/ehca/ehca_av.c
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_cq.c
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_qp.c
drivers/infiniband/hw/ehca/ehca_reqs.c
drivers/infiniband/hw/ehca/ehca_sqp.c
drivers/infiniband/hw/ipath/ipath_common.h
drivers/infiniband/hw/ipath/ipath_cq.c
drivers/infiniband/hw/ipath/ipath_debug.h
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_eeprom.c
drivers/infiniband/hw/ipath/ipath_file_ops.c
drivers/infiniband/hw/ipath/ipath_fs.c
drivers/infiniband/hw/ipath/ipath_iba6110.c
drivers/infiniband/hw/ipath/ipath_iba6120.c
drivers/infiniband/hw/ipath/ipath_init_chip.c
drivers/infiniband/hw/ipath/ipath_intr.c
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/ipath/ipath_keys.c
drivers/infiniband/hw/ipath/ipath_mad.c
drivers/infiniband/hw/ipath/ipath_qp.c
drivers/infiniband/hw/ipath/ipath_rc.c
drivers/infiniband/hw/ipath/ipath_registers.h
drivers/infiniband/hw/ipath/ipath_ruc.c
drivers/infiniband/hw/ipath/ipath_srq.c
drivers/infiniband/hw/ipath/ipath_stats.c
drivers/infiniband/hw/ipath/ipath_sysfs.c
drivers/infiniband/hw/ipath/ipath_ud.c
drivers/infiniband/hw/ipath/ipath_verbs.c
drivers/infiniband/hw/ipath/ipath_verbs.h
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_fs.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/iser/Kconfig
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/input/gameport/gameport.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/jornada680_kbd.c
drivers/input/keyboard/spitzkbd.c
drivers/input/misc/sparcspkr.c
drivers/input/mouse/alps.c
drivers/input/mouse/lifebook.c
drivers/input/mouse/psmouse-base.c
drivers/input/mousedev.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/usbtouchscreen.c
drivers/isdn/capi/capi.c
drivers/isdn/capi/capidrv.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/i4l/isdn_common.c
drivers/isdn/i4l/isdn_tty.c
drivers/kvm/kvm_main.c
drivers/leds/led-class.c
drivers/leds/led-core.c
drivers/leds/led-triggers.c
drivers/leds/leds-locomo.c
drivers/leds/leds.h
drivers/lguest/Kconfig
drivers/lguest/x86/core.c
drivers/macintosh/adb.c
drivers/macintosh/adbhid.c
drivers/macintosh/mediabay.c
drivers/macintosh/via-pmu.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid5.c
drivers/media/Kconfig
drivers/media/common/Kconfig
drivers/media/common/ir-functions.c
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/flexcop.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/bt8xx/bt878.h
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst_common.h
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/au6610.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/cxusb.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/digitv.h
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/gl861.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/gp8psk.h
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/opera1.h [deleted file]
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp702x.h
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/dvb-usb/vp7045.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/dib0070.c
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dibx000_common.h
drivers/media/dvb/frontends/mt2266.c
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/mt312.h
drivers/media/dvb/frontends/mt352.c
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/s5h1409.c
drivers/media/dvb/frontends/s5h1409.h
drivers/media/dvb/frontends/tda18271-common.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271-fe.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271-priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271-tables.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda827x.c
drivers/media/dvb/frontends/tda827x.h
drivers/media/dvb/frontends/ves1820.c
drivers/media/dvb/frontends/xc5000.c [new file with mode: 0644]
drivers/media/dvb/frontends/xc5000.h [new file with mode: 0644]
drivers/media/dvb/frontends/xc5000_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/frontends/zl10353.h
drivers/media/dvb/frontends/zl10353_priv.h
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_av.h
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c [new file with mode: 0644]
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt8xx/Kconfig
drivers/media/video/bt8xx/Makefile
drivers/media/video/bt8xx/bttv-audio-hook.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-audio-hook.h [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/bt8xx/bttv-vbi.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/cs5345.c [new file with mode: 0644]
drivers/media/video/cs53l32a.c
drivers/media/video/cx2341x.c
drivers/media/video/cx23885/Kconfig
drivers/media/video/cx23885/Makefile
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-reg.h
drivers/media/video/cx23885/cx23885-vbi.c [new file with mode: 0644]
drivers/media/video/cx23885/cx23885-video.c [new file with mode: 0644]
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-vbi.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/Makefile
drivers/media/video/em28xx/em28xx-audio.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/et61x251/et61x251_sensor.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/Kconfig
drivers/media/video/ivtv/Makefile
drivers/media/video/ivtv/ivtv-cards.c
drivers/media/video/ivtv/ivtv-cards.h
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-i2c.h
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-mailbox.c
drivers/media/video/ivtv/ivtv-mailbox.h
drivers/media/video/ivtv/ivtv-routing.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-version.h
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/ivtv/ivtv-yuv.h
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/m52790.c [new file with mode: 0644]
drivers/media/video/meye.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-kthreads.c
drivers/media/video/mt20xx.c
drivers/media/video/pvrusb2/Kconfig
drivers/media/video/pvrusb2/Makefile
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-context.c
drivers/media/video/pvrusb2/pvrusb2-context.h
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-debug.h
drivers/media/video/pvrusb2/pvrusb2-debugifc.c
drivers/media/video/pvrusb2/pvrusb2-devattr.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-devattr.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-eeprom.c
drivers/media/video/pvrusb2/pvrusb2-encoder.c
drivers/media/video/pvrusb2/pvrusb2-encoder.h
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-main.c
drivers/media/video/pvrusb2/pvrusb2-std.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-oss.c [deleted file]
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-vbi.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/sn9c102/Makefile
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/sn9c102/sn9c102_mt9v111.c [new file with mode: 0644]
drivers/media/video/stk-sensor.c [new file with mode: 0644]
drivers/media/video/stk-webcam.c [new file with mode: 0644]
drivers/media/video/stk-webcam.h [new file with mode: 0644]
drivers/media/video/tda7432.c
drivers/media/video/tda8290.c
drivers/media/video/tda8290.h
drivers/media/video/tda9875.c
drivers/media/video/tda9887.c
drivers/media/video/tda9887.h [new file with mode: 0644]
drivers/media/video/tea5761.c
drivers/media/video/tea5767.c
drivers/media/video/tea5767.h
drivers/media/video/tlv320aic23b.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-driver.h [deleted file]
drivers/media/video/tuner-i2c.h
drivers/media/video/tuner-simple.c
drivers/media/video/tuner-types.c
drivers/media/video/tuner-xc2028-types.h [new file with mode: 0644]
drivers/media/video/tuner-xc2028.c [new file with mode: 0644]
drivers/media/video/tuner-xc2028.h [new file with mode: 0644]
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvision/usbvision-cards.c
drivers/media/video/usbvision/usbvision-cards.h
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-int-device.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videobuf-dvb.c
drivers/media/video/videobuf-vmalloc.c
drivers/media/video/videodev.c
drivers/media/video/vivi.c
drivers/media/video/vp27smpx.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/media/video/zr364xx.c
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptscsih.c
drivers/message/i2o/i2o_scsi.c
drivers/mfd/ucb1x00-assabet.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00.h
drivers/misc/ibmasm/command.c
drivers/misc/ibmasm/ibmasm.h
drivers/misc/tifm_7xx1.c
drivers/misc/tifm_core.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/mtdchar.c
drivers/net/3c509.c
drivers/net/3c515.c
drivers/net/Kconfig
drivers/net/atl1/atl1_main.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/cassini.c
drivers/net/cassini.h
drivers/net/cpmac.c
drivers/net/dl2k.c
drivers/net/dl2k.h
drivers/net/e100.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/netdev.c
drivers/net/epic100.c
drivers/net/fec_8xx/fec_main.c
drivers/net/forcedeth.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/ibmveth.c
drivers/net/ipg.c
drivers/net/iseries_veth.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixp2000/ixpdev.c
drivers/net/loopback.c
drivers/net/macvlan.c
drivers/net/meth.c
drivers/net/mlx4/fw.c
drivers/net/myri10ge/myri10ge.c
drivers/net/natsemi.c
drivers/net/netx-eth.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/netxen/netxen_nic_niu.c
drivers/net/niu.c
drivers/net/niu.h
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcnet32.c
drivers/net/qla3xxx.c
drivers/net/r8169.c
drivers/net/s2io.c
drivers/net/sis190.c
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/tc35815.c
drivers/net/tulip/de4x5.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/tulip_core.c
drivers/net/tulip/xircom_cb.c
drivers/net/usb/asix.c
drivers/net/usb/kaweth.c
drivers/net/usb/mcs7830.c
drivers/net/veth.c
drivers/net/wan/cosa.c
drivers/net/wan/dscc4.c
drivers/net/wan/lmc/lmc_media.c
drivers/net/wan/sbni.h
drivers/net/wireless/Kconfig
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.h
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43/xmit.h
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwlwifi/iwl4965-base.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/xen-netfront.c
drivers/parisc/pdc_stable.c
drivers/pci/hotplug/acpiphp_ibm.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/rpadlpar_sysfs.c
drivers/pci/pci-driver.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pcmcia/ds.c
drivers/pnp/pnpacpi/rsparser.c
drivers/power/apm_power.c
drivers/power/power_supply_core.c
drivers/rtc/interface.c
drivers/s390/block/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3370_erp.c [deleted file]
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_9336_erp.c [deleted file]
drivers/s390/block/dasd_9343_erp.c [deleted file]
drivers/s390/block/dasd_alias.c [new file with mode: 0644]
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/dasd_proc.c
drivers/s390/block/dcssblk.c
drivers/s390/char/Makefile
drivers/s390/char/monwriter.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_chp.c [deleted file]
drivers/s390/char/sclp_cmd.c [new file with mode: 0644]
drivers/s390/char/sclp_config.c
drivers/s390/char/sclp_cpi.c
drivers/s390/char/sclp_cpi_sys.c [new file with mode: 0644]
drivers/s390/char/sclp_cpi_sys.h [new file with mode: 0644]
drivers/s390/char/sclp_info.c [deleted file]
drivers/s390/char/sclp_rw.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_core.c
drivers/s390/char/tape_proc.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/char/zcore.c
drivers/s390/cio/airq.c
drivers/s390/cio/airq.h [deleted file]
drivers/s390/cio/blacklist.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/cio.h
drivers/s390/cio/cio_debug.h
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_id.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/device_pgid.c
drivers/s390/cio/device_status.c
drivers/s390/cio/io_sch.h [new file with mode: 0644]
drivers/s390/cio/ioasm.h
drivers/s390/cio/qdio.c
drivers/s390/cio/qdio.h
drivers/s390/net/claw.c
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_proc.c
drivers/s390/net/smsgiucv.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs_driver.c
drivers/scsi/.gitignore
drivers/scsi/3w-9xxx.c
drivers/scsi/53c700.c
drivers/scsi/BusLogic.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/a2091.c
drivers/scsi/a3000.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/dpcsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/rx.c
drivers/scsi/advansys.c
drivers/scsi/aha152x.c
drivers/scsi/aha1542.c
drivers/scsi/aha1740.c
drivers/scsi/aic7xxx/Makefile
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/aic94xx/aic94xx_dev.c
drivers/scsi/aic94xx/aic94xx_dump.c
drivers/scsi/aic94xx/aic94xx_hwi.c
drivers/scsi/aic94xx/aic94xx_hwi.h
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/aic94xx/aic94xx_scb.c
drivers/scsi/aic94xx/aic94xx_sds.c
drivers/scsi/aic94xx/aic94xx_sds.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_task.c
drivers/scsi/aic94xx/aic94xx_tmf.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/atari_NCR5380.c
drivers/scsi/atp870u.c
drivers/scsi/ch.c
drivers/scsi/constants.c
drivers/scsi/dc395x.c
drivers/scsi/dpt_i2o.c
drivers/scsi/eata.c
drivers/scsi/eata_pio.c
drivers/scsi/fd_mcs.c
drivers/scsi/gdth.c
drivers/scsi/hosts.c
drivers/scsi/hptiop.c
drivers/scsi/hptiop.h
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/ide-scsi.c
drivers/scsi/imm.c
drivers/scsi/in2000.c
drivers/scsi/initio.c
drivers/scsi/ipr.c
drivers/scsi/ips.c
drivers/scsi/ips.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/iscsi_tcp.h
drivers/scsi/libiscsi.c
drivers/scsi/libsas/Kconfig
drivers/scsi/libsas/Makefile
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_host_smp.c [new file with mode: 0644]
drivers/scsi/libsas/sas_internal.h
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/libsas/sas_task.c [new file with mode: 0644]
drivers/scsi/libsrp.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_logmsg.h
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/lpfc/lpfc_vport.c
drivers/scsi/lpfc/lpfc_vport.h
drivers/scsi/megaraid.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/ncr53c8xx.c
drivers/scsi/pcmcia/Kconfig
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/ppa.c
drivers/scsi/psi240i.c [deleted file]
drivers/scsi/psi240i.h [deleted file]
drivers/scsi/psi_chip.h [deleted file]
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/Makefile
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_dfs.c [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_isr.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_netlink.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_tgt_if.c
drivers/scsi/scsi_tgt_lib.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/scsi_transport_srp.c
drivers/scsi/scsicam.c
drivers/scsi/sd.c
drivers/scsi/seagate.c [deleted file]
drivers/scsi/sg.c
drivers/scsi/sgiwd93.c
drivers/scsi/sr.c
drivers/scsi/sr.h
drivers/scsi/sr_ioctl.c
drivers/scsi/st.c
drivers/scsi/sun3_NCR5380.c
drivers/scsi/sym53c416.c
drivers/scsi/sym53c8xx_2/sym_glue.c
drivers/scsi/tmscsim.c
drivers/scsi/u14-34f.c
drivers/scsi/ultrastor.c
drivers/scsi/wd33c93.c
drivers/scsi/wd7000.c
drivers/serial/icom.c
drivers/serial/icom.h
drivers/spi/omap2_mcspi.c
drivers/spi/spi.c
drivers/spi/spi_bitbang.c
drivers/ssb/scan.c
drivers/uio/uio.c
drivers/usb/core/driver.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/pl2303.c
drivers/usb/storage/freecom.c
drivers/usb/storage/isd200.c
drivers/usb/storage/protocol.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/sddr09.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/transport.c
drivers/usb/storage/transport.h
drivers/video/atmel_lcdfb.c
drivers/video/console/Kconfig
drivers/video/modedb.c
drivers/video/ps3fb.c
drivers/video/s3c2410fb.c
drivers/video/uvesafb.c
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
drivers/watchdog/Kconfig
drivers/watchdog/w83697hf_wdt.c
fs/Kconfig
fs/binfmt_elf.c
fs/block_dev.c
fs/char_dev.c
fs/coda/psdev.c
fs/compat.c
fs/compat_ioctl.c
fs/configfs/dir.c
fs/configfs/file.c
fs/configfs/mount.c
fs/debugfs/inode.c
fs/dlm/lockspace.c
fs/ecryptfs/inode.c
fs/ecryptfs/main.c
fs/ecryptfs/super.c
fs/fat/fatent.c
fs/fs-writeback.c
fs/fuse/inode.c
fs/gfs2/Makefile
fs/gfs2/bmap.c
fs/gfs2/bmap.h
fs/gfs2/daemon.c
fs/gfs2/daemon.h
fs/gfs2/dir.c
fs/gfs2/eaops.c
fs/gfs2/eattr.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/locking/dlm/mount.c
fs/gfs2/locking/dlm/plock.c
fs/gfs2/locking/dlm/sysfs.c
fs/gfs2/locking/dlm/thread.c
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/gfs2/ops_address.c
fs/gfs2/ops_address.h
fs/gfs2/ops_file.c
fs/gfs2/ops_file.h [deleted file]
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/ops_inode.h
fs/gfs2/ops_super.c
fs/gfs2/ops_vm.c [deleted file]
fs/gfs2/ops_vm.h [deleted file]
fs/gfs2/quota.c
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/super.c
fs/gfs2/sys.c
fs/gfs2/trans.c
fs/gfs2/trans.h
fs/hfs/bfind.c
fs/hfs/brec.c
fs/hfs/btree.c
fs/hfs/hfs.h
fs/jbd/transaction.c
fs/jfs/jfs_dtree.c
fs/jfs/jfs_dtree.h
fs/jfs/jfs_imap.c
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_metapage.c
fs/jfs/jfs_mount.c
fs/jfs/jfs_umount.c
fs/jfs/namei.c
fs/jfs/resize.c
fs/jfs/super.c
fs/namei.c
fs/namespace.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4renewd.c
fs/nfs/nfs4state.c
fs/nfs/super.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfsxdr.c
fs/ocfs2/Makefile
fs/ocfs2/alloc.c
fs/ocfs2/aops.c
fs/ocfs2/buffer_head_io.c
fs/ocfs2/buffer_head_io.h
fs/ocfs2/cluster/heartbeat.h
fs/ocfs2/cluster/masklog.c
fs/ocfs2/cluster/sys.c
fs/ocfs2/cluster/tcp.h
fs/ocfs2/cluster/tcp_internal.h
fs/ocfs2/cluster/ver.c
fs/ocfs2/dcache.c
fs/ocfs2/dir.c
fs/ocfs2/dlm/dlmfsver.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlm/dlmver.c
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/endian.h
fs/ocfs2/export.c
fs/ocfs2/file.c
fs/ocfs2/file.h
fs/ocfs2/heartbeat.c
fs/ocfs2/heartbeat.h
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/ioctl.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/localalloc.c
fs/ocfs2/locks.c [new file with mode: 0644]
fs/ocfs2/locks.h [new file with mode: 0644]
fs/ocfs2/mmap.c
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/ocfs2_lockid.h
fs/ocfs2/resize.c [new file with mode: 0644]
fs/ocfs2/resize.h [new file with mode: 0644]
fs/ocfs2/slot_map.c
fs/ocfs2/slot_map.h
fs/ocfs2/suballoc.c
fs/ocfs2/suballoc.h
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/ocfs2/ver.c
fs/ocfs2/vote.c [deleted file]
fs/ocfs2/vote.h [deleted file]
fs/openpromfs/inode.c
fs/partitions/check.c
fs/proc/array.c
fs/proc/base.c
fs/proc/internal.h
fs/proc/proc_misc.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/read_write.c
fs/splice.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/group.c
fs/sysfs/symlink.c
fs/xfs/linux-2.6/xfs_file.c
include/acpi/acpi_bus.h
include/asm-arm/arch-pxa/hardware.h
include/asm-arm/system.h
include/asm-avr32/arch-at32ap/at32ap7000.h [deleted file]
include/asm-avr32/arch-at32ap/at32ap700x.h [new file with mode: 0644]
include/asm-avr32/arch-at32ap/cpu.h
include/asm-avr32/arch-at32ap/io.h
include/asm-avr32/irq.h
include/asm-avr32/kdebug.h
include/asm-avr32/ocd.h
include/asm-avr32/processor.h
include/asm-avr32/ptrace.h
include/asm-avr32/thread_info.h
include/asm-cris/arch-v10/ide.h
include/asm-cris/arch-v32/ide.h
include/asm-cris/page.h
include/asm-cris/unistd.h
include/asm-frv/ide.h
include/asm-generic/resource.h
include/asm-ia64/sn/xpc.h
include/asm-mips/cacheops.h
include/asm-mips/smtc_ipi.h
include/asm-powerpc/ide.h
include/asm-s390/airq.h [new file with mode: 0644]
include/asm-s390/cio.h
include/asm-s390/dasd.h
include/asm-s390/ipl.h
include/asm-s390/mmu_context.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/ptrace.h
include/asm-s390/qdio.h
include/asm-s390/rwsem.h
include/asm-s390/sclp.h
include/asm-s390/smp.h
include/asm-s390/spinlock.h
include/asm-s390/spinlock_types.h
include/asm-s390/tlbflush.h
include/asm-s390/zcrypt.h
include/asm-sh/cacheflush.h
include/asm-sh/uaccess.h
include/asm-x86/byteorder.h
include/asm-x86/msr.h
include/asm-x86/thread_info_32.h
include/asm-x86/thread_info_64.h
include/crypto/aead.h [new file with mode: 0644]
include/crypto/aes.h [new file with mode: 0644]
include/crypto/algapi.h
include/crypto/authenc.h [new file with mode: 0644]
include/crypto/ctr.h [new file with mode: 0644]
include/crypto/des.h [new file with mode: 0644]
include/crypto/internal/aead.h [new file with mode: 0644]
include/crypto/internal/skcipher.h [new file with mode: 0644]
include/crypto/scatterwalk.h [new file with mode: 0644]
include/crypto/sha.h
include/crypto/skcipher.h [new file with mode: 0644]
include/linux/Kbuild
include/linux/acpi.h
include/linux/ata.h
include/linux/attribute_container.h
include/linux/blkdev.h
include/linux/cdrom.h
include/linux/cpu.h
include/linux/cpumask.h
include/linux/crypto.h
include/linux/debug_locks.h
include/linux/device.h
include/linux/dlm.h
include/linux/dlmconstants.h [new file with mode: 0644]
include/linux/dmaengine.h
include/linux/dmi.h
include/linux/fs.h
include/linux/futex.h
include/linux/genhd.h
include/linux/hardirq.h
include/linux/hdreg.h
include/linux/hrtimer.h
include/linux/hw_random.h
include/linux/i2c-id.h
include/linux/ide.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/jiffies.h
include/linux/kernel.h
include/linux/key.h
include/linux/kobject.h
include/linux/kref.h
include/linux/latencytop.h [new file with mode: 0644]
include/linux/libata.h
include/linux/mm.h
include/linux/module.h
include/linux/netdevice.h
include/linux/notifier.h
include/linux/pci_hotplug.h
include/linux/pci_ids.h
include/linux/pktcdvd.h
include/linux/platform_device.h
include/linux/pm.h
include/linux/pm_legacy.h
include/linux/pnp.h
include/linux/ptrace.h
include/linux/rcuclassic.h [new file with mode: 0644]
include/linux/rcupdate.h
include/linux/rcupreempt.h [new file with mode: 0644]
include/linux/rcupreempt_trace.h [new file with mode: 0644]
include/linux/scatterlist.h
include/linux/sched.h
include/linux/security.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/smp_lock.h
include/linux/stacktrace.h
include/linux/sysdev.h
include/linux/sysfs.h
include/linux/tifm.h
include/linux/topology.h
include/linux/tty.h
include/linux/uio_driver.h
include/linux/workqueue.h
include/linux/writeback.h
include/media/cs5345.h [new file with mode: 0644]
include/media/cx2341x.h
include/media/cx25840.h
include/media/ir-common.h
include/media/m52790.h [new file with mode: 0644]
include/media/saa7146_vv.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-i2c-drv-legacy.h [new file with mode: 0644]
include/media/v4l2-i2c-drv.h [new file with mode: 0644]
include/media/v4l2-int-device.h
include/media/videobuf-core.h
include/net/if_inet6.h
include/net/ip.h
include/net/sch_generic.h
include/net/sctp/user.h
include/net/sock.h
include/net/xfrm.h
include/rdma/ib_mad.h
include/rdma/ib_verbs.h
include/rdma/rdma_user_cm.h
include/scsi/iscsi_if.h
include/scsi/iscsi_proto.h
include/scsi/libiscsi.h
include/scsi/libsas.h
include/scsi/sas.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_device.h
include/scsi/scsi_transport_iscsi.h
include/scsi/scsi_transport_sas.h
include/scsi/sd.h
init/Kconfig
init/do_mounts.c
init/main.c
kernel/Kconfig.hz
kernel/Kconfig.preempt
kernel/Makefile
kernel/acct.c
kernel/cpu.c
kernel/cpuset.c
kernel/fork.c
kernel/futex.c
kernel/hrtimer.c
kernel/kexec.c
kernel/kmod.c
kernel/ksysfs.c
kernel/kthread.c
kernel/latencytop.c [new file with mode: 0644]
kernel/lockdep.c
kernel/module.c
kernel/params.c
kernel/posix-cpu-timers.c
kernel/power/disk.c
kernel/power/main.c
kernel/power/pm.c
kernel/power/power.h
kernel/printk.c
kernel/profile.c
kernel/ptrace.c
kernel/rcuclassic.c [new file with mode: 0644]
kernel/rcupdate.c
kernel/rcupreempt.c [new file with mode: 0644]
kernel/rcupreempt_trace.c [new file with mode: 0644]
kernel/rcutorture.c
kernel/rtmutex-tester.c
kernel/sched.c
kernel/sched_debug.c
kernel/sched_fair.c
kernel/sched_idletask.c
kernel/sched_rt.c
kernel/softlockup.c
kernel/stop_machine.c
kernel/sysctl.c
kernel/sysctl_check.c
kernel/time/clocksource.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/timer.c
kernel/user.c
kernel/workqueue.c
lib/Kconfig.debug
lib/kernel_lock.c
lib/kobject.c
lib/kobject_uevent.c
lib/kref.c
mm/filemap_xip.c
mm/hugetlb.c
mm/memory.c
mm/mmap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/quicklist.c
mm/slab.c
mm/slub.c
net/802/tr.c
net/8021q/vlan.c
net/atm/mpc.c
net/ax25/af_ax25.c
net/bluetooth/hci_sysfs.c
net/bluetooth/rfcomm/tty.c
net/bridge/br_if.c
net/bridge/br_netfilter.c
net/bridge/br_private.h
net/bridge/br_sysfs_br.c
net/bridge/br_sysfs_if.c
net/core/dev.c
net/core/flow.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/skbuff.c
net/decnet/dn_route.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/fib_hash.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/inet_lro.c
net/ipv4/ip_output.c
net/ipv4/ipconfig.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv6/datagram.c
net/ipv6/icmp.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_output.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6t_eui64.c
net/ipv6/proc.c
net/ipv6/route.c
net/irda/af_irda.c
net/key/af_key.c
net/mac80211/ieee80211_ioctl.c
net/mac80211/rx.c
net/netfilter/xt_helper.c
net/rfkill/rfkill.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/sctp/ulpevent.c
net/sunrpc/auth_gss/auth_gss.c
net/x25/x25_forward.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
samples/Kconfig
samples/Makefile
samples/kobject/Makefile [new file with mode: 0644]
samples/kobject/kobject-example.c [new file with mode: 0644]
samples/kobject/kset-example.c [new file with mode: 0644]
security/commoncap.c
security/dummy.c
security/inode.c
security/keys/proc.c
security/security.c
security/selinux/hooks.c
security/selinux/include/objsec.h
security/selinux/netlabel.c
security/selinux/selinuxfs.c
security/selinux/ss/avtab.c
security/selinux/ss/mls.c
security/selinux/ss/services.c
sound/core/oss/mixer_oss.c
sound/oss/Kconfig
sound/oss/msnd.h

index 4953bc258729bd641e3fbdf33bd6efe8368e7803..6a0ad4715e9fb4f3df5068b0feb1a29100ffa42f 100644 (file)
@@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
            procfs-guide.xml writing_usb_driver.xml \
            kernel-api.xml filesystems.xml lsm.xml usb.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
-           genericirq.xml s390-drivers.xml uio-howto.xml
+           genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml
 
 ###
 # The build process is as follows (targets):
index 254e769282a46ed98ca6b8ddd1e5935fca70c933..3d2f31b99dd9f081b2a3032d5551c153eb60ab0f 100644 (file)
 !Iinclude/asm-s390/ccwdev.h
 !Edrivers/s390/cio/device.c
 !Edrivers/s390/cio/device_ops.c
+!Edrivers/s390/cio/airq.c
     </sect1>
     <sect1 id="cmf">
      <title>The channel-measurement facility</title>
diff --git a/Documentation/DocBook/scsi.tmpl b/Documentation/DocBook/scsi.tmpl
new file mode 100644 (file)
index 0000000..f299ab1
--- /dev/null
@@ -0,0 +1,409 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="scsimid">
+  <bookinfo>
+    <title>SCSI Interfaces Guide</title>
+
+    <authorgroup>
+      <author>
+        <firstname>James</firstname>
+        <surname>Bottomley</surname>
+        <affiliation>
+          <address>
+            <email>James.Bottomley@steeleye.com</email>
+          </address>
+        </affiliation>
+      </author>
+
+      <author>
+        <firstname>Rob</firstname>
+        <surname>Landley</surname>
+        <affiliation>
+          <address>
+            <email>rob@landley.net</email>
+          </address>
+        </affiliation>
+      </author>
+
+    </authorgroup>
+
+    <copyright>
+      <year>2007</year>
+      <holder>Linux Foundation</holder>
+    </copyright>
+
+    <legalnotice>
+      <para>
+        This documentation is free software; you can redistribute
+        it and/or modify it under the terms of the GNU General Public
+        License version 2.
+      </para>
+
+      <para>
+        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.
+        For more details see the file COPYING in the source
+        distribution of Linux.
+      </para>
+    </legalnotice>
+  </bookinfo>
+
+  <toc></toc>
+
+  <chapter id="intro">
+    <title>Introduction</title>
+    <sect1 id="protocol_vs_bus">
+      <title>Protocol vs bus</title>
+      <para>
+        Once upon a time, the Small Computer Systems Interface defined both
+        a parallel I/O bus and a data protocol to connect a wide variety of
+        peripherals (disk drives, tape drives, modems, printers, scanners,
+        optical drives, test equipment, and medical devices) to a host
+        computer.
+      </para>
+      <para>
+        Although the old parallel (fast/wide/ultra) SCSI bus has largely
+        fallen out of use, the SCSI command set is more widely used than ever
+        to communicate with devices over a number of different busses.
+      </para>
+      <para>
+        The <ulink url='http://www.t10.org/scsi-3.htm'>SCSI protocol</ulink>
+        is a big-endian peer-to-peer packet based protocol.  SCSI commands
+        are 6, 10, 12, or 16 bytes long, often followed by an associated data
+        payload.
+      </para>
+      <para>
+        SCSI commands can be transported over just about any kind of bus, and
+        are the default protocol for storage devices attached to USB, SATA,
+        SAS, Fibre Channel, FireWire, and ATAPI devices.  SCSI packets are
+        also commonly exchanged over Infiniband,
+        <ulink url='http://i2o.shadowconnect.com/faq.php'>I20</ulink>, TCP/IP
+        (<ulink url='http://en.wikipedia.org/wiki/ISCSI'>iSCSI</ulink>), even
+        <ulink url='http://cyberelk.net/tim/parport/parscsi.html'>Parallel
+        ports</ulink>.
+      </para>
+    </sect1>
+    <sect1 id="subsystem_design">
+      <title>Design of the Linux SCSI subsystem</title>
+      <para>
+        The SCSI subsystem uses a three layer design, with upper, mid, and low
+        layers.  Every operation involving the SCSI subsystem (such as reading
+        a sector from a disk) uses one driver at each of the 3 levels: one
+        upper layer driver, one lower layer driver, and the SCSI midlayer.
+      </para>
+      <para>
+        The SCSI upper layer provides the interface between userspace and the
+        kernel, in the form of block and char device nodes for I/O and
+        ioctl().  The SCSI lower layer contains drivers for specific hardware
+        devices.
+      </para>
+      <para>
+        In between is the SCSI mid-layer, analogous to a network routing
+        layer such as the IPv4 stack.  The SCSI mid-layer routes a packet
+        based data protocol between the upper layer's /dev nodes and the
+        corresponding devices in the lower layer.  It manages command queues,
+        provides error handling and power management functions, and responds
+        to ioctl() requests.
+      </para>
+    </sect1>
+  </chapter>
+
+  <chapter id="upper_layer">
+    <title>SCSI upper layer</title>
+    <para>
+      The upper layer supports the user-kernel interface by providing
+      device nodes.
+    </para>
+    <sect1 id="sd">
+      <title>sd (SCSI Disk)</title>
+      <para>sd (sd_mod.o)</para>
+<!-- !Idrivers/scsi/sd.c -->
+    </sect1>
+    <sect1 id="sr">
+      <title>sr (SCSI CD-ROM)</title>
+      <para>sr (sr_mod.o)</para>
+    </sect1>
+    <sect1 id="st">
+      <title>st (SCSI Tape)</title>
+      <para>st (st.o)</para>
+    </sect1>
+    <sect1 id="sg">
+      <title>sg (SCSI Generic)</title>
+      <para>sg (sg.o)</para>
+    </sect1>
+    <sect1 id="ch">
+      <title>ch (SCSI Media Changer)</title>
+      <para>ch (ch.c)</para>
+    </sect1>
+  </chapter>
+
+  <chapter id="mid_layer">
+    <title>SCSI mid layer</title>
+
+    <sect1 id="midlayer_implementation">
+      <title>SCSI midlayer implementation</title>
+      <sect2 id="scsi_device.h">
+        <title>include/scsi/scsi_device.h</title>
+        <para>
+        </para>
+!Iinclude/scsi/scsi_device.h
+      </sect2>
+
+      <sect2 id="scsi.c">
+        <title>drivers/scsi/scsi.c</title>
+        <para>Main file for the SCSI midlayer.</para>
+!Edrivers/scsi/scsi.c
+      </sect2>
+      <sect2 id="scsicam.c">
+        <title>drivers/scsi/scsicam.c</title>
+        <para>
+          <ulink url='http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf'>SCSI
+          Common Access Method</ulink> support functions, for use with
+          HDIO_GETGEO, etc.
+        </para>
+!Edrivers/scsi/scsicam.c
+      </sect2>
+      <sect2 id="scsi_error.c">
+        <title>drivers/scsi/scsi_error.c</title>
+        <para>Common SCSI error/timeout handling routines.</para>
+!Edrivers/scsi/scsi_error.c
+      </sect2>
+      <sect2 id="scsi_devinfo.c">
+        <title>drivers/scsi/scsi_devinfo.c</title>
+        <para>
+          Manage scsi_dev_info_list, which tracks blacklisted and whitelisted
+          devices.
+        </para>
+!Idrivers/scsi/scsi_devinfo.c
+      </sect2>
+      <sect2 id="scsi_ioctl.c">
+        <title>drivers/scsi/scsi_ioctl.c</title>
+        <para>
+          Handle ioctl() calls for SCSI devices.
+        </para>
+!Edrivers/scsi/scsi_ioctl.c
+      </sect2>
+      <sect2 id="scsi_lib.c">
+        <title>drivers/scsi/scsi_lib.c</title>
+        <para>
+          SCSI queuing library.
+        </para>
+!Edrivers/scsi/scsi_lib.c
+      </sect2>
+      <sect2 id="scsi_lib_dma.c">
+        <title>drivers/scsi/scsi_lib_dma.c</title>
+        <para>
+          SCSI library functions depending on DMA
+          (map and unmap scatter-gather lists).
+        </para>
+!Edrivers/scsi/scsi_lib_dma.c
+      </sect2>
+      <sect2 id="scsi_module.c">
+        <title>drivers/scsi/scsi_module.c</title>
+        <para>
+          The file drivers/scsi/scsi_module.c contains legacy support for
+          old-style host templates.  It should never be used by any new driver.
+        </para>
+      </sect2>
+      <sect2 id="scsi_proc.c">
+        <title>drivers/scsi/scsi_proc.c</title>
+        <para>
+          The functions in this file provide an interface between
+          the PROC file system and the SCSI device drivers
+          It is mainly used for debugging, statistics and to pass
+          information directly to the lowlevel driver.
+
+          I.E. plumbing to manage /proc/scsi/*
+        </para>
+!Idrivers/scsi/scsi_proc.c
+      </sect2>
+      <sect2 id="scsi_netlink.c">
+        <title>drivers/scsi/scsi_netlink.c</title>
+        <para>
+          Infrastructure to provide async events from transports to userspace
+          via netlink, using a single NETLINK_SCSITRANSPORT protocol for all
+          transports.
+
+          See <ulink url='http://marc.info/?l=linux-scsi&amp;m=115507374832500&amp;w=2'>the
+          original patch submission</ulink> for more details.
+        </para>
+!Idrivers/scsi/scsi_netlink.c
+      </sect2>
+      <sect2 id="scsi_scan.c">
+        <title>drivers/scsi/scsi_scan.c</title>
+        <para>
+          Scan a host to determine which (if any) devices are attached.
+
+          The general scanning/probing algorithm is as follows, exceptions are
+          made to it depending on device specific flags, compilation options,
+          and global variable (boot or module load time) settings.
+
+          A specific LUN is scanned via an INQUIRY command; if the LUN has a
+          device attached, a scsi_device is allocated and setup for it.
+
+          For every id of every channel on the given host, start by scanning
+          LUN 0.  Skip hosts that don't respond at all to a scan of LUN 0.
+          Otherwise, if LUN 0 has a device attached, allocate and setup a
+          scsi_device for it.  If target is SCSI-3 or up, issue a REPORT LUN,
+          and scan all of the LUNs returned by the REPORT LUN; else,
+          sequentially scan LUNs up until some maximum is reached, or a LUN is
+          seen that cannot have a device attached to it.
+        </para>
+!Idrivers/scsi/scsi_scan.c
+      </sect2>
+      <sect2 id="scsi_sysctl.c">
+        <title>drivers/scsi/scsi_sysctl.c</title>
+        <para>
+          Set up the sysctl entry: "/dev/scsi/logging_level"
+          (DEV_SCSI_LOGGING_LEVEL) which sets/returns scsi_logging_level.
+        </para>
+      </sect2>
+      <sect2 id="scsi_sysfs.c">
+        <title>drivers/scsi/scsi_sysfs.c</title>
+        <para>
+          SCSI sysfs interface routines.
+        </para>
+!Edrivers/scsi/scsi_sysfs.c
+      </sect2>
+      <sect2 id="hosts.c">
+        <title>drivers/scsi/hosts.c</title>
+        <para>
+          mid to lowlevel SCSI driver interface
+        </para>
+!Edrivers/scsi/hosts.c
+      </sect2>
+      <sect2 id="constants.c">
+        <title>drivers/scsi/constants.c</title>
+        <para>
+          mid to lowlevel SCSI driver interface
+        </para>
+!Edrivers/scsi/constants.c
+      </sect2>
+    </sect1>
+
+    <sect1 id="Transport_classes">
+      <title>Transport classes</title>
+      <para>
+        Transport classes are service libraries for drivers in the SCSI
+        lower layer, which expose transport attributes in sysfs.
+      </para>
+      <sect2 id="Fibre_Channel_transport">
+        <title>Fibre Channel transport</title>
+        <para>
+          The file drivers/scsi/scsi_transport_fc.c defines transport attributes
+          for Fibre Channel.
+        </para>
+!Edrivers/scsi/scsi_transport_fc.c
+      </sect2>
+      <sect2 id="iSCSI_transport">
+        <title>iSCSI transport class</title>
+        <para>
+          The file drivers/scsi/scsi_transport_iscsi.c defines transport
+          attributes for the iSCSI class, which sends SCSI packets over TCP/IP
+          connections.
+        </para>
+!Edrivers/scsi/scsi_transport_iscsi.c
+      </sect2>
+      <sect2 id="SAS_transport">
+        <title>Serial Attached SCSI (SAS) transport class</title>
+        <para>
+          The file drivers/scsi/scsi_transport_sas.c defines transport
+          attributes for Serial Attached SCSI, a variant of SATA aimed at
+          large high-end systems.
+        </para>
+        <para>
+          The SAS transport class contains common code to deal with SAS HBAs,
+          an aproximated representation of SAS topologies in the driver model,
+          and various sysfs attributes to expose these topologies and managment
+          interfaces to userspace.
+        </para>
+        <para>
+          In addition to the basic SCSI core objects this transport class
+          introduces two additional intermediate objects:  The SAS PHY
+          as represented by struct sas_phy defines an "outgoing" PHY on
+          a SAS HBA or Expander, and the SAS remote PHY represented by
+          struct sas_rphy defines an "incoming" PHY on a SAS Expander or
+          end device.  Note that this is purely a software concept, the
+          underlying hardware for a PHY and a remote PHY is the exactly
+          the same.
+        </para>
+        <para>
+          There is no concept of a SAS port in this code, users can see
+          what PHYs form a wide port based on the port_identifier attribute,
+          which is the same for all PHYs in a port.
+        </para>
+!Edrivers/scsi/scsi_transport_sas.c
+      </sect2>
+      <sect2 id="SATA_transport">
+        <title>SATA transport class</title>
+        <para>
+          The SATA transport is handled by libata, which has its own book of
+          documentation in this directory.
+        </para>
+      </sect2>
+      <sect2 id="SPI_transport">
+        <title>Parallel SCSI (SPI) transport class</title>
+        <para>
+          The file drivers/scsi/scsi_transport_spi.c defines transport
+          attributes for traditional (fast/wide/ultra) SCSI busses.
+        </para>
+!Edrivers/scsi/scsi_transport_spi.c
+      </sect2>
+      <sect2 id="SRP_transport">
+        <title>SCSI RDMA (SRP) transport class</title>
+        <para>
+          The file drivers/scsi/scsi_transport_srp.c defines transport
+          attributes for SCSI over Remote Direct Memory Access.
+        </para>
+!Edrivers/scsi/scsi_transport_srp.c
+      </sect2>
+    </sect1>
+
+  </chapter>
+
+  <chapter id="lower_layer">
+    <title>SCSI lower layer</title>
+    <sect1 id="hba_drivers">
+      <title>Host Bus Adapter transport types</title>
+      <para>
+        Many modern device controllers use the SCSI command set as a protocol to
+        communicate with their devices through many different types of physical
+        connections.
+      </para>
+      <para>
+        In SCSI language a bus capable of carrying SCSI commands is
+        called a "transport", and a controller connecting to such a bus is
+        called a "host bus adapter" (HBA).
+      </para>
+      <sect2 id="scsi_debug.c">
+        <title>Debug transport</title>
+        <para>
+          The file drivers/scsi/scsi_debug.c simulates a host adapter with a
+          variable number of disks (or disk like devices) attached, sharing a
+          common amount of RAM.  Does a lot of checking to make sure that we are
+          not getting blocks mixed up, and panics the kernel if anything out of
+          the ordinary is seen.
+        </para>
+        <para>
+          To be more realistic, the simulated devices have the transport
+          attributes of SAS disks.
+        </para>
+        <para>
+          For documentation see
+          <ulink url='http://www.torque.net/sg/sdebug26.html'>http://www.torque.net/sg/sdebug26.html</ulink>
+        </para>
+<!-- !Edrivers/scsi/scsi_debug.c -->
+      </sect2>
+      <sect2 id="todo">
+        <title>todo</title>
+        <para>Parallel (fast/wide/ultra) SCSI, USB, SATA,
+        SAS, Fibre Channel, FireWire, ATAPI devices, Infiniband,
+        I20, iSCSI, Parallel ports, netlink...
+        </para>
+      </sect2>
+    </sect1>
+  </chapter>
+</book>
index b629da33951d3945f619bf900862c163c43e849e..b3d93ee27693057e5ab5555049a0d9500e92b634 100644 (file)
@@ -96,7 +96,6 @@ static struct video_device my_radio
 {
         "My radio",
         VID_TYPE_TUNER,
-        VID_HARDWARE_MYRADIO,
         radio_open.
         radio_close,
         NULL,                /* no read */
@@ -118,13 +117,6 @@ static struct video_device my_radio
         indicates that the device can be tuned. Clearly our radio is going to have some
         way to change channel so it is tuneable.
   </para>
-  <para>
-        The VID_HARDWARE_ types are unique to each device. Numbers are assigned by
-        <email>alan@redhat.com</email> when device drivers are going to be released. Until then you
-        can pull a suitably large number out of your hat and use it. 10000 should be
-        safe for a very long time even allowing for the huge number of vendors
-        making new and different radio cards at the moment.
-  </para>
   <para>
         We declare an open and close routine, but we do not need read or write,
         which are used to read and write video data to or from the card itself. As
@@ -844,7 +836,6 @@ static struct video_device my_camera
         "My Camera",
         VID_TYPE_OVERLAY|VID_TYPE_SCALES|\
         VID_TYPE_CAPTURE|VID_TYPE_CHROMAKEY,
-        VID_HARDWARE_MYCAMERA,
         camera_open.
         camera_close,
         camera_read,      /* no read */
index 6221464d1a7e4a39539ba30fdf40b4b00279a60b..39ad8f56783a0faded737756afe6688bb6ae76be 100644 (file)
@@ -9,8 +9,8 @@ The first thing resembling RCU was published in 1980, when Kung and Lehman
 [Kung80] recommended use of a garbage collector to defer destruction
 of nodes in a parallel binary search tree in order to simplify its
 implementation.  This works well in environments that have garbage
-collectors, but current production garbage collectors incur significant
-read-side overhead.
+collectors, but most production garbage collectors incur significant
+overhead.
 
 In 1982, Manber and Ladner [Manber82,Manber84] recommended deferring
 destruction until all threads running at that time have terminated, again
@@ -99,16 +99,25 @@ locking, reduces contention, reduces memory latency for readers, and
 parallelizes pipeline stalls and memory latency for writers.  However,
 these techniques still impose significant read-side overhead in the
 form of memory barriers.  Researchers at Sun worked along similar lines
-in the same timeframe [HerlihyLM02,HerlihyLMS03].  These techniques
-can be thought of as inside-out reference counts, where the count is
-represented by the number of hazard pointers referencing a given data
-structure (rather than the more conventional counter field within the
-data structure itself).
+in the same timeframe [HerlihyLM02].  These techniques can be thought
+of as inside-out reference counts, where the count is represented by the
+number of hazard pointers referencing a given data structure (rather than
+the more conventional counter field within the data structure itself).
+
+By the same token, RCU can be thought of as a "bulk reference count",
+where some form of reference counter covers all reference by a given CPU
+or thread during a set timeframe.  This timeframe is related to, but
+not necessarily exactly the same as, an RCU grace period.  In classic
+RCU, the reference counter is the per-CPU bit in the "bitmask" field,
+and each such bit covers all references that might have been made by
+the corresponding CPU during the prior grace period.  Of course, RCU
+can be thought of in other terms as well.
 
 In 2003, the K42 group described how RCU could be used to create
-hot-pluggable implementations of operating-system functions.  Later that
-year saw a paper describing an RCU implementation of System V IPC
-[Arcangeli03], and an introduction to RCU in Linux Journal [McKenney03a].
+hot-pluggable implementations of operating-system functions [Appavoo03a].
+Later that year saw a paper describing an RCU implementation of System
+V IPC [Arcangeli03], and an introduction to RCU in Linux Journal
+[McKenney03a].
 
 2004 has seen a Linux-Journal article on use of RCU in dcache
 [McKenney04a], a performance comparison of locking to RCU on several
@@ -117,10 +126,19 @@ number of operating-system kernels [PaulEdwardMcKenneyPhD], a paper
 describing how to make RCU safe for soft-realtime applications [Sarma04c],
 and a paper describing SELinux performance with RCU [JamesMorris04b].
 
-2005 has seen further adaptation of RCU to realtime use, permitting
+2005 brought further adaptation of RCU to realtime use, permitting
 preemption of RCU realtime critical sections [PaulMcKenney05a,
 PaulMcKenney05b].
 
+2006 saw the first best-paper award for an RCU paper [ThomasEHart2006a],
+as well as further work on efficient implementations of preemptible
+RCU [PaulEMcKenney2006b], but priority-boosting of RCU read-side critical
+sections proved elusive.  An RCU implementation permitting general
+blocking in read-side critical sections appeared [PaulEMcKenney2006c],
+Robert Olsson described an RCU-protected trie-hash combination
+[RobertOlsson2006a].
+
+
 Bibtex Entries
 
 @article{Kung80
@@ -203,6 +221,41 @@ Bibtex Entries
 ,Address="New Orleans, LA"
 }
 
+@conference{Pu95a,
+Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and
+Crispin Cowan and Jon Inouye and Lakshmi Kethana and Jonathan Walpole and
+Ke Zhang",
+Title = "Optimistic Incremental Specialization: Streamlining a Commercial
+Operating System",
+Booktitle = "15\textsuperscript{th} ACM Symposium on
+Operating Systems Principles (SOSP'95)",
+address = "Copper Mountain, CO",
+month="December",
+year="1995",
+pages="314-321",
+annotation="
+       Uses a replugger, but with a flag to signal when people are
+       using the resource at hand.  Only one reader at a time.
+"
+}
+
+@conference{Cowan96a,
+Author = "Crispin Cowan and Tito Autrey and Charles Krasic and
+Calton Pu and Jonathan Walpole",
+Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System",
+Booktitle = "International Conference on Configurable Distributed Systems
+(ICCDS'96)",
+address = "Annapolis, MD",
+month="May",
+year="1996",
+pages="108",
+isbn="0-8186-7395-8",
+annotation="
+       Uses a replugger, but with a counter to signal when people are
+       using the resource at hand.  Allows multiple readers.
+"
+}
+
 @techreport{Slingwine95
 ,author="John D. Slingwine and Paul E. McKenney"
 ,title="Apparatus and Method for Achieving Reduced Overhead Mutual
@@ -312,6 +365,49 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 [Viewed June 23, 2004]"
 }
 
+@conference{Michael02a
+,author="Maged M. Michael"
+,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic
+Reads and Writes"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM
+Symposium on Principles of Distributed Computing}"
+,pages="21-30"
+,annotation="
+       Each thread keeps an array of pointers to items that it is
+       currently referencing.  Sort of an inside-out garbage collection
+       mechanism, but one that requires the accessing code to explicitly
+       state its needs.  Also requires read-side memory barriers on
+       most architectures.
+"
+}
+
+@conference{Michael02b
+,author="Maged M. Michael"
+,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM
+Symposium on Parallel
+Algorithms and Architecture}"
+,pages="73-82"
+,annotation="
+       Like the title says...
+"
+}
+
+@InProceedings{HerlihyLM02
+,author={Maurice Herlihy and Victor Luchangco and Mark Moir}
+,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized,
+Lock-Free Data Structures"
+,booktitle={Proceedings of 16\textsuperscript{th} International
+Symposium on Distributed Computing}
+,year=2002
+,month="October"
+,pages="339-353"
+}
+
 @article{Appavoo03a
 ,author="J. Appavoo and K. Hui and C. A. N. Soules and R. W. Wisniewski and
 D. M. {Da Silva} and O. Krieger and M. A. Auslander and D. J. Edelsohn and
@@ -447,3 +543,95 @@ Oregon Health and Sciences University"
        Realtime turns into making RCU yet more realtime friendly.
 "
 }
+
+@conference{ThomasEHart2006a
+,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown"
+,Title="Making Lockless Synchronization Fast: Performance Implications
+of Memory Reclamation"
+,Booktitle="20\textsuperscript{th} {IEEE} International Parallel and
+Distributed Processing Symposium"
+,month="April"
+,year="2006"
+,day="25-29"
+,address="Rhodes, Greece"
+,annotation="
+       Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free
+       reference counting.
+"
+}
+
+@Conference{PaulEMcKenney2006b
+,Author="Paul E. McKenney and Dipankar Sarma and Ingo Molnar and
+Suparna Bhattacharya"
+,Title="Extending RCU for Realtime and Embedded Workloads"
+,Booktitle="{Ottawa Linux Symposium}"
+,Month="July"
+,Year="2006"
+,pages="v2 123-138"
+,note="Available:
+\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
+\url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf}
+[Viewed January 1, 2007]"
+,annotation="
+       Described how to improve the -rt implementation of realtime RCU.
+"
+}
+
+@unpublished{PaulEMcKenney2006c
+,Author="Paul E. McKenney"
+,Title="Sleepable {RCU}"
+,month="October"
+,day="9"
+,year="2006"
+,note="Available:
+\url{http://lwn.net/Articles/202847/}
+Revised:
+\url{http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf}
+[Viewed August 21, 2006]"
+,annotation="
+       LWN article introducing SRCU.
+"
+}
+
+@unpublished{RobertOlsson2006a
+,Author="Robert Olsson and Stefan Nilsson"
+,Title="{TRASH}: A dynamic {LC}-trie and hash data structure"
+,month="August"
+,day="18"
+,year="2006"
+,note="Available:
+\url{http://www.nada.kth.se/~snilsson/public/papers/trash/trash.pdf}
+[Viewed February 24, 2007]"
+,annotation="
+       RCU-protected dynamic trie-hash combination.
+"
+}
+
+@unpublished{ThomasEHart2007a
+,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown and Jonathan Walpole"
+,Title="Performance of memory reclamation for lockless synchronization"
+,journal="J. Parallel Distrib. Comput."
+,year="2007"
+,note="To appear in J. Parallel Distrib. Comput.
+       \url{doi=10.1016/j.jpdc.2007.04.010}"
+,annotation={
+       Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free
+       reference counting.  Journal version of ThomasEHart2006a.
+}
+}
+
+@unpublished{PaulEMcKenney2007QRCUspin
+,Author="Paul E. McKenney"
+,Title="Using Promela and Spin to verify parallel algorithms"
+,month="August"
+,day="1"
+,year="2007"
+,note="Available:
+\url{http://lwn.net/Articles/243851/}
+[Viewed September 8, 2007]"
+,annotation="
+       LWN article describing Promela and spin, and also using Oleg
+       Nesterov's QRCU as an example (with Paul McKenney's fastpath).
+"
+}
+
index f84407cba8160a47ea57e46a640a54efafb905c5..95821a29ae418b6b275b01869fd40e29900baadf 100644 (file)
@@ -36,6 +36,14 @@ o    How can the updater tell when a grace period has completed
        executed in user mode, or executed in the idle loop, we can
        safely free up that item.
 
+       Preemptible variants of RCU (CONFIG_PREEMPT_RCU) get the
+       same effect, but require that the readers manipulate CPU-local
+       counters.  These counters allow limited types of blocking
+       within RCU read-side critical sections.  SRCU also uses
+       CPU-local counters, and permits general blocking within
+       RCU read-side critical sections.  These two variants of
+       RCU detect grace periods by sampling these counters.
+
 o      If I am running on a uniprocessor kernel, which can only do one
        thing at a time, why should I wait for a grace period?
 
@@ -46,7 +54,10 @@ o    How can I see where RCU is currently used in the Linux kernel?
        Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
        "rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
        "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
-       "synchronize_net", and "synchronize_srcu".
+       "synchronize_net", "synchronize_srcu", and the other RCU
+       primitives.  Or grab one of the cscope databases from:
+
+       http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html
 
 o      What guidelines should I follow when writing code that uses RCU?
 
@@ -67,7 +78,11 @@ o    I hear that RCU is patented?  What is with that?
 
 o      I hear that RCU needs work in order to support realtime kernels?
 
-       Yes, work in progress.
+       This work is largely completed.  Realtime-friendly RCU can be
+       enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter.
+       However, work is in progress for enabling priority boosting of
+       preempted RCU read-side critical sections.This is needed if you
+       have CPU-bound realtime threads.
 
 o      Where can I find more information on RCU?
 
index 25a3c3f7d378f344676652aec19fad62853fc6b1..2967a65269d8af7702dbe76f4780e14d91dd9061 100644 (file)
@@ -46,12 +46,13 @@ stat_interval       The number of seconds between output of torture
 
 shuffle_interval
                The number of seconds to keep the test threads affinitied
-               to a particular subset of the CPUs.  Used in conjunction
-               with test_no_idle_hz.
+               to a particular subset of the CPUs, defaults to 5 seconds.
+               Used in conjunction with test_no_idle_hz.
 
 test_no_idle_hz        Whether or not to test the ability of RCU to operate in
                a kernel that disables the scheduling-clock interrupt to
                idle CPUs.  Boolean parameter, "1" to test, "0" otherwise.
+               Defaults to omitting this test.
 
 torture_type   The type of RCU to test: "rcu" for the rcu_read_lock() API,
                "rcu_sync" for rcu_read_lock() with synchronous reclamation,
@@ -82,8 +83,6 @@ be evident.  ;-)
 
 The entries are as follows:
 
-o      "ggp": The number of counter flips (or batches) since boot.
-
 o      "rtc": The hexadecimal address of the structure currently visible
        to readers.
 
@@ -117,8 +116,8 @@ o   "Reader Pipe": Histogram of "ages" of structures seen by readers.
 o      "Reader Batch": Another histogram of "ages" of structures seen
        by readers, but in terms of counter flips (or batches) rather
        than in terms of grace periods.  The legal number of non-zero
-       entries is again two.  The reason for this separate view is
-       that it is easier to get the third entry to show up in the
+       entries is again two.  The reason for this separate view is that
+       it is sometimes easier to get the third entry to show up in the
        "Reader Batch" list than in the "Reader Pipe" list.
 
 o      "Free-Block Circulation": Shows the number of torture structures
index a741f658a3c9d7393c9693bb4486d30473438222..ba0aacde94fba2472d33ba9da5764a2b8cc5f63e 100644 (file)
@@ -50,7 +50,7 @@ additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets
                        cpu_possible_map = cpu_present_map + additional_cpus
 
 (*) Option valid only for following architectures
-- x86_64, ia64, s390
+- x86_64, ia64
 
 ia64 and x86_64 use the number of disabled local apics in ACPI tables MADT
 to determine the number of potentially hot-pluggable cpus. The implementation
@@ -109,12 +109,13 @@ Never use anything other than cpumask_t to represent bitmap of CPUs.
        for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
 
        #include <linux/cpu.h>
-       lock_cpu_hotplug() and unlock_cpu_hotplug():
+       get_online_cpus() and put_online_cpus():
 
-The above calls are used to inhibit cpu hotplug operations. While holding the
-cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid
-cpus going away, you could also use preempt_disable() and preempt_enable()
-for those sections. Just remember the critical section cannot call any
+The above calls are used to inhibit cpu hotplug operations. While the
+cpu_hotplug.refcount is non zero, the cpu_online_map will not change.
+If you merely need to avoid cpus going away, you could also use
+preempt_disable() and preempt_enable() for those sections.
+Just remember the critical section cannot call any
 function that can sleep or schedule this process away. The preempt_disable()
 will work as long as stop_machine_run() is used to take a cpu down.
 
index a2ac6d2947932022ddd8b6d906d13bd5882a0719..8b49302712a890365ff3edaa2571971608ccd381 100644 (file)
@@ -33,9 +33,16 @@ The idea is to make the user interface and algorithm registration API
 very simple, while hiding the core logic from both.  Many good ideas
 from existing APIs such as Cryptoapi and Nettle have been adapted for this.
 
-The API currently supports three types of transforms: Ciphers, Digests and
-Compressors.  The compression algorithms especially seem to be performing
-very well so far.
+The API currently supports five main types of transforms: AEAD (Authenticated
+Encryption with Associated Data), Block Ciphers, Ciphers, Compressors and
+Hashes.
+
+Please note that Block Ciphers is somewhat of a misnomer.  It is in fact
+meant to support all ciphers including stream ciphers.  The difference
+between Block Ciphers and Ciphers is that the latter operates on exactly
+one block while the former can operate on an arbitrary amount of data,
+subject to block size requirements (i.e., non-stream ciphers can only
+process multiples of blocks).
 
 Support for hardware crypto devices via an asynchronous interface is
 under development.
@@ -69,29 +76,12 @@ Here's an example of how to use the API:
 Many real examples are available in the regression test module (tcrypt.c).
 
 
-CONFIGURATION NOTES
-
-As Triple DES is part of the DES module, for those using modular builds,
-add the following line to /etc/modprobe.conf:
-
-  alias des3_ede des
-
-The Null algorithms reside in the crypto_null module, so these lines
-should also be added:
-
-  alias cipher_null crypto_null
-  alias digest_null crypto_null
-  alias compress_null crypto_null
-
-The SHA384 algorithm shares code within the SHA512 module, so you'll
-also need:
-  alias sha384 sha512
-
-
 DEVELOPER NOTES
 
 Transforms may only be allocated in user context, and cryptographic
-methods may only be called from softirq and user contexts.
+methods may only be called from softirq and user contexts.  For
+transforms with a setkey method it too should only be called from
+user context.
 
 When using the API for ciphers, performance will be optimal if each
 scatterlist contains data which is a multiple of the cipher's block
@@ -130,8 +120,9 @@ might already be working on.
 BUGS
 
 Send bug reports to:
-Herbert Xu <herbert@gondor.apana.org.au>
-Cc: David S. Miller <davem@redhat.com>
+linux-crypto@vger.kernel.org
+Cc: Herbert Xu <herbert@gondor.apana.org.au>,
+    David S. Miller <davem@redhat.com>
 
 
 FURTHER INFORMATION
index f2d658a6a942dff1cf79a0222105128299e723e2..c09a96b99354bf3fa9bbe17446b2e43d55213520 100644 (file)
@@ -46,8 +46,6 @@
 .mailmap
 .mm
 53c700_d.h
-53c7xx_d.h
-53c7xx_u.h
 53c8xx_d.h*
 BitKeeper
 COPYING
index ecb47adda0638b9ac4a79ddc7ae7537801edf24a..b7b1d1b1da469a527eb4940ce86b9834deb8a8ee 100644 (file)
@@ -78,6 +78,18 @@ Example:
 For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
 In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
 
+2c) Probing the cards with broken PCI subsystem ID
+--------------------------------------------------
+There are some TwinHan cards that the EEPROM has become corrupted for some
+reason. The cards do not have correct PCI subsystem ID. But we can force
+probing the cards with broken PCI subsystem ID
+
+       $ echo 109e 0878 $subvendor $subdevice > \
+               /sys/bus/pci/drivers/bt878/new_id
+
+109e: PCI_VENDOR_ID_BROOKTREE
+0878: PCI_DEVICE_ID_BROOKTREE_878
+
 Authors: Richard Walker,
         Jamie Honan,
         Michael Hunold,
index 20c4c8bac9d7d599fa43e1162b7db62cb7ad9011..9b8291f4c21134a76c4eaaaa2884c0a79fdc35d6 100644 (file)
@@ -295,16 +295,6 @@ Who:  linuxppc-dev@ozlabs.org
 
 ---------------------------
 
-What:  mthca driver's MSI support
-When:  January 2008
-Files: drivers/infiniband/hw/mthca/*.[ch]
-Why:   All mthca hardware also supports MSI-X, which provides
-       strictly more functionality than MSI.  So there is no point in
-       having both MSI-X and MSI support in the driver.
-Who:   Roland Dreier <rolandd@cisco.com>
-
----------------------------
-
 What:   sk98lin network driver
 When:   Feburary 2008
 Why:    In kernel tree version of driver is unmaintained. Sk98lin driver
index ed55238023a9843f7781ac6cfe94d174ba772072..c318a8bbb1ef1efdbd68930ed687595f3c397121 100644 (file)
@@ -35,7 +35,6 @@ Features which OCFS2 does not support yet:
        - Directory change notification (F_NOTIFY)
        - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
        - POSIX ACLs
-       - readpages / writepages (not user visible)
 
 Mount options
 =============
@@ -62,3 +61,18 @@ data=writeback               Data ordering is not preserved, data may be written
 preferred_slot=0(*)    During mount, try to use this filesystem slot first. If
                        it is in use by another node, the first empty one found
                        will be chosen. Invalid values will be ignored.
+commit=nrsec   (*)     Ocfs2 can be told to sync all its data and metadata
+                       every 'nrsec' seconds. The default value is 5 seconds.
+                       This means that if you lose your power, you will lose
+                       as much as the latest 5 seconds of work (your
+                       filesystem will not be damaged though, thanks to the
+                       journaling).  This default value (or any low value)
+                       will hurt performance, but it's good for data-safety.
+                       Setting it to 0 will have the same effect as leaving
+                       it at the default (5 seconds).
+                       Setting it to very large values will improve
+                       performance.
+localalloc=8(*)                Allows custom localalloc size in MB. If the value is too
+                       large, the fs will silently revert it to the default.
+                       Localalloc is not enabled for local mounts.
+localflocks            This disables cluster aware flock.
index 1d50f23a5cab092b237f09b21ff873f334224782..94e2e3b9e77f03ebcb0a3d0b146e53397a6fcfc0 100644 (file)
@@ -30,7 +30,7 @@
 ***
 ***  The CMD640 is also used on some Vesa Local Bus (VLB) cards, and is *NOT*
 ***  automatically detected by Linux.  For safe, reliable operation with such
-***  interfaces, one *MUST* use the "ide0=cmd640_vlb" kernel option.
+***  interfaces, one *MUST* use the "cmd640.probe_vlb" kernel option.
 ***
 ***  Use of the "serialize" option is no longer necessary.
 
@@ -244,10 +244,6 @@ Summary of ide driver parameters for kernel command line
 
  "hdx=nodma"           : disallow DMA
 
- "hdx=swapdata"                : when the drive is a disk, byte swap all data
-
- "hdx=bswap"           : same as above..........
-
  "hdx=scsi"            : the return of the ide-scsi flag, this is useful for
                          allowing ide-floppy, ide-tape, and ide-cdrom|writers
                          to use ide-scsi emulation on a device specific option.
@@ -292,9 +288,6 @@ The following are valid ONLY on ide0, which usually corresponds
 to the first ATA interface found on the particular host, and the defaults for
 the base,ctl ports must not be altered.
 
- "ide0=cmd640_vlb"     : *REQUIRED* for VLB cards with the CMD640 chip
-                         (not for PCI -- automatically detected)
-
  "ide=doubler"         : probe/support IDE doublers on Amiga
 
 There may be more options than shown -- use the source, Luke!
@@ -310,6 +303,10 @@ i.e. to enable probing for ALI M14xx chipsets (ali14xx host driver) use:
 * "probe" module parameter when ali14xx driver is compiled as module
   ("modprobe ali14xx probe")
 
+Also for legacy CMD640 host driver (cmd640) you need to use "probe_vlb"
+kernel paremeter to enable probing for VLB version of the chipset (PCI ones
+are detected automatically).
+
 ================================================================================
 
 IDE ATAPI streaming tape driver
index 5c7fbf9d96b40a32d674446a6120d206990d7d76..c18363bd8d11b1f8b3c725c7c12639568033a115 100644 (file)
@@ -138,6 +138,7 @@ Code        Seq#    Include File            Comments
 'm'    00-1F   net/irda/irmod.h        conflict!
 'n'    00-7F   linux/ncp_fs.h
 'n'    E0-FF   video/matrox.h          matroxfb
+'o'    00-1F   fs/ocfs2/ocfs2_fs.h     OCFS2
 'p'    00-0F   linux/phantom.h         conflict! (OpenHaptics needs this)
 'p'    00-3F   linux/mc146818rtc.h     conflict!
 'p'    40-7F   linux/nvram.h
index 33121d6c827c6e5fcc85d72b1f5ee5f166b743a2..880f882160e2d717d9d0a7e1727ff6f29e6dcec8 100644 (file)
@@ -34,6 +34,7 @@ parameter is applicable:
        ALSA    ALSA sound support is enabled.
        APIC    APIC support is enabled.
        APM     Advanced Power Management support is enabled.
+       AVR32   AVR32 architecture is enabled.
        AX25    Appropriate AX.25 support is enabled.
        BLACKFIN Blackfin architecture is enabled.
        DRM     Direct Rendering Management support is enabled.
@@ -369,7 +370,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        configured.  Potentially dangerous and should only be
                        used if you are entirely sure of the consequences.
 
-       chandev=        [HW,NET] Generic channel device initialisation
+       ccw_timeout_log [S390]
+                       See Documentation/s390/CommonIO for details.
 
        checkreqprot    [SELINUX] Set initial checkreqprot flag value.
                        Format: { "0" | "1" }
@@ -381,6 +383,12 @@ and is between 256 and 4096 characters. It is defined in the file
                        Value can be changed at runtime via
                                /selinux/checkreqprot.
 
+       cio_ignore=     [S390]
+                       See Documentation/s390/CommonIO for details.
+
+       cio_msg=        [S390]
+                       See Documentation/s390/CommonIO for details.
+
        clock=          [BUGS=X86-32, HW] gettimeofday clocksource override.
                        [Deprecated]
                        Forces specified clocksource (if available) to be used
@@ -527,29 +535,30 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format: <area>[,<node>]
                        See also Documentation/networking/decnet.txt.
 
-       default_blu=    [VT]
+       vt.default_blu= [VT]
                        Format: <blue0>,<blue1>,<blue2>,...,<blue15>
                        Change the default blue palette of the console.
                        This is a 16-member array composed of values
                        ranging from 0-255.
 
-       default_grn=    [VT]
+       vt.default_grn= [VT]
                        Format: <green0>,<green1>,<green2>,...,<green15>
                        Change the default green palette of the console.
                        This is a 16-member array composed of values
                        ranging from 0-255.
 
-       default_red=    [VT]
+       vt.default_red= [VT]
                        Format: <red0>,<red1>,<red2>,...,<red15>
                        Change the default red palette of the console.
                        This is a 16-member array composed of values
                        ranging from 0-255.
 
-       default_utf8=   [VT]
+       vt.default_utf8=
+                       [VT]
                        Format=<0|1>
                        Set system-wide default UTF-8 mode for all tty's.
-                       Default is 0 and by setting to 1, it enables UTF-8
-                       mode for all newly opened or allocated terminals.
+                       Default is 1, i.e. UTF-8 mode is enabled for all
+                       newly opened terminals.
 
        dhash_entries=  [KNL]
                        Set number of hash buckets for dentry cache.
@@ -882,6 +891,14 @@ and is between 256 and 4096 characters. It is defined in the file
        lapic_timer_c2_ok       [X86-32,x86-64,APIC] trust the local apic timer in
                        C2 power state.
 
+       libata.dma=     [LIBATA] DMA control
+                       libata.dma=0      Disable all PATA and SATA DMA
+                       libata.dma=1      PATA and SATA Disk DMA only
+                       libata.dma=2      ATAPI (CDROM) DMA only
+                       libata.dma=4      Compact Flash DMA only 
+                       Combinations also work, so libata.dma=3 enables DMA
+                       for disks and CDROMs, but not CFs.
+
        libata.noacpi   [LIBATA] Disables use of ACPI in libata suspend/resume
                        when set.
                        Format: <int>
@@ -1114,6 +1131,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        of returning the full 64-bit number.
                        The default is to return 64-bit inode numbers.
 
+       nmi_debug=      [KNL,AVR32] Specify one or more actions to take
+                       when a NMI is triggered.
+                       Format: [state][,regs][,debounce][,die]
+
        nmi_watchdog=   [KNL,BUGS=X86-32] Debugging features for SMP kernels
 
        no387           [BUGS=X86-32] Tells the kernel to use the 387 maths
@@ -1584,7 +1605,13 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format: <vendor>:<model>:<flags>
                        (flags are integer value)
 
-       scsi_logging=   [SCSI]
+       scsi_logging_level=     [SCSI] a bit mask of logging levels
+                       See drivers/scsi/scsi_logging.h for bits.  Also
+                       settable via sysctl at dev.scsi.logging_level
+                       (/proc/sys/dev/scsi/logging_level).
+                       There is also a nice 'scsi_logging_level' script in the
+                       S390-tools package, available for download at
+                       http://www-128.ibm.com/developerworks/linux/linux390/s390-tools-1.5.4.html
 
        scsi_mod.scan=  [SCSI] sync (default) scans SCSI busses as they are
                        discovered.  async scans them in kernel threads,
index ca86a885ad8f71c6f98647debd50bf293b33de47..bf3256e04027686430823fe32333fabf968a3de4 100644 (file)
-The kobject Infrastructure
+Everything you never wanted to know about kobjects, ksets, and ktypes
 
-Patrick Mochel <mochel@osdl.org>
+Greg Kroah-Hartman <gregkh@suse.de>
 
-Updated: 3 June 2003
+Based on an original article by Jon Corbet for lwn.net written October 1,
+2003 and located at http://lwn.net/Articles/51437/
 
+Last updated December 19, 2007
 
-Copyright (c)  2003 Patrick Mochel
-Copyright (c)  2003 Open Source Development Labs
 
+Part of the difficulty in understanding the driver model - and the kobject
+abstraction upon which it is built - is that there is no obvious starting
+place. Dealing with kobjects requires understanding a few different types,
+all of which make reference to each other. In an attempt to make things
+easier, we'll take a multi-pass approach, starting with vague terms and
+adding detail as we go. To that end, here are some quick definitions of
+some terms we will be working with.
 
-0. Introduction
+ - A kobject is an object of type struct kobject.  Kobjects have a name
+   and a reference count.  A kobject also has a parent pointer (allowing
+   objects to be arranged into hierarchies), a specific type, and,
+   usually, a representation in the sysfs virtual filesystem.
 
-The kobject infrastructure performs basic object management that larger
-data structures and subsystems can leverage, rather than reimplement
-similar functionality. This functionality primarily concerns:
+   Kobjects are generally not interesting on their own; instead, they are
+   usually embedded within some other structure which contains the stuff
+   the code is really interested in.
 
-- Object reference counting.
-- Maintaining lists (sets) of objects.
-- Object set locking.
-- Userspace representation. 
+   No structure should EVER have more than one kobject embedded within it.
+   If it does, the reference counting for the object is sure to be messed
+   up and incorrect, and your code will be buggy.  So do not do this.
 
-The infrastructure consists of a number of object types to support
-this functionality. Their programming interfaces are described below
-in detail, and briefly here:
+ - A ktype is the type of object that embeds a kobject.  Every structure
+   that embeds a kobject needs a corresponding ktype.  The ktype controls
+   what happens to the kobject when it is created and destroyed.
 
-- kobjects     a simple object.
-- kset         a set of objects of a certain type.
-- ktype                a set of helpers for objects of a common type. 
+ - A kset is a group of kobjects.  These kobjects can be of the same ktype
+   or belong to different ktypes.  The kset is the basic container type for
+   collections of kobjects. Ksets contain their own kobjects, but you can
+   safely ignore that implementation detail as the kset core code handles
+   this kobject automatically.
 
+   When you see a sysfs directory full of other directories, generally each
+   of those directories corresponds to a kobject in the same kset.
 
-The kobject infrastructure maintains a close relationship with the
-sysfs filesystem. Each kobject that is registered with the kobject
-core receives a directory in sysfs. Attributes about the kobject can
-then be exported. Please see Documentation/filesystems/sysfs.txt for
-more information. 
+We'll look at how to create and manipulate all of these types. A bottom-up
+approach will be taken, so we'll go back to kobjects.
 
-The kobject infrastructure provides a flexible programming interface,
-and allows kobjects and ksets to be used without being registered
-(i.e. with no sysfs representation). This is also described later. 
 
+Embedding kobjects
 
-1. kobjects
+It is rare for kernel code to create a standalone kobject, with one major
+exception explained below.  Instead, kobjects are used to control access to
+a larger, domain-specific object.  To this end, kobjects will be found
+embedded in other structures.  If you are used to thinking of things in
+object-oriented terms, kobjects can be seen as a top-level, abstract class
+from which other classes are derived.  A kobject implements a set of
+capabilities which are not particularly useful by themselves, but which are
+nice to have in other objects.  The C language does not allow for the
+direct expression of inheritance, so other techniques - such as structure
+embedding - must be used.
 
-1.1 Description
+So, for example, the UIO code has a structure that defines the memory
+region associated with a uio device:
 
+struct uio_mem {
+       struct kobject kobj;
+       unsigned long addr;
+       unsigned long size;
+       int memtype;
+       void __iomem *internal_addr;
+};
 
-struct kobject is a simple data type that provides a foundation for
-more complex object types. It provides a set of basic fields that
-almost all complex data types share. kobjects are intended to be
-embedded in larger data structures and replace fields they duplicate. 
+If you have a struct uio_mem structure, finding its embedded kobject is
+just a matter of using the kobj member.  Code that works with kobjects will
+often have the opposite problem, however: given a struct kobject pointer,
+what is the pointer to the containing structure?  You must avoid tricks
+(such as assuming that the kobject is at the beginning of the structure)
+and, instead, use the container_of() macro, found in <linux/kernel.h>:
 
-1.2 Definition
+       container_of(pointer, type, member)
 
-struct kobject {
-       const char              * k_name;
-       struct kref             kref;
-       struct list_head        entry;
-       struct kobject          * parent;
-       struct kset             * kset;
-       struct kobj_type        * ktype;
-       struct sysfs_dirent     * sd;
-       wait_queue_head_t       poll;
-};
+where pointer is the pointer to the embedded kobject, type is the type of
+the containing structure, and member is the name of the structure field to
+which pointer points.  The return value from container_of() is a pointer to
+the given type. So, for example, a pointer "kp" to a struct kobject
+embedded within a struct uio_mem could be converted to a pointer to the
+containing uio_mem structure with:
 
-void kobject_init(struct kobject *);
-int kobject_add(struct kobject *);
-int kobject_register(struct kobject *);
+    struct uio_mem *u_mem = container_of(kp, struct uio_mem, kobj);
 
-void kobject_del(struct kobject *);
-void kobject_unregister(struct kobject *);
+Programmers often define a simple macro for "back-casting" kobject pointers
+to the containing type.
 
-struct kobject * kobject_get(struct kobject *);
-void kobject_put(struct kobject *);
 
+Initialization of kobjects
 
-1.3 kobject Programming Interface
+Code which creates a kobject must, of course, initialize that object. Some
+of the internal fields are setup with a (mandatory) call to kobject_init():
 
-kobjects may be dynamically added and removed from the kobject core
-using kobject_register() and kobject_unregister(). Registration
-includes inserting the kobject in the list of its dominant kset and
-creating a directory for it in sysfs.
+    void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
 
-Alternatively, one may use a kobject without adding it to its kset's list
-or exporting it via sysfs, by simply calling kobject_init(). An
-initialized kobject may later be added to the object hierarchy by
-calling kobject_add(). An initialized kobject may be used for
-reference counting.
+The ktype is required for a kobject to be created properly, as every kobject
+must have an associated kobj_type.  After calling kobject_init(), to
+register the kobject with sysfs, the function kobject_add() must be called:
 
-Note: calling kobject_init() then kobject_add() is functionally
-equivalent to calling kobject_register().
+    int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);
 
-When a kobject is unregistered, it is removed from its kset's list,
-removed from the sysfs filesystem, and its reference count is decremented.
-List and sysfs removal happen in kobject_del(), and may be called
-manually. kobject_put() decrements the reference count, and may also
-be called manually. 
+This sets up the parent of the kobject and the name for the kobject
+properly.  If the kobject is to be associated with a specific kset,
+kobj->kset must be assigned before calling kobject_add().  If a kset is
+associated with a kobject, then the parent for the kobject can be set to
+NULL in the call to kobject_add() and then the kobject's parent will be the
+kset itself.
 
-A kobject's reference count may be incremented with kobject_get(),
-which returns a valid reference to a kobject; and decremented with 
-kobject_put(). An object's reference count may only be incremented if
-it is already positive. 
+As the name of the kobject is set when it is added to the kernel, the name
+of the kobject should never be manipulated directly.  If you must change
+the name of the kobject, call kobject_rename():
 
-When a kobject's reference count reaches 0, the method struct
-kobj_type::release() (which the kobject's kset points to) is called.
-This allows any memory allocated for the object to be freed.
+    int kobject_rename(struct kobject *kobj, const char *new_name);
 
+There is a function called kobject_set_name() but that is legacy cruft and
+is being removed.  If your code needs to call this function, it is
+incorrect and needs to be fixed.
 
-NOTE!!! 
+To properly access the name of the kobject, use the function
+kobject_name():
 
-It is _imperative_ that you supply a destructor for dynamically
-allocated kobjects to free them if you are using kobject reference
-counts. The reference count controls the lifetime of the object.
-If it goes to 0, then it is assumed that the object will
-be freed and cannot be used. 
+    const char *kobject_name(const struct kobject * kobj);
 
-More importantly, you must free the object there, and not immediately
-after an unregister call. If someone else is referencing the object
-(e.g. through a sysfs file), they will obtain a reference to the
-object, assume it's valid and operate on it. If the object is
-unregistered and freed in the meantime, the operation will then
-reference freed memory and go boom. 
+There is a helper function to both initialize and add the kobject to the
+kernel at the same time, called supprisingly enough kobject_init_and_add():
 
-This can be prevented, in the simplest case, by defining a release
-method and freeing the object from there only. Note that this will not
-secure reference count/object management models that use a dual
-reference count or do other wacky things with the reference count
-(like the networking layer). 
+    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+                             struct kobject *parent, const char *fmt, ...);
 
+The arguments are the same as the individual kobject_init() and
+kobject_add() functions described above.
 
-1.4 sysfs
 
-Each kobject receives a directory in sysfs. This directory is created
-under the kobject's parent directory. 
+Uevents
 
-If a kobject does not have a parent when it is registered, its parent
-becomes its dominant kset. 
+After a kobject has been registered with the kobject core, you need to
+announce to the world that it has been created.  This can be done with a
+call to kobject_uevent():
 
-If a kobject does not have a parent nor a dominant kset, its directory
-is created at the top-level of the sysfs partition.
+    int kobject_uevent(struct kobject *kobj, enum kobject_action action);
 
+Use the KOBJ_ADD action for when the kobject is first added to the kernel.
+This should be done only after any attributes or children of the kobject
+have been initialized properly, as userspace will instantly start to look
+for them when this call happens.
 
+When the kobject is removed from the kernel (details on how to do that is
+below), the uevent for KOBJ_REMOVE will be automatically created by the
+kobject core, so the caller does not have to worry about doing that by
+hand.
 
-2. ksets
 
-2.1 Description
+Reference counts
 
-A kset is a set of kobjects that are embedded in the same type. 
+One of the key functions of a kobject is to serve as a reference counter
+for the object in which it is embedded. As long as references to the object
+exist, the object (and the code which supports it) must continue to exist.
+The low-level functions for manipulating a kobject's reference counts are:
 
+    struct kobject *kobject_get(struct kobject *kobj);
+    void kobject_put(struct kobject *kobj);
 
-struct kset {
-       struct kobj_type        * ktype;
-       struct list_head        list;
-       struct kobject          kobj;
-       struct kset_uevent_ops  * uevent_ops;
-};
+A successful call to kobject_get() will increment the kobject's reference
+counter and return the pointer to the kobject.
 
+When a reference is released, the call to kobject_put() will decrement the
+reference count and, possibly, free the object. Note that kobject_init()
+sets the reference count to one, so the code which sets up the kobject will
+need to do a kobject_put() eventually to release that reference.
 
-void kset_init(struct kset * k);
-int kset_add(struct kset * k);
-int kset_register(struct kset * k);
-void kset_unregister(struct kset * k);
+Because kobjects are dynamic, they must not be declared statically or on
+the stack, but instead, always allocated dynamically.  Future versions of
+the kernel will contain a run-time check for kobjects that are created
+statically and will warn the developer of this improper usage.
 
-struct kset * kset_get(struct kset * k);
-void kset_put(struct kset * k);
+If all that you want to use a kobject for is to provide a reference counter
+for your structure, please use the struct kref instead; a kobject would be
+overkill.  For more information on how to use struct kref, please see the
+file Documentation/kref.txt in the Linux kernel source tree.
 
-struct kobject * kset_find_obj(struct kset *, char *);
 
+Creating "simple" kobjects
 
-The type that the kobjects are embedded in is described by the ktype
-pointer.
+Sometimes all that a developer wants is a way to create a simple directory
+in the sysfs hierarchy, and not have to mess with the whole complication of
+ksets, show and store functions, and other details.  This is the one
+exception where a single kobject should be created.  To create such an
+entry, use the function:
 
-A kset contains a kobject itself, meaning that it may be registered in
-the kobject hierarchy and exported via sysfs. More importantly, the
-kset may be embedded in a larger data type, and may be part of another
-kset (of that object type). 
+    struct kobject *kobject_create_and_add(char *name, struct kobject *parent);
 
-For example, a block device is an object (struct gendisk) that is
-contained in a set of block devices. It may also contain a set of
-partitions (struct hd_struct) that have been found on the device. The
-following code snippet illustrates how to express this properly.
+This function will create a kobject and place it in sysfs in the location
+underneath the specified parent kobject.  To create simple attributes
+associated with this kobject, use:
 
-        struct gendisk * disk;
-        ...
-        disk->kset.kobj.kset = &block_kset;
-        disk->kset.ktype = &partition_ktype;
-        kset_register(&disk->kset);
+    int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
+or
+    int sysfs_create_group(struct kobject *kobj, struct attribute_group *grp);
 
-- The kset that the disk's embedded object belongs to is the
-  block_kset, and is pointed to by disk->kset.kobj.kset. 
+Both types of attributes used here, with a kobject that has been created
+with the kobject_create_and_add(), can be of type kobj_attribute, so no
+special custom attribute is needed to be created.
 
-- The type of objects on the disk's _subordinate_ list are partitions, 
-  and is set in disk->kset.ktype. 
+See the example module, samples/kobject/kobject-example.c for an
+implementation of a simple kobject and attributes.
 
-- The kset is then registered, which handles initializing and adding
-  the embedded kobject to the hierarchy. 
 
 
-2.2 kset Programming Interface 
+ktypes and release methods
 
-All kset functions, except kset_find_obj(), eventually forward the
-calls to their embedded kobjects after performing kset-specific
-operations. ksets offer a similar programming model to kobjects: they
-may be used after they are initialized, without registering them in
-the hierarchy. 
+One important thing still missing from the discussion is what happens to a
+kobject when its reference count reaches zero. The code which created the
+kobject generally does not know when that will happen; if it did, there
+would be little point in using a kobject in the first place. Even
+predictable object lifecycles become more complicated when sysfs is brought
+in as other portions of the kernel can get a reference on any kobject that
+is registered in the system.
 
-kset_find_obj() may be used to locate a kobject with a particular
-name. The kobject, if found, is returned. 
+The end result is that a structure protected by a kobject cannot be freed
+before its reference count goes to zero. The reference count is not under
+the direct control of the code which created the kobject. So that code must
+be notified asynchronously whenever the last reference to one of its
+kobjects goes away.
 
-There are also some helper functions which names point to the formerly
-existing "struct subsystem", whose functions have been taken over by
-ksets.
+Once you registered your kobject via kobject_add(), you must never use
+kfree() to free it directly. The only safe way is to use kobject_put(). It
+is good practice to always use kobject_put() after kobject_init() to avoid
+errors creeping in.
 
+This notification is done through a kobject's release() method. Usually
+such a method has a form like:
 
-decl_subsys(name,type,uevent_ops)
+    void my_object_release(struct kobject *kobj)
+    {
+           struct my_object *mine = container_of(kobj, struct my_object, kobj);
 
-Declares a kset named '<name>_subsys' of type <type> with
-uevent_ops <uevent_ops>. For example,
+           /* Perform any additional cleanup on this object, then... */
+           kfree(mine);
+    }
 
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+One important point cannot be overstated: every kobject must have a
+release() method, and the kobject must persist (in a consistent state)
+until that method is called. If these constraints are not met, the code is
+flawed.  Note that the kernel will warn you if you forget to provide a
+release() method.  Do not try to get rid of this warning by providing an
+"empty" release function; you will be mocked mercilessly by the kobject
+maintainer if you attempt this.
 
-is equivalent to doing:
+Note, the name of the kobject is available in the release function, but it
+must NOT be changed within this callback.  Otherwise there will be a memory
+leak in the kobject core, which makes people unhappy.
 
-struct kset devices_subsys = {
-     .ktype = &ktype_devices,
-     .uevent_ops = &device_uevent_ops,
-};
-kobject_set_name(&devices_subsys, name);
+Interestingly, the release() method is not stored in the kobject itself;
+instead, it is associated with the ktype. So let us introduce struct
+kobj_type:
+
+    struct kobj_type {
+           void (*release)(struct kobject *);
+           struct sysfs_ops    *sysfs_ops;
+           struct attribute    **default_attrs;
+    };
 
-The objects that are registered with a subsystem that use the
-subsystem's default list must have their kset ptr set properly. These
-objects may have embedded kobjects or ksets. The
-following helper makes setting the kset easier:
+This structure is used to describe a particular type of kobject (or, more
+correctly, of containing object). Every kobject needs to have an associated
+kobj_type structure; a pointer to that structure must be specified when you
+call kobject_init() or kobject_init_and_add().
 
+The release field in struct kobj_type is, of course, a pointer to the
+release() method for this type of kobject. The other two fields (sysfs_ops
+and default_attrs) control how objects of this type are represented in
+sysfs; they are beyond the scope of this document.
 
-kobj_set_kset_s(obj,subsys)
+The default_attrs pointer is a list of default attributes that will be
+automatically created for any kobject that is registered with this ktype.
 
-- Assumes that obj->kobj exists, and is a struct kobject.
-- Sets the kset of that kobject to the kset <subsys>.
 
-int subsystem_register(struct kset *s);
-void subsystem_unregister(struct kset *s);
+ksets
 
-These are just wrappers around the respective kset_* functions.
+A kset is merely a collection of kobjects that want to be associated with
+each other.  There is no restriction that they be of the same ktype, but be
+very careful if they are not.
 
-2.3 sysfs
+A kset serves these functions:
 
-ksets are represented in sysfs when their embedded kobjects are
-registered. They follow the same rules of parenting, with one
-exception. If a kset does not have a parent, nor is its embedded
-kobject part of another kset, the kset's parent becomes its dominant
-subsystem. 
+ - It serves as a bag containing a group of objects. A kset can be used by
+   the kernel to track "all block devices" or "all PCI device drivers."
 
-If the kset does not have a parent, its directory is created at the
-sysfs root. This should only happen when the kset registered is
-embedded in a subsystem itself. 
+ - A kset is also a subdirectory in sysfs, where the associated kobjects
+   with the kset can show up.  Every kset contains a kobject which can be
+   set up to be the parent of other kobjects; the top-level directories of
+   the sysfs hierarchy are constructed in this way.
 
+ - Ksets can support the "hotplugging" of kobjects and influence how
+   uevent events are reported to user space.
 
-3. struct ktype
+In object-oriented terms, "kset" is the top-level container class; ksets
+contain their own kobject, but that kobject is managed by the kset code and
+should not be manipulated by any other user.
 
-3.1. Description
+A kset keeps its children in a standard kernel linked list.  Kobjects point
+back to their containing kset via their kset field. In almost all cases,
+the kobjects belonging to a ket have that kset (or, strictly, its embedded
+kobject) in their parent.
 
-struct kobj_type {
-       void (*release)(struct kobject *);
-       struct sysfs_ops        * sysfs_ops;
-       struct attribute        ** default_attrs;
+As a kset contains a kobject within it, it should always be dynamically
+created and never declared statically or on the stack.  To create a new
+kset use:
+  struct kset *kset_create_and_add(const char *name,
+                                  struct kset_uevent_ops *u,
+                                  struct kobject *parent);
+
+When you are finished with the kset, call:
+  void kset_unregister(struct kset *kset);
+to destroy it.
+
+An example of using a kset can be seen in the
+samples/kobject/kset-example.c file in the kernel tree.
+
+If a kset wishes to control the uevent operations of the kobjects
+associated with it, it can use the struct kset_uevent_ops to handle it:
+
+struct kset_uevent_ops {
+        int (*filter)(struct kset *kset, struct kobject *kobj);
+        const char *(*name)(struct kset *kset, struct kobject *kobj);
+        int (*uevent)(struct kset *kset, struct kobject *kobj,
+                      struct kobj_uevent_env *env);
 };
 
 
-Object types require specific functions for converting between the
-generic object and the more complex type. struct kobj_type provides
-the object-specific fields, which include:
+The filter function allows a kset to prevent a uevent from being emitted to
+userspace for a specific kobject.  If the function returns 0, the uevent
+will not be emitted.
+
+The name function will be called to override the default name of the kset
+that the uevent sends to userspace.  By default, the name will be the same
+as the kset itself, but this function, if present, can override that name.
+
+The uevent function will be called when the uevent is about to be sent to
+userspace to allow more environment variables to be added to the uevent.
+
+One might ask how, exactly, a kobject is added to a kset, given that no
+functions which perform that function have been presented.  The answer is
+that this task is handled by kobject_add().  When a kobject is passed to
+kobject_add(), its kset member should point to the kset to which the
+kobject will belong.  kobject_add() will handle the rest.
+
+If the kobject belonging to a kset has no parent kobject set, it will be
+added to the kset's directory.  Not all members of a kset do necessarily
+live in the kset directory.  If an explicit parent kobject is assigned
+before the kobject is added, the kobject is registered with the kset, but
+added below the parent kobject.
+
+
+Kobject removal
 
-- release: Called when the kobject's reference count reaches 0. This
-  should convert the object to the more complex type and free it. 
+After a kobject has been registered with the kobject core successfully, it
+must be cleaned up when the code is finished with it.  To do that, call
+kobject_put().  By doing this, the kobject core will automatically clean up
+all of the memory allocated by this kobject.  If a KOBJ_ADD uevent has been
+sent for the object, a corresponding KOBJ_REMOVE uevent will be sent, and
+any other sysfs housekeeping will be handled for the caller properly.
 
-- sysfs_ops: Provides conversion functions for sysfs access. Please
-  see the sysfs documentation for more information. 
+If you need to do a two-stage delete of the kobject (say you are not
+allowed to sleep when you need to destroy the object), then call
+kobject_del() which will unregister the kobject from sysfs.  This makes the
+kobject "invisible", but it is not cleaned up, and the reference count of
+the object is still the same.  At a later time call kobject_put() to finish
+the cleanup of the memory associated with the kobject.
 
-- default_attrs: Default attributes to be exported via sysfs when the
-  object is registered.Note that the last attribute has to be
-  initialized to NULL ! You can find a complete implementation
-  in block/genhd.c
+kobject_del() can be used to drop the reference to the parent object, if
+circular references are constructed.  It is valid in some cases, that a
+parent objects references a child.  Circular references _must_ be broken
+with an explicit call to kobject_del(), so that a release functions will be
+called, and the objects in the former circle release each other.
 
 
-Instances of struct kobj_type are not registered; only referenced by
-the kset. A kobj_type may be referenced by an arbitrary number of
-ksets, as there may be disparate sets of identical objects. 
+Example code to copy from
 
+For a more complete example of using ksets and kobjects properly, see the
+sample/kobject/kset-example.c code.
index 1a45f11e645e978f445ba7396f0c5411a1695e06..4269a1105b378fafcc689435a2531b9d9d4287db 100644 (file)
@@ -45,29 +45,6 @@ long fails. The definition looks like :
 typedef struct { atomic_long_t a; } local_t;
 
 
-* Rules to follow when using local atomic operations
-
-- Variables touched by local ops must be per cpu variables.
-- _Only_ the CPU owner of these variables must write to them.
-- This CPU can use local ops from any context (process, irq, softirq, nmi, ...)
-  to update its local_t variables.
-- Preemption (or interrupts) must be disabled when using local ops in
-  process context to   make sure the process won't be migrated to a
-  different CPU between getting the per-cpu variable and doing the
-  actual local op.
-- When using local ops in interrupt context, no special care must be
-  taken on a mainline kernel, since they will run on the local CPU with
-  preemption already disabled. I suggest, however, to explicitly
-  disable preemption anyway to make sure it will still work correctly on
-  -rt kernels.
-- Reading the local cpu variable will provide the current copy of the
-  variable.
-- Reads of these variables can be done from any CPU, because updates to
-  "long", aligned, variables are always atomic. Since no memory
-  synchronization is done by the writer CPU, an outdated copy of the
-  variable can be read when reading some _other_ cpu's variables.
-
-
 * Rules to follow when using local atomic operations
 
 - Variables touched by local ops must be per cpu variables.
index 248589e8bcf5b8da6be48877bccb0c233eb00be5..c93bed66e25d459d36bcd8a0d1308a1fac17c6c1 100644 (file)
@@ -867,66 +867,6 @@ controller and should be autodetected by the driver. An example is the
 24 bit region which is specified by a mask of 0x00fffffe.
 
 
-5.5) 53c7xx=
-------------
-
-Syntax: 53c7xx=<sub-options...>
-
-These options affect the A4000T, A4091, WarpEngine, Blizzard 603e+,
-and GForce 040/060 SCSI controllers on the Amiga, as well as the
-builtin MVME 16x SCSI controller.
-
-The <sub-options> is a comma-separated list of the sub-options listed
-below.
-
-5.5.1) nosync
--------------
-
-Syntax: nosync:0
-
-  Disables sync negotiation for all devices.  Any value after the
-  colon is acceptable (and has the same effect).
-
-5.5.2) noasync
---------------
-
-[OBSOLETE, REMOVED]
-
-5.5.3) nodisconnect
--------------------
-
-Syntax: nodisconnect:0
-
-  Disables SCSI disconnects.  Any value after the colon is acceptable
-  (and has the same effect).
-
-5.5.4) validids
----------------
-
-Syntax: validids:0xNN
-
-  Specify which SCSI ids the driver should pay attention to.  This is
-  a bitmask (i.e. to only pay attention to ID#4, you'd use 0x10).
-  Default is 0x7f (devices 0-6).
-
-5.5.5) opthi
-5.5.6) optlo
-------------
-
-Syntax: opthi:M,optlo:N
-
-  Specify options for "hostdata->options".  The acceptable definitions
-  are listed in drivers/scsi/53c7xx.h; the 32 high bits should be in
-  opthi and the 32 low bits in optlo.  They must be specified in the
-  order opthi=M,optlo=N.
-
-5.5.7) next
------------
-
-  No argument. Used to separate blocks of keywords when there's more
-  than one 53c7xx host adapter in the system.
-
-
 /* Local Variables: */
 /* mode: text       */
 /* End:             */
index 4f7da5a2bf4f8ce7c3300f49fae7e073cdf51380..ea72d2e66ca81a62fa493b695ed0e5cf94fc92a4 100644 (file)
@@ -61,7 +61,10 @@ Transmit path guidelines:
 2) Do not forget to update netdev->trans_start to jiffies after
    each new tx packet is given to the hardware.
 
-3) Do not forget that once you return 0 from your hard_start_xmit
+3) A hard_start_xmit method must not modify the shared parts of a
+   cloned SKB.
+
+4) Do not forget that once you return 0 from your hard_start_xmit
    method, it is your driver's responsibility to free up the SKB
    and in some finite amount of time.
 
index c1acf5eb3712a4b03d0be47e2bf31f2cd6793a33..afa6e521c685812591f1ec6770c00439b814d940 100644 (file)
@@ -12,8 +12,8 @@ and many Linux driver to support it.
 "wavelan" driver (old ISA Wavelan)
 ----------------
        o Config :      Network device -> Wireless LAN -> AT&T WaveLAN
-       o Location :    .../drivers/net/wavelan*
-       o in-line doc : .../drivers/net/wavelan.p.h
+       o Location :    .../drivers/net/wireless/wavelan*
+       o in-line doc : .../drivers/net/wireless/wavelan.p.h
        o on-line doc :
            http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
 
index c86dd38e228199566b23d997e926d562d6a04c8b..31b329172343546e8f1e1fb4a30549298d45ee68 100644 (file)
@@ -145,6 +145,7 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
                this option.
 
                   off or none: don't use autoconfiguration
+                               (do static IP assignment instead)
                  on or any:   use any protocol available in the kernel
                               (default)
                  dhcp:        use DHCP
index 481faf515d5360e608b6f4541ef03f759612bc4f..a327db67782abacc792b60c2db02366078d47e7a 100644 (file)
@@ -17,9 +17,9 @@ The User Interface
 ------------------
        The Linux Plug and Play user interface provides a means to activate PnP devices
 for legacy and user level drivers that do not support Linux Plug and Play.  The 
-user interface is integrated into driverfs.
+user interface is integrated into sysfs.
 
-In addition to the standard driverfs file the following are created in each 
+In addition to the standard sysfs file the following are created in each
 device's directory:
 id - displays a list of support EISA IDs
 options - displays possible resource configurations
index 86320aa3fb0b4728c2e6f581c2e346f3d018088d..8fbc0a852870f2a972b4d17adae71ba866bc5975 100644 (file)
@@ -4,6 +4,11 @@ S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
 Command line parameters
 -----------------------
 
+* ccw_timeout_log
+
+  Enable logging of debug information in case of ccw device timeouts.
+
+
 * cio_msg = yes | no
   
   Determines whether information on found devices and sensed device 
index 3081927cc2d64048c1bc02ddf0e33f737082f993..c4b7b2bd369ae74949cfd1182346dbc1d12427d6 100644 (file)
@@ -133,7 +133,7 @@ During its startup the Linux/390 system checks for peripheral devices. Each
 of those devices is uniquely defined by a so called subchannel by the ESA/390
 channel subsystem. While the subchannel numbers are system generated, each
 subchannel also takes a user defined attribute, the so called device number.
-Both subchannel number and device number cannot exceed 65535. During driverfs
+Both subchannel number and device number cannot exceed 65535. During sysfs
 initialisation, the information about control unit type and device types that 
 imply specific I/O commands (channel command words - CCWs) in order to operate
 the device are gathered. Device drivers can retrieve this set of hardware
index aa1f7e927834bf8ad7557b9a98eb40e28e3f69b7..c2e18e109858b288d29eafd9e9f7c8764a343dd8 100644 (file)
@@ -64,8 +64,6 @@ lpfc.txt
        - LPFC driver release notes
 megaraid.txt
        - Common Management Module, shared code handling ioctls for LSI drivers
-ncr53c7xx.txt
-       - info on driver for NCR53c7xx based adapters
 ncr53c8xx.txt
        - info on driver for NCR53c8xx based adapters
 osst.txt
index 5eb92754499098eaddaec839cb5d913157837fd1..91c81db0ba711c3594dbcbe8b6aa930bacb06b1f 100644 (file)
@@ -1,3 +1,162 @@
+1 Release Date    : Thur. Nov. 07 16:30:43 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.16
+3 Older Version   : 00.00.03.15
+
+1. Increased MFI_POLL_TIMEOUT_SECS to 60 seconds from 10. FW may take
+       a max of 60 seconds to respond to the INIT cmd.
+
+1 Release Date    : Fri. Sep. 07 16:30:43 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.15
+3 Older Version   : 00.00.03.14
+
+1. Added module parameter "poll_mode_io" to support for "polling"
+       (reduced interrupt operation).  In this mode, IO completion
+       interrupts are delayed. At the end of initiating IOs, the
+       driver schedules for cmd completion if there are pending cmds
+       to be completed.  A timer-based interrupt has also been added
+       to prevent IO completion processing from being delayed
+       indefinitely in the case that no new IOs are initiated.
+
+1 Release Date    : Fri. Sep. 07 16:30:43 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.14
+3 Older Version   : 00.00.03.13
+
+1. Setting the max_sectors_per_req based on max SGL supported by the
+       FW. Prior versions calculated this value from controller info
+       (max_sectors_1, max_sectors_2). For certain controllers/FW,
+       this was resulting in a value greater than max SGL supported
+       by the FW. Issue was first reported by users running LUKS+XFS
+       with megaraid_sas.  Thanks to RB for providing the logs and
+       duplication steps that helped to get to the root cause of the
+       issue.  2. Increased MFI_POLL_TIMEOUT_SECS to 60 seconds from
+       10. FW may take a max of 60 seconds to respond to the INIT
+       cmd.
+
+1 Release Date    : Fri. June. 15 16:30:43 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.13
+3 Older Version   : 00.00.03.12
+
+1. Added the megasas_reset_timer routine to intercept cmd timeout and throttle io.
+
+On Fri, 2007-03-16 at 16:44 -0600, James Bottomley wrote:
+It looks like megaraid_sas at least needs this to throttle its commands
+> as they begin to time out.  The code keeps the existing transport
+> template use of eh_timed_out (and allows the transport to override the
+> host if they both have this callback).
+>
+> James
+
+1 Release Date    : Sat May. 12 16:30:43 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.12
+3 Older Version   : 00.00.03.11
+
+1.  When MegaSAS driver receives reset call from OS, driver waits in reset
+routine for max 3 minutes for all pending command completion. Now driver will
+call completion routine every 5 seconds from the reset routine instead of
+waiting for depending on cmd completion from isr path.
+
+1 Release Date    : Mon Apr. 30 10:25:52 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.11
+3 Older Version   : 00.00.03.09
+
+       1. Memory Manager for IOCTL removed for 2.6 kernels.
+          pci_alloc_consistent replaced by dma_alloc_coherent. With this
+          change there is no need of memory manager in the driver code
+
+       On Wed, 2007-02-07 at 13:30 -0800, Andrew Morton wrote:
+       > I suspect all this horror is due to stupidity in the DMA API.
+       >
+       > pci_alloc_consistent() just goes and assumes GFP_ATOMIC, whereas
+       > the caller (megasas_mgmt_fw_ioctl) would have been perfectly happy
+       > to use GFP_KERNEL.
+       >
+       > I bet this fixes it
+
+       It does, but the DMA API was expanded to cope with this exact case, so
+       use dma_alloc_coherent() directly in the megaraid code instead.  The dev
+       is just &pci_dev->dev.
+
+       James <James.Bottomley@SteelEye.com>
+
+       3. SYNCHRONIZE_CACHE is not supported by FW and thus blocked by driver.
+       4. Hibernation support added
+       5. Performing diskdump while running IO in RHEL 4 was failing. Fixed.
+
+1 Release Date    : Fri Feb. 09 14:36:28 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.09
+3 Older Version   : 00.00.03.08
+
+i.     Under heavy IO mid-layer prints "DRIVER_TIMEOUT" errors
+
+       The driver now waits for 10 seconds to elapse instead of 5 (as in
+       previous release) to resume IO.
+
+1 Release Date    : Mon Feb. 05 11:35:24 PST 2007 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+2 Current Version : 00.00.03.08
+3 Older Version   : 00.00.03.07
+
+i.     Under heavy IO mid-layer prints "DRIVER_TIMEOUT" errors
+
+       Fix:    The driver is now throttling IO.
+       Checks added in megasas_queue_command to know if FW is able to
+       process commands within timeout period. If number of retries
+       is 2 or greater,the driver stops sending cmd to FW temporarily. IO is
+       resumed if pending cmd count reduces to 16 or 5 seconds has elapsed
+       from the time cmds were last sent to FW.
+
+ii.    FW enables WCE bit in Mode Sense cmd for drives that are configured
+       as WriteBack. The OS may send "SYNCHRONIZE_CACHE" cmd when Logical
+       Disks are exposed with WCE=1. User is advised to enable Write Back
+       mode only when the controller has battery backup. At this time
+       Synhronize cache is not supported by the FW. Driver will short-cycle
+       the cmd and return sucess without sending down to FW.
+
+1 Release Date    : Sun Jan. 14 11:21:32 PDT 2007 -
+                Sumant Patro <Sumant.Patro@lsil.com>/Bo Yang
+2 Current Version : 00.00.03.07
+3 Older Version   : 00.00.03.06
+
+i.     bios_param entry added in scsi_host_template that returns disk geometry
+       information.
+
+1 Release Date    : Fri Oct 20 11:21:32 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>/Bo Yang
+2 Current Version : 00.00.03.06
+3 Older Version   : 00.00.03.05
+
+1. Added new memory management module to support the IOCTL memory allocation. For IOCTL we try to allocate from the memory pool created during driver initialization. If mem pool is empty then we allocate at run time.
+2. Added check in megasas_queue_command and dpc/isr routine to see if we have already declared adapter dead
+   (hw_crit_error=1). If hw_crit_error==1, now we donot accept any processing of pending cmds/accept any cmd from OS
 
 1 Release Date    : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
 2 Current Version : 00.00.03.05
index a8257840695ae870828514813cf109f2aa767e5f..d16011a8618eab462e1a05dbd37a5ee7a141b1c6 100644 (file)
@@ -56,6 +56,10 @@ Supported Cards/Chipsets
        9005:0285:9005:02d1     Adaptec 5405 (Voodoo40)
        9005:0285:15d9:02d2     SMC     AOC-USAS-S8i-LP
        9005:0285:15d9:02d3     SMC     AOC-USAS-S8iR-LP
+       9005:0285:9005:02d4     Adaptec 2045 (Voodoo04 Lite)
+       9005:0285:9005:02d5     Adaptec 2405 (Voodoo40 Lite)
+       9005:0285:9005:02d6     Adaptec 2445 (Voodoo44 Lite)
+       9005:0285:9005:02d7     Adaptec 2805 (Voodoo80 Lite)
        1011:0046:9005:0364     Adaptec 5400S (Mustang)
        9005:0287:9005:0800     Adaptec Themisto (Jupiter)
        9005:0200:9005:0200     Adaptec Themisto (Jupiter)
index d28a31247d4c0997a10415d8562449afffeaac82..a6eb4add1be6d2b7dc1b553853fd04d3d2189b5b 100644 (file)
@@ -1,9 +1,9 @@
-HIGHPOINT ROCKETRAID 3xxx RAID DRIVER (hptiop)
+HIGHPOINT ROCKETRAID 3xxx/4xxx ADAPTER DRIVER (hptiop)
 
 Controller Register Map
 -------------------------
 
-The controller IOP is accessed via PCI BAR0.
+For Intel IOP based adapters, the controller IOP is accessed via PCI BAR0:
 
      BAR0 offset    Register
             0x10    Inbound Message Register 0
@@ -18,6 +18,24 @@ The controller IOP is accessed via PCI BAR0.
             0x40    Inbound Queue Port
             0x44    Outbound Queue Port
 
+For Marvell IOP based adapters, the IOP is accessed via PCI BAR0 and BAR1:
+
+     BAR0 offset    Register
+         0x20400    Inbound Doorbell Register
+         0x20404    Inbound Interrupt Mask Register
+         0x20408    Outbound Doorbell Register
+         0x2040C    Outbound Interrupt Mask Register
+
+     BAR1 offset    Register
+             0x0    Inbound Queue Head Pointer
+             0x4    Inbound Queue Tail Pointer
+             0x8    Outbound Queue Head Pointer
+             0xC    Outbound Queue Tail Pointer
+            0x10    Inbound Message Register
+            0x14    Outbound Message Register
+     0x40-0x1040    Inbound Queue
+   0x1040-0x2040    Outbound Queue
+
 
 I/O Request Workflow
 ----------------------
@@ -73,15 +91,9 @@ The driver exposes following sysfs attributes:
      driver-version        R     driver version string
      firmware-version      R     firmware version string
 
-The driver registers char device "hptiop" to communicate with HighPoint RAID
-management software. Its ioctl routine acts as a general binary interface 
-between the IOP firmware and HighPoint RAID management software. New management
-functions can be implemented in application/firmware without modification
-in driver code.
-
 
 -----------------------------------------------------------------------------
-Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
 
   This file is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/Documentation/scsi/ncr53c7xx.txt b/Documentation/scsi/ncr53c7xx.txt
deleted file mode 100644 (file)
index 91e9552..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-README for WarpEngine/A4000T/A4091 SCSI kernels.
-
-Use the following options to disable options in the SCSI driver.
-
-Using amiboot for example.....
-
-To disable Synchronous Negotiation....
-
-       amiboot -k kernel 53c7xx=nosync:0       
-
-To disable Disconnection....
-       
-       amiboot -k kernel 53c7xx=nodisconnect:0
-
-To disable certain SCSI devices...
-
-       amiboot -k kernel 53c7xx=validids:0x3F
-
-       this allows only device ID's 0,1,2,3,4 and 5 for linux to handle.
-       (this is a bitmasked field - i.e. each bit represents a SCSI ID)
-
-These commands work on a per controller basis and use the option 'next' to
-move to the next controller in the system.
-
-e.g.
-       amiboot -k kernel 53c7xx=nodisconnect:0,next,nosync:0
-
-       this uses No Disconnection on the first controller and Asynchronous
-       SCSI on the second controller.
-
-Known Issues:
-
-Two devices are known not to function with the default settings of using
-synchronous SCSI. These are the Archive Viper 150 Tape Drive and the 
-SyQuest SQ555 removeable hard drive. When using these devices on a controller
-use the 'nosync:0' option.
-
-Please try these options and post any problems/successes to me.
-
-Alan Hourihane <alanh@fairlite.demon.co.uk>
index 00cb646a4bdeefb36743232f3080c828e0f3d0ef..0924e6e142c40a2f7d6a5dec0ae107ff5d616d8c 100644 (file)
@@ -1,5 +1,7 @@
   0 -> UNKNOWN/GENERIC                                     [0070:3400]
   1 -> Hauppauge WinTV-HVR1800lp                           [0070:7600]
-  2 -> Hauppauge WinTV-HVR1800                             [0070:7800,0070:7801]
+  2 -> Hauppauge WinTV-HVR1800                             [0070:7800,0070:7801,0070:7809]
   3 -> Hauppauge WinTV-HVR1250                             [0070:7911]
   4 -> DViCO FusionHDTV5 Express                           [18ac:d500]
+  5 -> Hauppauge WinTV-HVR1500Q                            [0070:7790,0070:7797]
+  6 -> Hauppauge WinTV-HVR1500                             [0070:7710,0070:7717]
index 82ac8250e978b8e784d42888b445201726493389..bc5593bd9704dc8497d6d69d01642938bb20f5b9 100644 (file)
@@ -56,3 +56,4 @@
  55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM  [c180:c980]
  56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder   [0070:9600,0070:9601,0070:9602]
  57 -> ADS Tech Instant Video PCI                          [1421:0390]
+ 58 -> Pinnacle PCTV HD 800i                               [11bd:0051]
index 37f0e3cedf43dba5dacbba345ea58ecc05364888..6a8469f2bcaeb64c819e71a175df5c65120a036d 100644 (file)
@@ -1,14 +1,17 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2820/2840 video grabber        (em2820/em2840)
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2750,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
-  4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200]
-  5 -> MSI VOX USB 2.0                          (em2820/em2840) [eb1a:2820]
+  4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
+  5 -> MSI VOX USB 2.0                          (em2820/em2840)
   6 -> Terratec Cinergy 200 USB                 (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)
   8 -> Kworld USB2800                           (em2800)
-  9 -> Pinnacle Dazzle DVC 90                   (em2820/em2840) [2304:0207]
- 10 -> Hauppauge WinTV HVR 900                  (em2880)
- 11 -> Terratec Hybrid XS                       (em2880)
+  9 -> Pinnacle Dazzle DVC 90/DVC 100           (em2820/em2840) [2304:0207,2304:021a]
+ 10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
+ 11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
- 13 -> Terratec Prodigy XS                      (em2880)
+ 13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
+ 15 -> V-Gear PocketTV                          (em2800)
+ 16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513]
index ddd76a0eb1002d19a9e6ba6516f1ac7d0971f78d..a019e27e42b3ea446bd97563ff7586e25954e53b 100644 (file)
@@ -16,3 +16,9 @@
 16 -> GOTVIEW PCI DVD2 Deluxe                  [ffac:0600]
 17 -> Yuan MPC622                              [ff01:d998]
 18 -> Digital Cowboy DCT-MTVP1                         [1461:bfff]
+19 -> Yuan PG600V2/GotView PCI DVD Lite        [ffab:0600,ffad:0600]
+20 -> Club3D ZAP-TV1x01                                [ffab:0600]
+21 -> AverTV MCE 116 Plus                      [1461:c439]
+22 -> ASUS Falcon2                             [1043:4b66,1043:462e,1043:4b2e]
+23 -> AverMedia PVR-150 Plus                   [1461:c035]
+24 -> AverMedia EZMaker PCI Deluxe             [1461:c03f]
index a14545300e4c84d5916da0af643cf91b370fc4d8..5d3b6b4d251509f0ddbd0057fd9418e16a14cf54 100644 (file)
@@ -80,7 +80,7 @@
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
- 82 -> MSI TV@Anywhere plus                     [1462:6231]
+ 82 -> MSI TV@Anywhere plus                     [1462:6231,1462:8624]
  83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
  84 -> LifeView FlyDVB Trio                     [5168:0319]
  85 -> AverTV DVB-T 777                         [1461:2c05,1461:2c05]
 101 -> Pinnacle PCTV 310i                       [11bd:002f]
 102 -> Avermedia AVerTV Studio 507              [1461:9715]
 103 -> Compro Videomate DVB-T200A
-104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid     [0070:6701]
+104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid     [0070:6700,0070:6701,0070:6702,0070:6703,0070:6704,0070:6705]
 105 -> Terratec Cinergy HT PCMCIA               [153b:1172]
 106 -> Encore ENLTV                             [1131:2342,1131:2341,3016:2344]
 107 -> Encore ENLTV-FM                          [1131:230f]
 115 -> Sabrent PCMCIA TV-PCB05                  [0919:2003]
 116 -> 10MOONS TM300 TV Card                    [1131:2304]
 117 -> Avermedia Super 007                      [1461:f01d]
+118 -> Beholder BeholdTV 401                    [0000:4016]
+119 -> Beholder BeholdTV 403                    [0000:4036]
+120 -> Beholder BeholdTV 403 FM                 [0000:4037]
+121 -> Beholder BeholdTV 405                    [0000:4050]
+122 -> Beholder BeholdTV 405 FM                 [0000:4051]
+123 -> Beholder BeholdTV 407                    [0000:4070]
+124 -> Beholder BeholdTV 407 FM                 [0000:4071]
+125 -> Beholder BeholdTV 409                    [0000:4090]
+126 -> Beholder BeholdTV 505 FM/RDS             [0000:5051,0000:505B,5ace:5050]
+127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
+128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
+129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
+130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193]
index a88c02d238059b0fa277409f66860704f0b56509..0e2394695bb86843fb89a166eaa83727a2d9a37e 100644 (file)
@@ -52,7 +52,7 @@ tuner=50 - TCL 2002N
 tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
 tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
-tuner=54 - tda8290+75
+tuner=54 - Philips/NXP TDA 8290/8295 + 8275/8275A/18271
 tuner=55 - TCL 2002MB
 tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 tuner=57 - Philips FQ1236A MK4
@@ -69,7 +69,8 @@ tuner=67 - Philips TD1316 Hybrid Tuner
 tuner=68 - Philips TUV1236D ATSC/NTSC dual in
 tuner=69 - Tena TNF 5335 and similar models
 tuner=70 - Samsung TCPN 2121P30A
-tuner=71 - Xceive xc3028
+tuner=71 - Xceive xc2028/xc3028 tuner
 tuner=72 - Thomson FE6600
 tuner=73 - Samsung TCPG 6121P30A
 tuner=75 - Philips TEA5761 FM Radio
+tuner=76 - Xceive 5000 tuner
index 3d6850ef0245e1b872d4937688339f6a3980cfee..0b72d3fee17ef4bb02a8d37c763a5d73fb84f4d0 100644 (file)
@@ -62,3 +62,4 @@
  61 -> Pinnacle Studio Linx Video input cable (PAL)             [2304:0301]
  62 -> Pinnacle PCTV Bungee USB (PAL) FM                        [2304:0419]
  63 -> Hauppauge WinTv-USB                                      [2400:4200]
+ 64 -> Pinnacle Studio PCTV USB (NTSC) FM V3                    [2304:0113]
diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl
new file mode 100644 (file)
index 0000000..cced8ac
--- /dev/null
@@ -0,0 +1,926 @@
+#!/usr/bin/perl
+
+# Copyright (c) Mauro Carvalho Chehab <mchehab@infradead.org>
+# Released under GPLv2
+#
+# In order to use, you need to:
+#      1) Download the windows driver with something like:
+#              wget http://www.steventoth.net/linux/xc5000/HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip
+#      2) Extract the file hcw85bda.sys from the zip into the current dir:
+#              unzip -j HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip Driver85/hcw85bda.sys
+#      3) run the script:
+#              ./extract_xc3028.pl
+#      4) copy the generated file:
+#              cp xc3028-v27.fw /lib/firmware
+
+#use strict;
+use IO::Handle;
+
+my $debug=0;
+
+sub verify ($$)
+{
+       my ($filename, $hash) = @_;
+       my ($testhash);
+
+       if (system("which md5sum > /dev/null 2>&1")) {
+               die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n";
+       }
+
+       open(CMD, "md5sum ".$filename."|");
+       $testhash = <CMD>;
+       $testhash =~ /([a-zA-Z0-9]*)/;
+       $testhash = $1;
+       close CMD;
+               die "Hash of extracted file does not match (found $testhash, expected $hash!\n" if ($testhash ne $hash);
+}
+
+sub get_hunk ($$)
+{
+       my ($offset, $length) = @_;
+       my ($chunklength, $buf, $rcount, $out);
+
+       sysseek(INFILE, $offset, SEEK_SET);
+       while ($length > 0) {
+       # Calc chunk size
+               $chunklength = 2048;
+               $chunklength = $length if ($chunklength > $length);
+
+               $rcount = sysread(INFILE, $buf, $chunklength);
+               die "Ran out of data\n" if ($rcount != $chunklength);
+               $out .= $buf;
+               $length -= $rcount;
+       }
+       return $out;
+}
+
+sub write_le16($)
+{
+       my $val = shift;
+       my $msb = ($val >> 8) &0xff;
+       my $lsb = $val & 0xff;
+
+       syswrite(OUTFILE, chr($lsb).chr($msb));
+}
+
+sub write_le32($)
+{
+       my $val = shift;
+       my $l3 = ($val >> 24) & 0xff;
+       my $l2 = ($val >> 16) & 0xff;
+       my $l1 = ($val >> 8)  & 0xff;
+       my $l0 = $val         & 0xff;
+
+       syswrite(OUTFILE, chr($l0).chr($l1).chr($l2).chr($l3));
+}
+
+sub write_le64($$)
+{
+       my $msb_val = shift;
+       my $lsb_val = shift;
+       my $l7 = ($msb_val >> 24) & 0xff;
+       my $l6 = ($msb_val >> 16) & 0xff;
+       my $l5 = ($msb_val >> 8)  & 0xff;
+       my $l4 = $msb_val         & 0xff;
+
+       my $l3 = ($lsb_val >> 24) & 0xff;
+       my $l2 = ($lsb_val >> 16) & 0xff;
+       my $l1 = ($lsb_val >> 8)  & 0xff;
+       my $l0 = $lsb_val         & 0xff;
+
+       syswrite(OUTFILE,
+                chr($l0).chr($l1).chr($l2).chr($l3).
+                chr($l4).chr($l5).chr($l6).chr($l7));
+}
+
+sub write_hunk($$)
+{
+       my ($offset, $length) = @_;
+       my $out = get_hunk($offset, $length);
+
+       printf "(len %d) ",$length if ($debug);
+
+       for (my $i=0;$i<$length;$i++) {
+               printf "%02x ",ord(substr($out,$i,1)) if ($debug);
+       }
+       printf "\n" if ($debug);
+
+       syswrite(OUTFILE, $out);
+}
+
+sub write_hunk_fix_endian($$)
+{
+       my ($offset, $length) = @_;
+       my $out = get_hunk($offset, $length);
+
+       printf "(len_fix %d) ",$length if ($debug);
+
+       for (my $i=0;$i<$length;$i++) {
+               printf "%02x ",ord(substr($out,$i,1)) if ($debug);
+       }
+       printf "\n" if ($debug);
+
+       my $i=0;
+       while ($i<$length) {
+               my $size = ord(substr($out,$i,1))*256+ord(substr($out,$i+1,1));
+               syswrite(OUTFILE, substr($out,$i+1,1));
+               syswrite(OUTFILE, substr($out,$i,1));
+               $i+=2;
+               if ($size>0 && $size <0x8000) {
+                       for (my $j=0;$j<$size;$j++) {
+                               syswrite(OUTFILE, substr($out,$j+$i,1));
+                       }
+                       $i+=$size;
+               }
+       }
+}
+
+sub main_firmware($$$$)
+{
+       my $out;
+       my $j=0;
+       my $outfile = shift;
+       my $name    = shift;
+       my $version = shift;
+       my $nr_desc = shift;
+
+       for ($j = length($name); $j <32; $j++) {
+               $name = $name.chr(0);
+}
+
+       open OUTFILE, ">$outfile";
+       syswrite(OUTFILE, $name);
+       write_le16($version);
+       write_le16($nr_desc);
+
+       #
+       # Firmware 0, type: BASE FW   F8MHZ (0x00000003), id: (0000000000000000), size: 8718
+       #
+
+       write_le32(0x00000003);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(8718);                       # Size
+       write_hunk_fix_endian(813432, 8718);
+
+       #
+       # Firmware 1, type: BASE FW   F8MHZ MTS (0x00000007), id: (0000000000000000), size: 8712
+       #
+
+       write_le32(0x00000007);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(8712);                       # Size
+       write_hunk_fix_endian(822152, 8712);
+
+       #
+       # Firmware 2, type: BASE FW   FM (0x00000401), id: (0000000000000000), size: 8562
+       #
+
+       write_le32(0x00000401);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(8562);                       # Size
+       write_hunk_fix_endian(830872, 8562);
+
+       #
+       # Firmware 3, type: BASE FW   FM INPUT1 (0x00000c01), id: (0000000000000000), size: 8576
+       #
+
+       write_le32(0x00000c01);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(8576);                       # Size
+       write_hunk_fix_endian(839440, 8576);
+
+       #
+       # Firmware 4, type: BASE FW   (0x00000001), id: (0000000000000000), size: 8706
+       #
+
+       write_le32(0x00000001);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(8706);                       # Size
+       write_hunk_fix_endian(848024, 8706);
+
+       #
+       # Firmware 5, type: BASE FW   MTS (0x00000005), id: (0000000000000000), size: 8682
+       #
+
+       write_le32(0x00000005);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(8682);                       # Size
+       write_hunk_fix_endian(856736, 8682);
+
+       #
+       # Firmware 6, type: STD FW    (0x00000000), id: PAL/BG A2/A (0000000100000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000001, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(865424, 161);
+
+       #
+       # Firmware 7, type: STD FW    MTS (0x00000004), id: PAL/BG A2/A (0000000100000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000001, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(865592, 169);
+
+       #
+       # Firmware 8, type: STD FW    (0x00000000), id: PAL/BG A2/B (0000000200000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000002, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(865424, 161);
+
+       #
+       # Firmware 9, type: STD FW    MTS (0x00000004), id: PAL/BG A2/B (0000000200000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000002, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(865592, 169);
+
+       #
+       # Firmware 10, type: STD FW    (0x00000000), id: PAL/BG NICAM/A (0000000400000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000004, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(866112, 161);
+
+       #
+       # Firmware 11, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/A (0000000400000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000004, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(866280, 169);
+
+       #
+       # Firmware 12, type: STD FW    (0x00000000), id: PAL/BG NICAM/B (0000000800000007), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000008, 0x00000007);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(866112, 161);
+
+       #
+       # Firmware 13, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/B (0000000800000007), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000008, 0x00000007);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(866280, 169);
+
+       #
+       # Firmware 14, type: STD FW    (0x00000000), id: PAL/DK A2 (00000003000000e0), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(866800, 161);
+
+       #
+       # Firmware 15, type: STD FW    MTS (0x00000004), id: PAL/DK A2 (00000003000000e0), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(866968, 169);
+
+       #
+       # Firmware 16, type: STD FW    (0x00000000), id: PAL/DK NICAM (0000000c000000e0), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x0000000c, 0x000000e0);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(867144, 161);
+
+       #
+       # Firmware 17, type: STD FW    MTS (0x00000004), id: PAL/DK NICAM (0000000c000000e0), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x0000000c, 0x000000e0);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(867312, 169);
+
+       #
+       # Firmware 18, type: STD FW    (0x00000000), id: SECAM/K1 (0000000000200000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(867488, 161);
+
+       #
+       # Firmware 19, type: STD FW    MTS (0x00000004), id: SECAM/K1 (0000000000200000), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(867656, 169);
+
+       #
+       # Firmware 20, type: STD FW    (0x00000000), id: SECAM/K3 (0000000004000000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x04000000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(867832, 161);
+
+       #
+       # Firmware 21, type: STD FW    MTS (0x00000004), id: SECAM/K3 (0000000004000000), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x04000000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(868000, 169);
+
+       #
+       # Firmware 22, type: STD FW    D2633 DTV6 ATSC (0x00010030), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00010030);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868176, 149);
+
+       #
+       # Firmware 23, type: STD FW    D2620 DTV6 QAM (0x00000068), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000068);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868336, 149);
+
+       #
+       # Firmware 24, type: STD FW    D2633 DTV6 QAM (0x00000070), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000070);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868488, 149);
+
+       #
+       # Firmware 25, type: STD FW    D2620 DTV7 (0x00000088), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000088);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868648, 149);
+
+       #
+       # Firmware 26, type: STD FW    D2633 DTV7 (0x00000090), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000090);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868800, 149);
+
+       #
+       # Firmware 27, type: STD FW    D2620 DTV78 (0x00000108), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000108);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868960, 149);
+
+       #
+       # Firmware 28, type: STD FW    D2633 DTV78 (0x00000110), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000110);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(869112, 149);
+
+       #
+       # Firmware 29, type: STD FW    D2620 DTV8 (0x00000208), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000208);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868648, 149);
+
+       #
+       # Firmware 30, type: STD FW    D2633 DTV8 (0x00000210), id: (0000000000000000), size: 149
+       #
+
+       write_le32(0x00000210);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(149);                        # Size
+       write_hunk_fix_endian(868800, 149);
+
+       #
+       # Firmware 31, type: STD FW    FM (0x00000400), id: (0000000000000000), size: 135
+       #
+
+       write_le32(0x00000400);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le32(135);                        # Size
+       write_hunk_fix_endian(869584, 135);
+
+       #
+       # Firmware 32, type: STD FW    (0x00000000), id: PAL/I (0000000000000010), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(869728, 161);
+
+       #
+       # Firmware 33, type: STD FW    MTS (0x00000004), id: PAL/I (0000000000000010), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(869896, 169);
+
+       #
+       # Firmware 34, type: STD FW    (0x00000000), id: SECAM/L AM (0000001000400000), size: 169
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000010, 0x00400000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(870072, 169);
+
+       #
+       # Firmware 35, type: STD FW    (0x00000000), id: SECAM/L NICAM (0000000c00400000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x0000000c, 0x00400000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(870248, 161);
+
+       #
+       # Firmware 36, type: STD FW    (0x00000000), id: SECAM/Lc (0000000000800000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00800000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(870416, 161);
+
+       #
+       # Firmware 37, type: STD FW    (0x00000000), id: NTSC/M Kr (0000000000008000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(870584, 161);
+
+       #
+       # Firmware 38, type: STD FW    LCD (0x00001000), id: NTSC/M Kr (0000000000008000), size: 161
+       #
+
+       write_le32(0x00001000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(870752, 161);
+
+       #
+       # Firmware 39, type: STD FW    LCD NOGD (0x00003000), id: NTSC/M Kr (0000000000008000), size: 161
+       #
+
+       write_le32(0x00003000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(870920, 161);
+
+       #
+       # Firmware 40, type: STD FW    MTS (0x00000004), id: NTSC/M Kr (0000000000008000), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(871088, 169);
+
+       #
+       # Firmware 41, type: STD FW    (0x00000000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(871264, 161);
+
+       #
+       # Firmware 42, type: STD FW    LCD (0x00001000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+       #
+
+       write_le32(0x00001000);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(871432, 161);
+
+       #
+       # Firmware 43, type: STD FW    LCD NOGD (0x00003000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+       #
+
+       write_le32(0x00003000);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(871600, 161);
+
+       #
+       # Firmware 44, type: STD FW    (0x00000000), id: NTSC/M Jp (0000000000002000), size: 161
+       #
+
+       write_le32(0x00000000);                 # Type
+       write_le64(0x00000000, 0x00002000);     # ID
+       write_le32(161);                        # Size
+       write_hunk_fix_endian(871264, 161);
+
+       #
+       # Firmware 45, type: STD FW    MTS (0x00000004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+       #
+
+       write_le32(0x00000004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(871936, 169);
+
+       #
+       # Firmware 46, type: STD FW    MTS LCD (0x00001004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+       #
+
+       write_le32(0x00001004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(872112, 169);
+
+       #
+       # Firmware 47, type: STD FW    MTS LCD NOGD (0x00003004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+       #
+
+       write_le32(0x00003004);                 # Type
+       write_le64(0x00000000, 0x0000b700);     # ID
+       write_le32(169);                        # Size
+       write_hunk_fix_endian(872288, 169);
+
+       #
+       # Firmware 48, type: SCODE FW  HAS IF (0x60000000), IF = 3.28 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3280);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(811896, 192);
+
+       #
+       # Firmware 49, type: SCODE FW  HAS IF (0x60000000), IF = 3.30 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3300);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(813048, 192);
+
+       #
+       # Firmware 50, type: SCODE FW  HAS IF (0x60000000), IF = 3.44 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3440);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(812280, 192);
+
+       #
+       # Firmware 51, type: SCODE FW  HAS IF (0x60000000), IF = 3.46 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3460);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(812472, 192);
+
+       #
+       # Firmware 52, type: SCODE FW  DTV6 ATSC OREN36 HAS IF (0x60210020), IF = 3.80 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60210020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(3800);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(809784, 192);
+
+       #
+       # Firmware 53, type: SCODE FW  HAS IF (0x60000000), IF = 4.00 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4000);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(812088, 192);
+
+       #
+       # Firmware 54, type: SCODE FW  DTV6 ATSC TOYOTA388 HAS IF (0x60410020), IF = 4.08 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60410020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4080);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(809976, 192);
+
+       #
+       # Firmware 55, type: SCODE FW  HAS IF (0x60000000), IF = 4.20 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4200);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(811704, 192);
+
+       #
+       # Firmware 56, type: SCODE FW  MONO HAS IF (0x60008000), IF = 4.32 MHz id: NTSC/M Kr (0000000000008000), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le16(4320);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(808056, 192);
+
+       #
+       # Firmware 57, type: SCODE FW  HAS IF (0x60000000), IF = 4.45 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4450);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(812664, 192);
+
+       #
+       # Firmware 58, type: SCODE FW  HAS IF (0x60000000), IF = 4.50 MHz id: NTSC/M Jp (0000000000002000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00002000);     # ID
+       write_le16(4500);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(807672, 192);
+
+       #
+       # Firmware 59, type: SCODE FW  LCD NOGD IF HAS IF (0x60023000), IF = 4.60 MHz id: NTSC/M Kr (0000000000008000), size: 192
+       #
+
+       write_le32(0x60023000);                 # Type
+       write_le64(0x00000000, 0x00008000);     # ID
+       write_le16(4600);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(807864, 192);
+
+       #
+       # Firmware 60, type: SCODE FW  DTV78 ZARLINK456 HAS IF (0x62000100), IF = 4.76 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x62000100);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4760);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(807288, 192);
+
+       #
+       # Firmware 61, type: SCODE FW  HAS IF (0x60000000), IF = 4.94 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(4940);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(811512, 192);
+
+       #
+       # Firmware 62, type: SCODE FW  DTV7 ZARLINK456 HAS IF (0x62000080), IF = 5.26 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x62000080);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5260);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(810552, 192);
+
+       #
+       # Firmware 63, type: SCODE FW  MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000008, 0x00000007);     # ID
+       write_le16(5320);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(810744, 192);
+
+       #
+       # Firmware 64, type: SCODE FW  DTV8 CHINA HAS IF (0x64000200), IF = 5.40 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x64000200);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5400);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(807096, 192);
+
+       #
+       # Firmware 65, type: SCODE FW  DTV6 ATSC OREN538 HAS IF (0x60110020), IF = 5.58 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60110020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5580);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(809592, 192);
+
+       #
+       # Firmware 66, type: SCODE FW  HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2/B (0000000200000007), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000002, 0x00000007);     # ID
+       write_le16(5640);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(808440, 192);
+
+       #
+       # Firmware 67, type: SCODE FW  HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000008, 0x00000007);     # ID
+       write_le16(5740);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(808632, 192);
+
+       #
+       # Firmware 68, type: SCODE FW  DTV7 DIBCOM52 HAS IF (0x61000080), IF = 5.90 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x61000080);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(5900);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(810360, 192);
+
+       #
+       # Firmware 69, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/I (0000000000000010), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le16(6000);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(808824, 192);
+
+       #
+       # Firmware 70, type: SCODE FW  DTV6 QAM F6MHZ HAS IF (0x68000060), IF = 6.20 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x68000060);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(6200);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(809400, 192);
+
+       #
+       # Firmware 71, type: SCODE FW  HAS IF (0x60000000), IF = 6.24 MHz id: PAL/I (0000000000000010), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000010);     # ID
+       write_le16(6240);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(808248, 192);
+
+       #
+       # Firmware 72, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.32 MHz id: SECAM/K1 (0000000000200000), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le16(6320);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(811320, 192);
+
+       #
+       # Firmware 73, type: SCODE FW  HAS IF (0x60000000), IF = 6.34 MHz id: SECAM/K1 (0000000000200000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00200000);     # ID
+       write_le16(6340);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(809208, 192);
+
+       #
+       # Firmware 74, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.50 MHz id: SECAM/K3 (0000000004000000), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000000, 0x04000000);     # ID
+       write_le16(6500);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(811128, 192);
+
+       #
+       # Firmware 75, type: SCODE FW  DTV6 ATSC ATI638 HAS IF (0x60090020), IF = 6.58 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60090020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(6580);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(807480, 192);
+
+       #
+       # Firmware 76, type: SCODE FW  HAS IF (0x60000000), IF = 6.60 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le16(6600);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(809016, 192);
+
+       #
+       # Firmware 77, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.68 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+       #
+
+       write_le32(0x60008000);                 # Type
+       write_le64(0x00000003, 0x000000e0);     # ID
+       write_le16(6680);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(810936, 192);
+
+       #
+       # Firmware 78, type: SCODE FW  DTV6 ATSC TOYOTA794 HAS IF (0x60810020), IF = 8.14 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60810020);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(8140);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(810168, 192);
+
+       #
+       # Firmware 79, type: SCODE FW  HAS IF (0x60000000), IF = 8.20 MHz id: (0000000000000000), size: 192
+       #
+
+       write_le32(0x60000000);                 # Type
+       write_le64(0x00000000, 0x00000000);     # ID
+       write_le16(8200);                       # IF
+       write_le32(192);                        # Size
+       write_hunk(812856, 192);
+}
+
+sub extract_firmware {
+       my $sourcefile = "hcw85bda.sys";
+       my $hash = "0e44dbf63bb0169d57446aec21881ff2";
+       my $outfile = "xc3028-v27.fw";
+       my $name = "xc2028 firmware";
+       my $version = 519;
+       my $nr_desc = 80;
+       my $out;
+
+       verify($sourcefile, $hash);
+
+       open INFILE, "<$sourcefile";
+       main_firmware($outfile, $name, $version, $nr_desc);
+       close INFILE;
+}
+
+extract_firmware;
+printf "Firmwares generated.\n";
index 1ffad19ce8910b375fa46b192a66918e28ac33f3..b26f5195af51f58db1d4a04f2826e044b29bc8a2 100644 (file)
@@ -568,6 +568,7 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
 Many thanks to following persons for their contribute (listed in alphabetical
 order):
 
+- David Anderson for the donation of a webcam;
 - Luca Capello for the donation of a webcam;
 - Philippe Coval for having helped testing the PAS202BCA image sensor;
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
index 7047696c47a18b6172549c9174b5988a7c2881c4..488c1f31b99249b75a9686cf42f08329bea896c9 100644 (file)
@@ -1021,7 +1021,7 @@ void read_slab_dir(void)
        char *t;
        int count;
 
-       if (chdir("/sys/slab"))
+       if (chdir("/sys/kernel/slab"))
                fatal("SYSFS support for SLUB not active\n");
 
        dir = opendir(".");
index d17f324db9f51a538daccf3619b2eed445890525..dcf8bcf846d6a5486b737c840b4dce7d71ae89e2 100644 (file)
@@ -63,7 +63,7 @@ In case you forgot to enable debugging on the kernel command line: It is
 possible to enable debugging manually when the kernel is up. Look at the
 contents of:
 
-/sys/slab/<slab name>/
+/sys/kernel/slab/<slab name>/
 
 Look at the writable files. Writing 1 to them will enable the
 corresponding debug option. All options can be set on a slab that does
index bb7cb1d31ec70f3424e41e7b99b15c0ce5dbc87a..4cc4ba9d71500a4b5dd55b70ed9f54dc099b4ddd 100644 (file)
@@ -42,23 +42,27 @@ like this source file:  see Documentation/watchdog/src/watchdog-simple.c
 A more advanced driver could for example check that a HTTP server is
 still responding before doing the write call to ping the watchdog.
 
-When the device is closed, the watchdog is disabled.  This is not
-always such a good idea, since if there is a bug in the watchdog
-daemon and it crashes the system will not reboot.  Because of this,
-some of the drivers support the configuration option "Disable watchdog
-shutdown on close", CONFIG_WATCHDOG_NOWAYOUT.  If it is set to Y when
-compiling the kernel, there is no way of disabling the watchdog once
-it has been started.  So, if the watchdog daemon crashes, the system
-will reboot after the timeout has passed. Watchdog devices also usually
-support the nowayout module parameter so that this option can be controlled
-at runtime.
-
-Drivers will not disable the watchdog, unless a specific magic character 'V'
-has been sent /dev/watchdog just before closing the file.  If the userspace
-daemon closes the file without sending this special character, the driver
-will assume that the daemon (and userspace in general) died, and will stop
-pinging the watchdog without disabling it first.  This will then cause a
-reboot if the watchdog is not re-opened in sufficient time.
+When the device is closed, the watchdog is disabled, unless the "Magic
+Close" feature is supported (see below).  This is not always such a
+good idea, since if there is a bug in the watchdog daemon and it
+crashes the system will not reboot.  Because of this, some of the
+drivers support the configuration option "Disable watchdog shutdown on
+close", CONFIG_WATCHDOG_NOWAYOUT.  If it is set to Y when compiling
+the kernel, there is no way of disabling the watchdog once it has been
+started.  So, if the watchdog daemon crashes, the system will reboot
+after the timeout has passed. Watchdog devices also usually support
+the nowayout module parameter so that this option can be controlled at
+runtime.
+
+Magic Close feature:
+
+If a driver supports "Magic Close", the driver will not disable the
+watchdog unless a specific magic character 'V' has been sent to
+/dev/watchdog just before closing the file.  If the userspace daemon
+closes the file without sending this special character, the driver
+will assume that the daemon (and userspace in general) died, and will
+stop pinging the watchdog without disabling it first.  This will then
+cause a reboot if the watchdog is not re-opened in sufficient time.
 
 The ioctl API:
 
diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle
new file mode 100644 (file)
index 0000000..ecd9307
--- /dev/null
@@ -0,0 +1,701 @@
+Chinese translated version of Documentation/CodingStyle
+
+If you have any comment or update to the content, please post to LKML directly.
+However, if you have problem communicating in English you can also ask the
+Chinese maintainer for help.  Contact the Chinese maintainer, if this
+translation is outdated or there is problem with translation.
+
+Chinese maintainer: Zhang Le <r0bertz@gentoo.org>
+---------------------------------------------------------------------
+Documentation/CodingStyle的中文翻译
+
+如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可
+以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。
+
+中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org>
+中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org>
+中文版校译者: 王聪 Wang Cong <xiyou.wangcong@gmail.com>
+               wheelz <kernel.zeng@gmail.com>
+               管旭东 Xudong Guan <xudong.guan@gmail.com>
+               Li Zefan <lizf@cn.fujitsu.com>
+               Wang Chen <wangchen@cn.fujitsu.com>
+以下为正文
+---------------------------------------------------------------------
+
+               Linux内核代码风格
+
+这是一个简短的文档,描述了linux内核的首选代码风格。代码风格是因人而异的,而且我
+不愿意把我的观点强加给任何人,不过这里所讲述的是我必须要维护的代码所遵守的风格,
+并且我也希望绝大多数其他代码也能遵守这个风格。请在写代码时至少考虑一下本文所述的
+风格。
+
+首先,我建议你打印一份GNU代码规范,然后不要读它。烧了它,这是一个具有重大象征性
+意义的动作。
+
+不管怎样,现在我们开始:
+
+
+               第一章:缩进
+
+制表符是8个字符,所以缩进也是8个字符。有些异端运动试图将缩进变为4(乃至2)个字符
+深,这几乎相当于尝试将圆周率的值定义为3。
+
+理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕
+连续看了20小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。
+
+现在,有些人会抱怨8个字符的缩进会使代码向右边移动的太远,在80个字符的终端屏幕上
+就很难读这样的代码。这个问题的答案是,如果你需要3级以上的缩进,不管用何种方式你
+的代码已经有问题了,应该修正你的程序。
+
+简而言之,8个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的
+时候可以给你警告。留心这个警告。
+
+在switch语句中消除多级缩进的首选的方式是让“switch”和从属于它的“case”标签对齐于同
+一列,而不要“两次缩进”“case”标签。比如:
+
+       switch (suffix) {
+       case 'G':
+       case 'g':
+               mem <<= 30;
+               break;
+       case 'M':
+       case 'm':
+               mem <<= 20;
+               break;
+       case 'K':
+       case 'k':
+               mem <<= 10;
+               /* fall through */
+       default:
+               break;
+       }
+
+
+不要把多个语句放在一行里,除非你有什么东西要隐藏:
+
+       if (condition) do_this;
+         do_something_everytime;
+
+也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表
+达式。
+
+除了注释、文档和Kconfig之外,不要使用空格来缩进,前面的例子是例外,是有意为之。
+
+选用一个好的编辑器,不要在行尾留空格。
+
+
+               第二章:把长的行和字符串打散
+
+代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
+
+每一行的长度的限制是80列,我们强烈建议您遵守这个惯例。
+
+长于80列的语句要打散成有意义的片段。每个片段要明显短于原来的语句,而且放置的位置
+也明显的靠右。同样的规则也适用于有很长参数列表的函数头。长字符串也要打散成较短的
+字符串。唯一的例外是超过80列可以大幅度提高可读性并且不会隐藏信息的情况。
+
+void fun(int a, int b, int c)
+{
+       if (condition)
+               printk(KERN_WARNING "Warning this is a long printk with "
+                                               "3 parameters a: %u b: %u "
+                                               "c: %u \n", a, b, c);
+       else
+               next_statement;
+}
+
+               第三章:大括号和空格的放置
+
+C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放置策
+略并没有多少技术上的原因,不过首选的方式,就像Kernighan和Ritchie展示给我们的,是
+把起始大括号放在行尾,而把结束大括号放在行首,所以:
+
+       if (x is true) {
+               we do y
+       }
+
+这适用于所有的非函数语句块(if、switch、for、while、do)。比如:
+
+       switch (action) {
+       case KOBJ_ADD:
+               return "add";
+       case KOBJ_REMOVE:
+               return "remove";
+       case KOBJ_CHANGE:
+               return "change";
+       default:
+               return NULL;
+       }
+
+不过,有一个例外,那就是函数:函数的起始大括号放置于下一行的开头,所以:
+
+       int function(int x)
+       {
+               body of function
+       }
+
+全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道(
+a)K&R是_正确的_,并且(b)K&R是正确的。此外,不管怎样函数都是特殊的(在C语言中
+,函数是不能嵌套的)。
+
+注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是do语句中的
+“while”或者if语句中的“else”,像这样:
+
+       do {
+               body of do-loop
+       } while (condition);
+
+和
+
+       if (x == y) {
+               ..
+       } else if (x > y) {
+               ...
+       } else {
+               ....
+       }
+
+理由:K&R。
+
+也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可
+读性。因此,由于你的屏幕上的新行是不可再生资源(想想25行的终端屏幕),你将会有更
+多的空行来放置注释。
+
+当只有一个单独的语句的时候,不用加不必要的大括号。
+
+if (condition)
+       action();
+
+这点不适用于本身为某个条件语句的一个分支的单独语句。这时需要在两个分支里都使用大
+括号。
+
+if (condition) {
+       do_this();
+       do_that();
+} else {
+       otherwise();
+}
+
+               3.1:空格
+
+Linux内核的空格使用方式(主要)取决于它是用于函数还是关键字。(大多数)关键字后
+要加一个空格。值得注意的例外是sizeof、typeof、alignof和__attribute__,这些关键字
+某些程度上看起来更像函数(它们在Linux里也常常伴随小括号而使用,尽管在C语言里这样
+的小括号不是必需的,就像“struct fileinfo info”声明过后的“sizeof info”)。
+
+所以在这些关键字之后放一个空格:
+       if, switch, case, for, do, while
+但是不要在sizeof、typeof、alignof或者__attribute__这些关键字之后放空格。例如,
+       s = sizeof(struct file);
+
+不要在小括号里的表达式两侧加空格。这是一个反例:
+
+       s = sizeof( struct file );
+
+当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函
+数名,而不是靠近类型名。例子:
+
+       char *linux_banner;
+       unsigned long long memparse(char *ptr, char **retptr);
+       char *match_strdup(substring_t *s);
+
+在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符:
+
+       =  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=  ?  :
+
+但是一元操作符后不要加空格:
+       &  *  +  -  ~  !  sizeof  typeof  alignof  __attribute__  defined
+
+后缀自加和自减一元操作符前不加空格:
+       ++  --
+
+前缀自加和自减一元操作符后不加空格:
+       ++  --
+
+“.”和“->”结构体成员操作符前后不加空格。
+
+不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你
+就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不
+会移除已经加入的空白,就像你故意留下一个只有空白的行。包含行尾空白的行就这样产
+生了。
+
+当git发现补丁包含了行尾空白的时候会警告你,并且可以应你的要求去掉行尾空白;不过
+如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的上下文。
+
+
+               第四章:命名
+
+C是一个简朴的语言,你的命名也应该这样。和Modula-2和Pascal程序员不同,C程序员不使
+用类似ThisVariableIsATemporaryCounter这样华丽的名字。C程序员会称那个变量为“tmp”
+,这样写起来会更容易,而且至少不会令其难于理解。
+
+不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字
+。称一个全局函数为“foo”是一个难以饶恕的错误。
+
+全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函
+数。如果你有一个可以计算活动用户数量的函数,你应该叫它“count_active_users()”或者
+类似的名字,你不应该叫它“cntuser()”。
+
+在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而
+且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题的程序。
+
+本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计数器
+,它应该被称为“i”。叫它“loop_counter”并无益处,如果它没有被误解的可能的话。类似
+的,“tmp”可以用来称呼任意类型的临时变量。
+
+如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症
+。请看第六章(函数)。
+
+
+               第五章:Typedef
+
+不要使用类似“vps_t”之类的东西。
+
+对结构体和指针使用typedef是一个错误。当你在代码里看到:
+
+       vps_t a;
+
+这代表什么意思呢?
+
+相反,如果是这样
+
+       struct virtual_container *a;
+
+你就知道“a”是什么了。
+
+很多人认为typedef“能提高可读性”。实际不是这样的。它们只在下列情况下有用:
+
+ (a) 完全不透明的对象(这种情况下要主动使用typedef来隐藏这个对象实际上是什么)。
+
+     例如:“pte_t”等不透明对象,你只能用合适的访问函数来访问它们。
+
+     注意!不透明性和“访问函数”本身是不好的。我们使用pte_t等类型的原因在于真的是
+     完全没有任何共用的可访问信息。
+
+ (b) 清楚的整数类型,如此,这层抽象就可以帮助消除到底是“int”还是“long”的混淆。
+
+     u8/u16/u32是完全没有问题的typedef,不过它们更符合类别(d)而不是这里。
+
+     再次注意!要这样做,必须事出有因。如果某个变量是“unsigned long“,那么没有必要
+
+       typedef unsigned long myflags_t;
+
+     不过如果有一个明确的原因,比如它在某种情况下可能会是一个“unsigned int”而在
+     其他情况下可能为“unsigned long”,那么就不要犹豫,请务必使用typedef。
+
+ (c) 当你使用sparse按字面的创建一个新类型来做类型检查的时候。
+
+ (d) 和标准C99类型相同的类型,在某些例外的情况下。
+
+     虽然让眼睛和脑筋来适应新的标准类型比如“uint32_t”不需要花很多时间,可是有些
+     人仍然拒绝使用它们。
+
+     因此,Linux特有的等同于标准类型的“u8/u16/u32/u64”类型和它们的有符号类型是被
+     允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。
+
+     当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选择。
+
+ (e) 可以在用户空间安全使用的类型。
+
+     在某些用户空间可见的结构体里,我们不能要求C99类型而且不能用上面提到的“u32”
+     类型。因此,我们在与用户空间共享的所有结构体中使用__u32和类似的类型。
+
+可能还有其他的情况,不过基本的规则是永远不要使用typedef,除非你可以明确的应用上
+述某个规则中的一个。
+
+总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们就不
+应该是一个typedef。
+
+
+               第六章:函数
+
+函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完(我们都知
+道ISO/ANSI屏幕大小是80x24),只做一件事情,而且把它做好。
+
+一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理论上
+很简单的只有一个很长(但是简单)的case语句的函数,而且你需要在每个case里做很多很
+小的事情,这样的函数尽管很长,但也是可以的。
+
+不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能甚至
+搞不清楚这个函数的目的,你应该严格的遵守前面提到的长度限制。使用辅助函数,并为之
+取个具描述性的名字(如果你觉得它们的性能很重要的话,可以让编译器内联它们,这样的
+效果往往会比你写一个复杂函数的效果要好。)
+
+函数的另外一个衡量标准是本地变量的数量。此数量不应超过5-10个,否则你的函数就有
+问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟
+踪7个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可能会记不清你2
+个星期前做过的事情。
+
+在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的EXPORT*宏应该紧贴
+在它的结束大括号之下。比如:
+
+int system_is_up(void)
+{
+       return system_state == SYSTEM_RUNNING;
+}
+EXPORT_SYMBOL(system_is_up);
+
+在函数原型中,包含函数名和它们的数据类型。虽然C语言里没有这样的要求,在Linux里这
+是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
+
+
+               第七章:集中的函数退出途径
+
+虽然被某些人声称已经过时,但是goto语句的等价物还是经常被编译器所使用,具体形式是
+无条件跳转指令。
+
+当一个函数从多个位置退出并且需要做一些通用的清理工作的时候,goto的好处就显现出来
+了。
+
+理由是:
+
+- 无条件语句容易理解和跟踪
+- 嵌套程度减小
+- 可以避免由于修改时忘记更新某个单独的退出点而导致的错误
+- 减轻了编译器的工作,无需删除冗余代码;)
+
+int fun(int a)
+{
+       int result = 0;
+       char *buffer = kmalloc(SIZE);
+
+       if (buffer == NULL)
+               return -ENOMEM;
+
+       if (condition1) {
+               while (loop1) {
+                       ...
+               }
+               result = 1;
+               goto out;
+       }
+       ...
+out:
+       kfree(buffer);
+       return result;
+}
+
+               第八章:注释
+
+注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:更好
+的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。
+
+一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把注释
+放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能需要回到
+第六章看一看。你可以做一些小注释来注明或警告某些很聪明(或者槽糕)的做法,但不要
+加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,也可以加上它做这
+些事情的原因。
+
+当注释内核API函数时,请使用kernel-doc格式。请看
+Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc以获得详细信息。
+
+Linux的注释风格是C89“/* ... */”风格。不要使用C99风格“// ...”注释。
+
+长(多行)的首选注释风格是:
+
+       /*
+        * This is the preferred style for multi-line
+        * comments in the Linux kernel source code.
+        * Please use it consistently.
+        *
+        * Description:  A column of asterisks on the left side,
+        * with beginning and ending almost-blank lines.
+        */
+
+注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只
+声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段
+小注释来解释它们的用途了。
+
+
+               第九章:你已经把事情弄糟了
+
+这没什么,我们都是这样。可能你的使用了很长时间Unix的朋友已经告诉你“GNU emacs”能
+自动帮你格式化C源代码,而且你也注意到了,确实是这样,不过它所使用的默认值和我们
+想要的相去甚远(实际上,甚至比随机打的还要差——无数个猴子在GNU emacs里打字永远不
+会创造出一个好程序)(译注:请参考Infinite Monkey Theorem)
+
+所以你要么放弃GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,你可
+以把下面这段粘贴到你的.emacs文件里。
+
+(defun linux-c-mode ()
+  "C mode with adjusted defaults for use with the Linux kernel."
+  (interactive)
+  (c-mode)
+  (c-set-style "K&R")
+  (setq tab-width 8)
+  (setq indent-tabs-mode t)
+  (setq c-basic-offset 8))
+
+这样就定义了M-x linux-c-mode命令。当你hack一个模块的时候,如果你把字符串
+-*- linux-c -*-放在头两行的某个位置,这个模式将会被自动调用。如果你希望在你修改
+/usr/src/linux里的文件时魔术般自动打开linux-c-mode的话,你也可能需要添加
+
+(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
+                       auto-mode-alist))
+
+到你的.emacs文件里。
+
+不过就算你尝试让emacs正确的格式化代码失败了,也并不意味着你失去了一切:还可以用“
+indent”。
+
+不过,GNU indent也有和GNU emacs一样有问题的设定,所以你需要给它一些命令选项。不
+过,这还不算太糟糕,因为就算是GNU indent的作者也认同K&R的权威性(GNU的人并不是坏
+人,他们只是在这个问题上被严重的误导了),所以你只要给indent指定选项“-kr -i8”
+(代表“K&R,8个字符缩进”),或者使用“scripts/Lindent”,这样就可以以最时髦的方式
+缩进源代码。
+
+“indent”有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册页。不过
+记住:“indent”不能修正坏的编程习惯。
+
+
+               第十章:Kconfig配置文件
+
+对于遍布源码树的所有Kconfig*配置文件来说,它们缩进方式与C代码相比有所不同。紧挨
+在“config”定义下面的行缩进一个制表符,帮助信息则再多缩进2个空格。比如:
+
+config AUDIT
+       bool "Auditing support"
+       depends on NET
+       help
+         Enable auditing infrastructure that can be used with another
+         kernel subsystem, such as SELinux (which requires this for
+         logging of avc messages output).  Does not do system-call
+         auditing without CONFIG_AUDITSYSCALL.
+
+仍然被认为不够稳定的功能应该被定义为依赖于“EXPERIMENTAL”:
+
+config SLUB
+       depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
+       bool "SLUB (Unqueued Allocator)"
+       ...
+
+而那些危险的功能(比如某些文件系统的写支持)应该在它们的提示字符串里显著的声明这
+一点:
+
+config ADFS_FS_RW
+       bool "ADFS write support (DANGEROUS)"
+       depends on ADFS_FS
+       ...
+
+要查看配置文件的完整文档,请看Documentation/kbuild/kconfig-language.txt。
+
+
+               第十一章:数据结构
+
+如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引用计
+数器。内核里没有垃圾收集(并且内核之外的垃圾收集慢且效率低下),这意味着你绝对需
+要记录你对这种数据结构的使用情况。
+
+引用计数意味着你能够避免上锁,并且允许多个用户并行访问这个数据结构——而不需要担心
+这个数据结构仅仅因为暂时不被使用就消失了,那些用户可能不过是沉睡了一阵或者做了一
+些其他事情而已。
+
+注意上锁不能取代引用计数。上锁是为了保持数据结构的一致性,而引用计数是一个内存管
+理技巧。通常二者都需要,不要把两个搞混了。
+
+很多数据结构实际上有2级引用计数,它们通常有不同“类”的用户。子类计数器统计子类用
+户的数量,每当子类计数器减至零时,全局计数器减一。
+
+这种“多级引用计数”的例子可以在内存管理(“struct mm_struct”:mm_users和mm_count)
+和文件系统(“struct super_block”:s_count和s_active)中找到。
+
+记住:如果另一个执行线索可以找到你的数据结构,但是这个数据结构没有引用计数器,这
+里几乎肯定是一个bug。
+
+
+               第十二章:宏,枚举和RTL
+
+用于定义常量的宏的名字及枚举里的标签需要大写。
+
+#define CONSTANT 0x12345
+
+在定义几个相关的常量时,最好用枚举。
+
+宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母。
+
+一般的,如果能写成内联函数就不要写成像函数的宏。
+
+含有多个语句的宏应该被包含在一个do-while代码块里:
+
+#define macrofun(a, b, c)                      \
+       do {                                    \
+               if (a == 5)                     \
+                       do_this(b, c);          \
+       } while (0)
+
+使用宏的时候应避免的事情:
+
+1) 影响控制流程的宏:
+
+#define FOO(x)                                 \
+       do {                                    \
+               if (blah(x) < 0)                \
+                       return -EBUGGERED;      \
+       } while(0)
+
+非常不好。它看起来像一个函数,不过却能导致“调用”它的函数退出;不要打乱读者大脑里
+的语法分析器。
+
+2) 依赖于一个固定名字的本地变量的宏:
+
+#define FOO(val) bar(index, val)
+
+可能看起来像是个不错的东西,不过它非常容易把读代码的人搞糊涂,而且容易导致看起来
+不相关的改动带来错误。
+
+3) 作为左值的带参数的宏: FOO(x) = y;如果有人把FOO变成一个内联函数的话,这种用
+法就会出错了。
+
+4) 忘记了优先级:使用表达式定义常量的宏必须将表达式置于一对小括号之内。带参数的
+宏也要注意此类问题。
+
+#define CONSTANT 0x4000
+#define CONSTEXP (CONSTANT | 3)
+
+cpp手册对宏的讲解很详细。Gcc internals手册也详细讲解了RTL(译注:register
+transfer language),内核里的汇编语言经常用到它。
+
+
+               第十三章:打印内核消息
+
+内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。不要
+用不规范的单词比如“dont”,而要用“do not”或者“don't”。保证这些信息简单、明了、无
+歧义。
+
+内核信息不必以句号(译注:英文句号,即点)结束。
+
+在小括号里打印数字(%d)没有任何价值,应该避免这样做。
+
+<linux/device.h>里有一些驱动模型诊断宏,你应该使用它们,以确保信息对应于正确的
+设备和驱动,并且被标记了正确的消息级别。这些宏有:dev_err(), dev_warn(),
+dev_info()等等。对于那些不和某个特定设备相关连的信息,<linux/kernel.h>定义了
+pr_debug()和pr_info()。
+
+写出好的调试信息可以是一个很大的挑战;当你写出来之后,这些信息在远程除错的时候
+就会成为极大的帮助。当DEBUG符号没有被定义的时候,这些信息不应该被编译进内核里
+(也就是说,默认地,它们不应该被包含在内)。如果你使用dev_dbg()或者pr_debug(),
+就能自动达到这个效果。很多子系统拥有Kconfig选项来启用-DDEBUG。还有一个相关的惯例
+是使用VERBOSE_DEBUG来添加dev_vdbg()消息到那些已经由DEBUG启用的消息之上。
+
+
+               第十四章:分配内存
+
+内核提供了下面的一般用途的内存分配函数:kmalloc(),kzalloc(),kcalloc()和
+vmalloc()。请参考API文档以获取有关它们的详细信息。
+
+传递结构体大小的首选形式是这样的:
+
+       p = kmalloc(sizeof(*p), ...);
+
+另外一种传递方式中,sizeof的操作数是结构体的名字,这样会降低可读性,并且可能会引
+入bug。有可能指针变量类型被改变时,而对应的传递给内存分配函数的sizeof的结果不变。
+
+强制转换一个void指针返回值是多余的。C语言本身保证了从void指针到其他任何指针类型
+的转换是没有问题的。
+
+
+               第十五章:内联弊病
+
+有一个常见的误解是内联函数是gcc提供的可以让代码运行更快的一个选项。虽然使用内联
+函数有时候是恰当的(比如作为一种替代宏的方式,请看第十二章),不过很多情况下不是
+这样。inline关键字的过度使用会使内核变大,从而使整个系统运行速度变慢。因为大内核
+会占用更多的指令高速缓存(译注:一级缓存通常是指令缓存和数据缓存分开的)而且会导
+致pagecache的可用内存减少。想象一下,一次pagecache未命中就会导致一次磁盘寻址,将
+耗时5毫秒。5毫秒的时间内CPU能执行很多很多指令。
+
+一个基本的原则是如果一个函数有3行以上,就不要把它变成内联函数。这个原则的一个例
+外是,如果你知道某个参数是一个编译时常量,而且因为这个常量你确定编译器在编译时能
+优化掉你的函数的大部分代码,那仍然可以给它加上inline关键字。kmalloc()内联函数就
+是一个很好的例子。
+
+人们经常主张给static的而且只用了一次的函数加上inline,如此不会有任何损失,因为没
+有什么好权衡的。虽然从技术上说这是正确的,但是实际上这种情况下即使不加inline gcc
+也可以自动使其内联。而且其他用户可能会要求移除inline,由此而来的争论会抵消inline
+自身的潜在价值,得不偿失。
+
+
+               第十六章:函数返回值及命名
+
+函数可以返回很多种不同类型的值,最常见的一种是表明函数执行成功或者失败的值。这样
+的一个值可以表示为一个错误代码整数(-Exxx=失败,0=成功)或者一个“成功”布尔值(
+0=失败,非0=成功)。
+
+混合使用这两种表达方式是难于发现的bug的来源。如果C语言本身严格区分整形和布尔型变
+量,那么编译器就能够帮我们发现这些错误……不过C语言不区分。为了避免产生这种bug,请
+遵循下面的惯例:
+
+       如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代码整
+       数。如果是一个判断,那么函数应该返回一个“成功”布尔值。
+
+比如,“add work”是一个命令,所以add_work()函数在成功时返回0,在失败时返回-EBUSY。
+类似的,因为“PCI device present”是一个判断,所以pci_dev_present()函数在成功找到
+一个匹配的设备时应该返回1,如果找不到时应该返回0。
+
+所有导出(译注:EXPORT)的函数都必须遵守这个惯例,所有的公共函数也都应该如此。私
+有(static)函数不需要如此,但是我们也推荐这样做。
+
+返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。一般的,他们
+通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,他们使用
+NULL或者ERR_PTR机制来报告错误。
+
+
+               第十七章:不要重新发明内核宏
+
+头文件include/linux/kernel.h包含了一些宏,你应该使用它们,而不要自己写一些它们的
+变种。比如,如果你需要计算一个数组的长度,使用这个宏
+
+  #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+类似的,如果你要计算某结构体成员的大小,使用
+
+  #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+还有可以做严格的类型检查的min()和max()宏,如果你需要可以使用它们。你可以自己看看
+那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应在你的代码里
+自己重新定义。
+
+
+               第十八章:编辑器模式行和其他需要罗嗦的事情
+
+有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs
+能够解释被标记成这样的行:
+
+-*- mode: c -*-
+
+或者这样的:
+
+/*
+Local Variables:
+compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
+End:
+*/
+
+Vim能够解释这样的标记:
+
+/* vim:set sw=8 noet */
+
+不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不应
+该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制的模
+式,或者使用其他可以产生正确的缩进的巧妙方法。
+
+
+
+               附录 I:参考
+
+The C Programming Language, 第二版, 作者Brian W. Kernighan和Denni
+M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软皮),
+0-13-110370-9 (硬皮). URL: http://cm.bell-labs.com/cm/cs/cbook/
+
+The Practice of Programming 作者Brian W. Kernighan和Rob Pike.  Addison-Wesley,
+Inc., 1999.  ISBN 0-201-61586-X.  URL: http://cm.bell-labs.com/cm/cs/tpop/
+
+cpp,gcc,gcc internals和indent的GNU手册——和K&R及本文相符合的部分,全部可以在
+http://www.gnu.org/manual/找到
+
+WG14是C语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
+
+Kernel CodingStyle,作者greg@kroah.com发表于OLS 2002:
+http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
+
+--
+最后更新于2007年7月13日。
index 48fc67bfbe3d33a8c04817db587a107d29e09177..3d80e8af36eced538ba0dde705ac0302435b04c3 100644 (file)
@@ -1,10 +1,10 @@
 Chinese translated version of Documentation/HOWTO
 
 If you have any comment or update to the content, please contact the
-original document maintainer directly.  However, if you have problem
+original document maintainer directly.  However, if you have problem
 communicating in English you can also ask the Chinese maintainer for
-help.  Contact the Chinese maintainer, if this translation is outdated
-or there is problem with translation.
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
 
 Maintainer: Greg Kroah-Hartman <greg@kroah.com>
 Chinese maintainer: Li Yang <leoli@freescale.com>
@@ -85,7 +85,7 @@ Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的
 Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着
 不可估量的价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文
 档也放进内核。当内核的改动导致面向用户空间的接口发生变化时,最好将相关信
-息或手册页(manpages)的补丁发到mtk-manpages@gmx.net,以向手册页(manpages)
+息或手册页(manpages)的补丁发到mtk.manpages@gmail.com,以向手册页(manpages)
 的维护者解释这些变化。
 
 以下是内核代码中需要阅读的文档:
@@ -218,6 +218,8 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循
     时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
   - 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是
     6个星期。
+  - 以下地址跟踪了在每个-rc发布中发现的退步列表:
+    http://kernelnewbies.org/known_regressions
 
 关于内核发布,值得一提的是Andrew Morton在linux-kernel邮件列表中如是说:
        “没有人知道新内核何时会被发布,因为发布是根据已知bug的情况来决定
diff --git a/Documentation/zh_CN/SubmittingDrivers b/Documentation/zh_CN/SubmittingDrivers
new file mode 100644 (file)
index 0000000..5f4815c
--- /dev/null
@@ -0,0 +1,168 @@
+Chinese translated version of Documentation/SubmittingDrivers
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: Li Yang <leo@zh-kernel.org>
+---------------------------------------------------------------------
+Documentation/SubmittingDrivers 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 李阳  Li Yang <leo@zh-kernel.org>
+中文版翻译者: 李阳  Li Yang <leo@zh-kernel.org>
+中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
+               王聪 Wang Cong <xiyou.wangcong@gmail.com>
+               张巍 Zhang Wei <Wei.Zhang@freescale.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+如何向 Linux 内核提交驱动程序
+-----------------------------
+
+这篇文档将会解释如何向不同的内核源码树提交设备驱动程序。请注意,如果你感
+兴趣的是显卡驱动程序,你也许应该访问 XFree86 项目(http://www.xfree86.org/)
+和/或 X.org 项目 (http://x.org)。
+
+另请参阅 Documentation/SubmittingPatches 文档。
+
+
+分配设备号
+----------
+
+块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA(
+现在是 Torben Mathiasen)负责分配。申请的网址是 http://www.lanana.org/。
+即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
+请参阅 Documentation/devices.txt。
+
+如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
+制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
+
+设备驱动的提交对象
+------------------
+
+Linux 2.0:
+       此内核源码树不接受新的驱动程序。
+
+Linux 2.2:
+       此内核源码树不接受新的驱动程序。
+
+Linux 2.4:
+       如果所属的代码领域在内核的 MAINTAINERS 文件中列有一个总维护者,
+       那么请将驱动程序提交给他。如果此维护者没有回应或者你找不到恰当的
+       维护者,那么请联系 Willy Tarreau <w@1wt.eu>。
+
+Linux 2.6:
+       除了遵循和 2.4 版内核同样的规则外,你还需要在 linux-kernel 邮件
+       列表上跟踪最新的 API 变化。向 Linux 2.6 内核提交驱动的顶级联系人
+       是 Andrew Morton <akpm@osdl.org>。
+
+决定设备驱动能否被接受的条件
+----------------------------
+
+许可:              代码必须使用 GNU 通用公开许可证 (GPL) 提交给 Linux,但是
+               我们并不要求 GPL 是唯一的许可。你或许会希望同时使用多种
+               许可证发布,如果希望驱动程序可以被其他开源社区(比如BSD)
+               使用。请参考 include/linux/module.h 文件中所列出的可被
+               接受共存的许可。
+
+版权:              版权所有者必须同意使用 GPL 许可。最好提交者和版权所有者
+               是相同个人或实体。否则,必需列出授权使用 GPL 的版权所有
+               人或实体,以备验证之需。
+
+接口:              如果你的驱动程序使用现成的接口并且和其他同类的驱动程序行
+               为相似,而不是去发明无谓的新接口,那么它将会更容易被接受。
+               如果你需要一个 Linux 和 NT 的通用驱动接口,那么请在用
+               户空间实现它。
+
+代码:              请使用 Documentation/CodingStyle 中所描述的 Linux 代码风
+               格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
+               享的代码段)需要使用其他格式,而你却只希望维护一份代码,
+               那么请将它们很好地区分出来,并且注明原因。
+
+可移植性:        请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
+               尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
+               单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
+               x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
+               硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
+               可以被轻松地移植却是很简单的。
+
+清晰度:   做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
+               会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
+               隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
+
+电源管理:        因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
+               动程序也很有可能被使用在这些设备上。它应该支持最基本的电
+               源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
+               .suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
+               确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
+               函数定义成返回 -ENOSYS(功能未实现)错误。你还应该尝试确
+               保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
+               程序测试的指导,请参阅
+               Documentation/power/drivers-testing.txt。有关驱动程序电
+               源管理问题相对全面的概述,请参阅
+               Documentation/power/devices.txt。
+
+管理:              如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
+               些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
+               被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
+               好在代码注释中写明并且在 MAINTAINERS 文件中加入这个驱动
+               程序的条目。
+
+不影响设备驱动能否被接受的条件
+------------------------------
+
+供应商:   由硬件供应商来维护驱动程序通常是一件好事。不过,如果源码
+               树里已经有其他人提供了可稳定工作的驱动程序,那么请不要期
+               望“我是供应商”会成为内核改用你的驱动程序的理由。理想的情
+               况是:供应商与现有驱动程序的作者合作,构建一个统一完美的
+               驱动程序。
+
+作者:              驱动程序是由大的 Linux 公司研发还是由你个人编写,并不影
+               响其是否能被内核接受。没有人对内核源码树享有特权。只要你
+               充分了解内核社区,你就会发现这一点。
+
+
+资源列表
+--------
+
+Linux 内核主源码树:
+       ftp.??.kernel.org:/pub/linux/kernel/...
+       ?? == 你的国家代码,例如 "cn"、"us"、"uk"、"fr" 等等
+
+Linux 内核邮件列表:
+       linux-kernel@vger.kernel.org
+       [可通过向majordomo@vger.kernel.org发邮件来订阅]
+
+Linux 设备驱动程序,第三版(探讨 2.6.10 版内核):
+       http://lwn.net/Kernel/LDD3/ (免费版)
+
+LWN.net:
+       每周内核开发活动摘要 - http://lwn.net/
+       2.6 版中 API 的变更:
+               http://lwn.net/Articles/2.6-kernel-api/
+       将旧版内核的驱动程序移植到 2.6 版:
+               http://lwn.net/Articles/driver-porting/
+
+KernelTrap:
+       Linux 内核的最新动态以及开发者访谈
+       http://kerneltrap.org/
+
+内核新手(KernelNewbies):
+       为新的内核开发者提供文档和帮助
+       http://kernelnewbies.org/
+
+Linux USB项目:
+       http://www.linux-usb.org/
+
+写内核驱动的“不要”(Arjan van de Ven著):
+       http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
+
+内核清洁工 (Kernel Janitor):
+       http://janitor.kernelnewbies.org/
diff --git a/Documentation/zh_CN/SubmittingPatches b/Documentation/zh_CN/SubmittingPatches
new file mode 100644 (file)
index 0000000..985c92e
--- /dev/null
@@ -0,0 +1,416 @@
+Chinese translated version of Documentation/SubmittingPatches
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: TripleX Chung <triplex@zh-kernel.org>
+---------------------------------------------------------------------
+Documentation/SubmittingPatches 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
+中文版翻译者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
+中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
+               王聪 Wang Cong <xiyou.wangcong@gmail.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+   如何让你的改动进入内核
+     或者
+  获得亲爱的 Linus Torvalds 的关注和处理
+----------------------------------
+
+对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
+提交的流程会让人畏惧。本文档收集了一系列建议,这些建议可以大大的提高你
+的改动被接受的机会。
+阅读 Documentation/SubmitChecklist 来获得在提交代码前需要检查的项目的列
+表。如果你在提交一个驱动程序,那么同时阅读一下
+Documentation/SubmittingDrivers 。
+
+
+--------------------------
+第一节 - 创建并发送你的改动
+--------------------------
+
+1) "diff -up"
+-----------
+
+使用 "diff -up" 或者 "diff -uprN" 来创建补丁。
+
+所有内核的改动,都是以补丁的形式呈现的,补丁由 diff(1) 生成。创建补丁的
+时候,要确认它是以 "unified diff" 格式创建的,这种格式由 diff(1) 的 '-u'
+参数生成。而且,请使用 '-p' 参数,那样会显示每个改动所在的C函数,使得
+产生的补丁容易读得多。补丁应该基于内核源代码树的根目录,而不是里边的任
+何子目录。
+为一个单独的文件创建补丁,一般来说这样做就够了:
+
+        SRCTREE= linux-2.6
+        MYFILE=  drivers/net/mydriver.c
+
+        cd $SRCTREE
+        cp $MYFILE $MYFILE.orig
+        vi $MYFILE      # make your change
+        cd ..
+        diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch
+
+为多个文件创建补丁,你可以解开一个没有修改过的内核源代码树,然后和你自
+己的代码树之间做 diff 。例如:
+
+        MYSRC= /devel/linux-2.6
+
+        tar xvfz linux-2.6.12.tar.gz
+        mv linux-2.6.12 linux-2.6.12-vanilla
+        diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \
+                linux-2.6.12-vanilla $MYSRC > /tmp/patch
+
+"dontdiff" 是内核在编译的时候产生的文件的列表,列表中的文件在 diff(1)
+产生的补丁里会被跳过。"dontdiff" 文件被包含在2.6.12和之后版本的内核源代
+码树中。对于更早的内核版本,你可以从
+<http://www.xenotime.net/linux/doc/dontdiff> 获取它。
+确定你的补丁里没有包含任何不属于这次补丁提交的额外文件。记得在用diff(1)
+生成补丁之后,审阅一次补丁,以确保准确。
+如果你的改动很散乱,你应该研究一下如何将补丁分割成独立的部分,将改动分
+割成一系列合乎逻辑的步骤。这样更容易让其他内核开发者审核,如果你想你的
+补丁被接受,这是很重要的。下面这些脚本能够帮助你做这件事情:
+Quilt:
+http://savannah.nongnu.org/projects/quilt
+
+Andrew Morton 的补丁脚本:
+http://www.zip.com.au/~akpm/linux/patches/
+作为这些脚本的替代,quilt 是值得推荐的补丁管理工具(看上面的链接)。
+
+2)描述你的改动。
+描述你的改动包含的技术细节。
+
+要多具体就写多具体。最糟糕的描述可能是像下面这些语句:“更新了某驱动程
+序”,“修正了某驱动程序的bug”,或者“这个补丁包含了某子系统的修改,请
+使用。”
+
+如果你的描述开始变长,这表示你也许需要拆分你的补丁了,请看第3小节,
+继续。
+
+3)拆分你的改动
+
+将改动拆分,逻辑类似的放到同一个补丁文件里。
+
+例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动才分到两个或
+者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适
+应这些新的API,那么把这些修改分成两个补丁。
+
+另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
+单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
+
+如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。简单的在你的补
+丁描述里指出“这个补丁依赖某补丁”就好了。
+
+如果你不能将补丁浓缩成更少的文件,那么每次大约发送出15个,然后等待审查
+和整合。
+
+4)选择 e-mail 的收件人
+
+看一遍 MAINTAINERS 文件和源代码,看看你所的改动所在的内核子系统有没有指
+定的维护者。如果有,给他们发e-mail。
+
+如果没有找到维护者,或者维护者没有反馈,将你的补丁发送到内核开发者主邮
+件列表 linux-kernel@vger.kernel.org。大部分的内核开发者都跟踪这个邮件列
+表,可以评价你的改动。
+
+每次不要发送超过15个补丁到 vger 邮件列表!!!
+
+Linus Torvalds 是决定改动能否进入 Linux 内核的最终裁决者。他的 e-mail
+地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般
+的说,最好别给他发 e-mail。
+
+那些修正bug,“显而易见”的修改或者是类似的只需要很少讨论的补丁可以直接
+发送或者CC给Linus。那些需要讨论或者没有很清楚的好处的补丁,一般先发送到
+linux-kernel邮件列表。只有当补丁被讨论得差不多了,才提交给Linus。
+
+5)选择CC( e-mail 抄送)列表
+
+除非你有理由不这样做,否则CC linux-kernel@vger.kernel.org。
+
+除了 Linus 之外,其他内核开发者也需要注意到你的改动,这样他们才能评论你
+的改动并提供代码审查和建议。linux-kernel 是 Linux 内核开发者主邮件列表
+。其它的邮件列表为特定的子系统提供服务,比如 USB,framebuffer 设备,虚
+拟文件系统,SCSI 子系统,等等。查看 MAINTAINERS 文件来获得和你的改动有
+关的邮件列表。
+
+Majordomo lists of VGER.KERNEL.ORG at:
+        <http://vger.kernel.org/vger-lists.html>
+
+如果改动影响了用户空间和内核之间的接口,请给 MAN-PAGES 的维护者(列在
+MAITAINERS 文件里的)发送一个手册页(man-pages)补丁,或者至少通知一下改
+变,让一些信息有途径进入手册页。
+
+即使在第四步的时候,维护者没有作出回应,也要确认在修改他们的代码的时候
+,一直将维护者拷贝到CC列表中。
+
+对于小的补丁,你也许会CC到 Adrian Bunk 管理的搜集琐碎补丁的邮件列表
+(Trivial Patch Monkey)trivial@kernel.org,那里专门收集琐碎的补丁。下面这样
+的补丁会被看作“琐碎的”补丁:
+  文档的拼写修正。
+  修正会影响到 grep(1) 的拼写。
+  警告信息修正(频繁的打印无用的警告是不好的。)
+  编译错误修正(代码逻辑的确是对的,只是编译有问题。)
+  运行时修正(只要真的修正了错误。)
+  移除使用了被废弃的函数/宏的代码(例如 check_region。)
+  联系方式和文档修正。
+  用可移植的代码替换不可移植的代码(即使在体系结构相关的代码中,既然有
+  人拷贝,只要它是琐碎的)
+  任何文件的作者/维护者对该文件的改动(例如 patch monkey 在重传模式下)
+
+URL: <http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/>
+
+(译注,关于“琐碎补丁”的一些说明:因为原文的这一部分写得比较简单,所以不得不
+违例写一下译注。"trivial"这个英文单词的本意是“琐碎的,不重要的。”但是在这里
+有稍微有一些变化,例如对一些明显的NULL指针的修正,属于运行时修正,会被归类
+到琐碎补丁里。虽然NULL指针的修正很重要,但是这样的修正往往很小而且很容易得到
+检验,所以也被归入琐碎补丁。琐碎补丁更精确的归类应该是
+“simple, localized & easy to verify”,也就是说简单的,局部的和易于检验的。
+trivial@kernel.org邮件列表的目的是针对这样的补丁,为提交者提供一个中心,来
+降低提交的门槛。)
+
+6)没有 MIME 编码,没有链接,没有压缩,没有附件,只有纯文本。
+
+Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
+,可以“引用”你的改动很重要,使用一般的 e-mail 工具,他们就可以在你的
+代码的任何位置添加评论。
+
+因为这个原因,所有的提交的补丁都是 e-mail 中“内嵌”的。
+警告:如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的
+补丁。
+
+不要将补丁作为 MIME 编码的附件,不管是否压缩。很多流行的 e-mail 软件不
+是任何时候都将 MIME 编码的附件当作纯文本发送的,这会使得别人无法在你的
+代码中加评论。另外,MIME 编码的附件会让 Linus 多花一点时间来处理,这就
+降低了你的改动被接受的可能性。
+
+警告:一些邮件软件,比如 Mozilla 会将你的信息以如下格式发送:
+---- 邮件头 ----
+Content-Type: text/plain; charset=us-ascii; format=flowed
+---- 邮件头 ----
+问题在于 “format=flowed” 会让接收端的某些邮件软件将邮件中的制表符替换
+成空格以及做一些类似的替换。这样,你发送的时候看起来没问题的补丁就被破
+坏了。
+
+要修正这个问题,只需要将你的 mozilla 的 defaults/pref/mailnews.js 文件
+里的
+pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
+修改成
+pref("mailnews.display.disable_format_flowed_support", true);
+就可以了。
+
+7) e-mail 的大小
+
+给 Linus 发送补丁的时候,永远按照第6小节说的做。
+
+大的改动对邮件列表不合适,对某些维护者也不合适。如果你的补丁,在不压缩
+的情况下,超过了40kB,那么你最好将补丁放在一个能通过 internet 访问的服
+务器上,然后用指向你的补丁的 URL 替代。
+
+8) 指出你的内核版本
+
+在标题和在补丁的描述中,指出补丁对应的内核的版本,是很重要的。
+
+如果补丁不能干净的在最新版本的内核上打上,Linus 是不会接受它的。
+
+9) 不要气馁,继续提交。
+
+当你提交了改动以后,耐心地等待。如果 Linus 喜欢你的改动并且同意它,那么
+它将在下一个内核发布版本中出现。
+
+然而,如果你的改动没有出现在下一个版本的内核中,可能有若干原因。减少那
+些原因,修正错误,重新提交更新后的改动,是你自己的工作。
+
+Linus不给出任何评论就“丢弃”你的补丁是常见的事情。在系统中这样的事情很
+平常。如果他没有接受你的补丁,也许是由于以下原本:
+* 你的补丁不能在最新版本的内核上干净的打上。
+* 你的补丁在 linux-kernel 邮件列表中没有得到充分的讨论。
+* 风格问题(参照第2小节)
+* 邮件格式问题(重读本节)
+* 你的改动有技术问题。
+* 他收到了成吨的 e-mail,而你的在混乱中丢失了。
+* 你让人为难。
+
+有疑问的时候,在 linux-kernel 邮件列表上请求评论。
+
+10) 在标题上加上 PATCH 的字样
+
+Linus 和 linux-kernel 邮件列表的 e-mail 流量都很高,一个通常的约定是标
+题行以 [PATCH] 开头。这样可以让 Linus 和其他内核开发人员可以从 e-mail
+的讨论中很轻易的将补丁分辨出来。
+
+11)为你的工作签名
+
+为了加强对谁做了何事的追踪,尤其是对那些透过好几层的维护者的补丁,我们
+建议在发送出去的补丁上加一个 “sign-off” 的过程。
+
+"sign-off" 是在补丁的注释的最后的简单的一行文字,认证你编写了它或者其他
+人有权力将它作为开放源代码的补丁传递。规则很简单:如果你能认证如下信息
+:
+      开发者来源证书 1.1
+      对于本项目的贡献,我认证如下信息:
+      (a)这些贡献是完全或者部分的由我创建,我有权利以文件中指出
+       的开放源代码许可证提交它;或者
+      (b)这些贡献基于以前的工作,据我所知,这些以前的工作受恰当的开放
+       源代码许可证保护,而且,根据许可证,我有权提交修改后的贡献,
+       无论是完全还是部分由我创造,这些贡献都使用同一个开放源代码许可证
+       (除非我被允许用其它的许可证),正如文件中指出的;或者
+      (c)这些贡献由认证(a),(b)或者(c)的人直接提供给我,而
+       且我没有修改它。
+      (d)我理解并同意这个项目和贡献是公开的,贡献的记录(包括我
+       一起提交的个人记录,包括 sign-off )被永久维护并且可以和这个项目
+       或者开放源代码的许可证同步地再发行。
+       那么加入这样一行:
+       Signed-off-by: Random J Developer <random@developer.example.org>
+
+使用你的真名(抱歉,不能使用假名或者匿名。)
+
+有人在最后加上标签。现在这些东西会被忽略,但是你可以这样做,来标记公司
+内部的过程,或者只是指出关于 sign-off 的一些特殊细节。
+
+12)标准补丁格式
+
+标准的补丁,标题行是:
+    Subject: [PATCH 001/123] 子系统:一句话概述
+
+标准补丁的信体存在如下部分:
+
+  - 一个 "from" 行指出补丁作者。
+
+  - 一个空行
+
+  - 说明的主体,这些说明文字会被拷贝到描述该补丁的永久改动记录里。
+
+  - 一个由"---"构成的标记行
+
+  - 不合适放到改动记录里的额外的注解。
+
+  - 补丁本身(diff 输出)
+
+标题行的格式,使得对标题行按字母序排序非常的容易 - 很多 e-mail 客户端都
+可以支持 - 因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
+
+e-mail 标题中的“子系统”标识哪个内核子系统将被打补丁。
+
+e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。“一句话概述”
+不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
+丁),不要对每个补丁都使用同样的“一句话概述”。
+
+记住 e-mail 的“一句话概述”会成为该补丁的全局唯一标识。它会蔓延到 git
+的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
+丁。用户将希望通过 google 来搜索"一句话概述"来找到那些讨论这个补丁的文
+章。
+
+一些标题的例子:
+
+    Subject: [patch 2/5] ext2: improve scalability of bitmap searching
+    Subject: [PATCHv2 001/207] x86: fix eflags tracking
+
+"from" 行是信体里的最上面一行,具有如下格式:
+        From: Original Author <author@example.com>
+
+"from" 行指明在永久改动日志里,谁会被确认为作者。如果没有 "from" 行,那
+么邮件头里的 "From: " 行会被用来决定改动日志中的作者。
+
+说明的主题将会被提交到永久的源代码改动日志里,因此对那些早已经不记得和
+这个补丁相关的讨论细节的有能力的读者来说,是有意义的。
+
+"---" 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
+的。
+
+对于 "---" 标记之后的额外注解,一个好的用途就是用来写 diffstat,用来显
+示修改了什么文件和每个文件都增加和删除了多少行。diffstat 对于比较大的补
+丁特别有用。其余那些只是和时刻或者开发者相关的注解,不合适放到永久的改
+动日志里的,也应该放这里。
+使用 diffstat的选项 "-p 1 -w 70" 这样文件名就会从内核源代码树的目录开始
+,不会占用太宽的空间(很容易适合80列的宽度,也许会有一些缩进。)
+
+在后面的参考资料中能看到适当的补丁格式的更多细节。
+
+-------------------------------
+第二节 提示,建议和诀窍
+-------------------------------
+
+本节包含很多和提交到内核的代码有关的通常的"规则"。事情永远有例外...但是
+你必须真的有好的理由这样做。你可以把本节叫做Linus的计算机科学入门课。
+
+1) 读 Document/CodingStyle
+
+Nuff 说过,如果你的代码和这个偏离太多,那么它有可能会被拒绝,没有更多的
+审查,没有更多的评价。
+
+2) #ifdef 是丑陋的
+混杂了 ifdef 的代码难以阅读和维护。别这样做。作为替代,将你的 ifdef 放
+在头文件里,有条件地定义 "static inline" 函数,或者宏,在代码里用这些东
+西。让编译器把那些"空操作"优化掉。
+
+一个简单的例子,不好的代码:
+
+    dev = alloc_etherdev (sizeof(struct funky_private));
+    if (!dev)
+        return -ENODEV;
+    #ifdef CONFIG_NET_FUNKINESS
+    init_funky_net(dev);
+    #endif
+
+清理后的例子:
+
+(头文件里)
+    #ifndef CONFIG_NET_FUNKINESS
+    static inline void init_funky_net (struct net_device *d) {}
+    #endif
+
+(代码文件里)
+    dev = alloc_etherdev (sizeof(struct funky_private));
+    if (!dev)
+        return -ENODEV;
+    init_funky_net(dev);
+
+3) 'static inline' 比宏好
+
+Static inline 函数相比宏来说,是好得多的选择。Static inline 函数提供了
+类型安全,没有长度限制,没有格式限制,在 gcc 下开销和宏一样小。
+
+宏只在 static inline 函数不是最优的时候[在 fast paths 里有很少的独立的
+案例],或者不可能用 static inline 函数的时候[例如字符串分配]。
+应该用 'static inline' 而不是 'static __inline__', 'extern inline' 和
+'extern __inline__' 。
+
+4) 不要过度设计
+
+不要试图预计模糊的未来事情,这些事情也许有用也许没有用:"让事情尽可能的
+简单,而不是更简单"。
+
+----------------
+第三节 参考文献
+----------------
+
+Andrew Morton, "The perfect patch" (tpp).
+  <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+
+Jeff Garzik, "Linux kernel patch submission format".
+  <http://linux.yyz.us/patch-format.html>
+
+Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
+  <http://www.kroah.com/log/2005/03/31/>
+  <http://www.kroah.com/log/2005/07/08/>
+  <http://www.kroah.com/log/2005/10/19/>
+  <http://www.kroah.com/log/2006/01/11/>
+
+NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
+  <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+
+Kernel Documentation/CodingStyle:
+  <http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
+
+Linus Torvalds's mail on the canonical patch format:
+  <http://lkml.org/lkml/2005/4/7/183>
+--
diff --git a/Documentation/zh_CN/oops-tracing.txt b/Documentation/zh_CN/oops-tracing.txt
new file mode 100644 (file)
index 0000000..9312608
--- /dev/null
@@ -0,0 +1,212 @@
+Chinese translated version of Documentation/oops-tracing.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: Dave Young <hidave.darkstar@gmail.com>
+---------------------------------------------------------------------
+Documentation/oops-tracing.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
+中文版翻译者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
+中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
+               王聪 Wang Cong <xiyou.wangcong@gmail.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+注意: ksymoops 在2.6中是没有用的。 请以原有格式使用Oops(来自dmesg,等等)。
+忽略任何这样那样关于“解码Oops”或者“通过ksymoops运行”的文档。 如果你贴出运行过
+ksymoops的来自2.6的Oops,人们只会让你重贴一次。
+
+快速总结
+-------------
+
+发现Oops并发送给看似相关的内核领域的维护者。别太担心对不上号。如果你不确定就发给
+和你所做的事情相关的代码的负责人。 如果可重现试着描述怎样重构。 那甚至比oops更有
+价值。
+
+如果你对于发送给谁一无所知, 发给linux-kernel@vger.kernel.org。感谢你帮助Linux
+尽可能地稳定。
+
+Oops在哪里?
+----------------------
+
+通常Oops文本由klogd从内核缓冲区里读取并传给syslogd,由syslogd写到syslog文件中,
+典型地是/var/log/messages(依赖于/etc/syslog.conf)。有时klogd崩溃了,这种情况下你
+能够运行dmesg > file来从内核缓冲区中读取数据并保存下来。 否则你可以
+cat /proc/kmsg > file, 然而你必须介入中止传输, kmsg是一个“永不结束的文件”。如
+果机器崩溃坏到你不能输入命令或者磁盘不可用那么你有三种选择:-
+
+(1) 手抄屏幕上的文本待机器重启后再输入计算机。 麻烦但如果没有针对崩溃的准备,
+这是仅有的选择。 另外,你可以用数码相机把屏幕拍下来-不太好,但比没有强。 如果信
+息滚动到了终端的上面,你会发现以高分辩率启动(比如,vga=791)会让你读到更多的文
+本。(注意:这需要vesafb,所以对‘早期’的oops没有帮助)
+
+(2)用串口终端启动(请参看Documentation/serial-console.txt),运行一个null
+modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。
+
+(3)使用Kdump(请参看Documentation/kdump/kdump.txt),
+使用在Documentation/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
+环形缓冲区。
+
+完整信息
+----------------
+
+注意:以下来自于Linus的邮件适用于2.4内核。 我因为历史原因保留了它,并且因为其中
+一些信息仍然适用。 特别注意的是,请忽略任何ksymoops的引用。
+
+From: Linus Torvalds <torvalds@osdl.org>
+
+怎样跟踪Oops.. [原发到linux-kernel的一封邮件]
+
+主要的窍门是有五年和这些烦人的oops消息打交道的经验;-)
+
+实际上,你有办法使它更简单。我有两个不同的方法:
+
+       gdb /usr/src/linux/vmlinux
+       gdb> disassemble <offending_function>
+
+那是发现问题的简单办法,至少如果bug报告做的好的情况下(象这个一样-运行ksymoops
+得到oops发生的函数及函数内的偏移)。
+
+哦,如果报告发生的内核以相同的编译器和相似的配置编译它会有帮助的。
+
+另一件要做的事是反汇编bug报告的“Code”部分:ksymoops也会用正确的工具来做这件事,
+但如果没有那些工具你可以写一个傻程序:
+
+       char str[] = "\xXX\xXX\xXX...";
+       main(){}
+
+并用gcc -g编译它然后执行“disassemble str”(XX部分是由Oops报告的值-你可以仅剪切
+粘贴并用“\x”替换空格-我就是这么做的,因为我懒得写程序自动做这一切)。
+
+另外,你可以用scripts/decodecode这个shell脚本。它的使用方法是:
+decodecode < oops.txt
+
+“Code”之后的十六进制字节可能(在某些架构上)有一些当前指令之前的指令字节以及
+当前和之后的指令字节
+
+Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
+64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
+7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
+
+最后,如果你想知道代码来自哪里,你可以:
+
+       cd /usr/src/linux
+       make fs/buffer.s        # 或任何产生BUG的文件
+
+然后你会比gdb反汇编更清楚的知道发生了什么。
+
+现在,问题是把你所拥有的所有数据结合起来:C源码(关于它应该怎样的一般知识),
+汇编代码及其反汇编得到的代码(另外还有从“oops”消息得到的寄存器状态-对了解毁坏的
+指针有用,而且当你有了汇编代码你也能拿其它的寄存器和任何它们对应的C表达式做匹配
+)。
+
+实际上,你仅需看看哪里不匹配(这个例子是“Code”反汇编和编译器生成的代码不匹配)。
+然后你须要找出为什么不匹配。通常很简单-你看到代码使用了空指针然后你看代码想知道
+空指针是怎么出现的,还有检查它是否合法..
+
+现在,如果明白这是一项耗时的工作而且需要一丁点儿的专心,没错。这就是我为什么大多
+只是忽略那些没有符号表信息的崩溃报告的原因:简单的说太难查找了(我有一些
+程序用于在内核代码段中搜索特定的模式,而且有时我也已经能找出那些崩溃的地方,但是
+仅仅是找出正确的序列也确实需要相当扎实的内核知识)
+
+_有时_会发生这种情况,我仅看到崩溃中的反汇编代码序列, 然后我马上就明白问题出在
+哪里。这时我才意识到自己干这个工作已经太长时间了;-)
+
+               Linus
+
+
+---------------------------------------------------------------------------
+关于Oops跟踪的注解:
+
+为了帮助Linus和其它内核开发者,klogd纳入了大量的支持来处理保护错误。为了拥有对
+地址解析的完整支持至少应该使用1.3-pl3的sysklogd包。
+
+当保护错误发生时,klogd守护进程自动把内核日志信息中的重要地址翻译成它们相应的符
+号。
+
+klogd执行两种类型的地址解析。首先是静态翻译其次是动态翻译。静态翻译和ksymoops
+一样使用System.map文件。为了做静态翻译klogd守护进程必须在初始化时能找到system
+map文件。关于klogd怎样搜索map文件请参看klogd手册页。
+
+动态地址翻译在使用内核可装载模块时很重要。 因为内核模块的内存是从内核动态内存池
+里分配的,所以不管是模块开始位置还是模块中函数和符号的位置都不是固定的。
+
+内核支持允许程序决定装载哪些模块和它们在内存中位置的系统调用。使用这些系统调用
+klogd守护进程生成一张符号表用于调试发生在可装载模块中的保护错误。
+
+至少klogd会提供产生保护错误的模块名。还可有额外的符号信息供可装载模块开发者选择
+以从模块中输出符号信息。
+
+因为内核模块环境可能是动态的,所以必须有一种机制当模块环境发生改变时来通知klogd
+守护进程。 有一些可用的命令行选项允许klogd向当前执行中的守护进程发送信号,告知符
+号信息应该被刷新了。 更多信息请参看klogd手册页。
+
+sysklogd发布时包含一个补丁修改了modules-2.0.0包,无论何时一个模块装载或者卸载都
+会自动向klogd发送信号。打上这个补丁提供了必要的对调试发生于内核可装载模块的保护
+错误的无缝支持。
+
+以下是被klogd处理过的发生在可装载模块中的一个保护错误例子:
+---------------------------------------------------------------------------
+Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
+Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
+Aug 29 09:51:01 blizard kernel: *pde = 00000000
+Aug 29 09:51:01 blizard kernel: Oops: 0002
+Aug 29 09:51:01 blizard kernel: CPU:    0
+Aug 29 09:51:01 blizard kernel: EIP:    0010:[oops:_oops+16/3868]
+Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
+Aug 29 09:51:01 blizard kernel: eax: 315e97cc   ebx: 003a6f80   ecx: 001be77b   edx: 00237c0c
+Aug 29 09:51:01 blizard kernel: esi: 00000000   edi: bffffdb3   ebp: 00589f90   esp: 00589f8c
+Aug 29 09:51:01 blizard kernel: ds: 0018   es: 0018   fs: 002b   gs: 002b   ss: 0018
+Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
+Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
+Aug 29 09:51:01 blizard kernel:        00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
+Aug 29 09:51:01 blizard kernel:        bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
+Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
+Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
+---------------------------------------------------------------------------
+
+Dr. G.W. Wettstein           Oncology Research Div. Computing Facility
+Roger Maris Cancer Center    INTERNET: greg@wind.rmcc.com
+820 4th St. N.
+Fargo, ND  58122
+Phone: 701-234-7556
+
+
+---------------------------------------------------------------------------
+受污染的内核
+
+一些oops报告在程序记数器之后包含字符串'Tainted: '。这表明内核已经被一些东西给污
+染了。 该字符串之后紧跟着一系列的位置敏感的字符,每个代表一个特定的污染值。
+
+  1:'G'如果所有装载的模块都有GPL或相容的许可证,'P'如果装载了任何的专有模块。
+没有模块MODULE_LICENSE或者带有insmod认为是与GPL不相容的的MODULE_LICENSE的模块被
+认定是专有的。
+
+  2:'F'如果有任何通过“insmod -f”被强制装载的模块,' '如果所有模块都被正常装载。
+
+  3:'S'如果oops发生在SMP内核中,运行于没有证明安全运行多处理器的硬件。 当前这种
+情况仅限于几种不支持SMP的速龙处理器。
+
+  4:'R'如果模块通过“insmod -f”被强制装载,' '如果所有模块都被正常装载。
+
+  5:'M'如果任何处理器报告了机器检查异常,' '如果没有发生机器检查异常。
+
+  6:'B'如果页释放函数发现了一个错误的页引用或者一些非预期的页标志。
+
+  7:'U'如果用户或者用户应用程序特别请求设置污染标志,否则' '。
+
+  8:'D'如果内核刚刚死掉,比如有OOPS或者BUG。
+
+使用'Tainted: '字符串的主要原因是要告诉内核调试者,这是否是一个干净的内核亦或发
+生了任何的不正常的事。污染是永久的:即使出错的模块已经被卸载了,污染值仍然存在,
+以表明内核不再值得信任。
diff --git a/Documentation/zh_CN/sparse.txt b/Documentation/zh_CN/sparse.txt
new file mode 100644 (file)
index 0000000..75992a6
--- /dev/null
@@ -0,0 +1,100 @@
+Chinese translated version of Documentation/sparse.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: Li Yang <leo@zh-kernel.org>
+---------------------------------------------------------------------
+Documentation/sparse.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 李阳  Li Yang <leo@zh-kernel.org>
+中文版翻译者: 李阳  Li Yang <leo@zh-kernel.org>
+
+
+以下为正文
+---------------------------------------------------------------------
+
+Copyright 2004 Linus Torvalds
+Copyright 2004 Pavel Machek <pavel@suse.cz>
+Copyright 2006 Bob Copeland <me@bobcopeland.com>
+
+使用 sparse 工具做类型检查
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+"__bitwise" 是一种类型属性,所以你应该这样使用它:
+
+        typedef int __bitwise pm_request_t;
+
+        enum pm_request {
+                PM_SUSPEND = (__force pm_request_t) 1,
+                PM_RESUME = (__force pm_request_t) 2
+        };
+
+这样会使 PM_SUSPEND 和 PM_RESUME 成为位方式(bitwise)整数(使用"__force"
+是因为 sparse 会抱怨改变位方式的类型转换,但是这里我们确实需要强制进行转
+换)。而且因为所有枚举值都使用了相同的类型,这里的"enum pm_request"也将
+会使用那个类型做为底层实现。
+
+而且使用 gcc 编译的时候,所有的 __bitwise/__force 都会消失,最后在 gcc
+看来它们只不过是普通的整数。
+
+坦白来说,你并不需要使用枚举类型。上面那些实际都可以浓缩成一个特殊的"int
+__bitwise"类型。
+
+所以更简单的办法只要这样做:
+
+       typedef int __bitwise pm_request_t;
+
+       #define PM_SUSPEND ((__force pm_request_t) 1)
+       #define PM_RESUME ((__force pm_request_t) 2)
+
+现在你就有了严格的类型检查所需要的所有基础架构。
+
+一个小提醒:常数整数"0"是特殊的。你可以直接把常数零当作位方式整数使用而
+不用担心 sparse 会抱怨。这是因为"bitwise"(恰如其名)是用来确保不同位方
+式类型不会被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),对他们来说
+常数"0"确实是特殊的。
+
+获取 sparse 工具
+~~~~~~~~~~~~~~~~
+
+你可以从 Sparse 的主页获取最新的发布版本:
+
+       http://www.kernel.org/pub/linux/kernel/people/josh/sparse/
+
+或者,你也可以使用 git 克隆最新的 sparse 开发版本:
+
+       git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git
+
+DaveJ 把每小时自动生成的 git 源码树 tar 包放在以下地址:
+
+       http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
+
+一旦你下载了源码,只要以普通用户身份运行:
+
+       make
+       make install
+
+它将会被自动安装到你的 ~/bin 目录下。
+
+使用 sparse 工具
+~~~~~~~~~~~~~~~~
+
+用"make C=1"命令来编译内核,会对所有重新编译的 C 文件使用 sparse 工具。
+或者使用"make C=2"命令,无论文件是否被重新编译都会对其使用 sparse 工具。
+如果你已经编译了内核,用后一种方式可以很快地检查整个源码树。
+
+make 的可选变量 CHECKFLAGS 可以用来向 sparse 工具传递参数。编译系统会自
+动向 sparse 工具传递 -Wbitwise 参数。你可以定义 __CHECK_ENDIAN__ 来进行
+大小尾检查。
+
+       make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
+
+这些检查默认都是被关闭的,因为他们通常会产生大量的警告。
diff --git a/Documentation/zh_CN/stable_kernel_rules.txt b/Documentation/zh_CN/stable_kernel_rules.txt
new file mode 100644 (file)
index 0000000..b5b9b0a
--- /dev/null
@@ -0,0 +1,66 @@
+Chinese translated version of Documentation/stable_kernel_rules.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: TripleX Chung <triplex@zh-kernel.org>
+---------------------------------------------------------------------
+Documentation/stable_kernel_rules.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+
+中文版维护者: 钟宇  TripleX Chung <triplex@zh-kernel.org>
+中文版翻译者: 钟宇  TripleX Chung <triplex@zh-kernel.org>
+中文版校译者: 李阳  Li Yang <leo@zh-kernel.org>
+               Kangkai Yin <e12051@motorola.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+关于Linux 2.6稳定版发布,所有你想知道的事情。
+
+关于哪些类型的补丁可以被接收进入稳定版代码树,哪些不可以的规则:
+
+  - 必须是显而易见的正确,并且经过测试的。
+  - 连同上下文,不能大于100行。
+  - 必须只修正一件事情。
+  - 必须修正了一个给大家带来麻烦的真正的bug(不是“这也许是一个问题...”
+    那样的东西)。
+  - 必须修正带来如下后果的问题:编译错误(对被标记为CONFIG_BROKEN的例外),
+    内核崩溃,挂起,数据损坏,真正的安全问题,或者一些类似“哦,这不
+    好”的问题。简短的说,就是一些致命的问题。
+  - 没有“理论上的竞争条件”,除非能给出竞争条件如何被利用的解释。
+  - 不能存在任何的“琐碎的”修正(拼写修正,去掉多余空格之类的)。
+  - 必须被相关子系统的维护者接受。
+  - 必须遵循Documentation/SubmittingPatches里的规则。
+
+向稳定版代码树提交补丁的过程:
+
+  - 在确认了补丁符合以上的规则后,将补丁发送到stable@kernel.org。
+  - 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
+    到的是NAK回复。回复需要几天的时间,这取决于开发者的时间安排。
+  - 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
+  - 安全方面的补丁不要发到这个列表,应该发送到security@kernel.org。
+
+审查周期:
+
+  - 当稳定版的维护者决定开始一个审查周期,补丁将被发送到审查委员会,以
+    及被补丁影响的领域的维护者(除非提交者就是该领域的维护者)并且抄送
+    到linux-kernel邮件列表。
+  - 审查委员会有48小时的时间,用来决定给该补丁回复ACK还是NAK。
+  - 如果委员会中有成员拒绝这个补丁,或者linux-kernel列表上有人反对这个
+    补丁,并提出维护者和审查委员会之前没有意识到的问题,补丁会从队列中
+    丢弃。
+  - 在审查周期结束的时候,那些得到ACK回应的补丁将会被加入到最新的稳定版
+    发布中,一个新的稳定版发布就此产生。
+  - 安全性补丁将从内核安全小组那里直接接收到稳定版代码树中,而不是通过
+    通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。
+
+审查委员会:
+  - 由一些自愿承担这项任务的内核开发者,和几个非志愿的组成。
diff --git a/Documentation/zh_CN/volatile-considered-harmful.txt b/Documentation/zh_CN/volatile-considered-harmful.txt
new file mode 100644 (file)
index 0000000..ba8149d
--- /dev/null
@@ -0,0 +1,113 @@
+Chinese translated version of Documentation/volatile-considered-harmful.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Jonathan Corbet <corbet@lwn.net>
+Chinese maintainer: Bryan Wu <bryan.wu@analog.com>
+---------------------------------------------------------------------
+Documentation/volatile-considered-harmful.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: Jonathan Corbet <corbet@lwn.net>
+中文版维护者: 伍鹏  Bryan Wu <bryan.wu@analog.com>
+中文版翻译者: 伍鹏  Bryan Wu <bryan.wu@analog.com>
+中文版校译者: 张汉辉  Eugene Teo <eugeneteo@kernel.sg>
+               杨瑞  Dave Young <hidave.darkstar@gmail.com>
+以下为正文
+---------------------------------------------------------------------
+
+为什么不应该使用“volatile”类型
+------------------------------
+
+C程序员通常认为volatile表示某个变量可以在当前执行的线程之外被改变;因此,在内核
+中用到共享数据结构时,常常会有C程序员喜欢使用volatile这类变量。换句话说,他们经
+常会把volatile类型看成某种简易的原子变量,当然它们不是。在内核中使用volatile几
+乎总是错误的;本文档将解释为什么这样。
+
+理解volatile的关键是知道它的目的是用来消除优化,实际上很少有人真正需要这样的应
+用。在内核中,程序员必须防止意外的并发访问破坏共享的数据结构,这其实是一个完全
+不同的任务。用来防止意外并发访问的保护措施,可以更加高效的避免大多数优化相关的
+问题。
+
+像volatile一样,内核提供了很多原语来保证并发访问时的数据安全(自旋锁, 互斥量,内
+存屏障等等),同样可以防止意外的优化。如果可以正确使用这些内核原语,那么就没有
+必要再使用volatile。如果仍然必须使用volatile,那么几乎可以肯定在代码的某处有一
+个bug。在正确设计的内核代码中,volatile能带来的仅仅是使事情变慢。
+
+思考一下这段典型的内核代码:
+
+    spin_lock(&the_lock);
+    do_something_on(&shared_data);
+    do_something_else_with(&shared_data);
+    spin_unlock(&the_lock);
+
+如果所有的代码都遵循加锁规则,当持有the_lock的时候,不可能意外的改变shared_data的
+值。任何可能访问该数据的其他代码都会在这个锁上等待。自旋锁原语跟内存屏障一样—— 它
+们显式的用来书写成这样 —— 意味着数据访问不会跨越它们而被优化。所以本来编译器认为
+它知道在shared_data里面将有什么,但是因为spin_lock()调用跟内存屏障一样,会强制编
+译器忘记它所知道的一切。那么在访问这些数据时不会有优化的问题。
+
+如果shared_data被声名为volatile,锁操作将仍然是必须的。就算我们知道没有其他人正在
+使用它,编译器也将被阻止优化对临界区内shared_data的访问。在锁有效的同时,
+shared_data不是volatile的。在处理共享数据的时候,适当的锁操作可以不再需要
+volatile —— 并且是有潜在危害的。
+
+volatile的存储类型最初是为那些内存映射的I/O寄存器而定义。在内核里,寄存器访问也应
+该被锁保护,但是人们也不希望编译器“优化”临界区内的寄存器访问。内核里I/O的内存访问
+是通过访问函数完成的;不赞成通过指针对I/O内存的直接访问,并且不是在所有体系架构上
+都能工作。那些访问函数正是为了防止意外优化而写的,因此,再说一次,volatile类型不
+是必需的。
+
+另一种引起用户可能使用volatile的情况是当处理器正忙着等待一个变量的值。正确执行一
+个忙等待的方法是:
+
+    while (my_variable != what_i_want)
+        cpu_relax();
+
+cpu_relax()调用会降低CPU的能量消耗或者让位于超线程双处理器;它也作为内存屏障一样出
+现,所以,再一次,volatile不是必需的。当然,忙等待一开始就是一种反常规的做法。
+
+在内核中,一些稀少的情况下volatile仍然是有意义的:
+
+  - 在一些体系架构的系统上,允许直接的I/0内存访问,那么前面提到的访问函数可以使用
+    volatile。基本上,每一个访问函数调用它自己都是一个小的临界区域并且保证了按照
+    程序员期望的那样发生访问操作。
+
+  - 某些会改变内存的内联汇编代码虽然没有什么其他明显的附作用,但是有被GCC删除的可
+    能性。在汇编声明中加上volatile关键字可以防止这种删除操作。
+
+  - Jiffies变量是一种特殊情况,虽然每次引用它的时候都可以有不同的值,但读jiffies
+    变量时不需要任何特殊的加锁保护。所以jiffies变量可以使用volatile,但是不赞成
+    其他跟jiffies相同类型变量使用volatile。Jiffies被认为是一种“愚蠢的遗留物"
+    (Linus的话)因为解决这个问题比保持现状要麻烦的多。
+
+  - 由于某些I/0设备可能会修改连续一致的内存,所以有时,指向连续一致内存的数据结构
+    的指针需要正确的使用volatile。网络适配器使用的环状缓存区正是这类情形的一个例
+    子,其中适配器用改变指针来表示哪些描述符已经处理过了。
+
+对于大多代码,上述几种可以使用volatile的情况都不适用。所以,使用volatile是一种
+bug并且需要对这样的代码额外仔细检查。那些试图使用volatile的开发人员需要退一步想想
+他们真正想实现的是什么。
+
+非常欢迎删除volatile变量的补丁 - 只要证明这些补丁完整的考虑了并发问题。
+
+注释
+----
+
+[1] http://lwn.net/Articles/233481/
+[2] http://lwn.net/Articles/233482/
+
+致谢
+----
+
+最初由Randy Dunlap推动并作初步研究
+由Jonathan Corbet撰写
+参考Satyam Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
+H. Peter Anvin,Philipp Hahn和Stefan Richter的意见改善了本档。
index 79c711e6074bb763b483a747e24386585c35571b..59db481c77de81e808c489ec9a95be3f411dce35 100644 (file)
@@ -665,12 +665,18 @@ S:        Maintained
 
 ATMEL AT91 MCI DRIVER
 P:     Nicolas Ferre
-M:     nicolas.ferre@rfo.atmel.com
+M:     nicolas.ferre@atmel.com
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 W:     http://www.atmel.com/products/AT91/
 W:     http://www.at91.com/
 S:     Maintained
 
+ATMEL LCDFB DRIVER
+P:     Nicolas Ferre
+M:     nicolas.ferre@atmel.com
+L:     linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
+S:     Maintained
+
 ATMEL MACB ETHERNET DRIVER
 P:     Haavard Skinnemoen
 M:     hskinnemoen@atmel.com
@@ -1919,7 +1925,7 @@ INFINIBAND SUBSYSTEM
 P:     Roland Dreier
 M:     rolandd@cisco.com
 P:     Sean Hefty
-M:     mshefty@ichips.intel.com
+M:     sean.hefty@intel.com
 P:     Hal Rosenstock
 M:     hal.rosenstock@gmail.com 
 L:     general@lists.openfabrics.org
@@ -1984,29 +1990,27 @@ L:      netdev@vger.kernel.org
 S:     Maintained
 
 INTEL PRO/100 ETHERNET SUPPORT
-P:     John Ronciak
-M:     john.ronciak@intel.com
+P:     Auke Kok
+M:     auke-jan.h.kok@intel.com
 P:     Jesse Brandeburg
 M:     jesse.brandeburg@intel.com
 P:     Jeff Kirsher
 M:     jeffrey.t.kirsher@intel.com
-P:     Auke Kok
-M:     auke-jan.h.kok@intel.com
+P:     John Ronciak
+M:     john.ronciak@intel.com
 L:     e1000-devel@lists.sourceforge.net
 W:     http://sourceforge.net/projects/e1000/
 S:     Supported
 
 INTEL PRO/1000 GIGABIT ETHERNET SUPPORT
-P:     Jeb Cramer
-M:     cramerj@intel.com
-P:     John Ronciak
-M:     john.ronciak@intel.com
+P:     Auke Kok
+M:     auke-jan.h.kok@intel.com
 P:     Jesse Brandeburg
 M:     jesse.brandeburg@intel.com
 P:     Jeff Kirsher
 M:     jeffrey.t.kirsher@intel.com
-P:     Auke Kok
-M:     auke-jan.h.kok@intel.com
+P:     John Ronciak
+M:     john.ronciak@intel.com
 L:     e1000-devel@lists.sourceforge.net
 W:     http://sourceforge.net/projects/e1000/
 S:     Supported
@@ -2137,6 +2141,15 @@ L:       isdn4linux@listserv.isdn4linux.de
 W:     http://www.melware.de
 S:     Maintained
 
+IVTV VIDEO4LINUX DRIVER
+P:     Hans Verkuil
+M:     hverkuil@xs4all.nl
+L:     ivtv-devel@ivtvdriver.org
+L:     ivtv-users@ivtvdriver.org
+L:     video4linux-list@redhat.com
+W:     http://www.ivtvdriver.org
+S:     Maintained
+
 JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
 P:     David Woodhouse
 M:     dwmw2@infradead.org
@@ -2741,8 +2754,8 @@ T:        git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git
 S:     Maintained
 
 NETXEN (1/10) GbE SUPPORT
-P:     Amit S. Kale
-M:     amitkale@netxen.com
+P:     Dhananjay Phadke
+M:     dhananjay@netxen.com
 L:     netdev@vger.kernel.org
 W:     http://www.netxen.com
 S:     Supported
@@ -3256,8 +3269,10 @@ W:       http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 
 S390 ZFCP DRIVER
-P:     Swen Schillig
-M:     swen@vnet.ibm.com
+P:     Christof Schmitt
+M:     christof.schmitt@de.ibm.com
+P:     Martin Peschke
+M:     mp3@de.ibm.com
 M:     linux390@de.ibm.com
 L:     linux-s390@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
@@ -3613,8 +3628,10 @@ L:       linux-kernel@vger.kernel.org ?
 S:     Supported
 
 SPIDERNET NETWORK DRIVER for CELL
-P:     Linas Vepstas
-M:     linas@austin.ibm.com
+P:     Ishizaki Kou
+M:     kou.ishizaki@toshiba.co.jp
+P:     Jens Osterkamp
+M:     jens@de.ibm.com
 L:     netdev@vger.kernel.org
 S:     Supported
 
index fbb8dfc063d36070bc8b3336e7f696d0b15d3d61..189d8ef416e66c2b9abc848be40400a880776ac7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 24
-EXTRAVERSION = -rc6
+EXTRAVERSION =
 NAME = Arr Matey! A Hairy Bilge Rat!
 
 # *DOCUMENTATION*
@@ -12,7 +12,7 @@ NAME = Arr Matey! A Hairy Bilge Rat!
 
 # Do not:
 # o  use make's built-in rules and variables
-#    (this increases performance and avoid hard-to-debug behavour);
+#    (this increases performance and avoids hard-to-debug behaviour);
 # o  print "Entering directory ...";
 MAKEFLAGS += -rR --no-print-directory
 
@@ -1329,7 +1329,7 @@ else
 ALLINCLUDE_ARCHS := $(SRCARCH)
 endif
 else
-#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behavour.
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
 ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
 endif
 
diff --git a/arch/.gitignore b/arch/.gitignore
new file mode 100644 (file)
index 0000000..7414689
--- /dev/null
@@ -0,0 +1,2 @@
+i386
+x86_64
index ae79dd970b021ff84ca59d3b5f6b14a4b19ce25f..58c2669a1dd4fa431f32ecbe8416c24a540525ba 100644 (file)
@@ -225,7 +225,7 @@ alpha_fp_emul (unsigned long pc)
                                FP_UNPACK_SP(SB, &vb);
                                DR_c = DB_c;
                                DR_s = DB_s;
-                               DR_e = DB_e;
+                               DR_e = DB_e + (1024 - 128);
                                DR_f = SB_f << (52 - 23);
                                goto pack_d;
                        }
index c4de2d4664d7d504fd63715fb84ec7450ac53496..a04f507e7f2ca94f1b959d0e03dac7f0a3c73575 100644 (file)
@@ -1072,11 +1072,13 @@ source "drivers/rtc/Kconfig"
 
 source "drivers/dma/Kconfig"
 
+source "drivers/dca/Kconfig"
+
 endmenu
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
+source "arch/arm/Kconfig.instrumentation"
 
 source "arch/arm/Kconfig.debug"
 
diff --git a/arch/arm/Kconfig.instrumentation b/arch/arm/Kconfig.instrumentation
new file mode 100644 (file)
index 0000000..63b8c6d
--- /dev/null
@@ -0,0 +1,52 @@
+menuconfig INSTRUMENTATION
+       bool "Instrumentation Support"
+       default y
+       ---help---
+         Say Y here to get to see options related to performance measurement,
+         system-wide debugging, and testing. This option alone does not add any
+         kernel code.
+
+         If you say N, all options in this submenu will be skipped and
+         disabled. If you're trying to debug the kernel itself, go see the
+         Kernel Hacking menu.
+
+if INSTRUMENTATION
+
+config PROFILING
+       bool "Profiling support (EXPERIMENTAL)"
+       help
+         Say Y here to enable the extended profiling support mechanisms used
+         by profilers such as OProfile.
+
+config OPROFILE
+       tristate "OProfile system profiling (EXPERIMENTAL)"
+       depends on PROFILING && !UML
+       help
+         OProfile is a profiling system capable of profiling the
+         whole system, include the kernel, kernel modules, libraries,
+         and applications.
+
+         If unsure, say N.
+
+config OPROFILE_ARMV6
+       bool
+       depends on OPROFILE && CPU_V6 && !SMP
+       default y
+       select OPROFILE_ARM11_CORE
+
+config OPROFILE_MPCORE
+       bool
+       depends on OPROFILE && CPU_V6 && SMP
+       default y
+       select OPROFILE_ARM11_CORE
+
+config OPROFILE_ARM11_CORE
+       bool
+
+config MARKERS
+       bool "Activate markers"
+       help
+         Place an empty function call at each marker site. Can be
+         dynamically changed for a probe function.
+
+endif # INSTRUMENTATION
index 1533d3ecd7a05b71b559f56356560a37daabefcf..e59b5b84168dadc02493200f26ee86e426059f70 100644 (file)
@@ -79,17 +79,6 @@ static unsigned long dummy_gettimeoffset(void)
 }
 #endif
 
-/*
- * An implementation of printk_clock() independent from
- * sched_clock().  This avoids non-bootable kernels when
- * printk_clock is enabled.
- */
-unsigned long long printk_clock(void)
-{
-       return (unsigned long long)(jiffies - INITIAL_JIFFIES) *
-                       (1000000000 / HZ);
-}
-
 static unsigned long next_rtc_update;
 
 /*
@@ -195,7 +184,7 @@ static int leds_shutdown(struct sys_device *dev)
 }
 
 static struct sysdev_class leds_sysclass = {
-       set_kset_name("leds"),
+       .name           = "leds",
        .shutdown       = leds_shutdown,
        .suspend        = leds_suspend,
        .resume         = leds_resume,
@@ -369,7 +358,7 @@ static int timer_resume(struct sys_device *dev)
 #endif
 
 static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer"),
+       .name           = "timer",
        .suspend        = timer_suspend,
        .resume         = timer_resume,
 };
index d05b1b2be9fbe34fd70a0c2912a8372f999f13bc..53a5ef9e72eeec7844007282896002f0e0f8552e 100644 (file)
@@ -109,6 +109,15 @@ static struct spi_board_info ek_spi_devices[] = {
 #endif
 };
 
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("ics1523", 0x26),
+       },
+       {
+               I2C_BOARD_INFO("dac3550", 0x4d),
+       }
+};
+
 #define EK_FLASH_BASE  AT91_CHIPSELECT_0
 #define EK_FLASH_SIZE  0x200000
 
index 72280754354d3b98e7785c945abd0ec33930202c..df37e93c6fc92e51826fbf1c669c585b5d5d105f 100644 (file)
@@ -214,7 +214,7 @@ static int irq_resume(struct sys_device *dev)
 #endif
 
 static struct sysdev_class irq_class = {
-       set_kset_name("irq"),
+       .name           = "irq",
        .suspend        = irq_suspend,
        .resume         = irq_resume,
 };
index f65baa95986ea9717632690404dd77c47a1cc1c5..d5f6ea14fc7bdf241cbc9f26568d0abc3ac57e03 100644 (file)
@@ -40,31 +40,29 @@ static int fsample_keymap[] = {
        KEY(0,1,KEY_RIGHT),
        KEY(0,2,KEY_LEFT),
        KEY(0,3,KEY_DOWN),
-       KEY(0,4,KEY_CENTER),
-       KEY(0,5,KEY_0_5),
-       KEY(1,0,KEY_SOFT2),
+       KEY(0,4,KEY_ENTER),
+       KEY(1,0,KEY_F10),
        KEY(1,1,KEY_SEND),
        KEY(1,2,KEY_END),
        KEY(1,3,KEY_VOLUMEDOWN),
        KEY(1,4,KEY_VOLUMEUP),
        KEY(1,5,KEY_RECORD),
-       KEY(2,0,KEY_SOFT1),
+       KEY(2,0,KEY_F9),
        KEY(2,1,KEY_3),
        KEY(2,2,KEY_6),
        KEY(2,3,KEY_9),
-       KEY(2,4,KEY_SHARP),
-       KEY(2,5,KEY_2_5),
+       KEY(2,4,KEY_KPDOT),
        KEY(3,0,KEY_BACK),
        KEY(3,1,KEY_2),
        KEY(3,2,KEY_5),
        KEY(3,3,KEY_8),
        KEY(3,4,KEY_0),
-       KEY(3,5,KEY_HEADSETHOOK),
+       KEY(3,5,KEY_KPSLASH),
        KEY(4,0,KEY_HOME),
        KEY(4,1,KEY_1),
        KEY(4,2,KEY_4),
        KEY(4,3,KEY_7),
-       KEY(4,4,KEY_STAR),
+       KEY(4,4,KEY_KPASTERISK),
        KEY(4,5,KEY_POWER),
        0
 };
index 22db19a536478d3ad9f9a5ee1b96ad567f776ab2..182a98a9df4c9e33cd55169bdae113d01daed629 100644 (file)
@@ -36,8 +36,6 @@
 #include <asm/arch/omapfb.h>
 #include <asm/arch/lcd_mipid.h>
 
-#include "../plat-omap/dsp/dsp_common.h"
-
 #define ADS7846_PENDOWN_GPIO   15
 
 static void __init omap_nokia770_init_irq(void)
@@ -318,6 +316,8 @@ static __init int omap_dsp_init(void)
  out:
        return ret;
 }
+#else
+#define omap_dsp_init()                do {} while (0)
 #endif /* CONFIG_OMAP_DSP */
 
 static void __init omap_nokia770_init(void)
index 1d5c8d5097222ad1289b4edf8664febb66434b61..e44437e10eefe7a751230c4f72097f4f63b96508 100644 (file)
@@ -39,31 +39,29 @@ static int p2_keymap[] = {
        KEY(0,1,KEY_RIGHT),
        KEY(0,2,KEY_LEFT),
        KEY(0,3,KEY_DOWN),
-       KEY(0,4,KEY_CENTER),
-       KEY(0,5,KEY_0_5),
-       KEY(1,0,KEY_SOFT2),
+       KEY(0,4,KEY_ENTER),
+       KEY(1,0,KEY_F10),
        KEY(1,1,KEY_SEND),
        KEY(1,2,KEY_END),
        KEY(1,3,KEY_VOLUMEDOWN),
        KEY(1,4,KEY_VOLUMEUP),
        KEY(1,5,KEY_RECORD),
-       KEY(2,0,KEY_SOFT1),
+       KEY(2,0,KEY_F9),
        KEY(2,1,KEY_3),
        KEY(2,2,KEY_6),
        KEY(2,3,KEY_9),
-       KEY(2,4,KEY_SHARP),
-       KEY(2,5,KEY_2_5),
+       KEY(2,4,KEY_KPDOT),
        KEY(3,0,KEY_BACK),
        KEY(3,1,KEY_2),
        KEY(3,2,KEY_5),
        KEY(3,3,KEY_8),
        KEY(3,4,KEY_0),
-       KEY(3,5,KEY_HEADSETHOOK),
+       KEY(3,5,KEY_KPSLASH),
        KEY(4,0,KEY_HOME),
        KEY(4,1,KEY_1),
        KEY(4,2,KEY_4),
        KEY(4,3,KEY_7),
-       KEY(4,4,KEY_STAR),
+       KEY(4,4,KEY_KPASTERISK),
        KEY(4,5,KEY_POWER),
        0
 };
index 3bf01e28df334ceaaf49dc55c8d4cd59e00c09d4..d9805e3d930400de42e49afd8216e3a8c71bb745 100644 (file)
@@ -69,14 +69,14 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
 
 static unsigned short enable_dyn_sleep = 1;
 
-static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf)
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+                        char *buf)
 {
        return sprintf(buf, "%hu\n", enable_dyn_sleep);
 }
 
-static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
-                                             const char * buf,
-                                             size_t n)
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+                         const char * buf, size_t n)
 {
        unsigned short value;
        if (sscanf(buf, "%hu", &value) != 1 ||
@@ -88,16 +88,9 @@ static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
        return n;
 }
 
-static struct subsys_attribute sleep_while_idle_attr = {
-       .attr   = {
-               .name = __stringify(sleep_while_idle),
-               .mode = 0644,
-       },
-       .show   = omap_pm_sleep_while_idle_show,
-       .store  = omap_pm_sleep_while_idle_store,
-};
+static struct kobj_attribute sleep_while_idle_attr =
+       __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
 
-extern struct kset power_subsys;
 static void (*omap_sram_idle)(void) = NULL;
 static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
 
@@ -726,9 +719,9 @@ static int __init omap_pm_init(void)
        omap_pm_init_proc();
 #endif
 
-       error = subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+       error = sysfs_create_file(power_kobj, &sleep_while_idle_attr);
        if (error)
-               printk(KERN_ERR "subsys_create_file failed: %d\n", error);
+               printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
 
        if (cpu_is_omap16xx()) {
                /* configure LOW_PWR pin */
index 177664ccb2e230ab954fcbbdbf9913a6de499d88..a16349272f54db89e1c7fbfa1a846c57f2430047 100644 (file)
@@ -566,7 +566,7 @@ static int cmx270_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class cmx270_pm_sysclass = {
-       set_kset_name("pm"),
+       .name = "pm",
        .resume = cmx270_resume,
        .suspend = cmx270_suspend,
 };
index 26116440a7c927648d7b8a3e493bdf042cab3beb..78ebad063cba59bb9ef58ddb8918869411cc9e87 100644 (file)
@@ -122,7 +122,7 @@ static int lpd270_irq_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class lpd270_irq_sysclass = {
-       set_kset_name("cpld_irq"),
+       .name = "cpld_irq",
        .resume = lpd270_irq_resume,
 };
 
index 011a1a72b61c87241d15f3515facfb9c7917cd3f..1d3112dc629ea38a76f203adac5f96affe6b0f20 100644 (file)
@@ -126,7 +126,7 @@ static int lubbock_irq_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class lubbock_irq_sysclass = {
-       set_kset_name("cpld_irq"),
+       .name = "cpld_irq",
        .resume = lubbock_irq_resume,
 };
 
index a4bc3483cbb3f29540739f5268dedc02b21f7972..41d8c6cea62b4d26285f22a9eb23479bdcc5a501 100644 (file)
@@ -120,7 +120,7 @@ static int mainstone_irq_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class mainstone_irq_sysclass = {
-       set_kset_name("cpld_irq"),
+       .name = "cpld_irq",
        .resume = mainstone_irq_resume,
 };
 
index dcd81f8d0833f28da844c3e468bf89ea8becfa40..9732d5d9466b1381fdb1b6ce416403af4215675d 100644 (file)
@@ -178,13 +178,19 @@ static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
        SAVE(GAFR1_L); SAVE(GAFR1_U);
        SAVE(GAFR2_L); SAVE(GAFR2_U);
 
-       SAVE(ICMR);
+       SAVE(ICMR); ICMR = 0;
        SAVE(CKEN);
        SAVE(PSTR);
+
+       /* Clear GPIO transition detect bits */
+       GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
 }
 
 static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
 {
+       /* ensure not to come back here if it wasn't intended */
+       PSPR = 0;
+
        /* restore registers */
        RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
        RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
@@ -195,7 +201,12 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
        RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
        RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
 
+       PSSR = PSSR_RDH | PSSR_PH;
+
        RESTORE(CKEN);
+
+       ICLR = 0;
+       ICCR = 1;
        RESTORE(ICMR);
        RESTORE(PSTR);
 }
index aff71fec618ac7468cd3aca861873d86edb578a1..d0447723b73a111ea9b8edf5a531edfa36a473be 100644 (file)
@@ -43,11 +43,11 @@ pxa_cpu_save_cp:
 pxa_cpu_save_sp:
        @ preserve phys address of stack
        mov     r0, sp
-       mov     r2, lr
+       str     lr, [sp, #-4]!
        bl      sleep_phys_sp
        ldr     r1, =sleep_save_sp
        str     r0, [r1]
-       mov     pc, r2
+       ldr     pc, [sp], #4
 
 /*
  * pxa27x_cpu_suspend()
@@ -270,5 +270,3 @@ resume_after_mmu:
        mar     acc0, r2, r3
 #endif
        ldmfd   sp!, {r4 - r12, pc}             @ return to caller
-
-
index e580303cb0abbd86d1e97429ea21fceaeeb0efec..0e7991940f81b040c88ca73d5501038c3d69fbc8 100644 (file)
@@ -100,7 +100,7 @@ void __init s3c2410_init_clocks(int xtal)
 }
 
 struct sysdev_class s3c2410_sysclass = {
-       set_kset_name("s3c2410-core"),
+       .name = "s3c2410-core",
 };
 
 static struct sys_device s3c2410_sysdev = {
index 4f92a1562d77fa62043e5d4a29679a8d928a612d..265cd3f567a3fe164bbe9027cd2856120e725dd9 100644 (file)
@@ -196,7 +196,7 @@ void __init s3c2412_init_clocks(int xtal)
 */
 
 struct sysdev_class s3c2412_sysclass = {
-       set_kset_name("s3c2412-core"),
+       .name = "s3c2412-core",
 };
 
 static int __init s3c2412_core_init(void)
index c326983f4a8f5b66dcee243def28998c560d2bb2..78af7664988b98746f1499a79dd142a0fb33b5fd 100644 (file)
@@ -312,7 +312,7 @@ static int osiris_pm_resume(struct sys_device *sd)
 #endif
 
 static struct sysdev_class osiris_pm_sysclass = {
-       set_kset_name("mach-osiris"),
+       .name           = "mach-osiris",
        .suspend        = osiris_pm_suspend,
        .resume         = osiris_pm_resume,
 };
index 8d8117158d23aa5d9e22b59bbd7db5abfe67d805..9ce490560af98df561a7742a858515c17cc063fd 100644 (file)
@@ -43,7 +43,7 @@ static struct map_desc s3c2443_iodesc[] __initdata = {
 };
 
 struct sysdev_class s3c2443_sysclass = {
-       set_kset_name("s3c2443-core"),
+       .name = "s3c2443-core",
 };
 
 static struct sys_device s3c2443_sysdev = {
index edf3347d9c5b61bccce6859cc0fcde6fc935964b..3dc17d7bf38e823f407c05e30f1af20d8ae2022d 100644 (file)
@@ -283,7 +283,7 @@ static int sa1100irq_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class sa1100irq_sysclass = {
-       set_kset_name("sa11x0-irq"),
+       .name           = "sa11x0-irq",
        .suspend        = sa1100irq_suspend,
        .resume         = sa1100irq_resume,
 };
index a9de727c9327aa29eb266e45860a681e72f1d55c..0a5cf3a6438be268f792ae0cb1ec9d7c6a66692c 100644 (file)
@@ -96,7 +96,7 @@ static int op_arm_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class oprofile_sysclass = {
-       set_kset_name("oprofile"),
+       .name           = "oprofile",
        .resume         = op_arm_resume,
        .suspend        = op_arm_suspend,
 };
index 6097753394adaef923105fe47a6b6237fc1a27f7..b2a87b8ef6734e95a3fa207a357bb5c0ecde96bd 100644 (file)
@@ -1455,7 +1455,7 @@ static int omap_gpio_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class omap_gpio_sysclass = {
-       set_kset_name("gpio"),
+       .name           = "gpio",
        .suspend        = omap_gpio_suspend,
        .resume         = omap_gpio_resume,
 };
index 29696e46ed659bab0fdb00cc5fc0f17aaf8f1040..aae1b9cbaf44b77a0e9f4ea7e9f37c04cd1a1191 100644 (file)
@@ -1265,7 +1265,7 @@ static int s3c2410_dma_resume(struct sys_device *dev)
 #endif /* CONFIG_PM */
 
 struct sysdev_class dma_sysclass = {
-       set_kset_name("s3c24xx-dma"),
+       .name           = "s3c24xx-dma",
        .suspend        = s3c2410_dma_suspend,
        .resume         = s3c2410_dma_resume,
 };
index 3444b13afac52ad0a9694785f204f50c71c32ade..f197bb3a2366c980e6cf66d2042b7c19c524f4ee 100644 (file)
@@ -151,13 +151,13 @@ static int s3c244x_resume(struct sys_device *dev)
 /* Since the S3C2442 and S3C2440 share  items, put both sysclasses here */
 
 struct sysdev_class s3c2440_sysclass = {
-       set_kset_name("s3c2440-core"),
+       .name           = "s3c2440-core",
        .suspend        = s3c244x_suspend,
        .resume         = s3c244x_resume
 };
 
 struct sysdev_class s3c2442_sysclass = {
-       set_kset_name("s3c2442-core"),
+       .name           = "s3c2442-core",
        .suspend        = s3c244x_suspend,
        .resume         = s3c244x_resume
 };
index 54a2ad6d9ca25a314514b6e99543c392a37ddde9..791d0238c68f133d48664663c4812074737b0247 100644 (file)
@@ -361,10 +361,12 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
  *  OP_SCALAR - this operation always operates in scalar mode
  *  OP_SD - the instruction exceptionally writes to a single precision result.
  *  OP_DD - the instruction exceptionally writes to a double precision result.
+ *  OP_SM - the instruction exceptionally reads from a single precision operand.
  */
 #define OP_SCALAR      (1 << 0)
 #define OP_SD          (1 << 1)
 #define OP_DD          (1 << 1)
+#define OP_SM          (1 << 2)
 
 struct op {
        u32 (* const fn)(int dd, int dn, int dm, u32 fpscr);
index 190a09ad18ebe87217222c7eecc2c05823bec86f..6cac43bd1d86c63638993bafa8ba989fea52e91f 100644 (file)
@@ -668,8 +668,8 @@ static struct op fops_ext[32] = {
        [FEXT_TO_IDX(FEXT_FCMPZ)]       = { vfp_double_fcmpz,  OP_SCALAR },
        [FEXT_TO_IDX(FEXT_FCMPEZ)]      = { vfp_double_fcmpez, OP_SCALAR },
        [FEXT_TO_IDX(FEXT_FCVT)]        = { vfp_double_fcvts,  OP_SCALAR|OP_SD },
-       [FEXT_TO_IDX(FEXT_FUITO)]       = { vfp_double_fuito,  OP_SCALAR },
-       [FEXT_TO_IDX(FEXT_FSITO)]       = { vfp_double_fsito,  OP_SCALAR },
+       [FEXT_TO_IDX(FEXT_FUITO)]       = { vfp_double_fuito,  OP_SCALAR|OP_SM },
+       [FEXT_TO_IDX(FEXT_FSITO)]       = { vfp_double_fsito,  OP_SCALAR|OP_SM },
        [FEXT_TO_IDX(FEXT_FTOUI)]       = { vfp_double_ftoui,  OP_SCALAR|OP_SD },
        [FEXT_TO_IDX(FEXT_FTOUIZ)]      = { vfp_double_ftouiz, OP_SCALAR|OP_SD },
        [FEXT_TO_IDX(FEXT_FTOSI)]       = { vfp_double_ftosi,  OP_SCALAR|OP_SD },
@@ -1128,7 +1128,7 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
        u32 exceptions = 0;
        unsigned int dest;
        unsigned int dn = vfp_get_dn(inst);
-       unsigned int dm = vfp_get_dm(inst);
+       unsigned int dm;
        unsigned int vecitr, veclen, vecstride;
        struct op *fop;
 
@@ -1145,6 +1145,14 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
        else
                dest = vfp_get_dd(inst);
 
+       /*
+        * f[us]ito takes a sN operand, not a dN operand.
+        */
+       if (fop->flags & OP_SM)
+               dm = vfp_get_sm(inst);
+       else
+               dm = vfp_get_dm(inst);
+
        /*
         * If destination bank is zero, vector length is always '1'.
         * ARM DDI0100F C5.1.3, C5.3.2.
index b77abce10c7aa895689f6210944d0d5b780bba83..e34e2c9c94cb5b678eeae91929682ab081c7e661 100644 (file)
@@ -54,6 +54,9 @@ config ARCH_HAS_ILOG2_U32
 config ARCH_HAS_ILOG2_U64
        def_bool n
 
+config ARCH_SUPPORTS_OPROFILE
+       def_bool y
+
 config GENERIC_HWEIGHT
        def_bool y
 
@@ -81,19 +84,23 @@ config PLATFORM_AT32AP
        select MMU
        select PERFORMANCE_COUNTERS
 
-choice
-       prompt "AVR32 CPU type"
-       default CPU_AT32AP7000
+#
+# CPU types
+#
 
-config CPU_AT32AP7000
-       bool "AT32AP7000"
+# AP7000 derivatives
+config CPU_AT32AP700X
+       bool
        select PLATFORM_AT32AP
-endchoice
-
-#
-# CPU Daughterboards for ATSTK1000
-config BOARD_ATSTK1002
+config CPU_AT32AP7000
+       bool
+       select CPU_AT32AP700X
+config CPU_AT32AP7001
+       bool
+       select CPU_AT32AP700X
+config CPU_AT32AP7002
        bool
+       select CPU_AT32AP700X
 
 choice
        prompt "AVR32 board type"
@@ -101,10 +108,10 @@ choice
 
 config BOARD_ATSTK1000
        bool "ATSTK1000 evaluation board"
-       select BOARD_ATSTK1002 if CPU_AT32AP7000
 
 config BOARD_ATNGW100
        bool "ATNGW100 Network Gateway"
+       select CPU_AT32AP7000
 endchoice
 
 if BOARD_ATSTK1000
@@ -123,15 +130,15 @@ source "arch/avr32/mach-at32ap/Kconfig"
 
 config LOAD_ADDRESS
        hex
-       default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
+       default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
 
 config ENTRY_ADDRESS
        hex
-       default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
+       default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
 
 config PHYS_OFFSET
        hex
-       default 0x10000000 if CPU_AT32AP7000=y
+       default 0x10000000 if CPU_AT32AP700X=y
 
 source "kernel/Kconfig.preempt"
 
@@ -163,6 +170,16 @@ config OWNERSHIP_TRACE
          enabling Nexus-compliant debuggers to keep track of the PID of the
          currently executing task.
 
+config NMI_DEBUGGING
+       bool "NMI Debugging"
+       default n
+       help
+         Say Y here and pass the nmi_debug command-line parameter to
+         the kernel to turn on NMI debugging. Depending on the value
+         of the nmi_debug option, various pieces of information will
+         be dumped to the console when a Non-Maskable Interrupt
+         happens.
+
 # FPU emulation goes here
 
 source "kernel/Kconfig.hz"
@@ -219,6 +236,8 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+source "kernel/Kconfig.instrumentation"
+
 source "arch/avr32/Kconfig.debug"
 
 source "security/Kconfig"
index 64ace00fe6cb3b3bb1b9306cde6a7d8017cb0e7a..2283933a9a93eef48b2de37aefe944540af03ff4 100644 (file)
@@ -6,14 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config KPROBES
-       bool "Kprobes"
-       depends on DEBUG_KERNEL
-       help
-         Kprobes allows you to trap at almost any kernel address and
-          execute a callback function.  register_kprobe() establishes
-          a probepoint and specifies the callback.  Kprobes is useful
-          for kernel debugging, non-intrusive instrumentation and testing.
-          If in doubt, say "N".
-
 endmenu
index 87918647be6d6ed97dba60963f7995c134012d47..17a3529341ddef62eb5c6129a84e25622a280c4a 100644 (file)
@@ -16,7 +16,7 @@ KBUILD_AFLAGS += -mrelax -mno-pic
 CFLAGS_MODULE  += -mno-relax
 LDFLAGS_vmlinux        += --relax
 
-cpuflags-$(CONFIG_CPU_AT32AP7000)      += -mcpu=ap7000
+cpuflags-$(CONFIG_PLATFORM_AT32AP)     += -march=ap
 
 KBUILD_CFLAGS  += $(cpuflags-y)
 KBUILD_AFLAGS  += $(cpuflags-y)
@@ -31,6 +31,7 @@ core-$(CONFIG_BOARD_ATNGW100)         += arch/avr32/boards/atngw100/
 core-$(CONFIG_LOADER_U_BOOT)           += arch/avr32/boot/u-boot/
 core-y                                 += arch/avr32/kernel/
 core-y                                 += arch/avr32/mm/
+drivers-$(CONFIG_OPROFILE)             += arch/avr32/oprofile/
 libs-y                                 += arch/avr32/lib/
 
 archincdir-$(CONFIG_PLATFORM_AT32AP)   := arch-at32ap
index 52987c81d668d1c5825f3f209058e99080ab462e..a398be2849666bf974696ba383800df885ee3cf7 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/io.h>
 #include <asm/setup.h>
 
-#include <asm/arch/at32ap7000.h>
+#include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
 #include <asm/arch/portmux.h>
index 718578f640691c2e9b692c1b98acf53e6d7b5ca1..af90b00100fd0d96f58df404411e00affce02bcd 100644 (file)
@@ -1,34 +1,53 @@
 # STK1000 customization
 
-if BOARD_ATSTK1002
+if BOARD_ATSTK1000
 
-config BOARD_ATSTK1002_CUSTOM
-       bool "Non-default STK-1002 jumper settings"
+choice
+       prompt "ATSTK1000 CPU daughterboard type"
+       default BOARD_ATSTK1002
+
+config BOARD_ATSTK1002
+       bool "ATSTK1002"
+       select CPU_AT32AP7000
+
+config BOARD_ATSTK1003
+       bool "ATSTK1003"
+       select CPU_AT32AP7001
+
+config BOARD_ATSTK1004
+       bool "ATSTK1004"
+       select CPU_AT32AP7002
+
+endchoice
+
+
+config BOARD_ATSTK100X_CUSTOM
+       bool "Non-default STK1002/STK1003/STK1004 jumper settings"
        help
          You will normally leave the jumpers on the CPU card at their
          default settings.  If you need to use certain peripherals,
          you will need to change some of those jumpers.
 
-if BOARD_ATSTK1002_CUSTOM
+if BOARD_ATSTK100X_CUSTOM
 
-config BOARD_ATSTK1002_SW1_CUSTOM
+config BOARD_ATSTK100X_SW1_CUSTOM
        bool "SW1: use SSC1 (not SPI0)"
        help
          This also prevents using the external DAC as an audio interface,
          and means you can't initialize the on-board QVGA display.
 
-config BOARD_ATSTK1002_SW2_CUSTOM
+config BOARD_ATSTK100X_SW2_CUSTOM
        bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
        help
          If you change this you'll want an updated boot loader putting
          the console on UART-C not UART-A.
 
-config BOARD_ATSTK1002_SW3_CUSTOM
+config BOARD_ATSTK100X_SW3_CUSTOM
        bool "SW3: use TIMER1 (not SSC0 and GCLK)"
        help
          This also prevents using the external DAC as an audio interface.
 
-config BOARD_ATSTK1002_SW4_CUSTOM
+config BOARD_ATSTK100X_SW4_CUSTOM
        bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
        help
          To use the camera interface you'll need a custom card (on the
@@ -36,27 +55,29 @@ config BOARD_ATSTK1002_SW4_CUSTOM
 
 config BOARD_ATSTK1002_SW5_CUSTOM
        bool "SW5: use MACB1 (not LCDC)"
+       depends on BOARD_ATSTK1002
 
 config BOARD_ATSTK1002_SW6_CUSTOM
        bool "SW6: more GPIOs (not MACB0)"
+       depends on BOARD_ATSTK1002
 
 endif  # custom
 
-config BOARD_ATSTK1002_SPI1
+config BOARD_ATSTK100X_SPI1
        bool "Configure SPI1 controller"
-       depends on !BOARD_ATSTK1002_SW4_CUSTOM
+       depends on !BOARD_ATSTK100X_SW4_CUSTOM
        help
          All the signals for the second SPI controller are available on
          GPIO lines and accessed through the J1 jumper block.  Say "y"
          here to configure that SPI controller.
 
-config BOARD_ATSTK1002_J2_LED
+config BOARD_ATSTK1000_J2_LED
        bool
-       default BOARD_ATSTK1002_J2_LED8 || BOARD_ATSTK1002_J2_RGB
+       default BOARD_ATSTK1000_J2_LED8 || BOARD_ATSTK1000_J2_RGB
 
 choice
        prompt "LEDs connected to J2:"
-       depends on LEDS_GPIO && !BOARD_ATSTK1002_SW4_CUSTOM
+       depends on LEDS_GPIO && !BOARD_ATSTK100X_SW4_CUSTOM
        optional
        help
          Select this if you have jumpered the J2 jumper block to the
@@ -64,16 +85,21 @@ choice
          IDC cable.  A default "heartbeat" trigger is provided, but
          you can of course override this.
 
-config BOARD_ATSTK1002_J2_LED8
+config BOARD_ATSTK1000_J2_LED8
        bool "LED0..LED7"
        help
          Select this if J2 is jumpered to LED0..LED7 amber leds.
 
-config BOARD_ATSTK1002_J2_RGB
+config BOARD_ATSTK1000_J2_RGB
        bool "RGB leds"
        help
          Select this if J2 is jumpered to the RGB leds.
 
 endchoice
 
-endif  # stk 1002
+config BOARD_ATSTK1000_EXTDAC
+       bool
+       depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM
+       default y
+
+endif  # stk 1000
index 8e0992201bb98b931d9578feeac8a05d5a9ae828..beead86462e8a6a7f8f7797e746be176268394ba 100644 (file)
@@ -1,2 +1,4 @@
 obj-y                          += setup.o flash.o
 obj-$(CONFIG_BOARD_ATSTK1002)  += atstk1002.o
+obj-$(CONFIG_BOARD_ATSTK1003)  += atstk1003.o
+obj-$(CONFIG_BOARD_ATSTK1004)  += atstk1004.o
index 9a49ed036b72bd9660aca6f5ef5153fd6603ae28..9392d3252865a6886025167fe151e7356acf8f64 100644 (file)
@@ -12,4 +12,6 @@
 
 extern struct atmel_lcdfb_info atstk1000_lcdc_data;
 
+void atstk1000_setup_j2_leds(void);
+
 #endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */
index 5be0d13f4b03c53d8d843d9a698b885361d98bc0..000eb4220a12619b4e9b9922f5ed7d9e4c958064 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
 #include <linux/types.h>
@@ -22,7 +21,7 @@
 
 #include <asm/io.h>
 #include <asm/setup.h>
-#include <asm/arch/at32ap7000.h>
+#include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
 #include <asm/arch/portmux.h>
@@ -49,18 +48,16 @@ static struct eth_platform_data __initdata eth_data[2] = {
        },
 };
 
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
        .ssc_id         = 0,
        .shortname      = "AVR32 STK1000 external DAC",
 };
 #endif
-#endif
 
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
 static struct spi_board_info spi0_board_info[] __initdata = {
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
        {
                /* AT73C213 */
                .modalias       = "at73c213",
@@ -80,7 +77,7 @@ static struct spi_board_info spi0_board_info[] __initdata = {
 };
 #endif
 
-#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
 static struct spi_board_info spi1_board_info[] __initdata = { {
        /* patch in custom entries here */
 } };
@@ -141,68 +138,8 @@ static void __init set_hw_addr(struct platform_device *pdev)
        clk_put(pclk);
 }
 
-#ifdef CONFIG_BOARD_ATSTK1002_J2_LED
-
-static struct gpio_led stk_j2_led[] = {
-#ifdef CONFIG_BOARD_ATSTK1002_J2_LED8
-#define LEDSTRING "J2 jumpered to LED8"
-       { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
-       { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
-       { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
-       { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
-       { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
-       { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
-       { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
-       { .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
-                       .default_trigger = "heartbeat", },
-#else  /* RGB */
-#define LEDSTRING "J2 jumpered to RGB LEDs"
-       { .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
-       { .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
-       { .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
-
-       { .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
-                       .default_trigger = "heartbeat", },
-       { .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
-       { .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
-                       .default_trigger = "heartbeat", },
-       /* PB16, PB30 unused */
-#endif
-};
-
-static struct gpio_led_platform_data stk_j2_led_data = {
-       .num_leds       = ARRAY_SIZE(stk_j2_led),
-       .leds           = stk_j2_led,
-};
-
-static struct platform_device stk_j2_led_dev = {
-       .name           = "leds-gpio",
-       .id             = 2,    /* gpio block J2 */
-       .dev            = {
-               .platform_data  = &stk_j2_led_data,
-       },
-};
-
-static void setup_j2_leds(void)
-{
-       unsigned        i;
-
-       for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++)
-               at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
-
-       printk("STK1002: " LEDSTRING "\n");
-       platform_device_register(&stk_j2_led_dev);
-}
-
-#else
-static void setup_j2_leds(void)
-{
-}
-#endif
-
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-static void __init at73c213_set_clk(struct at73c213_board_info *info)
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static void __init atstk1002_setup_extdac(void)
 {
        struct clk *gclk;
        struct clk *pll;
@@ -220,7 +157,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info)
        }
 
        at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
-       info->dac_clk = gclk;
+       at73c213_data.dac_clk = gclk;
 
 err_set_clk:
        clk_put(pll);
@@ -229,12 +166,16 @@ err_pll:
 err_gclk:
        return;
 }
-#endif
-#endif
+#else
+static void __init atstk1002_setup_extdac(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
 
 void __init setup_board(void)
 {
-#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
        at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
 #else
        at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
@@ -271,7 +212,7 @@ static int __init atstk1002_init(void)
 
        at32_add_system_devices();
 
-#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
        at32_add_device_usart(1);
 #else
        at32_add_device_usart(0);
@@ -281,10 +222,10 @@ static int __init atstk1002_init(void)
 #ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
        set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
 #endif
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
        at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
 #endif
-#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
@@ -294,17 +235,12 @@ static int __init atstk1002_init(void)
                             fbmem_start, fbmem_size);
 #endif
        at32_add_device_usba(0, NULL);
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
        at32_add_device_ssc(0, ATMEL_SSC_TX);
 #endif
 
-       setup_j2_leds();
-
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-       at73c213_set_clk(&at73c213_data);
-#endif
-#endif
+       atstk1000_setup_j2_leds();
+       atstk1002_setup_extdac();
 
        return 0;
 }
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
new file mode 100644 (file)
index 0000000..a0b223d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * ATSTK1003 daughterboard-specific init code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/spi/at73c213.h>
+#include <linux/spi/spi.h>
+
+#include <asm/setup.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/board.h>
+#include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
+
+#include "atstk1000.h"
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static struct at73c213_board_info at73c213_data = {
+       .ssc_id         = 0,
+       .shortname      = "AVR32 STK1000 external DAC",
+};
+#endif
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+static struct spi_board_info spi0_board_info[] __initdata = {
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+       {
+               /* AT73C213 */
+               .modalias       = "at73c213",
+               .max_speed_hz   = 200000,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_1,
+               .platform_data  = &at73c213_data,
+       },
+#endif
+       /*
+        * We can control the LTV350QV LCD panel, but it isn't much
+        * point since we don't have an LCD controller...
+        */
+};
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+       /* patch in custom entries here */
+} };
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static void __init atstk1003_setup_extdac(void)
+{
+       struct clk *gclk;
+       struct clk *pll;
+
+       gclk = clk_get(NULL, "gclk0");
+       if (IS_ERR(gclk))
+               goto err_gclk;
+       pll = clk_get(NULL, "pll0");
+       if (IS_ERR(pll))
+               goto err_pll;
+
+       if (clk_set_parent(gclk, pll)) {
+               pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
+               goto err_set_clk;
+       }
+
+       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at73c213_data.dac_clk = gclk;
+
+err_set_clk:
+       clk_put(pll);
+err_pll:
+       clk_put(gclk);
+err_gclk:
+       return;
+}
+#else
+static void __init atstk1003_setup_extdac(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
+
+void __init setup_board(void)
+{
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+       at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
+#endif
+       /* USART 2/unused: expansion connector */
+       at32_map_usart(3, 2);   /* USART 3/C: /dev/ttyS2, DB9 */
+
+       at32_setup_serial_console(0);
+}
+
+static int __init atstk1003_init(void)
+{
+       /*
+        * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
+        * SDRAM-specific pins so that nobody messes with them.
+        */
+       at32_reserve_pin(GPIO_PIN_PE(0));       /* DATA[16]     */
+       at32_reserve_pin(GPIO_PIN_PE(1));       /* DATA[17]     */
+       at32_reserve_pin(GPIO_PIN_PE(2));       /* DATA[18]     */
+       at32_reserve_pin(GPIO_PIN_PE(3));       /* DATA[19]     */
+       at32_reserve_pin(GPIO_PIN_PE(4));       /* DATA[20]     */
+       at32_reserve_pin(GPIO_PIN_PE(5));       /* DATA[21]     */
+       at32_reserve_pin(GPIO_PIN_PE(6));       /* DATA[22]     */
+       at32_reserve_pin(GPIO_PIN_PE(7));       /* DATA[23]     */
+       at32_reserve_pin(GPIO_PIN_PE(8));       /* DATA[24]     */
+       at32_reserve_pin(GPIO_PIN_PE(9));       /* DATA[25]     */
+       at32_reserve_pin(GPIO_PIN_PE(10));      /* DATA[26]     */
+       at32_reserve_pin(GPIO_PIN_PE(11));      /* DATA[27]     */
+       at32_reserve_pin(GPIO_PIN_PE(12));      /* DATA[28]     */
+       at32_reserve_pin(GPIO_PIN_PE(13));      /* DATA[29]     */
+       at32_reserve_pin(GPIO_PIN_PE(14));      /* DATA[30]     */
+       at32_reserve_pin(GPIO_PIN_PE(15));      /* DATA[31]     */
+       at32_reserve_pin(GPIO_PIN_PE(26));      /* SDCS         */
+
+       at32_add_system_devices();
+
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+       at32_add_device_usart(1);
+#else
+       at32_add_device_usart(0);
+#endif
+       at32_add_device_usart(2);
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+       at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+       at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+       at32_add_device_mci(0);
+#endif
+       at32_add_device_usba(0, NULL);
+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
+
+       atstk1000_setup_j2_leds();
+       atstk1003_setup_extdac();
+
+       return 0;
+}
+postcore_initcall(atstk1003_init);
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
new file mode 100644 (file)
index 0000000..5a77030
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * ATSTK1003 daughterboard-specific init code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/spi/at73c213.h>
+#include <linux/spi/spi.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/setup.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/board.h>
+#include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
+
+#include "atstk1000.h"
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static struct at73c213_board_info at73c213_data = {
+       .ssc_id         = 0,
+       .shortname      = "AVR32 STK1000 external DAC",
+};
+#endif
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+static struct spi_board_info spi0_board_info[] __initdata = {
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+       {
+               /* AT73C213 */
+               .modalias       = "at73c213",
+               .max_speed_hz   = 200000,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_1,
+               .platform_data  = &at73c213_data,
+       },
+#endif
+       {
+               /* QVGA display */
+               .modalias       = "ltv350qv",
+               .max_speed_hz   = 16000000,
+               .chip_select    = 1,
+               .mode           = SPI_MODE_3,
+       },
+};
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+       /* patch in custom entries here */
+} };
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static void __init atstk1004_setup_extdac(void)
+{
+       struct clk *gclk;
+       struct clk *pll;
+
+       gclk = clk_get(NULL, "gclk0");
+       if (IS_ERR(gclk))
+               goto err_gclk;
+       pll = clk_get(NULL, "pll0");
+       if (IS_ERR(pll))
+               goto err_pll;
+
+       if (clk_set_parent(gclk, pll)) {
+               pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
+               goto err_set_clk;
+       }
+
+       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at73c213_data.dac_clk = gclk;
+
+err_set_clk:
+       clk_put(pll);
+err_pll:
+       clk_put(gclk);
+err_gclk:
+       return;
+}
+#else
+static void __init atstk1004_setup_extdac(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
+
+void __init setup_board(void)
+{
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+       at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
+#endif
+       /* USART 2/unused: expansion connector */
+       at32_map_usart(3, 2);   /* USART 3/C: /dev/ttyS2, DB9 */
+
+       at32_setup_serial_console(0);
+}
+
+static int __init atstk1004_init(void)
+{
+       at32_add_system_devices();
+
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+       at32_add_device_usart(1);
+#else
+       at32_add_device_usart(0);
+#endif
+       at32_add_device_usart(2);
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+       at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+       at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
+       at32_add_device_mci(0);
+#endif
+       at32_add_device_lcdc(0, &atstk1000_lcdc_data,
+                            fbmem_start, fbmem_size);
+       at32_add_device_usba(0, NULL);
+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
+
+       atstk1000_setup_j2_leds();
+       atstk1004_setup_extdac();
+
+       return 0;
+}
+postcore_initcall(atstk1004_init);
index c9af409ada9a99723217e0d29456cec470122b75..8bedf93876a377050cdb491643edbb9da45114ae 100644 (file)
 #include <linux/bootmem.h>
 #include <linux/fb.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/linkage.h>
 
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
+
+#include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
+#include <asm/arch/portmux.h>
 
 #include "atstk1000.h"
 
@@ -61,3 +65,63 @@ struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
        .default_monspecs       = &atstk1000_default_monspecs,
        .guard_time             = 2,
 };
+
+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED
+#include <linux/leds.h>
+
+static struct gpio_led stk1000_j2_led[] = {
+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED8
+#define LEDSTRING "J2 jumpered to LED8"
+       { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
+       { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
+       { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
+       { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
+       { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
+       { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
+       { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
+       { .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
+                       .default_trigger = "heartbeat", },
+#else  /* RGB */
+#define LEDSTRING "J2 jumpered to RGB LEDs"
+       { .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
+       { .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
+       { .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
+
+       { .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
+                       .default_trigger = "heartbeat", },
+       { .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
+       { .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
+                       .default_trigger = "heartbeat", },
+       /* PB16, PB30 unused */
+#endif
+};
+
+static struct gpio_led_platform_data stk1000_j2_led_data = {
+       .num_leds       = ARRAY_SIZE(stk1000_j2_led),
+       .leds           = stk1000_j2_led,
+};
+
+static struct platform_device stk1000_j2_led_dev = {
+       .name           = "leds-gpio",
+       .id             = 2,    /* gpio block J2 */
+       .dev            = {
+               .platform_data  = &stk1000_j2_led_data,
+       },
+};
+
+void __init atstk1000_setup_j2_leds(void)
+{
+       unsigned        i;
+
+       for (i = 0; i < ARRAY_SIZE(stk1000_j2_led); i++)
+               at32_select_gpio(stk1000_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
+
+       printk("STK1000: " LEDSTRING "\n");
+       platform_device_register(&stk1000_j2_led_dev);
+}
+#else /* CONFIG_BOARD_ATSTK1000_J2_LED */
+void __init atstk1000_setup_j2_leds(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_J2_LED */
index b799a68ffd9706d74afef2942d0ef0ea45b302ab..06046074d68b6bc392ba86834f415b959adae14d 100644 (file)
@@ -1,46 +1,51 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc5
-# Sat Jun 23 15:40:05 2007
+# Linux kernel version: 2.6.24-rc7
+# Wed Jan  9 23:20:41 2008
 #
 CONFIG_AVR32=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_BUG=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -61,35 +66,28 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_SLUB_DEBUG is not set
+CONFIG_SLUB_DEBUG=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -111,6 +109,7 @@ CONFIG_SUBARCH_AVR32B=y
 CONFIG_MMU=y
 CONFIG_PERFORMANCE_COUNTERS=y
 CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
 CONFIG_CPU_AT32AP7000=y
 # CONFIG_BOARD_ATSTK1000 is not set
 CONFIG_BOARD_ATNGW100=y
@@ -119,9 +118,9 @@ CONFIG_LOADER_U_BOOT=y
 #
 # Atmel AVR32 AP options
 #
-# CONFIG_AP7000_32_BIT_SMC is not set
-CONFIG_AP7000_16_BIT_SMC=y
-# CONFIG_AP7000_8_BIT_SMC is not set
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
 CONFIG_LOAD_ADDRESS=0x10000000
 CONFIG_ENTRY_ADDRESS=0x90000000
 CONFIG_PHYS_OFFSET=0x10000000
@@ -141,9 +140,11 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_OWNERSHIP_TRACE is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
@@ -153,13 +154,31 @@ CONFIG_HZ=250
 CONFIG_CMDLINE=""
 
 #
-# Bus options
+# Power management options
 #
-# CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
-# PCCARD (PCMCIA/CardBus) support
+# CPU Frequency scaling
 #
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
@@ -213,6 +232,7 @@ CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -240,6 +260,7 @@ CONFIG_IPV6_SIT=y
 # CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
 
 #
 # Core Netfilter Configuration
@@ -252,6 +273,7 @@ CONFIG_NF_CONNTRACK_MARK=y
 # CONFIG_NF_CONNTRACK_EVENTS is not set
 CONFIG_NF_CT_PROTO_GRE=m
 # CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
@@ -269,9 +291,11 @@ CONFIG_NETFILTER_XT_TARGET_MARK=m
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
 CONFIG_NETFILTER_XT_TARGET_NFLOG=m
 # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
 CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
 CONFIG_NETFILTER_XT_MATCH_COMMENT=m
 CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
 # CONFIG_NETFILTER_XT_MATCH_DCCP is not set
@@ -284,6 +308,7 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
 CONFIG_NETFILTER_XT_MATCH_MARK=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_REALM=m
@@ -292,6 +317,8 @@ CONFIG_NETFILTER_XT_MATCH_STATE=m
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
 CONFIG_NETFILTER_XT_MATCH_STRING=m
 CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 
 #
@@ -359,13 +386,19 @@ CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
+CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
 # CONFIG_DECNET is not set
+CONFIG_LLC=m
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -373,10 +406,6 @@ CONFIG_VLAN_8021Q=m
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
 CONFIG_NET_CLS_ROUTE=y
 
@@ -384,6 +413,7 @@ CONFIG_NET_CLS_ROUTE=y
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
@@ -397,6 +427,7 @@ CONFIG_NET_CLS_ROUTE=y
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -405,16 +436,13 @@ CONFIG_NET_CLS_ROUTE=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
@@ -434,6 +462,7 @@ CONFIG_MTD_BLOCK=y
 # CONFIG_INFTL is not set
 # CONFIG_RFD_FTL is not set
 # CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -493,20 +522,8 @@ CONFIG_MTD_DATAFLASH=y
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -517,11 +534,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+# CONFIG_MISC_DEVICES is not set
 # CONFIG_IDE is not set
 
 #
@@ -529,30 +542,42 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
+# CONFIG_MII is not set
 CONFIG_MACB=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
 
@@ -571,21 +596,14 @@ CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_MPPE=m
 CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
 CONFIG_SLHC=m
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -620,23 +638,50 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
 
 #
-# TPM devices
+# I2C Algorithms
 #
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # SPI support
@@ -655,13 +700,25 @@ CONFIG_SPI_ATMEL=y
 # SPI Protocol Masters
 #
 # CONFIG_SPI_AT25 is not set
-# CONFIG_SPI_SPIDEV is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Dallas's 1-wire bus
+# Watchdog Device Drivers
 #
-# CONFIG_W1 is not set
-# CONFIG_HWMON is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
 # Multifunction device drivers
@@ -678,23 +735,21 @@ CONFIG_SPI_ATMEL=y
 #
 # Graphics support
 #
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
 
 #
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_EHCI is not set
@@ -706,12 +761,47 @@ CONFIG_SPI_ATMEL=y
 #
 # USB Gadget Support
 #
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_SPI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 
@@ -726,53 +816,71 @@ CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-
-
-#
-# LED drivers
-#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
 
 #
-# LED Triggers
-#
-
-#
-# InfiniBand support
+# RTC interfaces
 #
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# I2C RTC drivers
 #
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
 
 #
-# Real Time Clock
+# SPI RTC drivers
 #
-# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
 
 #
-# DMA Engine support
+# Platform RTC drivers
 #
-# CONFIG_DMA_ENGINE is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# DMA Clients
+# on-CPU RTC drivers
 #
+CONFIG_RTC_DRV_AT32AP700X=y
 
 #
-# DMA Devices
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS=m
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS=m
 # CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -781,7 +889,8 @@ CONFIG_JBD=y
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
-# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
@@ -814,8 +923,7 @@ CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-CONFIG_CONFIGFS_FS=y
+CONFIG_CONFIGFS_FS=m
 
 #
 # Miscellaneous filesystems
@@ -830,10 +938,12 @@ CONFIG_CONFIGFS_FS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
 # CONFIG_JFFS2_SUMMARY is not set
 # CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
@@ -842,19 +952,21 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_SUNRPC_BIND34 is not set
@@ -871,23 +983,18 @@ CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
+CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -908,7 +1015,7 @@ CONFIG_NLS_CODEPAGE_850=y
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -921,18 +1028,19 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=y
-
-#
-# Distributed Lock Manager
-#
+CONFIG_NLS_UTF8=m
 # CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
 #
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
@@ -941,12 +1049,17 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -954,21 +1067,21 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
 CONFIG_FRAME_POINTER=y
 # CONFIG_FORCED_INLINING is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_KPROBES is not set
+# CONFIG_SAMPLES is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
@@ -989,6 +1102,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_FCRYPT is not set
@@ -1002,15 +1116,14 @@ CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_ARC4=m
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
@@ -1018,8 +1131,9 @@ CONFIG_CRYPTO_DEFLATE=y
 CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
 CONFIG_CRC32=y
+CONFIG_CRC7=m
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
index 3b977fdbaa78f25dd40af9d7f9affb955305d11a..2fb2ede5f2b4293cbca8c8f89d3e3594d407f32a 100644 (file)
@@ -1,48 +1,48 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc5
-# Sat Jun 23 15:32:08 2007
+# Linux kernel version: 2.6.24-rc7
+# Wed Jan  9 23:07:43 2008
 #
 CONFIG_AVR32=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_BUG=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-# CONFIG_TASK_XACCT is not set
-# CONFIG_UTS_NS is not set
-CONFIG_AUDIT=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
@@ -63,35 +63,28 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_SLUB_DEBUG is not set
+CONFIG_SLUB_DEBUG=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -99,12 +92,12 @@ CONFIG_BLOCK=y
 CONFIG_IOSCHED_NOOP=y
 # CONFIG_IOSCHED_AS is not set
 # CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_CFQ=y
 # CONFIG_DEFAULT_AS is not set
 # CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
 
 #
 # System Type and features
@@ -113,18 +106,27 @@ CONFIG_SUBARCH_AVR32B=y
 CONFIG_MMU=y
 CONFIG_PERFORMANCE_COUNTERS=y
 CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
 CONFIG_CPU_AT32AP7000=y
-CONFIG_BOARD_ATSTK1002=y
 CONFIG_BOARD_ATSTK1000=y
 # CONFIG_BOARD_ATNGW100 is not set
+CONFIG_BOARD_ATSTK1002=y
+# CONFIG_BOARD_ATSTK1003 is not set
+# CONFIG_BOARD_ATSTK1004 is not set
+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
+CONFIG_BOARD_ATSTK1000_EXTDAC=y
 CONFIG_LOADER_U_BOOT=y
 
 #
 # Atmel AVR32 AP options
 #
-# CONFIG_AP7000_32_BIT_SMC is not set
-CONFIG_AP7000_16_BIT_SMC=y
-# CONFIG_AP7000_8_BIT_SMC is not set
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
 CONFIG_LOAD_ADDRESS=0x10000000
 CONFIG_ENTRY_ADDRESS=0x90000000
 CONFIG_PHYS_OFFSET=0x10000000
@@ -144,9 +146,11 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_OWNERSHIP_TRACE is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
@@ -156,13 +160,31 @@ CONFIG_HZ=250
 CONFIG_CMDLINE=""
 
 #
-# Bus options
+# Power management options
 #
-# CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
-# PCCARD (PCMCIA/CardBus) support
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
 #
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
@@ -182,7 +204,12 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -191,36 +218,52 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IP_PNP_BOOTP is not set
 # CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
+CONFIG_BRIDGE=m
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
+CONFIG_LLC=m
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -228,16 +271,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
@@ -251,6 +291,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -259,16 +300,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
@@ -288,6 +326,7 @@ CONFIG_MTD_BLOCK=y
 # CONFIG_INFTL is not set
 # CONFIG_RFD_FTL is not set
 # CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -327,6 +366,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 #
 # Self-contained MTD device drivers
 #
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_M25P80=m
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -345,20 +386,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -369,42 +398,87 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ATMEL_SSC=m
 # CONFIG_IDE is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
-# CONFIG_ATA is not set
+# CONFIG_SCSI_PROC_FS is not set
 
 #
-# Multi-device support (RAID and LVM)
+# SCSI support type (disk, tape, CD-ROM)
 #
-# CONFIG_MD is not set
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
 
 #
-# Network device support
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_AT32=m
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
+# CONFIG_MII is not set
 CONFIG_MACB=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
 
@@ -423,27 +497,54 @@ CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 # CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
 CONFIG_SLHC=m
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
 
 #
-# ISDN subsystem
+# Input device support
 #
-# CONFIG_ISDN is not set
+CONFIG_INPUT=m
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=m
 
 #
-# Telephony Support
+# Userland interfaces
 #
-# CONFIG_PHONE is not set
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
 
 #
-# Input device support
+# Input Device Drivers
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_MOUSE_GPIO=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
@@ -472,35 +573,87 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
 
 #
-# TPM devices
+# I2C Algorithms
 #
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # SPI support
 #
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
 
 #
-# Dallas's 1-wire bus
+# SPI Protocol Masters
 #
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
 # Multifunction device drivers
@@ -517,23 +670,94 @@ CONFIG_UNIX98_PTYS=y
 #
 # Graphics support
 #
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_LTV350QV=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
+# CONFIG_LOGO is not set
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
 
 #
-# USB support
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
 #
+# SPI devices
+#
+CONFIG_SND_AT73C213=m
+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_EHCI is not set
@@ -545,47 +769,116 @@ CONFIG_UNIX98_PTYS=y
 #
 # USB Gadget Support
 #
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_SPI=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
 
 #
 # LED drivers
 #
+CONFIG_LEDS_GPIO=m
 
 #
 # LED Triggers
 #
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
 
 #
-# InfiniBand support
+# RTC interfaces
 #
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# I2C RTC drivers
 #
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
 
 #
-# Real Time Clock
+# SPI RTC drivers
 #
-# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
 
 #
-# DMA Engine support
+# Platform RTC drivers
 #
-# CONFIG_DMA_ENGINE is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# DMA Clients
+# on-CPU RTC drivers
 #
+CONFIG_RTC_DRV_AT32AP700X=y
 
 #
-# DMA Devices
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -593,8 +886,11 @@ CONFIG_UNIX98_PTYS=y
 CONFIG_EXT2_FS=m
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -609,7 +905,7 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
+CONFIG_FUSE_FS=m
 
 #
 # CD-ROM/DVD Filesystems
@@ -637,8 +933,7 @@ CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-CONFIG_CONFIGFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -652,11 +947,12 @@ CONFIG_CONFIGFS_FS=m
 # CONFIG_EFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
-CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
 # CONFIG_JFFS2_SUMMARY is not set
 # CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
@@ -665,10 +961,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
@@ -688,17 +981,12 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
@@ -739,17 +1027,18 @@ CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=m
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
 #
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
@@ -758,12 +1047,17 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -771,22 +1065,63 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_KPROBES is not set
+# CONFIG_SAMPLES is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
@@ -794,10 +1129,10 @@ CONFIG_FORCED_INLINING=y
 CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
 CONFIG_CRC32=y
+CONFIG_CRC7=m
 # CONFIG_LIBCRC32C is not set
-CONFIG_AUDIT_GENERIC=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
 CONFIG_PLIST=y
diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig
new file mode 100644 (file)
index 0000000..45e23e0
--- /dev/null
@@ -0,0 +1,1015 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc7
+# Wed Jan  9 22:54:34 2008
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+# CONFIG_TASK_XACCT is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type and features
+#
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
+CONFIG_CPU_AT32AP7001=y
+CONFIG_BOARD_ATSTK1000=y
+# CONFIG_BOARD_ATNGW100 is not set
+# CONFIG_BOARD_ATSTK1002 is not set
+CONFIG_BOARD_ATSTK1003=y
+# CONFIG_BOARD_ATSTK1004 is not set
+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_CMDLINE=""
+
+#
+# Power management options
+#
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_M25P80=m
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ATMEL_SSC=m
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_AT32=m
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=m
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_MOUSE_GPIO=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# SPI devices
+#
+CONFIG_SND_AT73C213=m
+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_SPI=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_AT32AP700X=y
+
+#
+# Userspace I/O
+#
+CONFIG_UIO=m
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+CONFIG_CRC7=m
+# CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig
new file mode 100644 (file)
index 0000000..634c527
--- /dev/null
@@ -0,0 +1,621 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc7
+# Wed Jan  9 23:04:20 2008
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
+CONFIG_SLOB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_MODULES is not set
+# CONFIG_BLOCK is not set
+
+#
+# System Type and features
+#
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
+CONFIG_CPU_AT32AP7002=y
+CONFIG_BOARD_ATSTK1000=y
+# CONFIG_BOARD_ATNGW100 is not set
+# CONFIG_BOARD_ATSTK1002 is not set
+# CONFIG_BOARD_ATSTK1003 is not set
+CONFIG_BOARD_ATSTK1004=y
+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_CMDLINE=""
+
+#
+# Power management options
+#
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_LTV350QV=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_AT32AP700X=y
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+# CONFIG_INSTRUMENTATION is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 2d6d48f35f69bb24d3666b8a3f796505587ab483..e4b6d122b03341702f7b2d1477fd6d45b3fe9481 100644 (file)
@@ -6,9 +6,10 @@ extra-y                                := head.o vmlinux.lds
 
 obj-$(CONFIG_SUBARCH_AVR32B)   += entry-avr32b.o
 obj-y                          += syscall_table.o syscall-stubs.o irq.o
-obj-y                          += setup.o traps.o semaphore.o ptrace.o
+obj-y                          += setup.o traps.o semaphore.o ocd.o ptrace.o
 obj-y                          += signal.o sys_avr32.o process.o time.o
 obj-y                          += init_task.o switch_to.o cpu.o
 obj-$(CONFIG_MODULES)          += module.o avr32_ksyms.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
+obj-$(CONFIG_NMI_DEBUGGING)    += nmi_debug.o
index 2714cf6452b5ca88edb63f19f20104dee79bce9a..b8409caeb23dccbca394127132bcdcc9e0360eab 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/percpu.h>
 #include <linux/param.h>
 #include <linux/errno.h>
+#include <linux/clk.h>
 
 #include <asm/setup.h>
 #include <asm/sysreg.h>
@@ -187,9 +188,20 @@ static int __init topology_init(void)
 
 subsys_initcall(topology_init);
 
+struct chip_id_map {
+       u16     mid;
+       u16     pn;
+       const char *name;
+};
+
+static const struct chip_id_map chip_names[] = {
+       { .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" },
+};
+#define NR_CHIP_NAMES ARRAY_SIZE(chip_names)
+
 static const char *cpu_names[] = {
        "Morgan",
-       "AP7000",
+       "AP7",
 };
 #define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
 
@@ -206,12 +218,32 @@ static const char *mmu_types[] = {
        "MPU"
 };
 
+static const char *cpu_feature_flags[] = {
+       "rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu",
+};
+
+static const char *get_chip_name(struct avr32_cpuinfo *cpu)
+{
+       unsigned int i;
+       unsigned int mid = avr32_get_manufacturer_id(cpu);
+       unsigned int pn = avr32_get_product_number(cpu);
+
+       for (i = 0; i < NR_CHIP_NAMES; i++) {
+               if (chip_names[i].mid == mid && chip_names[i].pn == pn)
+                       return chip_names[i].name;
+       }
+
+       return "(unknown)";
+}
+
 void __init setup_processor(void)
 {
        unsigned long config0, config1;
        unsigned long features;
        unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
+       unsigned device_id;
        unsigned tmp;
+       unsigned i;
 
        config0 = sysreg_read(CONFIG0);
        config1 = sysreg_read(CONFIG1);
@@ -221,11 +253,14 @@ void __init setup_processor(void)
        arch_rev = SYSREG_BFEXT(AR, config0);
        mmu_type = SYSREG_BFEXT(MMUT, config0);
 
+       device_id = ocd_read(DID);
+
        boot_cpu_data.arch_type = arch_id;
        boot_cpu_data.cpu_type = cpu_id;
        boot_cpu_data.arch_revision = arch_rev;
        boot_cpu_data.cpu_revision = cpu_rev;
        boot_cpu_data.tlb_config = mmu_type;
+       boot_cpu_data.device_id = device_id;
 
        tmp = SYSREG_BFEXT(ILSZ, config1);
        if (tmp) {
@@ -247,41 +282,34 @@ void __init setup_processor(void)
                return;
        }
 
-       printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
+       printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data),
+                       avr32_get_chip_revision(&boot_cpu_data) + 'A');
+       printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n",
                cpu_names[cpu_id], cpu_id, cpu_rev,
                arch_names[arch_id], arch_rev);
        printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
 
        printk ("CPU: features:");
        features = 0;
-       if (config0 & SYSREG_BIT(CONFIG0_R)) {
+       if (config0 & SYSREG_BIT(CONFIG0_R))
                features |= AVR32_FEATURE_RMW;
-               printk(" rmw");
-       }
-       if (config0 & SYSREG_BIT(CONFIG0_D)) {
+       if (config0 & SYSREG_BIT(CONFIG0_D))
                features |= AVR32_FEATURE_DSP;
-               printk(" dsp");
-       }
-       if (config0 & SYSREG_BIT(CONFIG0_S)) {
+       if (config0 & SYSREG_BIT(CONFIG0_S))
                features |= AVR32_FEATURE_SIMD;
-               printk(" simd");
-       }
-       if (config0 & SYSREG_BIT(CONFIG0_O)) {
+       if (config0 & SYSREG_BIT(CONFIG0_O))
                features |= AVR32_FEATURE_OCD;
-               printk(" ocd");
-       }
-       if (config0 & SYSREG_BIT(CONFIG0_P)) {
+       if (config0 & SYSREG_BIT(CONFIG0_P))
                features |= AVR32_FEATURE_PCTR;
-               printk(" perfctr");
-       }
-       if (config0 & SYSREG_BIT(CONFIG0_J)) {
+       if (config0 & SYSREG_BIT(CONFIG0_J))
                features |= AVR32_FEATURE_JAVA;
-               printk(" java");
-       }
-       if (config0 & SYSREG_BIT(CONFIG0_F)) {
+       if (config0 & SYSREG_BIT(CONFIG0_F))
                features |= AVR32_FEATURE_FPU;
-               printk(" fpu");
-       }
+
+       for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
+               if (features & (1 << i))
+                       printk(" %s", cpu_feature_flags[i]);
+
        printk("\n");
        boot_cpu_data.features = features;
 }
@@ -291,6 +319,8 @@ static int c_show(struct seq_file *m, void *v)
 {
        unsigned int icache_size, dcache_size;
        unsigned int cpu = smp_processor_id();
+       unsigned int freq;
+       unsigned int i;
 
        icache_size = boot_cpu_data.icache.ways *
                boot_cpu_data.icache.sets *
@@ -301,15 +331,21 @@ static int c_show(struct seq_file *m, void *v)
 
        seq_printf(m, "processor\t: %d\n", cpu);
 
+       seq_printf(m, "chip type\t: %s revision %c\n",
+                       get_chip_name(&boot_cpu_data),
+                       avr32_get_chip_revision(&boot_cpu_data) + 'A');
        if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
-               seq_printf(m, "cpu family\t: %s revision %d\n",
+               seq_printf(m, "cpu arch\t: %s revision %d\n",
                           arch_names[boot_cpu_data.arch_type],
                           boot_cpu_data.arch_revision);
        if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
-               seq_printf(m, "cpu type\t: %s revision %d\n",
+               seq_printf(m, "cpu core\t: %s revision %d\n",
                           cpu_names[boot_cpu_data.cpu_type],
                           boot_cpu_data.cpu_revision);
 
+       freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000;
+       seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000);
+
        seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
                   icache_size >> 10,
                   boot_cpu_data.icache.ways,
@@ -320,7 +356,13 @@ static int c_show(struct seq_file *m, void *v)
                   boot_cpu_data.dcache.ways,
                   boot_cpu_data.dcache.sets,
                   boot_cpu_data.dcache.linesz);
-       seq_printf(m, "bogomips\t: %lu.%02lu\n",
+
+       seq_printf(m, "features\t:");
+       for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
+               if (boot_cpu_data.features & (1 << i))
+                       seq_printf(m, " %s", cpu_feature_flags[i]);
+
+       seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
                   boot_cpu_data.loops_per_jiffy / (500000/HZ),
                   (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
 
@@ -343,7 +385,7 @@ static void c_stop(struct seq_file *m, void *v)
 
 }
 
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
        .start  = c_start,
        .next   = c_next,
        .stop   = c_stop,
index 61f2de266f62a3d0060900bdf4ea41bf160726af..a8e767d836aac621c0c449406e32d06b0d13d2db 100644 (file)
@@ -25,6 +25,17 @@ void ack_bad_irq(unsigned int irq)
        printk("unexpected IRQ %u\n", irq);
 }
 
+/* May be overridden by platform code */
+int __weak nmi_enable(void)
+{
+       return -ENOSYS;
+}
+
+void __weak nmi_disable(void)
+{
+
+}
+
 #ifdef CONFIG_PROC_FS
 int show_interrupts(struct seq_file *p, void *v)
 {
index 799ba89b07a88a0f5a6d044324a65bfef1d686b0..f820e9f25520655ae0ddb756928be4d2aba35eb6 100644 (file)
@@ -48,6 +48,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
        pr_debug("arming kprobe at %p\n", p->addr);
+       ocd_enable(NULL);
        *p->addr = BREAKPOINT_INSTRUCTION;
        flush_icache_range((unsigned long)p->addr,
                           (unsigned long)p->addr + sizeof(kprobe_opcode_t));
@@ -56,6 +57,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
        pr_debug("disarming kprobe at %p\n", p->addr);
+       ocd_disable(NULL);
        *p->addr = p->opcode;
        flush_icache_range((unsigned long)p->addr,
                           (unsigned long)p->addr + sizeof(kprobe_opcode_t));
@@ -260,9 +262,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 
 int __init arch_init_kprobes(void)
 {
-       printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
-       ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
-
        /* TODO: Register kretprobe trampoline */
        return 0;
 }
diff --git a/arch/avr32/kernel/nmi_debug.c b/arch/avr32/kernel/nmi_debug.c
new file mode 100644 (file)
index 0000000..3414b85
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/delay.h>
+#include <linux/kdebug.h>
+#include <linux/notifier.h>
+#include <linux/sched.h>
+
+#include <asm/irq.h>
+
+enum nmi_action {
+       NMI_SHOW_STATE  = 1 << 0,
+       NMI_SHOW_REGS   = 1 << 1,
+       NMI_DIE         = 1 << 2,
+       NMI_DEBOUNCE    = 1 << 3,
+};
+
+static unsigned long nmi_actions;
+
+static int nmi_debug_notify(struct notifier_block *self,
+               unsigned long val, void *data)
+{
+       struct die_args *args = data;
+
+       if (likely(val != DIE_NMI))
+               return NOTIFY_DONE;
+
+       if (nmi_actions & NMI_SHOW_STATE)
+               show_state();
+       if (nmi_actions & NMI_SHOW_REGS)
+               show_regs(args->regs);
+       if (nmi_actions & NMI_DEBOUNCE)
+               mdelay(10);
+       if (nmi_actions & NMI_DIE)
+               return NOTIFY_BAD;
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block nmi_debug_nb = {
+       .notifier_call = nmi_debug_notify,
+};
+
+static int __init nmi_debug_setup(char *str)
+{
+       char *p, *sep;
+
+       register_die_notifier(&nmi_debug_nb);
+       if (nmi_enable()) {
+               printk(KERN_WARNING "Unable to enable NMI.\n");
+               return 0;
+       }
+
+       if (*str != '=')
+               return 0;
+
+       for (p = str + 1; *p; p = sep + 1) {
+               sep = strchr(p, ',');
+               if (sep)
+                       *sep = 0;
+               if (strcmp(p, "state") == 0)
+                       nmi_actions |= NMI_SHOW_STATE;
+               else if (strcmp(p, "regs") == 0)
+                       nmi_actions |= NMI_SHOW_REGS;
+               else if (strcmp(p, "debounce") == 0)
+                       nmi_actions |= NMI_DEBOUNCE;
+               else if (strcmp(p, "die") == 0)
+                       nmi_actions |= NMI_DIE;
+               else
+                       printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
+                               p);
+               if (!sep)
+                       break;
+       }
+
+       return 0;
+}
+__setup("nmi_debug", nmi_debug_setup);
diff --git a/arch/avr32/kernel/ocd.c b/arch/avr32/kernel/ocd.c
new file mode 100644 (file)
index 0000000..c4f0232
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/ocd.h>
+
+static long ocd_count;
+static spinlock_t ocd_lock;
+
+/**
+ * ocd_enable - enable on-chip debugging
+ * @child: task to be debugged
+ *
+ * If @child is non-NULL, ocd_enable() first checks if debugging has
+ * already been enabled for @child, and if it has, does nothing.
+ *
+ * If @child is NULL (e.g. when debugging the kernel), or debugging
+ * has not already been enabled for it, ocd_enable() increments the
+ * reference count and enables the debugging hardware.
+ */
+void ocd_enable(struct task_struct *child)
+{
+       u32 dc;
+
+       if (child)
+               pr_debug("ocd_enable: child=%s [%u]\n",
+                               child->comm, child->pid);
+       else
+               pr_debug("ocd_enable (no child)\n");
+
+       if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
+               spin_lock(&ocd_lock);
+               ocd_count++;
+               dc = ocd_read(DC);
+               dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
+               ocd_write(DC, dc);
+               spin_unlock(&ocd_lock);
+       }
+}
+
+/**
+ * ocd_disable - disable on-chip debugging
+ * @child: task that was being debugged, but isn't anymore
+ *
+ * If @child is non-NULL, ocd_disable() checks if debugging is enabled
+ * for @child, and if it isn't, does nothing.
+ *
+ * If @child is NULL (e.g. when debugging the kernel), or debugging is
+ * enabled, ocd_disable() decrements the reference count, and if it
+ * reaches zero, disables the debugging hardware.
+ */
+void ocd_disable(struct task_struct *child)
+{
+       u32 dc;
+
+       if (!child)
+               pr_debug("ocd_disable (no child)\n");
+       else if (test_tsk_thread_flag(child, TIF_DEBUG))
+               pr_debug("ocd_disable: child=%s [%u]\n",
+                               child->comm, child->pid);
+
+       if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
+               spin_lock(&ocd_lock);
+               ocd_count--;
+
+               WARN_ON(ocd_count < 0);
+
+               if (ocd_count <= 0) {
+                       dc = ocd_read(DC);
+                       dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
+                       ocd_write(DC, dc);
+               }
+               spin_unlock(&ocd_lock);
+       }
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+static struct dentry *ocd_debugfs_root;
+static struct dentry *ocd_debugfs_DC;
+static struct dentry *ocd_debugfs_DS;
+static struct dentry *ocd_debugfs_count;
+
+static u64 ocd_DC_get(void *data)
+{
+       return ocd_read(DC);
+}
+static void ocd_DC_set(void *data, u64 val)
+{
+       ocd_write(DC, val);
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
+
+static u64 ocd_DS_get(void *data)
+{
+       return ocd_read(DS);
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
+
+static u64 ocd_count_get(void *data)
+{
+       return ocd_count;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
+
+static void ocd_debugfs_init(void)
+{
+       struct dentry *root;
+
+       root = debugfs_create_dir("ocd", NULL);
+       if (IS_ERR(root) || !root)
+               goto err_root;
+       ocd_debugfs_root = root;
+
+       ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
+                               root, NULL, &fops_DC);
+       if (!ocd_debugfs_DC)
+               goto err_DC;
+
+       ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
+                               NULL, &fops_DS);
+       if (!ocd_debugfs_DS)
+               goto err_DS;
+
+       ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
+                               NULL, &fops_count);
+       if (!ocd_debugfs_count)
+               goto err_count;
+
+       return;
+
+err_count:
+       debugfs_remove(ocd_debugfs_DS);
+err_DS:
+       debugfs_remove(ocd_debugfs_DC);
+err_DC:
+       debugfs_remove(ocd_debugfs_root);
+err_root:
+       printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
+}
+#else
+static inline void ocd_debugfs_init(void)
+{
+
+}
+#endif
+
+static int __init ocd_init(void)
+{
+       spin_lock_init(&ocd_lock);
+       ocd_debugfs_init();
+       return 0;
+}
+arch_initcall(ocd_init);
index 9d6dac8af7a2600d569d9c1669b9860594ae57e6..eaaa69bbdc38d5546b395311f29896a6a2c357db 100644 (file)
@@ -103,7 +103,7 @@ EXPORT_SYMBOL(kernel_thread);
  */
 void exit_thread(void)
 {
-       /* nothing to do */
+       ocd_disable(current);
 }
 
 void flush_thread(void)
@@ -345,6 +345,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        p->thread.cpu_context.ksp = (unsigned long)childregs;
        p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
 
+       if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
+               ocd_enable(p);
+
        return 0;
 }
 
index 002369e4409335f0515035f8d3b824d33e7edf74..1fed38fcf594cdfd043707a1d31b958ce8c4f8b0 100644 (file)
@@ -58,6 +58,7 @@ void ptrace_disable(struct task_struct *child)
 {
        clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
        clear_tsk_thread_flag(child, TIF_BREAKPOINT);
+       ocd_disable(child);
 }
 
 /*
@@ -144,10 +145,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        int ret;
 
-       pr_debug("ptrace: Enabling monitor mode...\n");
-       ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
-                       | (1 << OCD_DC_DBE_BIT));
-
        switch (request) {
        /* Read the word at location addr in the child process */
        case PTRACE_PEEKTEXT:
index 0ec14854a2000f272044706265cf0e400c120e77..5616a00c10ba2f3a9660b63a25e57d021c00da92 100644 (file)
@@ -270,19 +270,12 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
        if (!user_mode(regs))
                return 0;
 
-       if (try_to_freeze()) {
-               signr = 0;
-               if (!signal_pending(current))
-                       goto no_signal;
-       }
-
        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                oldset = &current->saved_sigmask;
        else if (!oldset)
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-no_signal:
        if (syscall) {
                switch (regs->r12) {
                case -ERESTART_RESTARTBLOCK:
index 7014a3571ec024a5cdccc4161817ceb73401013b..36a46c3ae30880c8f2b478f6c9df7c2d84b27247 100644 (file)
@@ -214,7 +214,7 @@ void __init time_init(void)
 }
 
 static struct sysdev_class timer_class = {
-       set_kset_name("timer"),
+       .name = "timer",
 };
 
 static struct sys_device timer_device = {
index 870c075e631479685f0af15a488ca68cecf3b877..cf6f686d9b0b4c97647316cd93a890930f100990 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
+#include <linux/kdebug.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
 #include <linux/sched.h>
@@ -107,9 +108,23 @@ void _exception(long signr, struct pt_regs *regs, int code,
 
 asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
 {
-       printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
-       show_regs_log_lvl(regs, KERN_ALERT);
-       show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
+       int ret;
+
+       nmi_enter();
+
+       ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT);
+       switch (ret) {
+       case NOTIFY_OK:
+       case NOTIFY_STOP:
+               return;
+       case NOTIFY_BAD:
+               die("Fatal Non-Maskable Interrupt", regs, SIGINT);
+       default:
+               break;
+       }
+
+       printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
+       nmi_disable();
 }
 
 asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
index eb307838457b3aea4b175e68759ce0d2186253c7..a7bbcc82058edc5828b7a67b3c90747f04ab5a88 100644 (file)
@@ -3,9 +3,9 @@ if PLATFORM_AT32AP
 menu "Atmel AVR32 AP options"
 
 choice
-       prompt "AT32AP7000 static memory bus width"
-       depends on CPU_AT32AP7000
-       default AP7000_16_BIT_SMC
+       prompt "AT32AP700x static memory bus width"
+       depends on CPU_AT32AP700X
+       default AP700X_16_BIT_SMC
        help
          Define the width of the AP7000 external static memory interface.
          This is used to determine how to mangle the address and/or data
@@ -15,13 +15,13 @@ choice
          width for all chip selects, excluding the flash (which is using
          raw access and is thus not affected by any of this.)
 
-config AP7000_32_BIT_SMC
+config AP700X_32_BIT_SMC
        bool "32 bit"
 
-config AP7000_16_BIT_SMC
+config AP700X_16_BIT_SMC
        bool "16 bit"
 
-config AP7000_8_BIT_SMC
+config AP700X_8_BIT_SMC
        bool "8 bit"
 
 endchoice
index a8b445046e3e3843135f2a1e4c21b93239b79d8b..5e9f8217befc16f4095918f8be3c710a1c4fb621 100644 (file)
@@ -1,4 +1,4 @@
 obj-y                          += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
-obj-$(CONFIG_CPU_AT32AP7000)   += at32ap7000.o
-obj-$(CONFIG_CPU_AT32AP7000)   += time-tc.o
+obj-$(CONFIG_CPU_AT32AP700X)   += at32ap700x.o
+obj-$(CONFIG_CPU_AT32AP700X)   += time-tc.o
 obj-$(CONFIG_CPU_FREQ_AT32AP)  += cpufreq.o
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
deleted file mode 100644 (file)
index 7c4388f..0000000
+++ /dev/null
@@ -1,1730 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Atmel Corporation
- *
- * 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/clk.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/spi/spi.h>
-
-#include <asm/io.h>
-
-#include <asm/arch/at32ap7000.h>
-#include <asm/arch/board.h>
-#include <asm/arch/portmux.h>
-
-#include <video/atmel_lcdc.h>
-
-#include "clock.h"
-#include "hmatrix.h"
-#include "pio.h"
-#include "pm.h"
-
-
-#define PBMEM(base)                                    \
-       {                                               \
-               .start          = base,                 \
-               .end            = base + 0x3ff,         \
-               .flags          = IORESOURCE_MEM,       \
-       }
-#define IRQ(num)                                       \
-       {                                               \
-               .start          = num,                  \
-               .end            = num,                  \
-               .flags          = IORESOURCE_IRQ,       \
-       }
-#define NAMED_IRQ(num, _name)                          \
-       {                                               \
-               .start          = num,                  \
-               .end            = num,                  \
-               .name           = _name,                \
-               .flags          = IORESOURCE_IRQ,       \
-       }
-
-/* REVISIT these assume *every* device supports DMA, but several
- * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
- */
-#define DEFINE_DEV(_name, _id)                                 \
-static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;             \
-static struct platform_device _name##_id##_device = {          \
-       .name           = #_name,                               \
-       .id             = _id,                                  \
-       .dev            = {                                     \
-               .dma_mask = &_name##_id##_dma_mask,             \
-               .coherent_dma_mask = DMA_32BIT_MASK,            \
-       },                                                      \
-       .resource       = _name##_id##_resource,                \
-       .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
-}
-#define DEFINE_DEV_DATA(_name, _id)                            \
-static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;             \
-static struct platform_device _name##_id##_device = {          \
-       .name           = #_name,                               \
-       .id             = _id,                                  \
-       .dev            = {                                     \
-               .dma_mask = &_name##_id##_dma_mask,             \
-               .platform_data  = &_name##_id##_data,           \
-               .coherent_dma_mask = DMA_32BIT_MASK,            \
-       },                                                      \
-       .resource       = _name##_id##_resource,                \
-       .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
-}
-
-#define select_peripheral(pin, periph, flags)                  \
-       at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
-
-#define DEV_CLK(_name, devname, bus, _index)                   \
-static struct clk devname##_##_name = {                                \
-       .name           = #_name,                               \
-       .dev            = &devname##_device.dev,                \
-       .parent         = &bus##_clk,                           \
-       .mode           = bus##_clk_mode,                       \
-       .get_rate       = bus##_clk_get_rate,                   \
-       .index          = _index,                               \
-}
-
-static DEFINE_SPINLOCK(pm_lock);
-
-unsigned long at32ap7000_osc_rates[3] = {
-       [0] = 32768,
-       /* FIXME: these are ATSTK1002-specific */
-       [1] = 20000000,
-       [2] = 12000000,
-};
-
-static unsigned long osc_get_rate(struct clk *clk)
-{
-       return at32ap7000_osc_rates[clk->index];
-}
-
-static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
-{
-       unsigned long div, mul, rate;
-
-       if (!(control & PM_BIT(PLLEN)))
-               return 0;
-
-       div = PM_BFEXT(PLLDIV, control) + 1;
-       mul = PM_BFEXT(PLLMUL, control) + 1;
-
-       rate = clk->parent->get_rate(clk->parent);
-       rate = (rate + div / 2) / div;
-       rate *= mul;
-
-       return rate;
-}
-
-static unsigned long pll0_get_rate(struct clk *clk)
-{
-       u32 control;
-
-       control = pm_readl(PLL0);
-
-       return pll_get_rate(clk, control);
-}
-
-static unsigned long pll1_get_rate(struct clk *clk)
-{
-       u32 control;
-
-       control = pm_readl(PLL1);
-
-       return pll_get_rate(clk, control);
-}
-
-/*
- * The AT32AP7000 has five primary clock sources: One 32kHz
- * oscillator, two crystal oscillators and two PLLs.
- */
-static struct clk osc32k = {
-       .name           = "osc32k",
-       .get_rate       = osc_get_rate,
-       .users          = 1,
-       .index          = 0,
-};
-static struct clk osc0 = {
-       .name           = "osc0",
-       .get_rate       = osc_get_rate,
-       .users          = 1,
-       .index          = 1,
-};
-static struct clk osc1 = {
-       .name           = "osc1",
-       .get_rate       = osc_get_rate,
-       .index          = 2,
-};
-static struct clk pll0 = {
-       .name           = "pll0",
-       .get_rate       = pll0_get_rate,
-       .parent         = &osc0,
-};
-static struct clk pll1 = {
-       .name           = "pll1",
-       .get_rate       = pll1_get_rate,
-       .parent         = &osc0,
-};
-
-/*
- * The main clock can be either osc0 or pll0.  The boot loader may
- * have chosen one for us, so we don't really know which one until we
- * have a look at the SM.
- */
-static struct clk *main_clock;
-
-/*
- * Synchronous clocks are generated from the main clock. The clocks
- * must satisfy the constraint
- *   fCPU >= fHSB >= fPB
- * i.e. each clock must not be faster than its parent.
- */
-static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
-{
-       return main_clock->get_rate(main_clock) >> shift;
-};
-
-static void cpu_clk_mode(struct clk *clk, int enabled)
-{
-       unsigned long flags;
-       u32 mask;
-
-       spin_lock_irqsave(&pm_lock, flags);
-       mask = pm_readl(CPU_MASK);
-       if (enabled)
-               mask |= 1 << clk->index;
-       else
-               mask &= ~(1 << clk->index);
-       pm_writel(CPU_MASK, mask);
-       spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long cpu_clk_get_rate(struct clk *clk)
-{
-       unsigned long cksel, shift = 0;
-
-       cksel = pm_readl(CKSEL);
-       if (cksel & PM_BIT(CPUDIV))
-               shift = PM_BFEXT(CPUSEL, cksel) + 1;
-
-       return bus_clk_get_rate(clk, shift);
-}
-
-static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
-{
-       u32 control;
-       unsigned long parent_rate, child_div, actual_rate, div;
-
-       parent_rate = clk->parent->get_rate(clk->parent);
-       control = pm_readl(CKSEL);
-
-       if (control & PM_BIT(HSBDIV))
-               child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
-       else
-               child_div = 1;
-
-       if (rate > 3 * (parent_rate / 4) || child_div == 1) {
-               actual_rate = parent_rate;
-               control &= ~PM_BIT(CPUDIV);
-       } else {
-               unsigned int cpusel;
-               div = (parent_rate + rate / 2) / rate;
-               if (div > child_div)
-                       div = child_div;
-               cpusel = (div > 1) ? (fls(div) - 2) : 0;
-               control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
-               actual_rate = parent_rate / (1 << (cpusel + 1));
-       }
-
-       pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
-                       clk->name, rate, actual_rate);
-
-       if (apply)
-               pm_writel(CKSEL, control);
-
-       return actual_rate;
-}
-
-static void hsb_clk_mode(struct clk *clk, int enabled)
-{
-       unsigned long flags;
-       u32 mask;
-
-       spin_lock_irqsave(&pm_lock, flags);
-       mask = pm_readl(HSB_MASK);
-       if (enabled)
-               mask |= 1 << clk->index;
-       else
-               mask &= ~(1 << clk->index);
-       pm_writel(HSB_MASK, mask);
-       spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long hsb_clk_get_rate(struct clk *clk)
-{
-       unsigned long cksel, shift = 0;
-
-       cksel = pm_readl(CKSEL);
-       if (cksel & PM_BIT(HSBDIV))
-               shift = PM_BFEXT(HSBSEL, cksel) + 1;
-
-       return bus_clk_get_rate(clk, shift);
-}
-
-static void pba_clk_mode(struct clk *clk, int enabled)
-{
-       unsigned long flags;
-       u32 mask;
-
-       spin_lock_irqsave(&pm_lock, flags);
-       mask = pm_readl(PBA_MASK);
-       if (enabled)
-               mask |= 1 << clk->index;
-       else
-               mask &= ~(1 << clk->index);
-       pm_writel(PBA_MASK, mask);
-       spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long pba_clk_get_rate(struct clk *clk)
-{
-       unsigned long cksel, shift = 0;
-
-       cksel = pm_readl(CKSEL);
-       if (cksel & PM_BIT(PBADIV))
-               shift = PM_BFEXT(PBASEL, cksel) + 1;
-
-       return bus_clk_get_rate(clk, shift);
-}
-
-static void pbb_clk_mode(struct clk *clk, int enabled)
-{
-       unsigned long flags;
-       u32 mask;
-
-       spin_lock_irqsave(&pm_lock, flags);
-       mask = pm_readl(PBB_MASK);
-       if (enabled)
-               mask |= 1 << clk->index;
-       else
-               mask &= ~(1 << clk->index);
-       pm_writel(PBB_MASK, mask);
-       spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long pbb_clk_get_rate(struct clk *clk)
-{
-       unsigned long cksel, shift = 0;
-
-       cksel = pm_readl(CKSEL);
-       if (cksel & PM_BIT(PBBDIV))
-               shift = PM_BFEXT(PBBSEL, cksel) + 1;
-
-       return bus_clk_get_rate(clk, shift);
-}
-
-static struct clk cpu_clk = {
-       .name           = "cpu",
-       .get_rate       = cpu_clk_get_rate,
-       .set_rate       = cpu_clk_set_rate,
-       .users          = 1,
-};
-static struct clk hsb_clk = {
-       .name           = "hsb",
-       .parent         = &cpu_clk,
-       .get_rate       = hsb_clk_get_rate,
-};
-static struct clk pba_clk = {
-       .name           = "pba",
-       .parent         = &hsb_clk,
-       .mode           = hsb_clk_mode,
-       .get_rate       = pba_clk_get_rate,
-       .index          = 1,
-};
-static struct clk pbb_clk = {
-       .name           = "pbb",
-       .parent         = &hsb_clk,
-       .mode           = hsb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .users          = 1,
-       .index          = 2,
-};
-
-/* --------------------------------------------------------------------
- *  Generic Clock operations
- * -------------------------------------------------------------------- */
-
-static void genclk_mode(struct clk *clk, int enabled)
-{
-       u32 control;
-
-       control = pm_readl(GCCTRL(clk->index));
-       if (enabled)
-               control |= PM_BIT(CEN);
-       else
-               control &= ~PM_BIT(CEN);
-       pm_writel(GCCTRL(clk->index), control);
-}
-
-static unsigned long genclk_get_rate(struct clk *clk)
-{
-       u32 control;
-       unsigned long div = 1;
-
-       control = pm_readl(GCCTRL(clk->index));
-       if (control & PM_BIT(DIVEN))
-               div = 2 * (PM_BFEXT(DIV, control) + 1);
-
-       return clk->parent->get_rate(clk->parent) / div;
-}
-
-static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
-{
-       u32 control;
-       unsigned long parent_rate, actual_rate, div;
-
-       parent_rate = clk->parent->get_rate(clk->parent);
-       control = pm_readl(GCCTRL(clk->index));
-
-       if (rate > 3 * parent_rate / 4) {
-               actual_rate = parent_rate;
-               control &= ~PM_BIT(DIVEN);
-       } else {
-               div = (parent_rate + rate) / (2 * rate) - 1;
-               control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
-               actual_rate = parent_rate / (2 * (div + 1));
-       }
-
-       dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
-               clk->name, rate, actual_rate);
-
-       if (apply)
-               pm_writel(GCCTRL(clk->index), control);
-
-       return actual_rate;
-}
-
-int genclk_set_parent(struct clk *clk, struct clk *parent)
-{
-       u32 control;
-
-       dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
-               clk->name, parent->name, clk->parent->name);
-
-       control = pm_readl(GCCTRL(clk->index));
-
-       if (parent == &osc1 || parent == &pll1)
-               control |= PM_BIT(OSCSEL);
-       else if (parent == &osc0 || parent == &pll0)
-               control &= ~PM_BIT(OSCSEL);
-       else
-               return -EINVAL;
-
-       if (parent == &pll0 || parent == &pll1)
-               control |= PM_BIT(PLLSEL);
-       else
-               control &= ~PM_BIT(PLLSEL);
-
-       pm_writel(GCCTRL(clk->index), control);
-       clk->parent = parent;
-
-       return 0;
-}
-
-static void __init genclk_init_parent(struct clk *clk)
-{
-       u32 control;
-       struct clk *parent;
-
-       BUG_ON(clk->index > 7);
-
-       control = pm_readl(GCCTRL(clk->index));
-       if (control & PM_BIT(OSCSEL))
-               parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
-       else
-               parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
-
-       clk->parent = parent;
-}
-
-/* --------------------------------------------------------------------
- *  System peripherals
- * -------------------------------------------------------------------- */
-static struct resource at32_pm0_resource[] = {
-       {
-               .start  = 0xfff00000,
-               .end    = 0xfff0007f,
-               .flags  = IORESOURCE_MEM,
-       },
-       IRQ(20),
-};
-
-static struct resource at32ap700x_rtc0_resource[] = {
-       {
-               .start  = 0xfff00080,
-               .end    = 0xfff000af,
-               .flags  = IORESOURCE_MEM,
-       },
-       IRQ(21),
-};
-
-static struct resource at32_wdt0_resource[] = {
-       {
-               .start  = 0xfff000b0,
-               .end    = 0xfff000cf,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct resource at32_eic0_resource[] = {
-       {
-               .start  = 0xfff00100,
-               .end    = 0xfff0013f,
-               .flags  = IORESOURCE_MEM,
-       },
-       IRQ(19),
-};
-
-DEFINE_DEV(at32_pm, 0);
-DEFINE_DEV(at32ap700x_rtc, 0);
-DEFINE_DEV(at32_wdt, 0);
-DEFINE_DEV(at32_eic, 0);
-
-/*
- * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
- * is always running.
- */
-static struct clk at32_pm_pclk = {
-       .name           = "pclk",
-       .dev            = &at32_pm0_device.dev,
-       .parent         = &pbb_clk,
-       .mode           = pbb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .users          = 1,
-       .index          = 0,
-};
-
-static struct resource intc0_resource[] = {
-       PBMEM(0xfff00400),
-};
-struct platform_device at32_intc0_device = {
-       .name           = "intc",
-       .id             = 0,
-       .resource       = intc0_resource,
-       .num_resources  = ARRAY_SIZE(intc0_resource),
-};
-DEV_CLK(pclk, at32_intc0, pbb, 1);
-
-static struct clk ebi_clk = {
-       .name           = "ebi",
-       .parent         = &hsb_clk,
-       .mode           = hsb_clk_mode,
-       .get_rate       = hsb_clk_get_rate,
-       .users          = 1,
-};
-static struct clk hramc_clk = {
-       .name           = "hramc",
-       .parent         = &hsb_clk,
-       .mode           = hsb_clk_mode,
-       .get_rate       = hsb_clk_get_rate,
-       .users          = 1,
-       .index          = 3,
-};
-
-static struct resource smc0_resource[] = {
-       PBMEM(0xfff03400),
-};
-DEFINE_DEV(smc, 0);
-DEV_CLK(pclk, smc0, pbb, 13);
-DEV_CLK(mck, smc0, hsb, 0);
-
-static struct platform_device pdc_device = {
-       .name           = "pdc",
-       .id             = 0,
-};
-DEV_CLK(hclk, pdc, hsb, 4);
-DEV_CLK(pclk, pdc, pba, 16);
-
-static struct clk pico_clk = {
-       .name           = "pico",
-       .parent         = &cpu_clk,
-       .mode           = cpu_clk_mode,
-       .get_rate       = cpu_clk_get_rate,
-       .users          = 1,
-};
-
-static struct resource dmaca0_resource[] = {
-       {
-               .start  = 0xff200000,
-               .end    = 0xff20ffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       IRQ(2),
-};
-DEFINE_DEV(dmaca, 0);
-DEV_CLK(hclk, dmaca0, hsb, 10);
-
-/* --------------------------------------------------------------------
- * HMATRIX
- * -------------------------------------------------------------------- */
-
-static struct clk hmatrix_clk = {
-       .name           = "hmatrix_clk",
-       .parent         = &pbb_clk,
-       .mode           = pbb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .index          = 2,
-       .users          = 1,
-};
-#define HMATRIX_BASE   ((void __iomem *)0xfff00800)
-
-#define hmatrix_readl(reg)                                     \
-       __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
-#define hmatrix_writel(reg,value)                              \
-       __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
-
-/*
- * Set bits in the HMATRIX Special Function Register (SFR) used by the
- * External Bus Interface (EBI). This can be used to enable special
- * features like CompactFlash support, NAND Flash support, etc. on
- * certain chipselects.
- */
-static inline void set_ebi_sfr_bits(u32 mask)
-{
-       u32 sfr;
-
-       clk_enable(&hmatrix_clk);
-       sfr = hmatrix_readl(SFR4);
-       sfr |= mask;
-       hmatrix_writel(SFR4, sfr);
-       clk_disable(&hmatrix_clk);
-}
-
-/* --------------------------------------------------------------------
- *  System Timer/Counter (TC)
- * -------------------------------------------------------------------- */
-static struct resource at32_systc0_resource[] = {
-       PBMEM(0xfff00c00),
-       IRQ(22),
-};
-struct platform_device at32_systc0_device = {
-       .name           = "systc",
-       .id             = 0,
-       .resource       = at32_systc0_resource,
-       .num_resources  = ARRAY_SIZE(at32_systc0_resource),
-};
-DEV_CLK(pclk, at32_systc0, pbb, 3);
-
-/* --------------------------------------------------------------------
- *  PIO
- * -------------------------------------------------------------------- */
-
-static struct resource pio0_resource[] = {
-       PBMEM(0xffe02800),
-       IRQ(13),
-};
-DEFINE_DEV(pio, 0);
-DEV_CLK(mck, pio0, pba, 10);
-
-static struct resource pio1_resource[] = {
-       PBMEM(0xffe02c00),
-       IRQ(14),
-};
-DEFINE_DEV(pio, 1);
-DEV_CLK(mck, pio1, pba, 11);
-
-static struct resource pio2_resource[] = {
-       PBMEM(0xffe03000),
-       IRQ(15),
-};
-DEFINE_DEV(pio, 2);
-DEV_CLK(mck, pio2, pba, 12);
-
-static struct resource pio3_resource[] = {
-       PBMEM(0xffe03400),
-       IRQ(16),
-};
-DEFINE_DEV(pio, 3);
-DEV_CLK(mck, pio3, pba, 13);
-
-static struct resource pio4_resource[] = {
-       PBMEM(0xffe03800),
-       IRQ(17),
-};
-DEFINE_DEV(pio, 4);
-DEV_CLK(mck, pio4, pba, 14);
-
-void __init at32_add_system_devices(void)
-{
-       platform_device_register(&at32_pm0_device);
-       platform_device_register(&at32_intc0_device);
-       platform_device_register(&at32ap700x_rtc0_device);
-       platform_device_register(&at32_wdt0_device);
-       platform_device_register(&at32_eic0_device);
-       platform_device_register(&smc0_device);
-       platform_device_register(&pdc_device);
-       platform_device_register(&dmaca0_device);
-
-       platform_device_register(&at32_systc0_device);
-
-       platform_device_register(&pio0_device);
-       platform_device_register(&pio1_device);
-       platform_device_register(&pio2_device);
-       platform_device_register(&pio3_device);
-       platform_device_register(&pio4_device);
-}
-
-/* --------------------------------------------------------------------
- *  USART
- * -------------------------------------------------------------------- */
-
-static struct atmel_uart_data atmel_usart0_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-static struct resource atmel_usart0_resource[] = {
-       PBMEM(0xffe00c00),
-       IRQ(6),
-};
-DEFINE_DEV_DATA(atmel_usart, 0);
-DEV_CLK(usart, atmel_usart0, pba, 3);
-
-static struct atmel_uart_data atmel_usart1_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-static struct resource atmel_usart1_resource[] = {
-       PBMEM(0xffe01000),
-       IRQ(7),
-};
-DEFINE_DEV_DATA(atmel_usart, 1);
-DEV_CLK(usart, atmel_usart1, pba, 4);
-
-static struct atmel_uart_data atmel_usart2_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-static struct resource atmel_usart2_resource[] = {
-       PBMEM(0xffe01400),
-       IRQ(8),
-};
-DEFINE_DEV_DATA(atmel_usart, 2);
-DEV_CLK(usart, atmel_usart2, pba, 5);
-
-static struct atmel_uart_data atmel_usart3_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-static struct resource atmel_usart3_resource[] = {
-       PBMEM(0xffe01800),
-       IRQ(9),
-};
-DEFINE_DEV_DATA(atmel_usart, 3);
-DEV_CLK(usart, atmel_usart3, pba, 6);
-
-static inline void configure_usart0_pins(void)
-{
-       select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
-       select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
-}
-
-static inline void configure_usart1_pins(void)
-{
-       select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
-       select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
-}
-
-static inline void configure_usart2_pins(void)
-{
-       select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
-       select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
-}
-
-static inline void configure_usart3_pins(void)
-{
-       select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
-       select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
-}
-
-static struct platform_device *__initdata at32_usarts[4];
-
-void __init at32_map_usart(unsigned int hw_id, unsigned int line)
-{
-       struct platform_device *pdev;
-
-       switch (hw_id) {
-       case 0:
-               pdev = &atmel_usart0_device;
-               configure_usart0_pins();
-               break;
-       case 1:
-               pdev = &atmel_usart1_device;
-               configure_usart1_pins();
-               break;
-       case 2:
-               pdev = &atmel_usart2_device;
-               configure_usart2_pins();
-               break;
-       case 3:
-               pdev = &atmel_usart3_device;
-               configure_usart3_pins();
-               break;
-       default:
-               return;
-       }
-
-       if (PXSEG(pdev->resource[0].start) == P4SEG) {
-               /* Addresses in the P4 segment are permanently mapped 1:1 */
-               struct atmel_uart_data *data = pdev->dev.platform_data;
-               data->regs = (void __iomem *)pdev->resource[0].start;
-       }
-
-       pdev->id = line;
-       at32_usarts[line] = pdev;
-}
-
-struct platform_device *__init at32_add_device_usart(unsigned int id)
-{
-       platform_device_register(at32_usarts[id]);
-       return at32_usarts[id];
-}
-
-struct platform_device *atmel_default_console_device;
-
-void __init at32_setup_serial_console(unsigned int usart_id)
-{
-       atmel_default_console_device = at32_usarts[usart_id];
-}
-
-/* --------------------------------------------------------------------
- *  Ethernet
- * -------------------------------------------------------------------- */
-
-static struct eth_platform_data macb0_data;
-static struct resource macb0_resource[] = {
-       PBMEM(0xfff01800),
-       IRQ(25),
-};
-DEFINE_DEV_DATA(macb, 0);
-DEV_CLK(hclk, macb0, hsb, 8);
-DEV_CLK(pclk, macb0, pbb, 6);
-
-static struct eth_platform_data macb1_data;
-static struct resource macb1_resource[] = {
-       PBMEM(0xfff01c00),
-       IRQ(26),
-};
-DEFINE_DEV_DATA(macb, 1);
-DEV_CLK(hclk, macb1, hsb, 9);
-DEV_CLK(pclk, macb1, pbb, 7);
-
-struct platform_device *__init
-at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
-{
-       struct platform_device *pdev;
-
-       switch (id) {
-       case 0:
-               pdev = &macb0_device;
-
-               select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
-               select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
-               select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
-               select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
-               select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
-               select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
-               select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
-               select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
-               select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
-               select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
-
-               if (!data->is_rmii) {
-                       select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
-                       select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
-                       select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
-                       select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
-                       select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
-                       select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
-                       select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
-                       select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
-                       select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
-               }
-               break;
-
-       case 1:
-               pdev = &macb1_device;
-
-               select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
-               select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
-               select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
-               select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
-               select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
-               select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
-               select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
-               select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
-               select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
-               select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
-
-               if (!data->is_rmii) {
-                       select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
-                       select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
-                       select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
-                       select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
-                       select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
-                       select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
-                       select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
-                       select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
-                       select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
-               }
-               break;
-
-       default:
-               return NULL;
-       }
-
-       memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
-       platform_device_register(pdev);
-
-       return pdev;
-}
-
-/* --------------------------------------------------------------------
- *  SPI
- * -------------------------------------------------------------------- */
-static struct resource atmel_spi0_resource[] = {
-       PBMEM(0xffe00000),
-       IRQ(3),
-};
-DEFINE_DEV(atmel_spi, 0);
-DEV_CLK(spi_clk, atmel_spi0, pba, 0);
-
-static struct resource atmel_spi1_resource[] = {
-       PBMEM(0xffe00400),
-       IRQ(4),
-};
-DEFINE_DEV(atmel_spi, 1);
-DEV_CLK(spi_clk, atmel_spi1, pba, 1);
-
-static void __init
-at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
-                     unsigned int n, const u8 *pins)
-{
-       unsigned int pin, mode;
-
-       for (; n; n--, b++) {
-               b->bus_num = bus_num;
-               if (b->chip_select >= 4)
-                       continue;
-               pin = (unsigned)b->controller_data;
-               if (!pin) {
-                       pin = pins[b->chip_select];
-                       b->controller_data = (void *)pin;
-               }
-               mode = AT32_GPIOF_OUTPUT;
-               if (!(b->mode & SPI_CS_HIGH))
-                       mode |= AT32_GPIOF_HIGH;
-               at32_select_gpio(pin, mode);
-       }
-}
-
-struct platform_device *__init
-at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
-{
-       /*
-        * Manage the chipselects as GPIOs, normally using the same pins
-        * the SPI controller expects; but boards can use other pins.
-        */
-       static u8 __initdata spi0_pins[] =
-               { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
-                 GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
-       static u8 __initdata spi1_pins[] =
-               { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
-                 GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
-       struct platform_device *pdev;
-
-       switch (id) {
-       case 0:
-               pdev = &atmel_spi0_device;
-               select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
-               select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
-               select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
-               at32_spi_setup_slaves(0, b, n, spi0_pins);
-               break;
-
-       case 1:
-               pdev = &atmel_spi1_device;
-               select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
-               select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
-               select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
-               at32_spi_setup_slaves(1, b, n, spi1_pins);
-               break;
-
-       default:
-               return NULL;
-       }
-
-       spi_register_board_info(b, n);
-       platform_device_register(pdev);
-       return pdev;
-}
-
-/* --------------------------------------------------------------------
- *  TWI
- * -------------------------------------------------------------------- */
-static struct resource atmel_twi0_resource[] __initdata = {
-       PBMEM(0xffe00800),
-       IRQ(5),
-};
-static struct clk atmel_twi0_pclk = {
-       .name           = "twi_pclk",
-       .parent         = &pba_clk,
-       .mode           = pba_clk_mode,
-       .get_rate       = pba_clk_get_rate,
-       .index          = 2,
-};
-
-struct platform_device *__init at32_add_device_twi(unsigned int id)
-{
-       struct platform_device *pdev;
-
-       if (id != 0)
-               return NULL;
-
-       pdev = platform_device_alloc("atmel_twi", id);
-       if (!pdev)
-               return NULL;
-
-       if (platform_device_add_resources(pdev, atmel_twi0_resource,
-                               ARRAY_SIZE(atmel_twi0_resource)))
-               goto err_add_resources;
-
-       select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
-       select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
-
-       atmel_twi0_pclk.dev = &pdev->dev;
-
-       platform_device_add(pdev);
-       return pdev;
-
-err_add_resources:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- * MMC
- * -------------------------------------------------------------------- */
-static struct resource atmel_mci0_resource[] __initdata = {
-       PBMEM(0xfff02400),
-       IRQ(28),
-};
-static struct clk atmel_mci0_pclk = {
-       .name           = "mci_clk",
-       .parent         = &pbb_clk,
-       .mode           = pbb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .index          = 9,
-};
-
-struct platform_device *__init at32_add_device_mci(unsigned int id)
-{
-       struct platform_device *pdev;
-
-       if (id != 0)
-               return NULL;
-
-       pdev = platform_device_alloc("atmel_mci", id);
-       if (!pdev)
-               return NULL;
-
-       if (platform_device_add_resources(pdev, atmel_mci0_resource,
-                               ARRAY_SIZE(atmel_mci0_resource)))
-               goto err_add_resources;
-
-       select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
-       select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
-       select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
-       select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
-       select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
-       select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
-
-       atmel_mci0_pclk.dev = &pdev->dev;
-
-       platform_device_add(pdev);
-       return pdev;
-
-err_add_resources:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- *  LCDC
- * -------------------------------------------------------------------- */
-static struct atmel_lcdfb_info atmel_lcdfb0_data;
-static struct resource atmel_lcdfb0_resource[] = {
-       {
-               .start          = 0xff000000,
-               .end            = 0xff000fff,
-               .flags          = IORESOURCE_MEM,
-       },
-       IRQ(1),
-       {
-               /* Placeholder for pre-allocated fb memory */
-               .start          = 0x00000000,
-               .end            = 0x00000000,
-               .flags          = 0,
-       },
-};
-DEFINE_DEV_DATA(atmel_lcdfb, 0);
-DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
-static struct clk atmel_lcdfb0_pixclk = {
-       .name           = "lcdc_clk",
-       .dev            = &atmel_lcdfb0_device.dev,
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 7,
-};
-
-struct platform_device *__init
-at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len)
-{
-       struct platform_device *pdev;
-       struct atmel_lcdfb_info *info;
-       struct fb_monspecs *monspecs;
-       struct fb_videomode *modedb;
-       unsigned int modedb_size;
-
-       /*
-        * Do a deep copy of the fb data, monspecs and modedb. Make
-        * sure all allocations are done before setting up the
-        * portmux.
-        */
-       monspecs = kmemdup(data->default_monspecs,
-                          sizeof(struct fb_monspecs), GFP_KERNEL);
-       if (!monspecs)
-               return NULL;
-
-       modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
-       modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
-       if (!modedb)
-               goto err_dup_modedb;
-       monspecs->modedb = modedb;
-
-       switch (id) {
-       case 0:
-               pdev = &atmel_lcdfb0_device;
-               select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-               select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-               select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-               select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-               select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-               select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-               select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-               select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-               select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-               select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-               select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-               select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-               select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-               select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-               select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-               select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-               select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-               select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-               select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-               select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-               select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-               select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-               select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-               select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-               select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-               select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-               select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-               select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-               select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-               select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-               select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-
-               clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
-               clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
-               break;
-
-       default:
-               goto err_invalid_id;
-       }
-
-       if (fbmem_len) {
-               pdev->resource[2].start = fbmem_start;
-               pdev->resource[2].end = fbmem_start + fbmem_len - 1;
-               pdev->resource[2].flags = IORESOURCE_MEM;
-       }
-
-       info = pdev->dev.platform_data;
-       memcpy(info, data, sizeof(struct atmel_lcdfb_info));
-       info->default_monspecs = monspecs;
-
-       platform_device_register(pdev);
-       return pdev;
-
-err_invalid_id:
-       kfree(modedb);
-err_dup_modedb:
-       kfree(monspecs);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- *  SSC
- * -------------------------------------------------------------------- */
-static struct resource ssc0_resource[] = {
-       PBMEM(0xffe01c00),
-       IRQ(10),
-};
-DEFINE_DEV(ssc, 0);
-DEV_CLK(pclk, ssc0, pba, 7);
-
-static struct resource ssc1_resource[] = {
-       PBMEM(0xffe02000),
-       IRQ(11),
-};
-DEFINE_DEV(ssc, 1);
-DEV_CLK(pclk, ssc1, pba, 8);
-
-static struct resource ssc2_resource[] = {
-       PBMEM(0xffe02400),
-       IRQ(12),
-};
-DEFINE_DEV(ssc, 2);
-DEV_CLK(pclk, ssc2, pba, 9);
-
-struct platform_device *__init
-at32_add_device_ssc(unsigned int id, unsigned int flags)
-{
-       struct platform_device *pdev;
-
-       switch (id) {
-       case 0:
-               pdev = &ssc0_device;
-               if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PA(21), PERIPH_A, 0); /* RF */
-               if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PA(22), PERIPH_A, 0); /* RK */
-               if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PA(23), PERIPH_A, 0); /* TK */
-               if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PA(24), PERIPH_A, 0); /* TF */
-               if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PA(25), PERIPH_A, 0); /* TD */
-               if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PA(26), PERIPH_A, 0); /* RD */
-               break;
-       case 1:
-               pdev = &ssc1_device;
-               if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
-               if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
-               if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
-               if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
-               if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
-               if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
-               break;
-       case 2:
-               pdev = &ssc2_device;
-               if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PB(13), PERIPH_A, 0); /* TD */
-               if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PB(14), PERIPH_A, 0); /* RD */
-               if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PB(15), PERIPH_A, 0); /* TK */
-               if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PB(16), PERIPH_A, 0); /* TF */
-               if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PB(17), PERIPH_A, 0); /* RF */
-               if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PB(18), PERIPH_A, 0); /* RK */
-               break;
-       default:
-               return NULL;
-       }
-
-       platform_device_register(pdev);
-       return pdev;
-}
-
-/* --------------------------------------------------------------------
- *  USB Device Controller
- * -------------------------------------------------------------------- */
-static struct resource usba0_resource[] __initdata = {
-       {
-               .start          = 0xff300000,
-               .end            = 0xff3fffff,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = 0xfff03000,
-               .end            = 0xfff033ff,
-               .flags          = IORESOURCE_MEM,
-       },
-       IRQ(31),
-};
-static struct clk usba0_pclk = {
-       .name           = "pclk",
-       .parent         = &pbb_clk,
-       .mode           = pbb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .index          = 12,
-};
-static struct clk usba0_hclk = {
-       .name           = "hclk",
-       .parent         = &hsb_clk,
-       .mode           = hsb_clk_mode,
-       .get_rate       = hsb_clk_get_rate,
-       .index          = 6,
-};
-
-struct platform_device *__init
-at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
-{
-       struct platform_device *pdev;
-
-       if (id != 0)
-               return NULL;
-
-       pdev = platform_device_alloc("atmel_usba_udc", 0);
-       if (!pdev)
-               return NULL;
-
-       if (platform_device_add_resources(pdev, usba0_resource,
-                                         ARRAY_SIZE(usba0_resource)))
-               goto out_free_pdev;
-
-       if (data) {
-               if (platform_device_add_data(pdev, data, sizeof(*data)))
-                       goto out_free_pdev;
-
-               if (data->vbus_pin != GPIO_PIN_NONE)
-                       at32_select_gpio(data->vbus_pin, 0);
-       }
-
-       usba0_pclk.dev = &pdev->dev;
-       usba0_hclk.dev = &pdev->dev;
-
-       platform_device_add(pdev);
-
-       return pdev;
-
-out_free_pdev:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- * IDE / CompactFlash
- * -------------------------------------------------------------------- */
-static struct resource at32_smc_cs4_resource[] __initdata = {
-       {
-               .start  = 0x04000000,
-               .end    = 0x07ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       IRQ(~0UL), /* Magic IRQ will be overridden */
-};
-static struct resource at32_smc_cs5_resource[] __initdata = {
-       {
-               .start  = 0x20000000,
-               .end    = 0x23ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       IRQ(~0UL), /* Magic IRQ will be overridden */
-};
-
-static int __init at32_init_ide_or_cf(struct platform_device *pdev,
-               unsigned int cs, unsigned int extint)
-{
-       static unsigned int extint_pin_map[4] __initdata = {
-               GPIO_PIN_PB(25),
-               GPIO_PIN_PB(26),
-               GPIO_PIN_PB(27),
-               GPIO_PIN_PB(28),
-       };
-       static bool common_pins_initialized __initdata = false;
-       unsigned int extint_pin;
-       int ret;
-
-       if (extint >= ARRAY_SIZE(extint_pin_map))
-               return -EINVAL;
-       extint_pin = extint_pin_map[extint];
-
-       switch (cs) {
-       case 4:
-               ret = platform_device_add_resources(pdev,
-                               at32_smc_cs4_resource,
-                               ARRAY_SIZE(at32_smc_cs4_resource));
-               if (ret)
-                       return ret;
-
-               select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
-               set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
-               break;
-       case 5:
-               ret = platform_device_add_resources(pdev,
-                               at32_smc_cs5_resource,
-                               ARRAY_SIZE(at32_smc_cs5_resource));
-               if (ret)
-                       return ret;
-
-               select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
-               set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (!common_pins_initialized) {
-               select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
-               select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
-               select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
-               select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
-               common_pins_initialized = true;
-       }
-
-       at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
-
-       pdev->resource[1].start = EIM_IRQ_BASE + extint;
-       pdev->resource[1].end = pdev->resource[1].start;
-
-       return 0;
-}
-
-struct platform_device *__init
-at32_add_device_ide(unsigned int id, unsigned int extint,
-                   struct ide_platform_data *data)
-{
-       struct platform_device *pdev;
-
-       pdev = platform_device_alloc("at32_ide", id);
-       if (!pdev)
-               goto fail;
-
-       if (platform_device_add_data(pdev, data,
-                               sizeof(struct ide_platform_data)))
-               goto fail;
-
-       if (at32_init_ide_or_cf(pdev, data->cs, extint))
-               goto fail;
-
-       platform_device_add(pdev);
-       return pdev;
-
-fail:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-struct platform_device *__init
-at32_add_device_cf(unsigned int id, unsigned int extint,
-                   struct cf_platform_data *data)
-{
-       struct platform_device *pdev;
-
-       pdev = platform_device_alloc("at32_cf", id);
-       if (!pdev)
-               goto fail;
-
-       if (platform_device_add_data(pdev, data,
-                               sizeof(struct cf_platform_data)))
-               goto fail;
-
-       if (at32_init_ide_or_cf(pdev, data->cs, extint))
-               goto fail;
-
-       if (data->detect_pin != GPIO_PIN_NONE)
-               at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
-       if (data->reset_pin != GPIO_PIN_NONE)
-               at32_select_gpio(data->reset_pin, 0);
-       if (data->vcc_pin != GPIO_PIN_NONE)
-               at32_select_gpio(data->vcc_pin, 0);
-       /* READY is used as extint, so we can't select it as gpio */
-
-       platform_device_add(pdev);
-       return pdev;
-
-fail:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- * AC97C
- * -------------------------------------------------------------------- */
-static struct resource atmel_ac97c0_resource[] __initdata = {
-       PBMEM(0xfff02800),
-       IRQ(29),
-};
-static struct clk atmel_ac97c0_pclk = {
-       .name           = "pclk",
-       .parent         = &pbb_clk,
-       .mode           = pbb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .index          = 10,
-};
-
-struct platform_device *__init at32_add_device_ac97c(unsigned int id)
-{
-       struct platform_device *pdev;
-
-       if (id != 0)
-               return NULL;
-
-       pdev = platform_device_alloc("atmel_ac97c", id);
-       if (!pdev)
-               return NULL;
-
-       if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
-                               ARRAY_SIZE(atmel_ac97c0_resource)))
-               goto err_add_resources;
-
-       select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
-       select_peripheral(PB(21), PERIPH_B, 0); /* SDO  */
-       select_peripheral(PB(22), PERIPH_B, 0); /* SDI  */
-       select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
-
-       atmel_ac97c0_pclk.dev = &pdev->dev;
-
-       platform_device_add(pdev);
-       return pdev;
-
-err_add_resources:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- * ABDAC
- * -------------------------------------------------------------------- */
-static struct resource abdac0_resource[] __initdata = {
-       PBMEM(0xfff02000),
-       IRQ(27),
-};
-static struct clk abdac0_pclk = {
-       .name           = "pclk",
-       .parent         = &pbb_clk,
-       .mode           = pbb_clk_mode,
-       .get_rate       = pbb_clk_get_rate,
-       .index          = 8,
-};
-static struct clk abdac0_sample_clk = {
-       .name           = "sample_clk",
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 6,
-};
-
-struct platform_device *__init at32_add_device_abdac(unsigned int id)
-{
-       struct platform_device *pdev;
-
-       if (id != 0)
-               return NULL;
-
-       pdev = platform_device_alloc("abdac", id);
-       if (!pdev)
-               return NULL;
-
-       if (platform_device_add_resources(pdev, abdac0_resource,
-                               ARRAY_SIZE(abdac0_resource)))
-               goto err_add_resources;
-
-       select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
-       select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
-       select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
-       select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
-
-       abdac0_pclk.dev = &pdev->dev;
-       abdac0_sample_clk.dev = &pdev->dev;
-
-       platform_device_add(pdev);
-       return pdev;
-
-err_add_resources:
-       platform_device_put(pdev);
-       return NULL;
-}
-
-/* --------------------------------------------------------------------
- *  GCLK
- * -------------------------------------------------------------------- */
-static struct clk gclk0 = {
-       .name           = "gclk0",
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 0,
-};
-static struct clk gclk1 = {
-       .name           = "gclk1",
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 1,
-};
-static struct clk gclk2 = {
-       .name           = "gclk2",
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 2,
-};
-static struct clk gclk3 = {
-       .name           = "gclk3",
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 3,
-};
-static struct clk gclk4 = {
-       .name           = "gclk4",
-       .mode           = genclk_mode,
-       .get_rate       = genclk_get_rate,
-       .set_rate       = genclk_set_rate,
-       .set_parent     = genclk_set_parent,
-       .index          = 4,
-};
-
-struct clk *at32_clock_list[] = {
-       &osc32k,
-       &osc0,
-       &osc1,
-       &pll0,
-       &pll1,
-       &cpu_clk,
-       &hsb_clk,
-       &pba_clk,
-       &pbb_clk,
-       &at32_pm_pclk,
-       &at32_intc0_pclk,
-       &hmatrix_clk,
-       &ebi_clk,
-       &hramc_clk,
-       &smc0_pclk,
-       &smc0_mck,
-       &pdc_hclk,
-       &pdc_pclk,
-       &dmaca0_hclk,
-       &pico_clk,
-       &pio0_mck,
-       &pio1_mck,
-       &pio2_mck,
-       &pio3_mck,
-       &pio4_mck,
-       &at32_systc0_pclk,
-       &atmel_usart0_usart,
-       &atmel_usart1_usart,
-       &atmel_usart2_usart,
-       &atmel_usart3_usart,
-       &macb0_hclk,
-       &macb0_pclk,
-       &macb1_hclk,
-       &macb1_pclk,
-       &atmel_spi0_spi_clk,
-       &atmel_spi1_spi_clk,
-       &atmel_twi0_pclk,
-       &atmel_mci0_pclk,
-       &atmel_lcdfb0_hck1,
-       &atmel_lcdfb0_pixclk,
-       &ssc0_pclk,
-       &ssc1_pclk,
-       &ssc2_pclk,
-       &usba0_hclk,
-       &usba0_pclk,
-       &atmel_ac97c0_pclk,
-       &abdac0_pclk,
-       &abdac0_sample_clk,
-       &gclk0,
-       &gclk1,
-       &gclk2,
-       &gclk3,
-       &gclk4,
-};
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
-
-void __init at32_portmux_init(void)
-{
-       at32_init_pio(&pio0_device);
-       at32_init_pio(&pio1_device);
-       at32_init_pio(&pio2_device);
-       at32_init_pio(&pio3_device);
-       at32_init_pio(&pio4_device);
-}
-
-void __init at32_clock_init(void)
-{
-       u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
-       int i;
-
-       if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
-               main_clock = &pll0;
-               cpu_clk.parent = &pll0;
-       } else {
-               main_clock = &osc0;
-               cpu_clk.parent = &osc0;
-       }
-
-       if (pm_readl(PLL0) & PM_BIT(PLLOSC))
-               pll0.parent = &osc1;
-       if (pm_readl(PLL1) & PM_BIT(PLLOSC))
-               pll1.parent = &osc1;
-
-       genclk_init_parent(&gclk0);
-       genclk_init_parent(&gclk1);
-       genclk_init_parent(&gclk2);
-       genclk_init_parent(&gclk3);
-       genclk_init_parent(&gclk4);
-       genclk_init_parent(&atmel_lcdfb0_pixclk);
-       genclk_init_parent(&abdac0_sample_clk);
-
-       /*
-        * Turn on all clocks that have at least one user already, and
-        * turn off everything else. We only do this for module
-        * clocks, and even though it isn't particularly pretty to
-        * check the address of the mode function, it should do the
-        * trick...
-        */
-       for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
-               struct clk *clk = at32_clock_list[i];
-
-               if (clk->users == 0)
-                       continue;
-
-               if (clk->mode == &cpu_clk_mode)
-                       cpu_mask |= 1 << clk->index;
-               else if (clk->mode == &hsb_clk_mode)
-                       hsb_mask |= 1 << clk->index;
-               else if (clk->mode == &pba_clk_mode)
-                       pba_mask |= 1 << clk->index;
-               else if (clk->mode == &pbb_clk_mode)
-                       pbb_mask |= 1 << clk->index;
-       }
-
-       pm_writel(CPU_MASK, cpu_mask);
-       pm_writel(HSB_MASK, hsb_mask);
-       pm_writel(PBA_MASK, pba_mask);
-       pm_writel(PBB_MASK, pbb_mask);
-}
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
new file mode 100644 (file)
index 0000000..14e61f0
--- /dev/null
@@ -0,0 +1,1743 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/board.h>
+#include <asm/arch/portmux.h>
+
+#include <video/atmel_lcdc.h>
+
+#include "clock.h"
+#include "hmatrix.h"
+#include "pio.h"
+#include "pm.h"
+
+
+#define PBMEM(base)                                    \
+       {                                               \
+               .start          = base,                 \
+               .end            = base + 0x3ff,         \
+               .flags          = IORESOURCE_MEM,       \
+       }
+#define IRQ(num)                                       \
+       {                                               \
+               .start          = num,                  \
+               .end            = num,                  \
+               .flags          = IORESOURCE_IRQ,       \
+       }
+#define NAMED_IRQ(num, _name)                          \
+       {                                               \
+               .start          = num,                  \
+               .end            = num,                  \
+               .name           = _name,                \
+               .flags          = IORESOURCE_IRQ,       \
+       }
+
+/* REVISIT these assume *every* device supports DMA, but several
+ * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
+ */
+#define DEFINE_DEV(_name, _id)                                 \
+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;             \
+static struct platform_device _name##_id##_device = {          \
+       .name           = #_name,                               \
+       .id             = _id,                                  \
+       .dev            = {                                     \
+               .dma_mask = &_name##_id##_dma_mask,             \
+               .coherent_dma_mask = DMA_32BIT_MASK,            \
+       },                                                      \
+       .resource       = _name##_id##_resource,                \
+       .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
+}
+#define DEFINE_DEV_DATA(_name, _id)                            \
+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;             \
+static struct platform_device _name##_id##_device = {          \
+       .name           = #_name,                               \
+       .id             = _id,                                  \
+       .dev            = {                                     \
+               .dma_mask = &_name##_id##_dma_mask,             \
+               .platform_data  = &_name##_id##_data,           \
+               .coherent_dma_mask = DMA_32BIT_MASK,            \
+       },                                                      \
+       .resource       = _name##_id##_resource,                \
+       .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
+}
+
+#define select_peripheral(pin, periph, flags)                  \
+       at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+
+#define DEV_CLK(_name, devname, bus, _index)                   \
+static struct clk devname##_##_name = {                                \
+       .name           = #_name,                               \
+       .dev            = &devname##_device.dev,                \
+       .parent         = &bus##_clk,                           \
+       .mode           = bus##_clk_mode,                       \
+       .get_rate       = bus##_clk_get_rate,                   \
+       .index          = _index,                               \
+}
+
+static DEFINE_SPINLOCK(pm_lock);
+
+unsigned long at32ap7000_osc_rates[3] = {
+       [0] = 32768,
+       /* FIXME: these are ATSTK1002-specific */
+       [1] = 20000000,
+       [2] = 12000000,
+};
+
+static unsigned long osc_get_rate(struct clk *clk)
+{
+       return at32ap7000_osc_rates[clk->index];
+}
+
+static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
+{
+       unsigned long div, mul, rate;
+
+       if (!(control & PM_BIT(PLLEN)))
+               return 0;
+
+       div = PM_BFEXT(PLLDIV, control) + 1;
+       mul = PM_BFEXT(PLLMUL, control) + 1;
+
+       rate = clk->parent->get_rate(clk->parent);
+       rate = (rate + div / 2) / div;
+       rate *= mul;
+
+       return rate;
+}
+
+static unsigned long pll0_get_rate(struct clk *clk)
+{
+       u32 control;
+
+       control = pm_readl(PLL0);
+
+       return pll_get_rate(clk, control);
+}
+
+static unsigned long pll1_get_rate(struct clk *clk)
+{
+       u32 control;
+
+       control = pm_readl(PLL1);
+
+       return pll_get_rate(clk, control);
+}
+
+/*
+ * The AT32AP7000 has five primary clock sources: One 32kHz
+ * oscillator, two crystal oscillators and two PLLs.
+ */
+static struct clk osc32k = {
+       .name           = "osc32k",
+       .get_rate       = osc_get_rate,
+       .users          = 1,
+       .index          = 0,
+};
+static struct clk osc0 = {
+       .name           = "osc0",
+       .get_rate       = osc_get_rate,
+       .users          = 1,
+       .index          = 1,
+};
+static struct clk osc1 = {
+       .name           = "osc1",
+       .get_rate       = osc_get_rate,
+       .index          = 2,
+};
+static struct clk pll0 = {
+       .name           = "pll0",
+       .get_rate       = pll0_get_rate,
+       .parent         = &osc0,
+};
+static struct clk pll1 = {
+       .name           = "pll1",
+       .get_rate       = pll1_get_rate,
+       .parent         = &osc0,
+};
+
+/*
+ * The main clock can be either osc0 or pll0.  The boot loader may
+ * have chosen one for us, so we don't really know which one until we
+ * have a look at the SM.
+ */
+static struct clk *main_clock;
+
+/*
+ * Synchronous clocks are generated from the main clock. The clocks
+ * must satisfy the constraint
+ *   fCPU >= fHSB >= fPB
+ * i.e. each clock must not be faster than its parent.
+ */
+static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
+{
+       return main_clock->get_rate(main_clock) >> shift;
+};
+
+static void cpu_clk_mode(struct clk *clk, int enabled)
+{
+       unsigned long flags;
+       u32 mask;
+
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(CPU_MASK);
+       if (enabled)
+               mask |= 1 << clk->index;
+       else
+               mask &= ~(1 << clk->index);
+       pm_writel(CPU_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long cpu_clk_get_rate(struct clk *clk)
+{
+       unsigned long cksel, shift = 0;
+
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(CPUDIV))
+               shift = PM_BFEXT(CPUSEL, cksel) + 1;
+
+       return bus_clk_get_rate(clk, shift);
+}
+
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+       u32 control;
+       unsigned long parent_rate, child_div, actual_rate, div;
+
+       parent_rate = clk->parent->get_rate(clk->parent);
+       control = pm_readl(CKSEL);
+
+       if (control & PM_BIT(HSBDIV))
+               child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+       else
+               child_div = 1;
+
+       if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+               actual_rate = parent_rate;
+               control &= ~PM_BIT(CPUDIV);
+       } else {
+               unsigned int cpusel;
+               div = (parent_rate + rate / 2) / rate;
+               if (div > child_div)
+                       div = child_div;
+               cpusel = (div > 1) ? (fls(div) - 2) : 0;
+               control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+               actual_rate = parent_rate / (1 << (cpusel + 1));
+       }
+
+       pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+                       clk->name, rate, actual_rate);
+
+       if (apply)
+               pm_writel(CKSEL, control);
+
+       return actual_rate;
+}
+
+static void hsb_clk_mode(struct clk *clk, int enabled)
+{
+       unsigned long flags;
+       u32 mask;
+
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(HSB_MASK);
+       if (enabled)
+               mask |= 1 << clk->index;
+       else
+               mask &= ~(1 << clk->index);
+       pm_writel(HSB_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long hsb_clk_get_rate(struct clk *clk)
+{
+       unsigned long cksel, shift = 0;
+
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(HSBDIV))
+               shift = PM_BFEXT(HSBSEL, cksel) + 1;
+
+       return bus_clk_get_rate(clk, shift);
+}
+
+static void pba_clk_mode(struct clk *clk, int enabled)
+{
+       unsigned long flags;
+       u32 mask;
+
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(PBA_MASK);
+       if (enabled)
+               mask |= 1 << clk->index;
+       else
+               mask &= ~(1 << clk->index);
+       pm_writel(PBA_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long pba_clk_get_rate(struct clk *clk)
+{
+       unsigned long cksel, shift = 0;
+
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(PBADIV))
+               shift = PM_BFEXT(PBASEL, cksel) + 1;
+
+       return bus_clk_get_rate(clk, shift);
+}
+
+static void pbb_clk_mode(struct clk *clk, int enabled)
+{
+       unsigned long flags;
+       u32 mask;
+
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(PBB_MASK);
+       if (enabled)
+               mask |= 1 << clk->index;
+       else
+               mask &= ~(1 << clk->index);
+       pm_writel(PBB_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long pbb_clk_get_rate(struct clk *clk)
+{
+       unsigned long cksel, shift = 0;
+
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(PBBDIV))
+               shift = PM_BFEXT(PBBSEL, cksel) + 1;
+
+       return bus_clk_get_rate(clk, shift);
+}
+
+static struct clk cpu_clk = {
+       .name           = "cpu",
+       .get_rate       = cpu_clk_get_rate,
+       .set_rate       = cpu_clk_set_rate,
+       .users          = 1,
+};
+static struct clk hsb_clk = {
+       .name           = "hsb",
+       .parent         = &cpu_clk,
+       .get_rate       = hsb_clk_get_rate,
+};
+static struct clk pba_clk = {
+       .name           = "pba",
+       .parent         = &hsb_clk,
+       .mode           = hsb_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 1,
+};
+static struct clk pbb_clk = {
+       .name           = "pbb",
+       .parent         = &hsb_clk,
+       .mode           = hsb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 2,
+};
+
+/* --------------------------------------------------------------------
+ *  Generic Clock operations
+ * -------------------------------------------------------------------- */
+
+static void genclk_mode(struct clk *clk, int enabled)
+{
+       u32 control;
+
+       control = pm_readl(GCCTRL(clk->index));
+       if (enabled)
+               control |= PM_BIT(CEN);
+       else
+               control &= ~PM_BIT(CEN);
+       pm_writel(GCCTRL(clk->index), control);
+}
+
+static unsigned long genclk_get_rate(struct clk *clk)
+{
+       u32 control;
+       unsigned long div = 1;
+
+       control = pm_readl(GCCTRL(clk->index));
+       if (control & PM_BIT(DIVEN))
+               div = 2 * (PM_BFEXT(DIV, control) + 1);
+
+       return clk->parent->get_rate(clk->parent) / div;
+}
+
+static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+       u32 control;
+       unsigned long parent_rate, actual_rate, div;
+
+       parent_rate = clk->parent->get_rate(clk->parent);
+       control = pm_readl(GCCTRL(clk->index));
+
+       if (rate > 3 * parent_rate / 4) {
+               actual_rate = parent_rate;
+               control &= ~PM_BIT(DIVEN);
+       } else {
+               div = (parent_rate + rate) / (2 * rate) - 1;
+               control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
+               actual_rate = parent_rate / (2 * (div + 1));
+       }
+
+       dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+               clk->name, rate, actual_rate);
+
+       if (apply)
+               pm_writel(GCCTRL(clk->index), control);
+
+       return actual_rate;
+}
+
+int genclk_set_parent(struct clk *clk, struct clk *parent)
+{
+       u32 control;
+
+       dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+               clk->name, parent->name, clk->parent->name);
+
+       control = pm_readl(GCCTRL(clk->index));
+
+       if (parent == &osc1 || parent == &pll1)
+               control |= PM_BIT(OSCSEL);
+       else if (parent == &osc0 || parent == &pll0)
+               control &= ~PM_BIT(OSCSEL);
+       else
+               return -EINVAL;
+
+       if (parent == &pll0 || parent == &pll1)
+               control |= PM_BIT(PLLSEL);
+       else
+               control &= ~PM_BIT(PLLSEL);
+
+       pm_writel(GCCTRL(clk->index), control);
+       clk->parent = parent;
+
+       return 0;
+}
+
+static void __init genclk_init_parent(struct clk *clk)
+{
+       u32 control;
+       struct clk *parent;
+
+       BUG_ON(clk->index > 7);
+
+       control = pm_readl(GCCTRL(clk->index));
+       if (control & PM_BIT(OSCSEL))
+               parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
+       else
+               parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
+
+       clk->parent = parent;
+}
+
+/* --------------------------------------------------------------------
+ *  System peripherals
+ * -------------------------------------------------------------------- */
+static struct resource at32_pm0_resource[] = {
+       {
+               .start  = 0xfff00000,
+               .end    = 0xfff0007f,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(20),
+};
+
+static struct resource at32ap700x_rtc0_resource[] = {
+       {
+               .start  = 0xfff00080,
+               .end    = 0xfff000af,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(21),
+};
+
+static struct resource at32_wdt0_resource[] = {
+       {
+               .start  = 0xfff000b0,
+               .end    = 0xfff000cf,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct resource at32_eic0_resource[] = {
+       {
+               .start  = 0xfff00100,
+               .end    = 0xfff0013f,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(19),
+};
+
+DEFINE_DEV(at32_pm, 0);
+DEFINE_DEV(at32ap700x_rtc, 0);
+DEFINE_DEV(at32_wdt, 0);
+DEFINE_DEV(at32_eic, 0);
+
+/*
+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+ * is always running.
+ */
+static struct clk at32_pm_pclk = {
+       .name           = "pclk",
+       .dev            = &at32_pm0_device.dev,
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 0,
+};
+
+static struct resource intc0_resource[] = {
+       PBMEM(0xfff00400),
+};
+struct platform_device at32_intc0_device = {
+       .name           = "intc",
+       .id             = 0,
+       .resource       = intc0_resource,
+       .num_resources  = ARRAY_SIZE(intc0_resource),
+};
+DEV_CLK(pclk, at32_intc0, pbb, 1);
+
+static struct clk ebi_clk = {
+       .name           = "ebi",
+       .parent         = &hsb_clk,
+       .mode           = hsb_clk_mode,
+       .get_rate       = hsb_clk_get_rate,
+       .users          = 1,
+};
+static struct clk hramc_clk = {
+       .name           = "hramc",
+       .parent         = &hsb_clk,
+       .mode           = hsb_clk_mode,
+       .get_rate       = hsb_clk_get_rate,
+       .users          = 1,
+       .index          = 3,
+};
+
+static struct resource smc0_resource[] = {
+       PBMEM(0xfff03400),
+};
+DEFINE_DEV(smc, 0);
+DEV_CLK(pclk, smc0, pbb, 13);
+DEV_CLK(mck, smc0, hsb, 0);
+
+static struct platform_device pdc_device = {
+       .name           = "pdc",
+       .id             = 0,
+};
+DEV_CLK(hclk, pdc, hsb, 4);
+DEV_CLK(pclk, pdc, pba, 16);
+
+static struct clk pico_clk = {
+       .name           = "pico",
+       .parent         = &cpu_clk,
+       .mode           = cpu_clk_mode,
+       .get_rate       = cpu_clk_get_rate,
+       .users          = 1,
+};
+
+static struct resource dmaca0_resource[] = {
+       {
+               .start  = 0xff200000,
+               .end    = 0xff20ffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(2),
+};
+DEFINE_DEV(dmaca, 0);
+DEV_CLK(hclk, dmaca0, hsb, 10);
+
+/* --------------------------------------------------------------------
+ * HMATRIX
+ * -------------------------------------------------------------------- */
+
+static struct clk hmatrix_clk = {
+       .name           = "hmatrix_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 2,
+       .users          = 1,
+};
+#define HMATRIX_BASE   ((void __iomem *)0xfff00800)
+
+#define hmatrix_readl(reg)                                     \
+       __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+#define hmatrix_writel(reg,value)                              \
+       __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+
+/*
+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
+ * External Bus Interface (EBI). This can be used to enable special
+ * features like CompactFlash support, NAND Flash support, etc. on
+ * certain chipselects.
+ */
+static inline void set_ebi_sfr_bits(u32 mask)
+{
+       u32 sfr;
+
+       clk_enable(&hmatrix_clk);
+       sfr = hmatrix_readl(SFR4);
+       sfr |= mask;
+       hmatrix_writel(SFR4, sfr);
+       clk_disable(&hmatrix_clk);
+}
+
+/* --------------------------------------------------------------------
+ *  System Timer/Counter (TC)
+ * -------------------------------------------------------------------- */
+static struct resource at32_systc0_resource[] = {
+       PBMEM(0xfff00c00),
+       IRQ(22),
+};
+struct platform_device at32_systc0_device = {
+       .name           = "systc",
+       .id             = 0,
+       .resource       = at32_systc0_resource,
+       .num_resources  = ARRAY_SIZE(at32_systc0_resource),
+};
+DEV_CLK(pclk, at32_systc0, pbb, 3);
+
+/* --------------------------------------------------------------------
+ *  PIO
+ * -------------------------------------------------------------------- */
+
+static struct resource pio0_resource[] = {
+       PBMEM(0xffe02800),
+       IRQ(13),
+};
+DEFINE_DEV(pio, 0);
+DEV_CLK(mck, pio0, pba, 10);
+
+static struct resource pio1_resource[] = {
+       PBMEM(0xffe02c00),
+       IRQ(14),
+};
+DEFINE_DEV(pio, 1);
+DEV_CLK(mck, pio1, pba, 11);
+
+static struct resource pio2_resource[] = {
+       PBMEM(0xffe03000),
+       IRQ(15),
+};
+DEFINE_DEV(pio, 2);
+DEV_CLK(mck, pio2, pba, 12);
+
+static struct resource pio3_resource[] = {
+       PBMEM(0xffe03400),
+       IRQ(16),
+};
+DEFINE_DEV(pio, 3);
+DEV_CLK(mck, pio3, pba, 13);
+
+static struct resource pio4_resource[] = {
+       PBMEM(0xffe03800),
+       IRQ(17),
+};
+DEFINE_DEV(pio, 4);
+DEV_CLK(mck, pio4, pba, 14);
+
+void __init at32_add_system_devices(void)
+{
+       platform_device_register(&at32_pm0_device);
+       platform_device_register(&at32_intc0_device);
+       platform_device_register(&at32ap700x_rtc0_device);
+       platform_device_register(&at32_wdt0_device);
+       platform_device_register(&at32_eic0_device);
+       platform_device_register(&smc0_device);
+       platform_device_register(&pdc_device);
+       platform_device_register(&dmaca0_device);
+
+       platform_device_register(&at32_systc0_device);
+
+       platform_device_register(&pio0_device);
+       platform_device_register(&pio1_device);
+       platform_device_register(&pio2_device);
+       platform_device_register(&pio3_device);
+       platform_device_register(&pio4_device);
+}
+
+/* --------------------------------------------------------------------
+ *  USART
+ * -------------------------------------------------------------------- */
+
+static struct atmel_uart_data atmel_usart0_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+static struct resource atmel_usart0_resource[] = {
+       PBMEM(0xffe00c00),
+       IRQ(6),
+};
+DEFINE_DEV_DATA(atmel_usart, 0);
+DEV_CLK(usart, atmel_usart0, pba, 3);
+
+static struct atmel_uart_data atmel_usart1_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+static struct resource atmel_usart1_resource[] = {
+       PBMEM(0xffe01000),
+       IRQ(7),
+};
+DEFINE_DEV_DATA(atmel_usart, 1);
+DEV_CLK(usart, atmel_usart1, pba, 4);
+
+static struct atmel_uart_data atmel_usart2_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+static struct resource atmel_usart2_resource[] = {
+       PBMEM(0xffe01400),
+       IRQ(8),
+};
+DEFINE_DEV_DATA(atmel_usart, 2);
+DEV_CLK(usart, atmel_usart2, pba, 5);
+
+static struct atmel_uart_data atmel_usart3_data = {
+       .use_dma_tx     = 1,
+       .use_dma_rx     = 1,
+};
+static struct resource atmel_usart3_resource[] = {
+       PBMEM(0xffe01800),
+       IRQ(9),
+};
+DEFINE_DEV_DATA(atmel_usart, 3);
+DEV_CLK(usart, atmel_usart3, pba, 6);
+
+static inline void configure_usart0_pins(void)
+{
+       select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
+       select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
+}
+
+static inline void configure_usart1_pins(void)
+{
+       select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
+       select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
+}
+
+static inline void configure_usart2_pins(void)
+{
+       select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
+       select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
+}
+
+static inline void configure_usart3_pins(void)
+{
+       select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
+       select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
+}
+
+static struct platform_device *__initdata at32_usarts[4];
+
+void __init at32_map_usart(unsigned int hw_id, unsigned int line)
+{
+       struct platform_device *pdev;
+
+       switch (hw_id) {
+       case 0:
+               pdev = &atmel_usart0_device;
+               configure_usart0_pins();
+               break;
+       case 1:
+               pdev = &atmel_usart1_device;
+               configure_usart1_pins();
+               break;
+       case 2:
+               pdev = &atmel_usart2_device;
+               configure_usart2_pins();
+               break;
+       case 3:
+               pdev = &atmel_usart3_device;
+               configure_usart3_pins();
+               break;
+       default:
+               return;
+       }
+
+       if (PXSEG(pdev->resource[0].start) == P4SEG) {
+               /* Addresses in the P4 segment are permanently mapped 1:1 */
+               struct atmel_uart_data *data = pdev->dev.platform_data;
+               data->regs = (void __iomem *)pdev->resource[0].start;
+       }
+
+       pdev->id = line;
+       at32_usarts[line] = pdev;
+}
+
+struct platform_device *__init at32_add_device_usart(unsigned int id)
+{
+       platform_device_register(at32_usarts[id]);
+       return at32_usarts[id];
+}
+
+struct platform_device *atmel_default_console_device;
+
+void __init at32_setup_serial_console(unsigned int usart_id)
+{
+       atmel_default_console_device = at32_usarts[usart_id];
+}
+
+/* --------------------------------------------------------------------
+ *  Ethernet
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_CPU_AT32AP7000
+static struct eth_platform_data macb0_data;
+static struct resource macb0_resource[] = {
+       PBMEM(0xfff01800),
+       IRQ(25),
+};
+DEFINE_DEV_DATA(macb, 0);
+DEV_CLK(hclk, macb0, hsb, 8);
+DEV_CLK(pclk, macb0, pbb, 6);
+
+static struct eth_platform_data macb1_data;
+static struct resource macb1_resource[] = {
+       PBMEM(0xfff01c00),
+       IRQ(26),
+};
+DEFINE_DEV_DATA(macb, 1);
+DEV_CLK(hclk, macb1, hsb, 9);
+DEV_CLK(pclk, macb1, pbb, 7);
+
+struct platform_device *__init
+at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
+{
+       struct platform_device *pdev;
+
+       switch (id) {
+       case 0:
+               pdev = &macb0_device;
+
+               select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
+               select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
+               select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
+               select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
+               select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
+               select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
+               select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
+               select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
+               select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
+               select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+
+               if (!data->is_rmii) {
+                       select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
+                       select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
+                       select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
+                       select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
+                       select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
+                       select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
+                       select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
+                       select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
+                       select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
+               }
+               break;
+
+       case 1:
+               pdev = &macb1_device;
+
+               select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
+               select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
+               select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
+               select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
+               select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
+               select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
+               select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
+               select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
+               select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
+               select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
+
+               if (!data->is_rmii) {
+                       select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
+                       select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
+                       select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
+                       select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
+                       select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
+                       select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
+                       select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
+                       select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
+                       select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
+               }
+               break;
+
+       default:
+               return NULL;
+       }
+
+       memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
+       platform_device_register(pdev);
+
+       return pdev;
+}
+#endif
+
+/* --------------------------------------------------------------------
+ *  SPI
+ * -------------------------------------------------------------------- */
+static struct resource atmel_spi0_resource[] = {
+       PBMEM(0xffe00000),
+       IRQ(3),
+};
+DEFINE_DEV(atmel_spi, 0);
+DEV_CLK(spi_clk, atmel_spi0, pba, 0);
+
+static struct resource atmel_spi1_resource[] = {
+       PBMEM(0xffe00400),
+       IRQ(4),
+};
+DEFINE_DEV(atmel_spi, 1);
+DEV_CLK(spi_clk, atmel_spi1, pba, 1);
+
+static void __init
+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
+                     unsigned int n, const u8 *pins)
+{
+       unsigned int pin, mode;
+
+       for (; n; n--, b++) {
+               b->bus_num = bus_num;
+               if (b->chip_select >= 4)
+                       continue;
+               pin = (unsigned)b->controller_data;
+               if (!pin) {
+                       pin = pins[b->chip_select];
+                       b->controller_data = (void *)pin;
+               }
+               mode = AT32_GPIOF_OUTPUT;
+               if (!(b->mode & SPI_CS_HIGH))
+                       mode |= AT32_GPIOF_HIGH;
+               at32_select_gpio(pin, mode);
+       }
+}
+
+struct platform_device *__init
+at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
+{
+       /*
+        * Manage the chipselects as GPIOs, normally using the same pins
+        * the SPI controller expects; but boards can use other pins.
+        */
+       static u8 __initdata spi0_pins[] =
+               { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
+                 GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
+       static u8 __initdata spi1_pins[] =
+               { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
+                 GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
+       struct platform_device *pdev;
+
+       switch (id) {
+       case 0:
+               pdev = &atmel_spi0_device;
+               select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
+               select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
+               select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
+               at32_spi_setup_slaves(0, b, n, spi0_pins);
+               break;
+
+       case 1:
+               pdev = &atmel_spi1_device;
+               select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
+               select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
+               select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
+               at32_spi_setup_slaves(1, b, n, spi1_pins);
+               break;
+
+       default:
+               return NULL;
+       }
+
+       spi_register_board_info(b, n);
+       platform_device_register(pdev);
+       return pdev;
+}
+
+/* --------------------------------------------------------------------
+ *  TWI
+ * -------------------------------------------------------------------- */
+static struct resource atmel_twi0_resource[] __initdata = {
+       PBMEM(0xffe00800),
+       IRQ(5),
+};
+static struct clk atmel_twi0_pclk = {
+       .name           = "twi_pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 2,
+};
+
+struct platform_device *__init at32_add_device_twi(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_twi", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, atmel_twi0_resource,
+                               ARRAY_SIZE(atmel_twi0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
+       select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
+
+       atmel_twi0_pclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * MMC
+ * -------------------------------------------------------------------- */
+static struct resource atmel_mci0_resource[] __initdata = {
+       PBMEM(0xfff02400),
+       IRQ(28),
+};
+static struct clk atmel_mci0_pclk = {
+       .name           = "mci_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 9,
+};
+
+struct platform_device *__init at32_add_device_mci(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_mci", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, atmel_mci0_resource,
+                               ARRAY_SIZE(atmel_mci0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
+       select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
+       select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
+       select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
+       select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
+       select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+
+       atmel_mci0_pclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ *  LCDC
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
+static struct atmel_lcdfb_info atmel_lcdfb0_data;
+static struct resource atmel_lcdfb0_resource[] = {
+       {
+               .start          = 0xff000000,
+               .end            = 0xff000fff,
+               .flags          = IORESOURCE_MEM,
+       },
+       IRQ(1),
+       {
+               /* Placeholder for pre-allocated fb memory */
+               .start          = 0x00000000,
+               .end            = 0x00000000,
+               .flags          = 0,
+       },
+};
+DEFINE_DEV_DATA(atmel_lcdfb, 0);
+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
+static struct clk atmel_lcdfb0_pixclk = {
+       .name           = "lcdc_clk",
+       .dev            = &atmel_lcdfb0_device.dev,
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 7,
+};
+
+struct platform_device *__init
+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+                    unsigned long fbmem_start, unsigned long fbmem_len)
+{
+       struct platform_device *pdev;
+       struct atmel_lcdfb_info *info;
+       struct fb_monspecs *monspecs;
+       struct fb_videomode *modedb;
+       unsigned int modedb_size;
+
+       /*
+        * Do a deep copy of the fb data, monspecs and modedb. Make
+        * sure all allocations are done before setting up the
+        * portmux.
+        */
+       monspecs = kmemdup(data->default_monspecs,
+                          sizeof(struct fb_monspecs), GFP_KERNEL);
+       if (!monspecs)
+               return NULL;
+
+       modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
+       modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
+       if (!modedb)
+               goto err_dup_modedb;
+       monspecs->modedb = modedb;
+
+       switch (id) {
+       case 0:
+               pdev = &atmel_lcdfb0_device;
+               select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
+               select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+               select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+               select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+               select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
+               select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
+               select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+               select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
+               select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
+               select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
+               select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
+               select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
+               select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+               select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+               select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+               select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
+               select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
+               select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
+               select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
+               select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
+               select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+               select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+               select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+               select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+               select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+               select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+               select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+               select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+               select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+               select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+               select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+
+               clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
+               clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
+               break;
+
+       default:
+               goto err_invalid_id;
+       }
+
+       if (fbmem_len) {
+               pdev->resource[2].start = fbmem_start;
+               pdev->resource[2].end = fbmem_start + fbmem_len - 1;
+               pdev->resource[2].flags = IORESOURCE_MEM;
+       }
+
+       info = pdev->dev.platform_data;
+       memcpy(info, data, sizeof(struct atmel_lcdfb_info));
+       info->default_monspecs = monspecs;
+
+       platform_device_register(pdev);
+       return pdev;
+
+err_invalid_id:
+       kfree(modedb);
+err_dup_modedb:
+       kfree(monspecs);
+       return NULL;
+}
+#endif
+
+/* --------------------------------------------------------------------
+ *  SSC
+ * -------------------------------------------------------------------- */
+static struct resource ssc0_resource[] = {
+       PBMEM(0xffe01c00),
+       IRQ(10),
+};
+DEFINE_DEV(ssc, 0);
+DEV_CLK(pclk, ssc0, pba, 7);
+
+static struct resource ssc1_resource[] = {
+       PBMEM(0xffe02000),
+       IRQ(11),
+};
+DEFINE_DEV(ssc, 1);
+DEV_CLK(pclk, ssc1, pba, 8);
+
+static struct resource ssc2_resource[] = {
+       PBMEM(0xffe02400),
+       IRQ(12),
+};
+DEFINE_DEV(ssc, 2);
+DEV_CLK(pclk, ssc2, pba, 9);
+
+struct platform_device *__init
+at32_add_device_ssc(unsigned int id, unsigned int flags)
+{
+       struct platform_device *pdev;
+
+       switch (id) {
+       case 0:
+               pdev = &ssc0_device;
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+               break;
+       case 1:
+               pdev = &ssc1_device;
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
+               break;
+       case 2:
+               pdev = &ssc2_device;
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+               break;
+       default:
+               return NULL;
+       }
+
+       platform_device_register(pdev);
+       return pdev;
+}
+
+/* --------------------------------------------------------------------
+ *  USB Device Controller
+ * -------------------------------------------------------------------- */
+static struct resource usba0_resource[] __initdata = {
+       {
+               .start          = 0xff300000,
+               .end            = 0xff3fffff,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = 0xfff03000,
+               .end            = 0xfff033ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       IRQ(31),
+};
+static struct clk usba0_pclk = {
+       .name           = "pclk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 12,
+};
+static struct clk usba0_hclk = {
+       .name           = "hclk",
+       .parent         = &hsb_clk,
+       .mode           = hsb_clk_mode,
+       .get_rate       = hsb_clk_get_rate,
+       .index          = 6,
+};
+
+struct platform_device *__init
+at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_usba_udc", 0);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, usba0_resource,
+                                         ARRAY_SIZE(usba0_resource)))
+               goto out_free_pdev;
+
+       if (data) {
+               if (platform_device_add_data(pdev, data, sizeof(*data)))
+                       goto out_free_pdev;
+
+               if (data->vbus_pin != GPIO_PIN_NONE)
+                       at32_select_gpio(data->vbus_pin, 0);
+       }
+
+       usba0_pclk.dev = &pdev->dev;
+       usba0_hclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+
+       return pdev;
+
+out_free_pdev:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * IDE / CompactFlash
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7001)
+static struct resource at32_smc_cs4_resource[] __initdata = {
+       {
+               .start  = 0x04000000,
+               .end    = 0x07ffffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(~0UL), /* Magic IRQ will be overridden */
+};
+static struct resource at32_smc_cs5_resource[] __initdata = {
+       {
+               .start  = 0x20000000,
+               .end    = 0x23ffffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(~0UL), /* Magic IRQ will be overridden */
+};
+
+static int __init at32_init_ide_or_cf(struct platform_device *pdev,
+               unsigned int cs, unsigned int extint)
+{
+       static unsigned int extint_pin_map[4] __initdata = {
+               GPIO_PIN_PB(25),
+               GPIO_PIN_PB(26),
+               GPIO_PIN_PB(27),
+               GPIO_PIN_PB(28),
+       };
+       static bool common_pins_initialized __initdata = false;
+       unsigned int extint_pin;
+       int ret;
+
+       if (extint >= ARRAY_SIZE(extint_pin_map))
+               return -EINVAL;
+       extint_pin = extint_pin_map[extint];
+
+       switch (cs) {
+       case 4:
+               ret = platform_device_add_resources(pdev,
+                               at32_smc_cs4_resource,
+                               ARRAY_SIZE(at32_smc_cs4_resource));
+               if (ret)
+                       return ret;
+
+               select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+               set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
+               break;
+       case 5:
+               ret = platform_device_add_resources(pdev,
+                               at32_smc_cs5_resource,
+                               ARRAY_SIZE(at32_smc_cs5_resource));
+               if (ret)
+                       return ret;
+
+               select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+               set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!common_pins_initialized) {
+               select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
+               select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
+               select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
+               select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
+               common_pins_initialized = true;
+       }
+
+       at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+
+       pdev->resource[1].start = EIM_IRQ_BASE + extint;
+       pdev->resource[1].end = pdev->resource[1].start;
+
+       return 0;
+}
+
+struct platform_device *__init
+at32_add_device_ide(unsigned int id, unsigned int extint,
+                   struct ide_platform_data *data)
+{
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc("at32_ide", id);
+       if (!pdev)
+               goto fail;
+
+       if (platform_device_add_data(pdev, data,
+                               sizeof(struct ide_platform_data)))
+               goto fail;
+
+       if (at32_init_ide_or_cf(pdev, data->cs, extint))
+               goto fail;
+
+       platform_device_add(pdev);
+       return pdev;
+
+fail:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+struct platform_device *__init
+at32_add_device_cf(unsigned int id, unsigned int extint,
+                   struct cf_platform_data *data)
+{
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc("at32_cf", id);
+       if (!pdev)
+               goto fail;
+
+       if (platform_device_add_data(pdev, data,
+                               sizeof(struct cf_platform_data)))
+               goto fail;
+
+       if (at32_init_ide_or_cf(pdev, data->cs, extint))
+               goto fail;
+
+       if (data->detect_pin != GPIO_PIN_NONE)
+               at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
+       if (data->reset_pin != GPIO_PIN_NONE)
+               at32_select_gpio(data->reset_pin, 0);
+       if (data->vcc_pin != GPIO_PIN_NONE)
+               at32_select_gpio(data->vcc_pin, 0);
+       /* READY is used as extint, so we can't select it as gpio */
+
+       platform_device_add(pdev);
+       return pdev;
+
+fail:
+       platform_device_put(pdev);
+       return NULL;
+}
+#endif
+
+/* --------------------------------------------------------------------
+ * AC97C
+ * -------------------------------------------------------------------- */
+static struct resource atmel_ac97c0_resource[] __initdata = {
+       PBMEM(0xfff02800),
+       IRQ(29),
+};
+static struct clk atmel_ac97c0_pclk = {
+       .name           = "pclk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 10,
+};
+
+struct platform_device *__init at32_add_device_ac97c(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_ac97c", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
+                               ARRAY_SIZE(atmel_ac97c0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
+       select_peripheral(PB(21), PERIPH_B, 0); /* SDO  */
+       select_peripheral(PB(22), PERIPH_B, 0); /* SDI  */
+       select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
+
+       atmel_ac97c0_pclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * ABDAC
+ * -------------------------------------------------------------------- */
+static struct resource abdac0_resource[] __initdata = {
+       PBMEM(0xfff02000),
+       IRQ(27),
+};
+static struct clk abdac0_pclk = {
+       .name           = "pclk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 8,
+};
+static struct clk abdac0_sample_clk = {
+       .name           = "sample_clk",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 6,
+};
+
+struct platform_device *__init at32_add_device_abdac(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("abdac", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, abdac0_resource,
+                               ARRAY_SIZE(abdac0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
+       select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
+       select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
+       select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
+
+       abdac0_pclk.dev = &pdev->dev;
+       abdac0_sample_clk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ *  GCLK
+ * -------------------------------------------------------------------- */
+static struct clk gclk0 = {
+       .name           = "gclk0",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 0,
+};
+static struct clk gclk1 = {
+       .name           = "gclk1",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 1,
+};
+static struct clk gclk2 = {
+       .name           = "gclk2",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 2,
+};
+static struct clk gclk3 = {
+       .name           = "gclk3",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 3,
+};
+static struct clk gclk4 = {
+       .name           = "gclk4",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 4,
+};
+
+struct clk *at32_clock_list[] = {
+       &osc32k,
+       &osc0,
+       &osc1,
+       &pll0,
+       &pll1,
+       &cpu_clk,
+       &hsb_clk,
+       &pba_clk,
+       &pbb_clk,
+       &at32_pm_pclk,
+       &at32_intc0_pclk,
+       &hmatrix_clk,
+       &ebi_clk,
+       &hramc_clk,
+       &smc0_pclk,
+       &smc0_mck,
+       &pdc_hclk,
+       &pdc_pclk,
+       &dmaca0_hclk,
+       &pico_clk,
+       &pio0_mck,
+       &pio1_mck,
+       &pio2_mck,
+       &pio3_mck,
+       &pio4_mck,
+       &at32_systc0_pclk,
+       &atmel_usart0_usart,
+       &atmel_usart1_usart,
+       &atmel_usart2_usart,
+       &atmel_usart3_usart,
+#if defined(CONFIG_CPU_AT32AP7000)
+       &macb0_hclk,
+       &macb0_pclk,
+       &macb1_hclk,
+       &macb1_pclk,
+#endif
+       &atmel_spi0_spi_clk,
+       &atmel_spi1_spi_clk,
+       &atmel_twi0_pclk,
+       &atmel_mci0_pclk,
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
+       &atmel_lcdfb0_hck1,
+       &atmel_lcdfb0_pixclk,
+#endif
+       &ssc0_pclk,
+       &ssc1_pclk,
+       &ssc2_pclk,
+       &usba0_hclk,
+       &usba0_pclk,
+       &atmel_ac97c0_pclk,
+       &abdac0_pclk,
+       &abdac0_sample_clk,
+       &gclk0,
+       &gclk1,
+       &gclk2,
+       &gclk3,
+       &gclk4,
+};
+unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
+
+void __init at32_portmux_init(void)
+{
+       at32_init_pio(&pio0_device);
+       at32_init_pio(&pio1_device);
+       at32_init_pio(&pio2_device);
+       at32_init_pio(&pio3_device);
+       at32_init_pio(&pio4_device);
+}
+
+void __init at32_clock_init(void)
+{
+       u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
+       int i;
+
+       if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
+               main_clock = &pll0;
+               cpu_clk.parent = &pll0;
+       } else {
+               main_clock = &osc0;
+               cpu_clk.parent = &osc0;
+       }
+
+       if (pm_readl(PLL0) & PM_BIT(PLLOSC))
+               pll0.parent = &osc1;
+       if (pm_readl(PLL1) & PM_BIT(PLLOSC))
+               pll1.parent = &osc1;
+
+       genclk_init_parent(&gclk0);
+       genclk_init_parent(&gclk1);
+       genclk_init_parent(&gclk2);
+       genclk_init_parent(&gclk3);
+       genclk_init_parent(&gclk4);
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
+       genclk_init_parent(&atmel_lcdfb0_pixclk);
+#endif
+       genclk_init_parent(&abdac0_sample_clk);
+
+       /*
+        * Turn on all clocks that have at least one user already, and
+        * turn off everything else. We only do this for module
+        * clocks, and even though it isn't particularly pretty to
+        * check the address of the mode function, it should do the
+        * trick...
+        */
+       for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
+               struct clk *clk = at32_clock_list[i];
+
+               if (clk->users == 0)
+                       continue;
+
+               if (clk->mode == &cpu_clk_mode)
+                       cpu_mask |= 1 << clk->index;
+               else if (clk->mode == &hsb_clk_mode)
+                       hsb_mask |= 1 << clk->index;
+               else if (clk->mode == &pba_clk_mode)
+                       pba_mask |= 1 << clk->index;
+               else if (clk->mode == &pbb_clk_mode)
+                       pbb_mask |= 1 << clk->index;
+       }
+
+       pm_writel(CPU_MASK, cpu_mask);
+       pm_writel(HSB_MASK, hsb_mask);
+       pm_writel(PBA_MASK, pba_mask);
+       pm_writel(PBB_MASK, pbb_mask);
+}
index f5bfd4c81fe70b883fdd620fdd5796fdb41328e3..c36a6d59d6f0785e900a7e905189e577bd4693bc 100644 (file)
 #define EIC_MODE                               0x0014
 #define EIC_EDGE                               0x0018
 #define EIC_LEVEL                              0x001c
-#define EIC_TEST                               0x0020
 #define EIC_NMIC                               0x0024
 
-/* Bitfields in TEST */
-#define EIC_TESTEN_OFFSET                      31
-#define EIC_TESTEN_SIZE                                1
-
 /* Bitfields in NMIC */
-#define EIC_EN_OFFSET                          0
-#define EIC_EN_SIZE                            1
+#define EIC_NMIC_ENABLE                                (1 << 0)
 
 /* Bit manipulation macros */
 #define EIC_BIT(name)                                  \
@@ -63,6 +57,9 @@ struct eic {
        unsigned int first_irq;
 };
 
+static struct eic *nmi_eic;
+static bool nmi_enabled;
+
 static void eic_ack_irq(unsigned int irq)
 {
        struct eic *eic = get_irq_chip_data(irq);
@@ -133,8 +130,11 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
                eic_writel(eic, EDGE, edge);
                eic_writel(eic, LEVEL, level);
 
-               if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+               if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
                        flow_type |= IRQ_LEVEL;
+                       __set_irq_handler_unlocked(irq, handle_level_irq);
+               } else
+                       __set_irq_handler_unlocked(irq, handle_edge_irq);
                desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
                desc->status |= flow_type;
        }
@@ -154,9 +154,8 @@ static struct irq_chip eic_chip = {
 static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
 {
        struct eic *eic = desc->handler_data;
-       struct irq_desc *ext_desc;
        unsigned long status, pending;
-       unsigned int i, ext_irq;
+       unsigned int i;
 
        status = eic_readl(eic, ISR);
        pending = status & eic_readl(eic, IMR);
@@ -165,15 +164,28 @@ static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
                i = fls(pending) - 1;
                pending &= ~(1 << i);
 
-               ext_irq = i + eic->first_irq;
-               ext_desc = irq_desc + ext_irq;
-               if (ext_desc->status & IRQ_LEVEL)
-                       handle_level_irq(ext_irq, ext_desc);
-               else
-                       handle_edge_irq(ext_irq, ext_desc);
+               generic_handle_irq(i + eic->first_irq);
        }
 }
 
+int nmi_enable(void)
+{
+       nmi_enabled = true;
+
+       if (nmi_eic)
+               eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
+
+       return 0;
+}
+
+void nmi_disable(void)
+{
+       if (nmi_eic)
+               eic_writel(nmi_eic, NMIC, 0);
+
+       nmi_enabled = false;
+}
+
 static int __init eic_probe(struct platform_device *pdev)
 {
        struct eic *eic;
@@ -214,14 +226,13 @@ static int __init eic_probe(struct platform_device *pdev)
        pattern = eic_readl(eic, MODE);
        nr_irqs = fls(pattern);
 
-       /* Trigger on falling edge unless overridden by driver */
-       eic_writel(eic, MODE, 0UL);
+       /* Trigger on low level unless overridden by driver */
        eic_writel(eic, EDGE, 0UL);
+       eic_writel(eic, LEVEL, 0UL);
 
        eic->chip = &eic_chip;
 
        for (i = 0; i < nr_irqs; i++) {
-               /* NOTE the handler we set here is ignored by the demux */
                set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
                                         handle_level_irq);
                set_irq_chip_data(eic->first_irq + i, eic);
@@ -230,6 +241,16 @@ static int __init eic_probe(struct platform_device *pdev)
        set_irq_chained_handler(int_irq, demux_eic_irq);
        set_irq_data(int_irq, eic);
 
+       if (pdev->id == 0) {
+               nmi_eic = eic;
+               if (nmi_enabled)
+                       /*
+                        * Someone tried to enable NMI before we were
+                        * ready. Do it now.
+                        */
+                       nmi_enable();
+       }
+
        dev_info(&pdev->dev,
                 "External Interrupt Controller at 0x%p, IRQ %u\n",
                 eic->regs, int_irq);
index 177fea8f7b711e90d87e208db5f9d36adaef3be6..6d8c794c3b81bbd528f170c9dba7fa46e50c525c 100644 (file)
@@ -41,6 +41,13 @@ static struct page *__dma_alloc(struct device *dev, size_t size,
        struct page *page, *free, *end;
        int order;
 
+       /* Following is a work-around (a.k.a. hack) to prevent pages
+        * with __GFP_COMP being passed to split_page() which cannot
+        * handle them.  The real problem is that this flag probably
+        * should be 0 on AVR32 as it is not supported on this
+        * platform--see CONFIG_HUGETLB_PAGE. */
+       gfp &= ~(__GFP_COMP);
+
        size = PAGE_ALIGN(size);
        order = get_order(size);
 
index 56672018e42f2e25c62240556693842e45ee3cc0..b835257a8fa39d88d794ad2667ef9f46a4e6028c 100644 (file)
@@ -348,7 +348,7 @@ static int tlb_show(struct seq_file *tlb, void *v)
        return 0;
 }
 
-static struct seq_operations tlb_ops = {
+static const struct seq_operations tlb_ops = {
        .start          = tlb_start,
        .next           = tlb_next,
        .stop           = tlb_stop,
diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
new file mode 100644 (file)
index 0000000..1fe81c3
--- /dev/null
@@ -0,0 +1,8 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+oprofile-y             := $(addprefix ../../../drivers/oprofile/,      \
+                               oprof.o cpu_buffer.o buffer_sync.o      \
+                               event_buffer.o oprofile_files.o         \
+                               oprofilefs.o oprofile_stats.o           \
+                               timer_int.o)
+oprofile-y             += op_model_avr32.o
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
new file mode 100644 (file)
index 0000000..e2f876b
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * AVR32 Performance Counter Driver
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * 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.
+ *
+ * Author: Ronny Pedersen
+ */
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include <asm/intc.h>
+#include <asm/sysreg.h>
+#include <asm/system.h>
+
+#define AVR32_PERFCTR_IRQ_GROUP        0
+#define AVR32_PERFCTR_IRQ_LINE 1
+
+enum { PCCNT, PCNT0, PCNT1, NR_counter };
+
+struct avr32_perf_counter {
+       unsigned long   enabled;
+       unsigned long   event;
+       unsigned long   count;
+       unsigned long   unit_mask;
+       unsigned long   kernel;
+       unsigned long   user;
+
+       u32             ie_mask;
+       u32             flag_mask;
+};
+
+static struct avr32_perf_counter counter[NR_counter] = {
+       {
+               .ie_mask        = SYSREG_BIT(IEC),
+               .flag_mask      = SYSREG_BIT(FC),
+       }, {
+               .ie_mask        = SYSREG_BIT(IE0),
+               .flag_mask      = SYSREG_BIT(F0),
+       }, {
+               .ie_mask        = SYSREG_BIT(IE1),
+               .flag_mask      = SYSREG_BIT(F1),
+       },
+};
+
+static void avr32_perf_counter_reset(void)
+{
+       /* Reset all counter and disable/clear all interrupts */
+       sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
+                               | SYSREG_BIT(PCCR_C)
+                               | SYSREG_BIT(FC)
+                               | SYSREG_BIT(F0)
+                               | SYSREG_BIT(F1)));
+}
+
+static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
+{
+       struct avr32_perf_counter *ctr = dev_id;
+       struct pt_regs *regs;
+       u32 pccr;
+
+       if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
+                                       & (1 << AVR32_PERFCTR_IRQ_LINE))))
+               return IRQ_NONE;
+
+       regs = get_irq_regs();
+       pccr = sysreg_read(PCCR);
+
+       /* Clear the interrupt flags we're about to handle */
+       sysreg_write(PCCR, pccr);
+
+       /* PCCNT */
+       if (ctr->enabled && (pccr & ctr->flag_mask)) {
+               sysreg_write(PCCNT, -ctr->count);
+               oprofile_add_sample(regs, PCCNT);
+       }
+       ctr++;
+       /* PCNT0 */
+       if (ctr->enabled && (pccr & ctr->flag_mask)) {
+               sysreg_write(PCNT0, -ctr->count);
+               oprofile_add_sample(regs, PCNT0);
+       }
+       ctr++;
+       /* PCNT1 */
+       if (ctr->enabled && (pccr & ctr->flag_mask)) {
+               sysreg_write(PCNT1, -ctr->count);
+               oprofile_add_sample(regs, PCNT1);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int avr32_perf_counter_create_files(struct super_block *sb,
+               struct dentry *root)
+{
+       struct dentry *dir;
+       unsigned int i;
+       char filename[4];
+
+       for (i = 0; i < NR_counter; i++) {
+               snprintf(filename, sizeof(filename), "%u", i);
+               dir = oprofilefs_mkdir(sb, root, filename);
+
+               oprofilefs_create_ulong(sb, dir, "enabled",
+                               &counter[i].enabled);
+               oprofilefs_create_ulong(sb, dir, "event",
+                               &counter[i].event);
+               oprofilefs_create_ulong(sb, dir, "count",
+                               &counter[i].count);
+
+               /* Dummy entries */
+               oprofilefs_create_ulong(sb, dir, "kernel",
+                               &counter[i].kernel);
+               oprofilefs_create_ulong(sb, dir, "user",
+                               &counter[i].user);
+               oprofilefs_create_ulong(sb, dir, "unit_mask",
+                               &counter[i].unit_mask);
+       }
+
+       return 0;
+}
+
+static int avr32_perf_counter_setup(void)
+{
+       struct avr32_perf_counter *ctr;
+       u32 pccr;
+       int ret;
+       int i;
+
+       pr_debug("avr32_perf_counter_setup\n");
+
+       if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
+               printk(KERN_ERR
+                       "oprofile: setup: perf counter already enabled\n");
+               return -EBUSY;
+       }
+
+       ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
+                       avr32_perf_counter_interrupt, IRQF_SHARED,
+                       "oprofile", counter);
+       if (ret)
+               return ret;
+
+       avr32_perf_counter_reset();
+
+       pccr = 0;
+       for (i = PCCNT; i < NR_counter; i++) {
+               ctr = &counter[i];
+               if (!ctr->enabled)
+                       continue;
+
+               pr_debug("enabling counter %d...\n", i);
+
+               pccr |= ctr->ie_mask;
+
+               switch (i) {
+               case PCCNT:
+                       /* PCCNT always counts cycles, so no events */
+                       sysreg_write(PCCNT, -ctr->count);
+                       break;
+               case PCNT0:
+                       pccr |= SYSREG_BF(CONF0, ctr->event);
+                       sysreg_write(PCNT0, -ctr->count);
+                       break;
+               case PCNT1:
+                       pccr |= SYSREG_BF(CONF1, ctr->event);
+                       sysreg_write(PCNT1, -ctr->count);
+                       break;
+               }
+       }
+
+       pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
+
+       sysreg_write(PCCR, pccr);
+
+       return 0;
+}
+
+static void avr32_perf_counter_shutdown(void)
+{
+       pr_debug("avr32_perf_counter_shutdown\n");
+
+       avr32_perf_counter_reset();
+       free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
+}
+
+static int avr32_perf_counter_start(void)
+{
+       pr_debug("avr32_perf_counter_start\n");
+
+       sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
+
+       return 0;
+}
+
+static void avr32_perf_counter_stop(void)
+{
+       pr_debug("avr32_perf_counter_stop\n");
+
+       sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
+}
+
+static struct oprofile_operations avr32_perf_counter_ops __initdata = {
+       .create_files   = avr32_perf_counter_create_files,
+       .setup          = avr32_perf_counter_setup,
+       .shutdown       = avr32_perf_counter_shutdown,
+       .start          = avr32_perf_counter_start,
+       .stop           = avr32_perf_counter_stop,
+       .cpu_type       = "avr32",
+};
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+       if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
+               return -ENODEV;
+
+       memcpy(ops, &avr32_perf_counter_ops,
+                       sizeof(struct oprofile_operations));
+
+       printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
+
+       return 0;
+}
+
+void oprofile_arch_exit(void)
+{
+
+}
index 2a3a7ea5958c004085e034bd5c9091a87ea751b3..25232ba081193fca739fcb9bb1fef89deb96795b 100644 (file)
@@ -65,6 +65,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config HARDWARE_PM
+       def_bool y
+       depends on OPROFILE
+
 source "init/Kconfig"
 source "kernel/Kconfig.preempt"
 
index 88eff7f54ea6cc17ab28e70b33155957ba3acdb1..1d1936a18133d36376186baea9a1d76434f408dc 100644 (file)
@@ -6,136 +6,9 @@
 *!
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init
 *!
-*! $Log: ds1302.c,v $
-*! Revision 1.18  2005/01/24 09:11:26  mikaelam
-*! Minor changes to get DS1302 RTC chip driver to work
-*!
-*! Revision 1.17  2005/01/05 06:11:22  starvik
-*! No need to do local_irq_disable after local_irq_save.
-*!
-*! Revision 1.16  2004/12/13 12:21:52  starvik
-*! Added I/O and DMA allocators from Linux 2.4
-*!
-*! Revision 1.14  2004/08/24 06:48:43  starvik
-*! Whitespace cleanup
-*!
-*! Revision 1.13  2004/05/28 09:26:59  starvik
-*! Modified I2C initialization to work in 2.6.
-*!
-*! Revision 1.12  2004/05/14 07:58:03  starvik
-*! Merge of changes from 2.4
-*!
-*! Revision 1.10  2004/02/04 09:25:12  starvik
-*! Merge of Linux 2.6.2
-*!
-*! Revision 1.9  2003/07/04 08:27:37  starvik
-*! Merge of Linux 2.5.74
-*!
-*! Revision 1.8  2003/04/09 05:20:47  starvik
-*! Merge of Linux 2.5.67
-*!
-*! Revision 1.6  2003/01/09 14:42:51  starvik
-*! Merge of Linux 2.5.55
-*!
-*! Revision 1.4  2002/12/11 13:13:57  starvik
-*! Added arch/ to v10 specific includes
-*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
-*!
-*! Revision 1.3  2002/11/20 11:56:10  starvik
-*! Merge of Linux 2.5.48
-*!
-*! Revision 1.2  2002/11/18 13:16:06  starvik
-*! Linux 2.5 port of latest 2.4 drivers
-*!
-*! Revision 1.15  2002/10/11 16:14:33  johana
-*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the
-*! trcklecharge register.
-*!
-*! Revision 1.14  2002/10/10 12:15:38  magnusmn
-*! Added support for having the RST signal on bit g0
-*!
-*! Revision 1.13  2002/05/29 15:16:08  johana
-*! Removed unused variables.
-*!
-*! Revision 1.12  2002/04/10 15:35:25  johana
-*! Moved probe function closer to init function and marked it __init.
-*!
-*! Revision 1.11  2001/06/14 12:35:52  jonashg
-*! The ATA hack is back. It is unfortunately the only way to set g27 to output.
-*!
-*! Revision 1.9  2001/06/14 10:00:14  jonashg
-*! No need for tempudelay to be inline anymore (had to adjust the usec to
-*! loops conversion because of this to make it slow enough to be a udelay).
-*!
-*! Revision 1.8  2001/06/14 08:06:32  jonashg
-*! Made tempudelay delay usecs (well, just a tad more).
-*!
-*! Revision 1.7  2001/06/13 14:18:11  jonashg
-*! Only allow processes with SYS_TIME capability to set time and charge.
-*!
-*! Revision 1.6  2001/06/12 15:22:07  jonashg
-*! * Made init function __init.
-*! * Parameter to out_byte() is unsigned char.
-*! * The magic number 42 has got a name.
-*! * Removed comment about /proc (nothing is exported there).
-*!
-*! Revision 1.5  2001/06/12 14:35:13  jonashg
-*! Gave the module a name and added it to printk's.
-*!
-*! Revision 1.4  2001/05/31 14:53:40  jonashg
-*! Made tempudelay() inline so that the watchdog doesn't reset (see
-*! function comment).
-*!
-*! Revision 1.3  2001/03/26 16:03:06  bjornw
-*! Needs linux/config.h
-*!
-*! Revision 1.2  2001/03/20 19:42:00  bjornw
-*! Use the ETRAX prefix on the DS1302 options
-*!
-*! Revision 1.1  2001/03/20 09:13:50  magnusmn
-*! Linux 2.4 port
-*!
-*! Revision 1.10  2000/07/05 15:38:23  bjornw
-*! Dont update kernel time when a RTC_SET_TIME is done
-*!
-*! Revision 1.9  2000/03/02 15:42:59  macce
-*! * Hack to make RTC work on all 2100/2400
-*!
-*! Revision 1.8  2000/02/23 16:59:18  torbjore
-*! added setup of R_GEN_CONFIG when RTC is connected to the generic port.
-*!
-*! Revision 1.7  2000/01/17 15:51:43  johana
-*! Added RTC_SET_CHARGE ioctl to enable trickle charger.
-*!
-*! Revision 1.6  1999/10/27 13:19:47  bjornw
-*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel.
-*! /dev/rtc calls it now.
-*!
-*! Revision 1.5  1999/10/27 12:39:37  bjornw
-*! Disabled superuser check. Anyone can now set the time.
-*!
-*! Revision 1.4  1999/09/02 13:27:46  pkj
-*! Added shadow for R_PORT_PB_CONFIG.
-*! Renamed port_g_shadow to port_g_data_shadow.
-*!
-*! Revision 1.3  1999/09/02 08:28:06  pkj
-*! Made it possible to select either port PB or the generic port for the RST
-*! signal line to the DS1302 RTC.
-*! Also make sure the RST bit is configured as output on Port PB (if used).
-*!
-*! Revision 1.2  1999/09/01 14:47:20  bjornw
-*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read
-*! and set the date. Register as major 121.
-*!
-*! Revision 1.1  1999/09/01 09:45:29  bjornw
-*! Implemented a DS1302 RTC driver.
-*!
-*!
 *! ---------------------------------------------------------------------------
 *!
-*! (C) Copyright 1999, 2000, 2001, 2002, 2003, 2004  Axis Communications AB, LUND, SWEDEN
-*!
-*! $Id: ds1302.c,v 1.18 2005/01/24 09:11:26 mikaelam Exp $
+*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
 
 #include <asm/rtc.h>
 #include <asm/arch/io_interface_mux.h>
 
+#include "i2c.h"
+
 #define RTC_MAJOR_NR 121 /* local major, change later */
 
 static const char ds1302_name[] = "ds1302";
index 3a9114e89edfcc1f2ef6e87b8e7c7bc6ca1fd35d..f3b327d4ed9cf912040a56310b69cad7063f7fd8 100644 (file)
@@ -392,6 +392,7 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
        if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) ||
            ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) ||
            ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) {
+               local_irq_restore(flags);
                printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n",
                       ioif);
                return -EBUSY;
index 41d4a5f93284abe34e1838c1e5379d1ab120956a..b6be705c2a3e6fb7ec2994600e47deaebfcadbfa 100644 (file)
@@ -7,7 +7,7 @@
  *
  *  Ideas also taken from arch/arm.
  *
- *  Copyright (C) 2000, 2001 Axis Communications AB
+ *  Copyright (C) 2000-2007 Axis Communications AB
  *
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  */
 #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
 
-int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
+void do_signal(int canrestart, struct pt_regs *regs);
 
 /*
- * Atomically swap in the new signal mask, and wait for a signal.  Define 
+ * Atomically swap in the new signal mask, and wait for a signal.  Define
  * dummy arguments to be able to reach the regs argument.  (Note that this
  * arrangement relies on old_sigset_t occupying one register.)
  */
-int
-sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, 
-               long srp, struct pt_regs *regs)
+int sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
+       long srp, struct pt_regs *regs)
 {
-       sigset_t saveset;
-
        mask &= _BLOCKABLE;
        spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
+       current->saved_sigmask = current->blocked;
        siginitset(&current->blocked, mask);
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
-
-       regs->r10 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(0, &saveset, regs))
-                       /* We will get here twice: once to call the signal
-                          handler, then again to return from the
-                          sigsuspend system call.  When calling the
-                          signal handler, R10 holds the signal number as
-                          set through do_signal.  The sigsuspend call
-                          will return with the restored value set above;
-                          always -EINTR.  */
-                       return regs->r10;
-       }
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_thread_flag(TIF_RESTORE_SIGMASK);
+       return -ERESTARTNOHAND;
 }
 
-/* Define dummy arguments to be able to reach the regs argument.  (Note that
- * this arrangement relies on size_t occupying one register.)
- */
-int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, 
-                  long mof, long srp, struct pt_regs *regs)
-{
-       sigset_t saveset, newset;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (copy_from_user(&newset, unewset, sizeof(newset)))
-               return -EFAULT;
-       sigdelsetmask(&newset, ~_BLOCKABLE);
-
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs->r10 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(0, &saveset, regs))
-                       /* We will get here twice: once to call the signal
-                          handler, then again to return from the
-                          sigsuspend system call.  When calling the
-                          signal handler, R10 holds the signal number as
-                          set through do_signal.  The sigsuspend call
-                          will return with the restored value set above;
-                          always -EINTR.  */
-                       return regs->r10;
-       }
-}
-
-int 
-sys_sigaction(int sig, const struct old_sigaction __user *act,
-             struct old_sigaction *oact)
+int sys_sigaction(int sig, const struct old_sigaction __user *act,
+       struct old_sigaction *oact)
 {
        struct k_sigaction new_ka, old_ka;
        int ret;
@@ -147,8 +93,7 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
        return ret;
 }
 
-int
-sys_sigaltstack(const stack_t *uss, stack_t __user *uoss)
+int sys_sigaltstack(const stack_t *uss, stack_t __user *uoss)
 {
        return do_sigaltstack(uss, uoss, rdusp());
 }
@@ -205,7 +150,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
 
        /* TODO: the other ports use regs->orig_XX to disable syscall checks
         * after this completes, but we don't use that mechanism. maybe we can
-        * use it now ? 
+        * use it now ?
         */
 
        return err;
@@ -216,7 +161,7 @@ badframe:
 
 /* Define dummy arguments to be able to reach the regs argument.  */
 
-asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, 
+asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
                              long srp, struct pt_regs *regs)
 {
        struct sigframe __user *frame = (struct sigframe *)rdusp();
@@ -243,7 +188,7 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
        current->blocked = set;
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
-       
+
        if (restore_sigcontext(regs, &frame->sc))
                goto badframe;
 
@@ -254,11 +199,11 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
-}      
+}
 
 /* Define dummy arguments to be able to reach the regs argument.  */
 
-asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, 
+asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
                                 long mof, long srp, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
@@ -282,7 +227,7 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
        current->blocked = set;
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
-       
+
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
 
@@ -294,14 +239,14 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
-}      
+}
 
 /*
  * Set up a signal frame.
  */
 
-static int
-setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask)
+static int setup_sigcontext(struct sigcontext __user *sc,
+       struct pt_regs *regs, unsigned long mask)
 {
        int err = 0;
        unsigned long usp = rdusp();
@@ -324,10 +269,11 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo
        return err;
 }
 
-/* figure out where we want to put the new signal frame - usually on the stack */
+/* Figure out where we want to put the new signal frame
+ * - usually on the stack. */
 
 static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 {
        unsigned long sp = rdusp();
 
@@ -345,15 +291,15 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 }
 
 /* grab and setup a signal frame.
- * 
+ *
  * basically we stack a lot of state info, and arrange for the
  * user-mode program to return to the kernel using either a
  * trampoline which performs the syscall sigreturn, or a provided
  * user-mode trampoline.
  */
 
-static void setup_frame(int sig, struct k_sigaction *ka,
-                       sigset_t *set, struct pt_regs * regs)
+static int setup_frame(int sig, struct k_sigaction *ka,
+                      sigset_t *set, struct pt_regs *regs)
 {
        struct sigframe __user *frame;
        unsigned long return_ip;
@@ -401,14 +347,15 @@ static void setup_frame(int sig, struct k_sigaction *ka,
 
        wrusp((unsigned long)frame);
 
-       return;
+       return 0;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return -EFAULT;
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                          sigset_t *set, struct pt_regs * regs)
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+       sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
        unsigned long return_ip;
@@ -443,9 +390,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                /* trampoline - the desired return ip is the retcode itself */
                return_ip = (unsigned long)&frame->retcode;
                /* This is movu.w __NR_rt_sigreturn, r9; break 13; */
-               err |= __put_user(0x9c5f,            (short __user*)(frame->retcode+0));
-               err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2));
-               err |= __put_user(0xe93d,            (short __user*)(frame->retcode+4));
+               err |= __put_user(0x9c5f, (short __user *)(frame->retcode+0));
+               err |= __put_user(__NR_rt_sigreturn,
+                       (short __user *)(frame->retcode+2));
+               err |= __put_user(0xe93d, (short __user *)(frame->retcode+4));
        }
 
        if (err)
@@ -455,73 +403,81 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        /* Set up registers for signal handler */
 
-       regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
-       regs->srp = return_ip;                          /* what we enter LATER */
-       regs->r10 = sig;                                /* first argument is signo */
-        regs->r11 = (unsigned long) &frame->info;       /* second argument is (siginfo_t *) */
-        regs->r12 = 0;                                  /* third argument is unused */
-
-       /* actually move the usp to reflect the stacked frame */
-
+       /* What we enter NOW   */
+       regs->irp = (unsigned long) ka->sa.sa_handler;
+       /* What we enter LATER */
+       regs->srp = return_ip;
+       /* First argument is signo */
+       regs->r10 = sig;
+       /* Second argument is (siginfo_t *) */
+       regs->r11 = (unsigned long)&frame->info;
+       /* Third argument is unused */
+       regs->r12 = 0;
+
+       /* Actually move the usp to reflect the stacked frame */
        wrusp((unsigned long)frame);
 
-       return;
+       return 0;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler
- */    
+ */
 
-static inline void
-handle_signal(int canrestart, unsigned long sig,
-             siginfo_t *info, struct k_sigaction *ka,
-              sigset_t *oldset, struct pt_regs * regs)
+static inline int handle_signal(int canrestart, unsigned long sig,
+       siginfo_t *info, struct k_sigaction *ka,
+       sigset_t *oldset, struct pt_regs *regs)
 {
+       int ret;
+
        /* Are we from a system call? */
        if (canrestart) {
                /* If so, check system call restarting.. */
                switch (regs->r10) {
-                       case -ERESTART_RESTARTBLOCK:
-                       case -ERESTARTNOHAND:
-                               /* ERESTARTNOHAND means that the syscall should only be
-                                  restarted if there was no handler for the signal, and since
-                                  we only get here if there is a handler, we don't restart */
+               case -ERESTART_RESTARTBLOCK:
+               case -ERESTARTNOHAND:
+                       /* ERESTARTNOHAND means that the syscall should
+                        * only be restarted if there was no handler for
+                        * the signal, and since we only get here if there
+                        * is a handler, we don't restart */
+                       regs->r10 = -EINTR;
+                       break;
+               case -ERESTARTSYS:
+                       /* ERESTARTSYS means to restart the syscall if
+                        * there is no handler or the handler was
+                        * registered with SA_RESTART */
+                       if (!(ka->sa.sa_flags & SA_RESTART)) {
                                regs->r10 = -EINTR;
                                break;
-
-                       case -ERESTARTSYS:
-                               /* ERESTARTSYS means to restart the syscall if there is no
-                                  handler or the handler was registered with SA_RESTART */
-                               if (!(ka->sa.sa_flags & SA_RESTART)) {
-                                       regs->r10 = -EINTR;
-                                       break;
-                               }
-                       /* fallthrough */
-                       case -ERESTARTNOINTR:
-                               /* ERESTARTNOINTR means that the syscall should be called again
-                                  after the signal handler returns. */
-                               RESTART_CRIS_SYS(regs);
+                       }
+               /* fallthrough */
+               case -ERESTARTNOINTR:
+                       /* ERESTARTNOINTR means that the syscall should
+                        * be called again after the signal handler returns. */
+                       RESTART_CRIS_SYS(regs);
                }
        }
 
        /* Set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
-               setup_rt_frame(sig, ka, info, oldset, regs);
+               ret = setup_rt_frame(sig, ka, info, oldset, regs);
        else
-               setup_frame(sig, ka, oldset, regs);
-
-       if (ka->sa.sa_flags & SA_ONESHOT)
-               ka->sa.sa_handler = SIG_DFL;
-
-       spin_lock_irq(&current->sighand->siglock);
-       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&current->blocked,sig);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+               ret = setup_frame(sig, ka, oldset, regs);
+
+       if (ret == 0) {
+               spin_lock_irq(&current->sighand->siglock);
+               sigorsets(&current->blocked, &current->blocked,
+                       &ka->sa.sa_mask);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked, sig);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+       return ret;
 }
 
 /*
@@ -536,11 +492,12 @@ handle_signal(int canrestart, unsigned long sig,
  * mode below.
  */
 
-int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+void do_signal(int canrestart, struct pt_regs *regs)
 {
        siginfo_t info;
        int signr;
         struct k_sigaction ka;
+       sigset_t *oldset;
 
        /*
         * We want the common case to go fast, which
@@ -549,16 +506,26 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
         * if so.
         */
        if (!user_mode(regs))
-               return 1;
+               return;
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(canrestart, signr, &info, &ka, oldset, regs);
-               return 1;
+               if (handle_signal(canrestart, signr, &info, &ka,
+                               oldset, regs)) {
+                       /* a signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TIF_RESTORE_SIGMASK flag */
+                       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               }
+               return;
        }
 
        /* Did we come from a system call? */
@@ -569,10 +536,16 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
                    regs->r10 == -ERESTARTNOINTR) {
                        RESTART_CRIS_SYS(regs);
                }
-               if (regs->r10 == -ERESTART_RESTARTBLOCK){
+               if (regs->r10 == -ERESTART_RESTARTBLOCK) {
                        regs->r10 = __NR_restart_syscall;
                        regs->irp -= 2;
                }
        }
-       return 0;
+
+       /* if there's no signal to deliver, we just put the saved sigmask
+        * back */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
 }
index 5976f6199c47237937b2e7a4bd15709203472cf9..9310a7b476e95cf6353180de4e88bc8ba4f9f592 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/swap.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/vmstat.h>
 #include <asm/arch/svinto.h>
 #include <asm/types.h>
 #include <asm/signal.h>
index 9859d49d088bfb0c714bc71180279df06babf8b6..97a7876ed6819061fec0a9be042f60be1d260d77 100644 (file)
@@ -9,7 +9,8 @@
  */    
 
 #include <asm-generic/vmlinux.lds.h>
-               
+#include <asm/page.h>
+
 jiffies = jiffies_64;
 SECTIONS
 {
@@ -23,7 +24,7 @@ SECTIONS
        _stext = .;
        __stext = .;
        .text : {
-               *(.text)
+               TEXT_TEXT
                SCHED_TEXT
                LOCK_TEXT
                *(.fixup)
@@ -49,10 +50,10 @@ SECTIONS
        __edata = . ;                 /* End of data section */
        _edata = . ;
 
-       . = ALIGN(8192);              /* init_task and stack, must be aligned */
+       . = ALIGN(PAGE_SIZE);   /* init_task and stack, must be aligned */
        .data.init_task : { *(.data.init_task) }
 
-       . = ALIGN(8192);              /* Init code and data */
+       . = ALIGN(PAGE_SIZE);   /* Init code and data */
        __init_begin = .;
        .init.text : { 
                   _sinittext = .;
@@ -66,13 +67,7 @@ SECTIONS
        __setup_end = .;
        .initcall.init : {
                __initcall_start = .;
-               *(.initcall1.init);
-               *(.initcall2.init);
-               *(.initcall3.init);
-               *(.initcall4.init);
-               *(.initcall5.init);
-               *(.initcall6.init);
-               *(.initcall7.init);
+               INITCALLS
                __initcall_end = .;     
        }
 
@@ -88,16 +83,18 @@ SECTIONS
                __initramfs_start = .;
                *(.init.ramfs)
                __initramfs_end = .;
-               /* We fill to the next page, so we can discard all init
-                  pages without needing to consider what payload might be
-                  appended to the kernel image.  */
-               FILL (0); 
-               . = ALIGN (8192);
        }
 #endif
-       
        __vmlinux_end = .;            /* last address of the physical file */
-       __init_end = .;
+
+       /*
+        * We fill to the next page, so we can discard all init
+        * pages without needing to consider what payload might be
+        * appended to the kernel image.
+        */
+       . = ALIGN(PAGE_SIZE);
+
+       __init_end = .;
 
        __data_end = . ;              /* Move to _edata ? */
        __bss_start = .;              /* BSS */
index 11f9895ded5056d4b51192c06c3726433beed1ed..f4bdc1dfa3204f931cfbbda7b9442524874b258b 100644 (file)
@@ -20,6 +20,9 @@
 
 #define IOP_TIMEOUT 100
 
+#error "This driver is broken with regard to its driver core usage."
+#error "Please contact <greg@kroah.com> for details on how to fix it properly."
+
 static struct device iop_spu_device[2] = {
        { .bus_id =     "iop-spu0", },
        { .bus_id =     "iop-spu1", },
@@ -192,6 +195,13 @@ int iop_start_mpu(unsigned int start_addr)
 
 static int __init iop_fw_load_init(void)
 {
+#if 0
+       /*
+        * static struct devices can not be added directly to sysfs by ignoring
+        * the driver model infrastructure.  To fix this properly, please use
+        * the platform_bus to register these devices to be able to properly
+        * use the firmware infrastructure.
+        */
        device_initialize(&iop_spu_device[0]);
        kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");
        kobject_add(&iop_spu_device[0].kobj);
@@ -201,6 +211,7 @@ static int __init iop_fw_load_init(void)
        device_initialize(&iop_mpu_device);
        kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");
        kobject_add(&iop_mpu_device.kobj);
+#endif
        return 0;
 }
 
index 4ac2b1f1bd3b7fb49b4407c32b0482a5226b7a61..86028c69861e23373b1162fc20607a858da3b3e3 100644 (file)
@@ -71,8 +71,6 @@ unsigned long __per_cpu_offset[NR_CPUS];
 EXPORT_SYMBOL(__per_cpu_offset);
 #endif
 
-extern void ia64_setup_printk_clock(void);
-
 DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
 DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
 unsigned long ia64_cycles_per_usec;
@@ -507,8 +505,6 @@ setup_arch (char **cmdline_p)
        /* process SAL system table: */
        ia64_sal_init(__va(efi.sal_systab));
 
-       ia64_setup_printk_clock();
-
 #ifdef CONFIG_SMP
        cpu_physical_id(0) = hard_smp_processor_id();
 #endif
index 2bb84214e5f1384f2208b47f637a644aa94e747e..3ab04272097031c19f5000bb07c9e606412df2f7 100644 (file)
@@ -344,33 +344,6 @@ udelay (unsigned long usecs)
 }
 EXPORT_SYMBOL(udelay);
 
-static unsigned long long ia64_itc_printk_clock(void)
-{
-       if (ia64_get_kr(IA64_KR_PER_CPU_DATA))
-               return sched_clock();
-       return 0;
-}
-
-static unsigned long long ia64_default_printk_clock(void)
-{
-       return (unsigned long long)(jiffies_64 - INITIAL_JIFFIES) *
-               (1000000000/HZ);
-}
-
-unsigned long long (*ia64_printk_clock)(void) = &ia64_default_printk_clock;
-
-unsigned long long printk_clock(void)
-{
-       return ia64_printk_clock();
-}
-
-void __init
-ia64_setup_printk_clock(void)
-{
-       if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
-               ia64_printk_clock = ia64_itc_printk_clock;
-}
-
 /* IA64 doesn't cache the timezone */
 void update_vsyscall_tz(void)
 {
index 14261fee5f4dbdb1ef88beb9b02c2dbf41906151..a2484fc1a06c43482e575888ca1991d45faf43e7 100644 (file)
@@ -354,27 +354,27 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
        if (unlikely(retval < 0))
                return retval;
 
-       all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj;
-       kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache");
-       all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry;
-       retval = kobject_register(&all_cpu_cache_info[cpu].kobj);
+       retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj,
+                                     &cache_ktype_percpu_entry, &sys_dev->kobj,
+                                     "%s", "cache");
 
        for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) {
                this_object = LEAF_KOBJECT_PTR(cpu,i);
-               this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj;
-               kobject_set_name(&(this_object->kobj), "index%1lu", i);
-               this_object->kobj.ktype = &cache_ktype;
-               retval = kobject_register(&(this_object->kobj));
+               retval = kobject_init_and_add(&(this_object->kobj),
+                                             &cache_ktype,
+                                             &all_cpu_cache_info[cpu].kobj,
+                                             "index%1lu", i);
                if (unlikely(retval)) {
                        for (j = 0; j < i; j++) {
-                               kobject_unregister(
-                                       &(LEAF_KOBJECT_PTR(cpu,j)->kobj));
+                               kobject_put(&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
                        }
-                       kobject_unregister(&all_cpu_cache_info[cpu].kobj);
+                       kobject_put(&all_cpu_cache_info[cpu].kobj);
                        cpu_cache_sysfs_exit(cpu);
                        break;
                }
+               kobject_uevent(&(this_object->kobj), KOBJ_ADD);
        }
+       kobject_uevent(&all_cpu_cache_info[cpu].kobj, KOBJ_ADD);
        return retval;
 }
 
@@ -385,10 +385,10 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
        unsigned long i;
 
        for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++)
-               kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
+               kobject_put(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
 
        if (all_cpu_cache_info[cpu].kobj.parent) {
-               kobject_unregister(&all_cpu_cache_info[cpu].kobj);
+               kobject_put(&all_cpu_cache_info[cpu].kobj);
                memset(&all_cpu_cache_info[cpu].kobj,
                        0,
                        sizeof(struct kobject));
index 2173de9fe9173773a960dbd9347367242968011f..f6a1aeb742b3827acce249f7e5c84137678be1e6 100644 (file)
@@ -1488,16 +1488,19 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
              case LDFA_OP:
              case LDFCCLR_OP:
              case LDFCNC_OP:
-             case LDF_IMM_OP:
-             case LDFA_IMM_OP:
-             case LDFCCLR_IMM_OP:
-             case LDFCNC_IMM_OP:
                if (u.insn.x)
                        ret = emulate_load_floatpair(ifa, u.insn, regs);
                else
                        ret = emulate_load_float(ifa, u.insn, regs);
                break;
 
+             case LDF_IMM_OP:
+             case LDFA_IMM_OP:
+             case LDFCCLR_IMM_OP:
+             case LDFCNC_IMM_OP:
+               ret = emulate_load_float(ifa, u.insn, regs);
+               break;
+
              case STF_OP:
              case STF_IMM_OP:
                ret = emulate_store_float(ifa, u.insn, regs);
index 1f38a3a68390f0502a04c2a3fca273b37e7d3a7d..bb1d249296408d3def799a759ee48e5b0b415378 100644 (file)
@@ -64,7 +64,6 @@ extern void sn_timer_init(void);
 extern unsigned long last_time_offset;
 extern void (*ia64_mark_idle) (int);
 extern void snidle(int);
-extern unsigned long long (*ia64_printk_clock)(void);
 
 unsigned long sn_rtc_cycles_per_second;
 EXPORT_SYMBOL(sn_rtc_cycles_per_second);
@@ -360,14 +359,6 @@ sn_scan_pcdp(void)
 
 static unsigned long sn2_rtc_initial;
 
-static unsigned long long ia64_sn2_printk_clock(void)
-{
-       unsigned long rtc_now = rtc_time();
-
-       return (rtc_now - sn2_rtc_initial) *
-               (1000000000 / sn_rtc_cycles_per_second);
-}
-
 /**
  * sn_setup - SN platform setup routine
  * @cmdline_p: kernel command line
@@ -468,8 +459,6 @@ void __init sn_setup(char **cmdline_p)
 
        platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR;
 
-       ia64_printk_clock = ia64_sn2_printk_clock;
-
        printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
 
        /*
index 54e8973b6e99d21679c2083d76c8c0ea2cdfaedf..98e7c7dbfdd84082d5b2adf72d19b6b3309f2762 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2007 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
  * PIO read fails, the MCA handler will force the error to look
  * corrected and vector to the xp_error_PIOR which will return an error.
  *
+ * The definition of "consumption" and the time it takes for an MCA
+ * to surface is processor implementation specific.  This code
+ * is sufficient on Itanium through the Montvale processor family.
+ * It may need to be adjusted for future processor implementations.
+ *
  *     extern int xp_nofault_PIOR(void *remote_register);
  */
 
@@ -22,11 +27,10 @@ xp_nofault_PIOR:
        mov     r8=r0                   // Stage a success return value
        ld8.acq r9=[r32];;              // PIO Read the specified register
        adds    r9=1,r9;;               // Add to force consumption
-       or      r9=r9,r9;;              // Or to force consumption
+       srlz.i;;                        // Allow time for MCA to surface
        br.ret.sptk.many b0;;           // Return success
 
        .global xp_error_PIOR
 xp_error_PIOR:
        mov     r8=1                    // Return value of 1
        br.ret.sptk.many b0;;           // Return failure
-
index c6fc405a6c8e33348bfe69c1720dada4df2ab4be..b22c043b6ef8e311702a6d8ac0b7064b10336c84 100644 (file)
@@ -59,6 +59,8 @@ config BCM47XX
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SSB
        select SSB_DRIVER_MIPS
+       select SSB_DRIVER_EXTIF
+       select SSB_PCICORE_HOSTMODE if PCI
        select GENERIC_GPIO
        select SYS_HAS_EARLY_PRINTK
        select CFE
@@ -992,8 +994,6 @@ config BOOT_ELF64
 
 menu "CPU selection"
 
-source "kernel/time/Kconfig"
-
 choice
        prompt "CPU type"
        default CPU_R4X00
@@ -1768,6 +1768,8 @@ config NR_CPUS
          performance should round up your number of processors to the next
          power of two.
 
+source "kernel/time/Kconfig"
+
 #
 # Timer Interrupt Frequency Configuration
 #
index 6fa70a36a250aaf4eb8ab3b8482244daefedca9d..ce771487567d5e3ee29fc4bd01a9211e23bd8554 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * BRIEF MODULE DESCRIPTION
- *     Alchemy/AMD Au1x00 pci support.
+ *     Alchemy/AMD Au1x00 PCI support.
  *
- * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2001-2003, 2007 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
  *             ppopov@mvista.com or source@mvista.com
  *
@@ -66,6 +66,8 @@ static unsigned long virt_io_addr;
 
 static int __init au1x_pci_setup(void)
 {
+       extern void au1x_pci_cfg_init(void);
+
 #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
        virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START,
                        Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1);
@@ -94,6 +96,8 @@ static int __init au1x_pci_setup(void)
        set_io_port_base(virt_io_addr);
 #endif
 
+       au1x_pci_cfg_init();
+
        register_pci_controller(&au1x_controller);
        return 0;
 }
index db330e811025d36cf9a33a1b2a2c6d169d1a9e23..d1ba701c9dd195fdcfaf9a2bea47f81703450260 100644 (file)
@@ -4,10 +4,15 @@
 #include <linux/io.h>
 #include <linux/serial_reg.h>
 
+#include <cobalt.h>
+
 #define UART_BASE      ((void __iomem *)CKSEG1ADDR(0x1c800000))
 
 void prom_putchar(char c)
 {
+       if (cobalt_board_id <= COBALT_BRD_ID_QUBE1)
+               return;
+
        while (!(readb(UART_BASE + UART_LSR) & UART_LSR_THRE))
                ;
 
index 2367687310630c40a68b11423a21dab45cc6b2a9..50be56c9e9ef590e9960337de7da248f5eaed575 100644 (file)
@@ -136,7 +136,8 @@ EXPORT(_stext)
         * kernel load address.  This is needed because this platform does
         * not have a ELF loader yet.
         */
-       __INIT
+FEXPORT(__kernel_entry)
+       j       kernel_entry
 #endif
 
        __INIT_REFOK
index 4710135771085dd658cd69e5e9553e609c42acb8..197d7977de356e603465f62e780f945eb3dbe16f 100644 (file)
@@ -238,7 +238,7 @@ static int i8259A_shutdown(struct sys_device *dev)
 }
 
 static struct sysdev_class i8259_sysdev_class = {
-       set_kset_name("i8259"),
+       .name = "i8259",
        .resume = i8259A_resume,
        .shutdown = i8259A_shutdown,
 };
index 892665bb12b1ec766491222ac67c2f9103c12ef4..bb4f00c0cbe94f8a5dfe1c822a072f1c6d4de928 100644 (file)
@@ -58,13 +58,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
        if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
                return -EFAULT;
 
-       lock_cpu_hotplug();
+       get_online_cpus();
        read_lock(&tasklist_lock);
 
        p = find_process_by_pid(pid);
        if (!p) {
                read_unlock(&tasklist_lock);
-               unlock_cpu_hotplug();
+               put_online_cpus();
                return -ESRCH;
        }
 
@@ -106,7 +106,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 
 out_unlock:
        put_task_struct(p);
-       unlock_cpu_hotplug();
+       put_online_cpus();
        return retval;
 }
 
@@ -125,7 +125,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
        if (len < real_len)
                return -EINVAL;
 
-       lock_cpu_hotplug();
+       get_online_cpus();
        read_lock(&tasklist_lock);
 
        retval = -ESRCH;
@@ -140,7 +140,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
 
 out_unlock:
        read_unlock(&tasklist_lock);
-       unlock_cpu_hotplug();
+       put_online_cpus();
        if (retval)
                return retval;
        if (copy_to_user(user_mask_ptr, &mask, real_len))
index 7f6ddcb5d48532657a52b80461644dd05c467551..f8a535afce3943d434ae0fe42a727f9aba654694 100644 (file)
@@ -269,7 +269,7 @@ static void __init bootmem_init(void)
 
 static void __init bootmem_init(void)
 {
-       unsigned long init_begin, reserved_end;
+       unsigned long reserved_end;
        unsigned long mapstart = ~0UL;
        unsigned long bootmap_size;
        int i;
@@ -344,7 +344,6 @@ static void __init bootmem_init(void)
                                         min_low_pfn, max_low_pfn);
 
 
-       init_begin = PFN_UP(__pa_symbol(&__init_begin));
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long start, end;
 
@@ -352,8 +351,8 @@ static void __init bootmem_init(void)
                end = PFN_DOWN(boot_mem_map.map[i].addr
                                + boot_mem_map.map[i].size);
 
-               if (start <= init_begin)
-                       start = init_begin;
+               if (start <= min_low_pfn)
+                       start = min_low_pfn;
                if (start >= end)
                        continue;
 
index 1ecfbb7eba6cd25f0637137b6b6272a9ccdd0bc8..2995be1ab3cada3d9771e46cb95727f601cbad53 100644 (file)
@@ -147,9 +147,9 @@ static __init int cpu_has_mfc0_count_bug(void)
                        return 1;
 
                /*
-                * I don't have erratas for newer R4400 so be paranoid.
+                * we assume newer revisions are ok
                 */
-               return 1;
+               return 0;
        }
 
        return 0;
index 5332449ec040fcc08769407b799101ee12d1a603..460626b6d62fc4cce318667032ccefa1f0de80aa 100644 (file)
@@ -12,11 +12,11 @@ endif
 
 MKLASATIMG = mklasatimg
 MKLASATIMG_ARCH = mq2,mqpro,sp100,sp200
-KERNEL_IMAGE = $(TOPDIR)/vmlinux
+KERNEL_IMAGE = vmlinux
 KERNEL_START = $(shell $(NM) $(KERNEL_IMAGE) | grep " _text" | cut -f1 -d\ )
 KERNEL_ENTRY = $(shell $(NM) $(KERNEL_IMAGE) | grep kernel_entry | cut -f1 -d\ )
 
-LDSCRIPT= -L$(obj) -Tromscript.normal
+LDSCRIPT= -L$(srctree)/$(src) -Tromscript.normal
 
 HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \
                -D_kernel_entry=0x$(KERNEL_ENTRY) \
@@ -24,7 +24,7 @@ HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \
                -D TIMESTAMP=$(shell date +%s)
 
 $(obj)/head.o: $(obj)/head.S $(KERNEL_IMAGE)
-       $(CC) -fno-pic $(HEAD_DEFINES) -I$(TOPDIR)/include -c -o $@ $<
+       $(CC) -fno-pic $(HEAD_DEFINES) $(LINUXINCLUDE) -c -o $@ $<
 
 OBJECTS = head.o kImage.o
 
index 2c5c27c8e86df597681f0afd216a0af26f64f1c4..dc272c1882337167a0350d87afc978702b1c0f0a 100644 (file)
@@ -169,7 +169,6 @@ void __init prom_meminit(void)
 
 void __init prom_free_prom_memory(void)
 {
-#if 0 /* for now ...  */
        unsigned long addr;
        int i;
 
@@ -181,5 +180,4 @@ void __init prom_free_prom_memory(void)
                free_init_pages("prom memory",
                                addr, addr + boot_mem_map.map[i].size);
        }
-#endif
 }
index 7a1bb51f81ee150e1b5ec38d6b645da8bc1605c3..583d468d98a947cfc95e4cd09872911128f1fa34 100644 (file)
@@ -39,16 +39,18 @@ static void atlas_machine_power_off(void);
 
 static void mips_machine_restart(char *command)
 {
-       unsigned int __iomem *softres_reg = ioremap(SOFTRES_REG, sizeof(unsigned int));
+       unsigned int __iomem *softres_reg =
+               ioremap(SOFTRES_REG, sizeof(unsigned int));
 
-       writew(GORESET, softres_reg);
+       __raw_writel(GORESET, softres_reg);
 }
 
 static void mips_machine_halt(void)
 {
-        unsigned int __iomem *softres_reg = ioremap(SOFTRES_REG, sizeof(unsigned int));
+       unsigned int __iomem *softres_reg =
+               ioremap(SOFTRES_REG, sizeof(unsigned int));
 
-       writew(GORESET, softres_reg);
+       __raw_writel(GORESET, softres_reg);
 }
 
 #if defined(CONFIG_MIPS_ATLAS)
index 9a2636e5624378fc1d9cefef136f1c271b80937e..bc43a5c2224dec370d3aeab2fb25cb0eb84c7ff1 100644 (file)
@@ -149,7 +149,7 @@ void __init plat_mem_setup(void)
        /* Check PCI clock */
        {
                unsigned int __iomem *jmpr_p = (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int));
-               int jmpr = (readw(jmpr_p) >> 2) & 0x07;
+               int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07;
                static const int pciclocks[] __initdata = {
                        33, 20, 25, 30, 12, 16, 37, 10
                };
index ae76795685cc2ee2789596dfbdfeba6c40b47808..810535dd091be1f1aaff24c6403f0686b8b01d63 100644 (file)
@@ -45,7 +45,7 @@ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
 
-#ifdef CONFIG_ZONE_DMA32
+#ifdef CONFIG_ZONE_DMA
        if (dev == NULL)
                gfp |= __GFP_DMA;
        else if (dev->coherent_dma_mask < DMA_BIT_MASK(24))
index f7df1142912b27266066273d6344cd760a264480..9553b14002dda51a757cf06ccb0bca5483b86c1a 100644 (file)
@@ -177,7 +177,7 @@ static char irq_tab_raq2[] __initdata = {
 
 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
-       if (cobalt_board_id < COBALT_BRD_ID_QUBE2)
+       if (cobalt_board_id <= COBALT_BRD_ID_QUBE1)
                return irq_tab_qube1[slot];
 
        if (cobalt_board_id == COBALT_BRD_ID_RAQ2)
index 6b29904acf451936093ccbaa8d2af9b759502325..1314bd58f0365415a4553a8282d981e36ff54c73 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * BRIEF MODULE DESCRIPTION
- *     Alchemy/AMD Au1x00 pci support.
+ *     Alchemy/AMD Au1x00 PCI support.
  *
- * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2001-2003, 2007 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
  *             ppopov@mvista.com or source@mvista.com
  *
@@ -69,10 +69,27 @@ void mod_wired_entry(int entry, unsigned long entrylo0,
        write_c0_pagemask(old_pagemask);
 }
 
-struct vm_struct *pci_cfg_vm;
+static struct vm_struct *pci_cfg_vm;
 static int pci_cfg_wired_entry;
-static int first_cfg = 1;
-unsigned long last_entryLo0, last_entryLo1;
+static unsigned long last_entryLo0, last_entryLo1;
+
+/*
+ * We can't ioremap the entire pci config space because it's too large.
+ * Nor can we call ioremap dynamically because some device drivers use
+ * the PCI config routines from within interrupt handlers and that
+ * becomes a problem in get_vm_area().  We use one wired TLB to handle
+ * all config accesses for all busses.
+ */
+void __init au1x_pci_cfg_init(void)
+{
+       /* Reserve a wired entry for PCI config accesses */
+       pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP);
+       if (!pci_cfg_vm)
+               panic(KERN_ERR "PCI unable to get vm area\n");
+       pci_cfg_wired_entry = read_c0_wired();
+       add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K);
+       last_entryLo0 = last_entryLo1 = 0xffffffff;
+}
 
 static int config_access(unsigned char access_type, struct pci_bus *bus,
                         unsigned int dev_fn, unsigned char where,
@@ -97,27 +114,6 @@ static int config_access(unsigned char access_type, struct pci_bus *bus,
                        Au1500_PCI_STATCMD);
        au_sync_udelay(1);
 
-       /*
-        * We can't ioremap the entire pci config space because it's
-        * too large. Nor can we call ioremap dynamically because some
-        * device drivers use the pci config routines from within
-        * interrupt handlers and that becomes a problem in get_vm_area().
-        * We use one wired tlb to handle all config accesses for all
-        * busses. To improve performance, if the current device
-        * is the same as the last device accessed, we don't touch the
-        * tlb.
-        */
-       if (first_cfg) {
-               /* reserve a wired entry for pci config accesses */
-               first_cfg = 0;
-               pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP);
-               if (!pci_cfg_vm)
-                       panic(KERN_ERR "PCI unable to get vm area\n");
-               pci_cfg_wired_entry = read_c0_wired();
-               add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K);
-               last_entryLo0  = last_entryLo1 = 0xffffffff;
-       }
-
        /* Allow board vendors to implement their own off-chip idsel.
         * If it doesn't succeed, may as well bail out at this point.
         */
@@ -144,9 +140,12 @@ static int config_access(unsigned char access_type, struct pci_bus *bus,
        /* page boundary */
        cfg_base = cfg_base & PAGE_MASK;
 
+       /*
+        * To improve performance, if the current device is the same as
+        * the last device accessed, we don't touch the TLB.
+        */
        entryLo0 = (6 << 26)  | (cfg_base >> 6) | (2 << 3) | 7;
        entryLo1 = (6 << 26)  | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7;
-
        if ((entryLo0 != last_entryLo0) || (entryLo1 != last_entryLo1)) {
                mod_wired_entry(pci_cfg_wired_entry, entryLo0, entryLo1,
                                (unsigned long)pci_cfg_vm->addr, PM_4K);
index fe54514493044d8a9c70d9686518617531838d23..e95881897ec904b0489233f3fb1fd771a7da20e3 100644 (file)
@@ -42,6 +42,10 @@ static int
 mace_pci_read_config(struct pci_bus *bus, unsigned int devfn,
                     int reg, int size, u32 *val)
 {
+       u32 control = mace->pci.control;
+
+       /* disable master aborts interrupts during config read */
+       mace->pci.control = control & ~MACEPCI_CONTROL_MAR_INT;
        mace->pci.config_addr = mkaddr(bus, devfn, reg);
        switch (size) {
        case 1:
@@ -54,6 +58,9 @@ mace_pci_read_config(struct pci_bus *bus, unsigned int devfn,
                *val = mace->pci.config_data.l;
                break;
        }
+       /* ack possible master abort */
+       mace->pci.error &= ~MACEPCI_ERROR_MASTER_ABORT;
+       mace->pci.control = control;
 
        DPRINTK("read%d: reg=%08x,val=%02x\n", size * 8, reg, *val);
 
index 618ea7dbc47444535cc53095f5f738fda0470b4c..532b561b44425d5fa58c951b0bbce8d25b2069eb 100644 (file)
@@ -119,6 +119,7 @@ static struct pci_controller mace_pci_controller = {
        .iommu          = 0,
        .mem_offset     = MACE_PCI_MEM_OFFSET,
        .io_offset      = 0,
+       .io_map_base    = CKSEG1ADDR(MACEPCI_LOW_IO),
 };
 
 static int __init mace_init(void)
@@ -135,7 +136,8 @@ static int __init mace_init(void)
        BUG_ON(request_irq(MACE_PCI_BRIDGE_IRQ, macepci_error, 0,
                           "MACE PCI error", NULL));
 
-       iomem_resource = mace_pci_mem_resource;
+       /* extend memory resources */
+       iomem_resource.end = mace_pci_mem_resource.end;
        ioport_resource = mace_pci_io_resource;
 
        register_pci_controller(&mace_pci_controller);
index e818fd0f1584f0938a467791be9492c2c4607821..6d494e0de3d97cb60beea553a515d8a9c65281ec 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
@@ -41,11 +40,60 @@ static cycle_t hpt_read(void)
        return read_c0_count2();
 }
 
+static struct clocksource pnx_clocksource = {
+       .name           = "pnx8xxx",
+       .rating         = 200,
+       .read           = hpt_read,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
 static void timer_ack(void)
 {
        write_c0_compare(cpj);
 }
 
+static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *c = dev_id;
+
+       /* clear MATCH, signal the event */
+       c->event_handler(c);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction pnx8xxx_timer_irq = {
+       .handler        = pnx8xxx_timer_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .name           = "pnx8xxx_timer",
+};
+
+static irqreturn_t monotonic_interrupt(int irq, void *dev_id)
+{
+       /* Timer 2 clear interrupt */
+       write_c0_compare2(-1);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction monotonic_irqaction = {
+       .handler = monotonic_interrupt,
+       .flags = IRQF_DISABLED,
+       .name = "Monotonic timer",
+};
+
+static int pnx8xxx_set_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+{
+       write_c0_compare(delta);
+       return 0;
+}
+
+static struct clock_event_device pnx8xxx_clockevent = {
+       .name           = "pnx8xxx_clockevent",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .set_next_event = pnx8xxx_set_next_event,
+};
+
 /*
  * plat_time_init() - it does the following things:
  *
@@ -58,11 +106,34 @@ static void timer_ack(void)
 
 __init void plat_time_init(void)
 {
+       unsigned int             configPR;
        unsigned int             n;
        unsigned int             m;
        unsigned int             p;
        unsigned int             pow2p;
 
+       clockevents_register_device(&pnx8xxx_clockevent);
+       clocksource_register(&pnx_clocksource);
+
+       setup_irq(PNX8550_INT_TIMER1, &pnx8xxx_timer_irq);
+       setup_irq(PNX8550_INT_TIMER2, &monotonic_irqaction);
+
+       /* Timer 1 start */
+       configPR = read_c0_config7();
+       configPR &= ~0x00000008;
+       write_c0_config7(configPR);
+
+       /* Timer 2 start */
+       configPR = read_c0_config7();
+       configPR &= ~0x00000010;
+       write_c0_config7(configPR);
+
+       /* Timer 3 stop */
+       configPR = read_c0_config7();
+       configPR |= 0x00000020;
+       write_c0_config7(configPR);
+
+
         /* PLL0 sets MIPS clock (PLL1 <=> TM1, PLL6 <=> TM2, PLL5 <=> mem) */
         /* (but only if CLK_MIPS_CTL select value [bits 3:1] is 1:  FIXME) */
 
@@ -87,42 +158,6 @@ __init void plat_time_init(void)
        write_c0_count2(0);
        write_c0_compare2(0xffffffff);
 
-       clocksource_mips.read = hpt_read;
-       mips_timer_ack = timer_ack;
-}
-
-static irqreturn_t monotonic_interrupt(int irq, void *dev_id)
-{
-       /* Timer 2 clear interrupt */
-       write_c0_compare2(-1);
-       return IRQ_HANDLED;
 }
 
-static struct irqaction monotonic_irqaction = {
-       .handler = monotonic_interrupt,
-       .flags = IRQF_DISABLED,
-       .name = "Monotonic timer",
-};
 
-void __init plat_timer_setup(struct irqaction *irq)
-{
-       int configPR;
-
-       setup_irq(PNX8550_INT_TIMER1, irq);
-       setup_irq(PNX8550_INT_TIMER2, &monotonic_irqaction);
-
-       /* Timer 1 start */
-       configPR = read_c0_config7();
-       configPR &= ~0x00000008;
-       write_c0_config7(configPR);
-
-       /* Timer 2 start */
-       configPR = read_c0_config7();
-       configPR &= ~0x00000010;
-       write_c0_config7(configPR);
-
-       /* Timer 3 stop */
-       configPR = read_c0_config7();
-       configPR |= 0x00000020;
-       write_c0_config7(configPR);
-}
index cab7cc22ab67407a8f2f37d4706a574c303ed3fb..b0ea0e43ba482b542f533d172277c6c03cee7bbd 100644 (file)
@@ -426,7 +426,6 @@ static void ip32_irq0(void)
 
        crime_int = crime->istat & crime_mask;
        irq = MACE_VID_IN1_IRQ + __ffs(crime_int);
-       crime_int = 1 << irq;
 
        if (crime_int & CRIME_MACEISA_INT_MASK) {
                unsigned long mace_int = mace->perif.ctrl.istat;
index 77febd68fcd47ec0ea6b5bcd7876b62fe283121e..89a71f49b692a31450911cc2be04f378c71f079d 100644 (file)
 #include <asm/ip32/mace.h>
 #include <asm/ip32/ip32_ints.h>
 
-/*
- * .iobase isn't a constant (in the sense of C) so we fill it in at runtime.
- */
-#define MACE_PORT(int)                                                 \
+#define MACEISA_SERIAL1_OFFS   offsetof(struct sgi_mace, isa.serial1)
+#define MACEISA_SERIAL2_OFFS   offsetof(struct sgi_mace, isa.serial2)
+
+#define MACE_PORT(offset,_irq)                                         \
 {                                                                      \
-       .irq            = int,                                          \
+       .mapbase        = MACE_BASE + offset,                           \
+       .irq            = _irq,                                         \
        .uartclk        = 1843200,                                      \
        .iotype         = UPIO_MEM,                                     \
-       .flags          = UPF_SKIP_TEST,                                \
+       .flags          = UPF_SKIP_TEST|UPF_IOREMAP,                    \
        .regshift       = 8,                                            \
 }
 
 static struct plat_serial8250_port uart8250_data[] = {
-       MACE_PORT(MACEISA_SERIAL1_IRQ),
-       MACE_PORT(MACEISA_SERIAL2_IRQ),
+       MACE_PORT(MACEISA_SERIAL1_OFFS, MACEISA_SERIAL1_IRQ),
+       MACE_PORT(MACEISA_SERIAL2_OFFS, MACEISA_SERIAL2_IRQ),
        { },
 };
 
@@ -41,9 +42,6 @@ static struct platform_device uart8250_device = {
 
 static int __init uart8250_init(void)
 {
-       uart8250_data[0].membase = (void __iomem *) &mace->isa.serial1;
-       uart8250_data[1].membase = (void __iomem *) &mace->isa.serial2;
-
        return platform_device_register(&uart8250_device);
 }
 
index 4a8152375efe2614a3947cca200b96006f92d6f8..632e5d201353ca9bf92613487f2545e75c3cf34f 100644 (file)
@@ -598,8 +598,8 @@ static int __init rbtx4938_ethaddr_init(void)
                        printk(KERN_WARNING "seeprom: bad checksum.\n");
        }
        for (i = 0; i < 2; i++) {
-               unsigned int slot = TX4938_PCIC_IDSEL_AD_TO_SLOT(31 - i);
-               unsigned int id = (1 << 8) | PCI_DEVFN(slot, 0); /* bus 1 */
+               unsigned int id =
+                       TXX9_IRQ_BASE + (i ? TX4938_IR_ETH1 : TX4938_IR_ETH0);
                struct platform_device *pdev;
                if (!(tx4938_ccfgptr->pcfg &
                      (i ? TX4938_PCFG_ETH1_SEL : TX4938_PCFG_ETH0_SEL)))
index ad0420da8921616f3c74c668a3c862b9048530a4..66e0ebb1a36487ec10dba9404e8f9f7e15b4ca73 100644 (file)
@@ -2,7 +2,7 @@
  * This file adds the header file glue so that the shared files
  * flatdevicetree.[ch] can compile and work in the powerpc bootwrapper.
  *
- * strncmp & strchr copied from <file:lib/strings.c>
+ * strncmp & strchr copied from <file:lib/string.c>
  * Copyright (C) 1991, 1992  Linus Torvalds
  *
  * Maintained by: Mark A. Greer <mgreer@mvista.com>
index 2d0c9ef555e9e4578d9df93ff91e025697069c4e..79a85d656871650d43e327b5661785a525039ddb 100644 (file)
@@ -278,6 +278,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
        unsigned long flags;
        struct scatterlist *s, *outs, *segstart;
        int outcount, incount, i;
+       unsigned int align;
        unsigned long handle;
 
        BUG_ON(direction == DMA_NONE);
@@ -309,7 +310,12 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                /* Allocate iommu entries for that segment */
                vaddr = (unsigned long) sg_virt(s);
                npages = iommu_num_pages(vaddr, slen);
-               entry = iommu_range_alloc(tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, 0);
+               align = 0;
+               if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
+                   (vaddr & ~PAGE_MASK) == 0)
+                       align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
+               entry = iommu_range_alloc(tbl, npages, &handle,
+                                         mask >> IOMMU_PAGE_SHIFT, align);
 
                DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
 
@@ -572,7 +578,7 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
 {
        dma_addr_t dma_handle = DMA_ERROR_CODE;
        unsigned long uaddr;
-       unsigned int npages;
+       unsigned int npages, align;
 
        BUG_ON(direction == DMA_NONE);
 
@@ -580,8 +586,13 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
        npages = iommu_num_pages(uaddr, size);
 
        if (tbl) {
+               align = 0;
+               if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && size >= PAGE_SIZE &&
+                   ((unsigned long)vaddr & ~PAGE_MASK) == 0)
+                       align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
+
                dma_handle = iommu_alloc(tbl, vaddr, npages, direction,
-                                        mask >> IOMMU_PAGE_SHIFT, 0);
+                                        mask >> IOMMU_PAGE_SHIFT, align);
                if (dma_handle == DMA_ERROR_CODE) {
                        if (printk_ratelimit())  {
                                printk(KERN_INFO "iommu_alloc failed, "
index 1add6efdb315065e4b424114944911ddb89a3c0e..5d89a21dd0d69b793989c79d169e6ce6fab60020 100644 (file)
@@ -2216,6 +2216,45 @@ static void __init fixup_device_tree_efika(void)
                        prom_printf("fixup_device_tree_efika: ",
                                "skipped entry %x - setprop error\n", i);
        }
+
+       /* Make sure ethernet mdio bus node exists */
+       node = call_prom("finddevice", 1, 1, ADDR("/builtin/mdio"));
+       if (!PHANDLE_VALID(node)) {
+               prom_printf("Adding Ethernet MDIO node\n");
+               call_prom("interpret", 1, 1,
+                       " s\" /builtin\" find-device"
+                       " new-device"
+                               " 1 encode-int s\" #address-cells\" property"
+                               " 0 encode-int s\" #size-cells\" property"
+                               " s\" mdio\" 2dup device-name device-type"
+                               " s\" mpc5200b-fec-phy\" encode-string"
+                               " s\" compatible\" property"
+                               " 0xf0003000 0x400 reg"
+                               " 0x2 encode-int"
+                               " 0x5 encode-int encode+"
+                               " 0x3 encode-int encode+"
+                               " s\" interrupts\" property"
+                       " finish-device");
+       };
+
+       /* Make sure ethernet phy device node exist */
+       node = call_prom("finddevice", 1, 1, ADDR("/builtin/mdio/ethernet-phy"));
+       if (!PHANDLE_VALID(node)) {
+               prom_printf("Adding Ethernet PHY node\n");
+               call_prom("interpret", 1, 1,
+                       " s\" /builtin/mdio\" find-device"
+                       " new-device"
+                               " s\" ethernet-phy\" device-name"
+                               " 0x10 encode-int s\" reg\" property"
+                               " my-self"
+                               " ihandle>phandle"
+                       " finish-device"
+                       " s\" /builtin/ethernet\" find-device"
+                               " encode-int"
+                               " s\" phy-handle\" property"
+                       " device-end");
+       }
+
 }
 #else
 #define fixup_device_tree_efika()
index 27922dff8b94e34614890f7764ce10c014b6fb65..50d7372bc2ce4f01cb9e78abe41148f5dc2ecf23 100644 (file)
@@ -292,6 +292,8 @@ void slb_initialize(void)
 
        create_shadowed_slbe(VMALLOC_START, mmu_kernel_ssize, vflags, 1);
 
+       slb_shadow_clear(2);
+
        /* We don't bolt the stack for the time being - we're in boot,
         * so the stack is in the bolted segment.  By the time it goes
         * elsewhere, we'll call _switch() which will bolt in the new
index c83c3e3f51784c55a3ed85f4e67e2e2513cec2f3..a088622036437e8a64c9be58f73e8606c0bb5db5 100644 (file)
@@ -459,7 +459,7 @@ static int spu_shutdown(struct sys_device *sysdev)
 }
 
 static struct sysdev_class spu_sysdev_class = {
-       set_kset_name("spu"),
+       .name = "spu",
        .shutdown = spu_shutdown,
 };
 
index 6e2a45e60261f99bf3814daeddd65e45fc2de07a..9ad53e637aee4c111b747acae0f58d1fa89131fe 100644 (file)
@@ -192,15 +192,6 @@ void do_notify_spus_active(void)
                mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
 }
-EXPORT_SYMBOL_GPL(do_notify_spus_active);
-
-#ifndef MODULE
-void notify_spus_active(void)
-{
-       do_notify_spus_active();
-}
-EXPORT_SYMBOL_GPL(notify_spus_active);
-#endif
 
 /**
  * spu_bind_context - bind spu context to physical spu
index 999f5e160897ba23ba07d7b6ae766d028fa26a7e..84c0d4ef76a2d1c3c88b744a56d0ce2c14cb5c9e 100644 (file)
@@ -663,7 +663,7 @@ static int pmacpic_resume(struct sys_device *sysdev)
 #endif /* CONFIG_PM && CONFIG_PPC32 */
 
 static struct sysdev_class pmacpic_sysclass = {
-       set_kset_name("pmac_pic"),
+       .name = "pmac_pic",
 };
 
 static struct sys_device device_pmacpic = {
index fc48b96c81bff2ee1ec79eef9d1f13f62b6693cf..c4ad54e0f288cde7934c1cbbdda987ea249e8e7b 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/vdso_datapage.h>
 #include <asm/pSeries_reconfig.h>
 #include "xics.h"
+#include "plpar_wrappers.h"
 
 /* This version can't take the spinlock, because it never returns */
 static struct rtas_args rtas_stop_self_args = {
@@ -58,6 +59,7 @@ static void pseries_mach_cpu_die(void)
        local_irq_disable();
        idle_task_exit();
        xics_teardown_cpu(0);
+       unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
        rtas_stop_self();
        /* Should never get here... */
        BUG();
@@ -151,7 +153,7 @@ static int pseries_add_processor(struct device_node *np)
        for (i = 0; i < nthreads; i++)
                cpu_set(i, tmp);
 
-       lock_cpu_hotplug();
+       cpu_maps_update_begin();
 
        BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
 
@@ -188,7 +190,7 @@ static int pseries_add_processor(struct device_node *np)
        }
        err = 0;
 out_unlock:
-       unlock_cpu_hotplug();
+       cpu_maps_update_done();
        return err;
 }
 
@@ -209,7 +211,7 @@ static void pseries_remove_processor(struct device_node *np)
 
        nthreads = len / sizeof(u32);
 
-       lock_cpu_hotplug();
+       cpu_maps_update_begin();
        for (i = 0; i < nthreads; i++) {
                for_each_present_cpu(cpu) {
                        if (get_hard_smp_processor_id(cpu) != intserv[i])
@@ -223,7 +225,7 @@ static void pseries_remove_processor(struct device_node *np)
                        printk(KERN_WARNING "Could not find cpu to remove "
                               "with physical id 0x%x\n", intserv[i]);
        }
-       unlock_cpu_hotplug();
+       cpu_maps_update_done();
 }
 
 static int pseries_smp_notifier(struct notifier_block *nb,
index 73e69023d90a9f57b76a718c910dde2aa3b24f0b..e95fc1594c84b0d8f76c351c459ce8b74b2db816 100644 (file)
 
 unsigned long rtas_poweron_auto; /* default and normal state is 0 */
 
-static ssize_t auto_poweron_show(struct kset *kset, char *buf)
+static ssize_t auto_poweron_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buf)
 {
         return sprintf(buf, "%lu\n", rtas_poweron_auto);
 }
 
-static ssize_t
-auto_poweron_store(struct kset *kset, const char *buf, size_t n)
+static ssize_t auto_poweron_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buf, size_t n)
 {
        int ret;
        unsigned long ups_restart;
@@ -47,17 +49,11 @@ auto_poweron_store(struct kset *kset, const char *buf, size_t n)
        return -EINVAL;
 }
 
-static struct subsys_attribute auto_poweron_attr = {
-        .attr   = {
-                .name = __stringify(auto_poweron),
-                .mode = 0644,
-        },
-        .show   = auto_poweron_show,
-        .store  = auto_poweron_store,
-};
+static struct kobj_attribute auto_poweron_attr =
+       __ATTR(auto_poweron, 0644, auto_poweron_show, auto_poweron_store);
 
 #ifndef CONFIG_PM
-decl_subsys(power,NULL,NULL);
+struct kobject *power_kobj;
 
 static struct attribute *g[] = {
         &auto_poweron_attr.attr,
@@ -70,18 +66,16 @@ static struct attribute_group attr_group = {
 
 static int __init pm_init(void)
 {
-        int error = subsystem_register(&power_subsys);
-        if (!error)
-                error = sysfs_create_group(&power_subsys.kobj, &attr_group);
-        return error;
+       power_kobj = kobject_create_and_add("power", NULL);
+       if (!power_kobj)
+               return -ENOMEM;
+       return sysfs_create_group(power_kobj, &attr_group);
 }
 core_initcall(pm_init);
 #else
-extern struct kset power_subsys;
-
 static int __init apo_pm_init(void)
 {
-       return (subsys_create_file(&power_subsys, &auto_poweron_attr));
+       return (sysfs_create_file(power_kobj, &auto_poweron_attr));
 }
 __initcall(apo_pm_init);
 #endif
index 73401c820110a2a877f999c702e83d593e4f9f08..e3078ce41518aec0abb0579a5c2f9cb21315dd44 100644 (file)
@@ -382,7 +382,7 @@ static void do_event_scan_all_cpus(long delay)
 {
        int cpu;
 
-       lock_cpu_hotplug();
+       get_online_cpus();
        cpu = first_cpu(cpu_online_map);
        for (;;) {
                set_cpus_allowed(current, cpumask_of_cpu(cpu));
@@ -390,15 +390,15 @@ static void do_event_scan_all_cpus(long delay)
                set_cpus_allowed(current, CPU_MASK_ALL);
 
                /* Drop hotplug lock, and sleep for the specified delay */
-               unlock_cpu_hotplug();
+               put_online_cpus();
                msleep_interruptible(delay);
-               lock_cpu_hotplug();
+               get_online_cpus();
 
                cpu = next_cpu(cpu, cpu_online_map);
                if (cpu == NR_CPUS)
                        break;
        }
-       unlock_cpu_hotplug();
+       put_online_cpus();
 }
 
 static int rtasd(void *unused)
index 05a56e55804c3ab4395671b9bd2a4713972cbf20..e898ff4d2b97c9218e2bbb0793e21df86d5b5d28 100644 (file)
@@ -725,7 +725,7 @@ unsigned int ipic_get_irq(void)
 }
 
 static struct sysdev_class ipic_sysclass = {
-       set_kset_name("ipic"),
+       .name = "ipic",
 };
 
 static struct sys_device device_ipic = {
index e47938899a9268c3e926979f7f15e73394810c3d..212a94f5d34b5e6d20ca4169e6014de284a87ebe 100644 (file)
@@ -1584,7 +1584,7 @@ static struct sysdev_class mpic_sysclass = {
        .resume = mpic_resume,
        .suspend = mpic_suspend,
 #endif
-       set_kset_name("mpic"),
+       .name = "mpic",
 };
 
 static int mpic_init_sys(void)
index e1c0fd6dbc1aaf23400cc385d946602de5831d2d..f59444d3be752aa9580d751a9a76c0cd008a5f85 100644 (file)
@@ -483,7 +483,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
 }
 
 static struct sysdev_class qe_ic_sysclass = {
-       set_kset_name("qe_ic"),
+       .name = "qe_ic",
 };
 
 static struct sys_device device_qe_ic = {
index aa07b63c0a6cb95fca625d0afa7b2f9e62ff8234..9ed36dd9cbff3a08f4db0c79e4aa5f62fb68ae8f 100644 (file)
@@ -436,7 +436,6 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
  */
 static ctl_table htab_ctl_table[]={
        {
-               .ctl_name       = KERN_PPC_L2CR,
                .procname       = "l2cr",
                .mode           = 0644,
                .proc_handler   = &proc_dol2crvec,
index 9192777d0f78469c9791970327a2b97f4d7d47c8..4f163e20939e2ba94feb6f70a48ad72bed03bdf9 100644 (file)
@@ -614,7 +614,7 @@ int ipic_get_irq(void)
 }
 
 static struct sysdev_class ipic_sysclass = {
-       set_kset_name("ipic"),
+       .name = "ipic",
 };
 
 static struct sys_device device_ipic = {
index 18ec94733293538228d97f311d9e50003f28540a..da36522d327a778fbf4921bbd099a5cefb85af46 100644 (file)
@@ -1043,7 +1043,7 @@ int openpic_resume(struct sys_device *sysdev)
 #endif /* CONFIG_PM */
 
 static struct sysdev_class openpic_sysclass = {
-       set_kset_name("openpic"),
+       .name = "openpic",
 };
 
 static struct sys_device device_openpic = {
index d585207f9f77855e0c8f126dfc52014fbc4328af..449075a0479803f9c17d52fc240f8dbeffcf4478 100644 (file)
@@ -666,7 +666,7 @@ int openpic2_resume(struct sys_device *sysdev)
 
 /* HACK ALERT */
 static struct sysdev_class openpic2_sysclass = {
-       set_kset_name("openpic2"),
+       .name = "openpic2",
 };
 
 static struct sys_device device_openpic2 = {
index 1330061020ab54e718ddaed14d71b05c20ae4bf9..6ef54d27fc001720f738aa3f066e15497503c064 100644 (file)
@@ -276,9 +276,6 @@ source "kernel/Kconfig.preempt"
 
 source "mm/Kconfig"
 
-config HOLES_IN_ZONE
-       def_bool y
-
 comment "I/O subsystem configuration"
 
 config MACHCHK_WARNING
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
deleted file mode 100644 (file)
index d1defbb..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-config CRYPTO_SHA1_S390
-       tristate "SHA1 digest algorithm"
-       depends on S390
-       select CRYPTO_ALGAPI
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
-config CRYPTO_SHA256_S390
-       tristate "SHA256 digest algorithm"
-       depends on S390
-       select CRYPTO_ALGAPI
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA256 secure hash standard (DFIPS 180-2).
-
-         This version of SHA implements a 256 bit hash with 128 bits of
-         security against collision attacks.
-
-config CRYPTO_DES_S390
-       tristate "DES and Triple DES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_BLKCIPHER
-       help
-         This us the s390 hardware accelerated implementation of the
-         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
-config CRYPTO_AES_S390
-       tristate "AES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_BLKCIPHER
-       help
-         This is the s390 hardware accelerated implementation of the
-         AES cipher algorithms (FIPS-197). AES uses the Rijndael
-         algorithm.
-
-         Rijndael appears to be consistently a very good performer in
-         both hardware and software across a wide range of computing
-         environments regardless of its use in feedback or non-feedback
-         modes. Its key setup time is excellent, and its key agility is
-         good. Rijndael's very low memory requirements make it very well
-         suited for restricted-space environments, in which it also
-         demonstrates excellent performance. Rijndael's operations are
-         among the easiest to defend against power and timing attacks.
-
-         On s390 the System z9-109 currently only supports the key size
-         of 128 bit.
-
-config S390_PRNG
-       tristate "Pseudo random number generator device driver"
-       depends on S390
-       default "m"
-       help
-         Select this option if you want to use the s390 pseudo random number
-         generator. The PRNG is part of the cryptographic processor functions
-         and uses triple-DES to generate secure random numbers like the
-         ANSI X9.17 standard. The PRNG is usable via the char device
-         /dev/prandom.
index 512669691ad01b9513ce5c283d5d9db6e75e5aed..a3f67f8b5427a29628c0c1498de0757a0dab81d2 100644 (file)
@@ -6,6 +6,7 @@
  * s390 Version:
  *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
+ *             Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback
  *
  * Derived from "crypto/aes_generic.c"
  *
  *
  */
 
+#include <crypto/aes.h>
 #include <crypto/algapi.h>
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include "crypt_s390.h"
 
-#define AES_MIN_KEY_SIZE       16
-#define AES_MAX_KEY_SIZE       32
-
-/* data block size for all key lengths */
-#define AES_BLOCK_SIZE         16
-
 #define AES_KEYLEN_128         1
 #define AES_KEYLEN_192         2
 #define AES_KEYLEN_256         4
@@ -39,45 +36,89 @@ struct s390_aes_ctx {
        long enc;
        long dec;
        int key_len;
+       union {
+               struct crypto_blkcipher *blk;
+               struct crypto_cipher *cip;
+       } fallback;
 };
 
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-                      unsigned int key_len)
+/*
+ * Check if the key_len is supported by the HW.
+ * Returns 0 if it is, a positive number if it is not and software fallback is
+ * required or a negative number in case the key size is not valid
+ */
+static int need_fallback(unsigned int key_len)
 {
-       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-       u32 *flags = &tfm->crt_flags;
-
        switch (key_len) {
        case 16:
                if (!(keylen_flag & AES_KEYLEN_128))
-                       goto fail;
+                       return 1;
                break;
        case 24:
                if (!(keylen_flag & AES_KEYLEN_192))
-                       goto fail;
-
+                       return 1;
                break;
        case 32:
                if (!(keylen_flag & AES_KEYLEN_256))
-                       goto fail;
+                       return 1;
                break;
        default:
-               goto fail;
+               return -1;
                break;
        }
+       return 0;
+}
+
+static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
+               unsigned int key_len)
+{
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       int ret;
+
+       sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+       sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+                       CRYPTO_TFM_REQ_MASK);
+
+       ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
+       if (ret) {
+               tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+               tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
+                               CRYPTO_TFM_RES_MASK);
+       }
+       return ret;
+}
+
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+                      unsigned int key_len)
+{
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+       int ret;
+
+       ret = need_fallback(key_len);
+       if (ret < 0) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
 
        sctx->key_len = key_len;
-       memcpy(sctx->key, in_key, key_len);
-       return 0;
-fail:
-       *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-       return -EINVAL;
+       if (!ret) {
+               memcpy(sctx->key, in_key, key_len);
+               return 0;
+       }
+
+       return setkey_fallback_cip(tfm, in_key, key_len);
 }
 
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
+       if (unlikely(need_fallback(sctx->key_len))) {
+               crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
+               return;
+       }
+
        switch (sctx->key_len) {
        case 16:
                crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
@@ -98,6 +139,11 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
+       if (unlikely(need_fallback(sctx->key_len))) {
+               crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
+               return;
+       }
+
        switch (sctx->key_len) {
        case 16:
                crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
@@ -114,6 +160,29 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
        }
 }
 
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+       const char *name = tfm->__crt_alg->cra_name;
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+       sctx->fallback.cip = crypto_alloc_cipher(name, 0,
+                       CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+       if (IS_ERR(sctx->fallback.cip)) {
+               printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+               return PTR_ERR(sctx->fallback.blk);
+       }
+
+       return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_cipher(sctx->fallback.cip);
+       sctx->fallback.cip = NULL;
+}
 
 static struct crypto_alg aes_alg = {
        .cra_name               =       "aes",
@@ -125,6 +194,8 @@ static struct crypto_alg aes_alg = {
        .cra_ctxsize            =       sizeof(struct s390_aes_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
+       .cra_init               =       fallback_init_cip,
+       .cra_exit               =       fallback_exit_cip,
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       AES_MIN_KEY_SIZE,
@@ -136,10 +207,70 @@ static struct crypto_alg aes_alg = {
        }
 };
 
+static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key,
+               unsigned int len)
+{
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       unsigned int ret;
+
+       sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+       sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+                       CRYPTO_TFM_REQ_MASK);
+
+       ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len);
+       if (ret) {
+               tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+               tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
+                               CRYPTO_TFM_RES_MASK);
+       }
+       return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+               struct scatterlist *dst, struct scatterlist *src,
+               unsigned int nbytes)
+{
+       unsigned int ret;
+       struct crypto_blkcipher *tfm;
+       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+
+       tfm = desc->tfm;
+       desc->tfm = sctx->fallback.blk;
+
+       ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+       desc->tfm = tfm;
+       return ret;
+}
+
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+               struct scatterlist *dst, struct scatterlist *src,
+               unsigned int nbytes)
+{
+       unsigned int ret;
+       struct crypto_blkcipher *tfm;
+       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+
+       tfm = desc->tfm;
+       desc->tfm = sctx->fallback.blk;
+
+       ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+       desc->tfm = tfm;
+       return ret;
+}
+
 static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
                           unsigned int key_len)
 {
        struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       int ret;
+
+       ret = need_fallback(key_len);
+       if (ret > 0) {
+               sctx->key_len = key_len;
+               return setkey_fallback_blk(tfm, in_key, key_len);
+       }
 
        switch (key_len) {
        case 16:
@@ -188,6 +319,9 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
        struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
        struct blkcipher_walk walk;
 
+       if (unlikely(need_fallback(sctx->key_len)))
+               return fallback_blk_enc(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
 }
@@ -199,10 +333,37 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
        struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
        struct blkcipher_walk walk;
 
+       if (unlikely(need_fallback(sctx->key_len)))
+               return fallback_blk_dec(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
 }
 
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+       const char *name = tfm->__crt_alg->cra_name;
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+       sctx->fallback.blk = crypto_alloc_blkcipher(name, 0,
+                       CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+       if (IS_ERR(sctx->fallback.blk)) {
+               printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+               return PTR_ERR(sctx->fallback.blk);
+       }
+
+       return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_blkcipher(sctx->fallback.blk);
+       sctx->fallback.blk = NULL;
+}
+
 static struct crypto_alg ecb_aes_alg = {
        .cra_name               =       "ecb(aes)",
        .cra_driver_name        =       "ecb-aes-s390",
@@ -214,6 +375,8 @@ static struct crypto_alg ecb_aes_alg = {
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(ecb_aes_alg.cra_list),
+       .cra_init               =       fallback_init_blk,
+       .cra_exit               =       fallback_exit_blk,
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       AES_MIN_KEY_SIZE,
@@ -229,6 +392,13 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
                           unsigned int key_len)
 {
        struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       int ret;
+
+       ret = need_fallback(key_len);
+       if (ret > 0) {
+               sctx->key_len = key_len;
+               return setkey_fallback_blk(tfm, in_key, key_len);
+       }
 
        switch (key_len) {
        case 16:
@@ -283,6 +453,9 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
        struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
        struct blkcipher_walk walk;
 
+       if (unlikely(need_fallback(sctx->key_len)))
+               return fallback_blk_enc(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
 }
@@ -294,6 +467,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
        struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
        struct blkcipher_walk walk;
 
+       if (unlikely(need_fallback(sctx->key_len)))
+               return fallback_blk_dec(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
 }
@@ -309,6 +485,8 @@ static struct crypto_alg cbc_aes_alg = {
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(cbc_aes_alg.cra_list),
+       .cra_init               =       fallback_init_blk,
+       .cra_exit               =       fallback_exit_blk,
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       AES_MIN_KEY_SIZE,
@@ -336,14 +514,10 @@ static int __init aes_init(void)
                return -EOPNOTSUPP;
 
        /* z9 109 and z9 BC/EC only support 128 bit key length */
-       if (keylen_flag == AES_KEYLEN_128) {
-               aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
-               ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
-               cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
+       if (keylen_flag == AES_KEYLEN_128)
                printk(KERN_INFO
-                      "aes_s390: hardware acceleration only available for"
+                      "aes_s390: hardware acceleration only available for "
                       "128 bit keys\n");
-       }
 
        ret = crypto_register_alg(&aes_alg);
        if (ret)
@@ -382,4 +556,3 @@ MODULE_ALIAS("aes");
 
 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
 MODULE_LICENSE("GPL");
-
index 8eb3a1aedc228b68336824121260107ce190c3ae..0cfefddd83755366fee0dae7634ccca6342b21dd 100644 (file)
@@ -90,7 +90,7 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
        int ret = 0;
        int tmp;
 
-       /* nbytes can be arbitrary long, we spilt it into chunks */
+       /* nbytes can be arbitrary length, we split it into chunks */
        while (nbytes) {
                /* same as in extract_entropy_user in random.c */
                if (need_resched()) {
@@ -146,7 +146,7 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
        return ret;
 }
 
-static struct file_operations prng_fops = {
+static const struct file_operations prng_fops = {
        .owner          = THIS_MODULE,
        .open           = &prng_open,
        .release        = NULL,
index 5245717295b82f5e9a42d07af8a6c160c6367cbf..4b010ff814c9caa3f439cb7e849aa8c501bdace1 100644 (file)
@@ -490,7 +490,7 @@ static struct super_operations hypfs_s_ops = {
        .show_options   = hypfs_show_options,
 };
 
-static decl_subsys(s390, NULL, NULL);
+static struct kobject *s390_kobj;
 
 static int __init hypfs_init(void)
 {
@@ -506,17 +506,18 @@ static int __init hypfs_init(void)
                        goto fail_diag;
                }
        }
-       kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
-       rc = subsystem_register(&s390_subsys);
-       if (rc)
+       s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
+       if (!s390_kobj) {
+               rc = -ENOMEM;;
                goto fail_sysfs;
+       }
        rc = register_filesystem(&hypfs_type);
        if (rc)
                goto fail_filesystem;
        return 0;
 
 fail_filesystem:
-       subsystem_unregister(&s390_subsys);
+       kobject_put(s390_kobj);
 fail_sysfs:
        if (!MACHINE_IS_VM)
                hypfs_diag_exit();
@@ -530,7 +531,7 @@ static void __exit hypfs_exit(void)
        if (!MACHINE_IS_VM)
                hypfs_diag_exit();
        unregister_filesystem(&hypfs_type);
-       subsystem_unregister(&s390_subsys);
+       kobject_put(s390_kobj);
 }
 
 module_init(hypfs_init)
index 56cb71007cd9a26277c4bc6c3a7873fe357e291e..b3b650a93c7c752f6d95c5b789beef5cfbd99589 100644 (file)
@@ -31,7 +31,3 @@ S390_KEXEC_OBJS := machine_kexec.o crash.o
 S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
 obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
 
-#
-# This is just to get the dependencies...
-#
-binfmt_elf32.o:        $(TOPDIR)/fs/binfmt_elf.c
index 1b3af7dab8161bf08ec6fd3d5110170b2c89f914..9f7b73b180f00a064ce36457b9ba88e0ecb38c79 100644 (file)
@@ -276,7 +276,7 @@ void __init startup_init(void)
        create_kernel_nss();
        sort_main_extable();
        setup_lowcore_early();
-       sclp_readinfo_early();
+       sclp_read_info_early();
        sclp_facilities_detect();
        memsize = sclp_memory_detect();
 #ifndef CONFIG_64BIT
index a87b1976d409e3b94a7972998379731d08bcab6a..79dccd206a6ea48122374b73783dfb13f005a113 100644 (file)
@@ -157,7 +157,7 @@ startup_continue:
        .long   0xb2b10000              # store facility list
        tm      0xc8,0x08               # check bit for clearing-by-ASCE
        bno     0f-.LPG1(%r13)
-       lhi     %r1,2094
+       lhi     %r1,2048
        lhi     %r2,0
        .long   0xb98e2001
        oi      7(%r12),0x80            # set IDTE flag
index ce0856d32500215ef1942d03a0a61f000767d4fa..db28cca81fef75ec6c1ffcec76c14218dff80d34 100644 (file)
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/ipl.c
  *    ipl/reipl/dump support for Linux on s390.
  *
- *    Copyright (C) IBM Corp. 2005,2006
+ *    Copyright IBM Corp. 2005,2007
  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  *              Heiko Carstens <heiko.carstens@de.ibm.com>
  *              Volker Sameske <sameske@de.ibm.com>
 #define IPL_FCP_DUMP_STR       "fcp_dump"
 #define IPL_NSS_STR            "nss"
 
+#define DUMP_CCW_STR           "ccw"
+#define DUMP_FCP_STR           "fcp"
+#define DUMP_NONE_STR          "none"
+
+/*
+ * Four shutdown trigger types are supported:
+ * - panic
+ * - halt
+ * - power off
+ * - reipl
+ */
+#define ON_PANIC_STR           "on_panic"
+#define ON_HALT_STR            "on_halt"
+#define ON_POFF_STR            "on_poff"
+#define ON_REIPL_STR           "on_reboot"
+
+struct shutdown_action;
+struct shutdown_trigger {
+       char *name;
+       struct shutdown_action *action;
+};
+
+/*
+ * Five shutdown action types are supported:
+ */
+#define SHUTDOWN_ACTION_IPL_STR                "ipl"
+#define SHUTDOWN_ACTION_REIPL_STR      "reipl"
+#define SHUTDOWN_ACTION_DUMP_STR       "dump"
+#define SHUTDOWN_ACTION_VMCMD_STR      "vmcmd"
+#define SHUTDOWN_ACTION_STOP_STR       "stop"
+
+struct shutdown_action {
+       char *name;
+       void (*fn) (struct shutdown_trigger *trigger);
+       int (*init) (void);
+};
+
 static char *ipl_type_str(enum ipl_type type)
 {
        switch (type) {
@@ -54,10 +91,6 @@ enum dump_type {
        DUMP_TYPE_FCP   = 4,
 };
 
-#define DUMP_NONE_STR   "none"
-#define DUMP_CCW_STR    "ccw"
-#define DUMP_FCP_STR    "fcp"
-
 static char *dump_type_str(enum dump_type type)
 {
        switch (type) {
@@ -99,30 +132,6 @@ enum dump_method {
        DUMP_METHOD_FCP_DIAG,
 };
 
-enum shutdown_action {
-       SHUTDOWN_REIPL,
-       SHUTDOWN_DUMP,
-       SHUTDOWN_STOP,
-};
-
-#define SHUTDOWN_REIPL_STR "reipl"
-#define SHUTDOWN_DUMP_STR  "dump"
-#define SHUTDOWN_STOP_STR  "stop"
-
-static char *shutdown_action_str(enum shutdown_action action)
-{
-       switch (action) {
-       case SHUTDOWN_REIPL:
-               return SHUTDOWN_REIPL_STR;
-       case SHUTDOWN_DUMP:
-               return SHUTDOWN_DUMP_STR;
-       case SHUTDOWN_STOP:
-               return SHUTDOWN_STOP_STR;
-       default:
-               return NULL;
-       }
-}
-
 static int diag308_set_works = 0;
 
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
@@ -140,8 +149,6 @@ static enum dump_method dump_method = DUMP_METHOD_NONE;
 static struct ipl_parameter_block *dump_block_fcp;
 static struct ipl_parameter_block *dump_block_ccw;
 
-static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
-
 static struct sclp_ipl_info sclp_ipl_info;
 
 int diag308(unsigned long subcode, void *addr)
@@ -162,22 +169,25 @@ EXPORT_SYMBOL_GPL(diag308);
 /* SYSFS */
 
 #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)            \
-static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,       \
+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,    \
+               struct kobj_attribute *attr,                            \
                char *page)                                             \
 {                                                                      \
        return sprintf(page, _format, _value);                          \
 }                                                                      \
-static struct subsys_attribute sys_##_prefix##_##_name##_attr =                \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr =          \
        __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
 
 #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)  \
-static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,       \
+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,    \
+               struct kobj_attribute *attr,                            \
                char *page)                                             \
 {                                                                      \
        return sprintf(page, _fmt_out,                                  \
                        (unsigned long long) _value);                   \
 }                                                                      \
-static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,      \
+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,   \
+               struct kobj_attribute *attr,                            \
                const char *buf, size_t len)                            \
 {                                                                      \
        unsigned long long value;                                       \
@@ -186,25 +196,27 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \
        _value = value;                                                 \
        return len;                                                     \
 }                                                                      \
-static struct subsys_attribute sys_##_prefix##_##_name##_attr =                \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr =          \
        __ATTR(_name,(S_IRUGO | S_IWUSR),                               \
                        sys_##_prefix##_##_name##_show,                 \
                        sys_##_prefix##_##_name##_store);
 
 #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
-static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,       \
+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,    \
+               struct kobj_attribute *attr,                            \
                char *page)                                             \
 {                                                                      \
        return sprintf(page, _fmt_out, _value);                         \
 }                                                                      \
-static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,      \
+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,   \
+               struct kobj_attribute *attr,                            \
                const char *buf, size_t len)                            \
 {                                                                      \
-       if (sscanf(buf, _fmt_in, _value) != 1)                          \
-               return -EINVAL;                                         \
+       strncpy(_value, buf, sizeof(_value) - 1);                       \
+       strstrip(_value);                                               \
        return len;                                                     \
 }                                                                      \
-static struct subsys_attribute sys_##_prefix##_##_name##_attr =                \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr =          \
        __ATTR(_name,(S_IRUGO | S_IWUSR),                               \
                        sys_##_prefix##_##_name##_show,                 \
                        sys_##_prefix##_##_name##_store);
@@ -240,44 +252,19 @@ static __init enum ipl_type get_ipl_type(void)
        return IPL_TYPE_FCP;
 }
 
-void __init setup_ipl_info(void)
-{
-       ipl_info.type = get_ipl_type();
-       switch (ipl_info.type) {
-       case IPL_TYPE_CCW:
-               ipl_info.data.ccw.dev_id.devno = ipl_devno;
-               ipl_info.data.ccw.dev_id.ssid = 0;
-               break;
-       case IPL_TYPE_FCP:
-       case IPL_TYPE_FCP_DUMP:
-               ipl_info.data.fcp.dev_id.devno =
-                       IPL_PARMBLOCK_START->ipl_info.fcp.devno;
-               ipl_info.data.fcp.dev_id.ssid = 0;
-               ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
-               ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
-               break;
-       case IPL_TYPE_NSS:
-               strncpy(ipl_info.data.nss.name, kernel_nss_name,
-                       sizeof(ipl_info.data.nss.name));
-               break;
-       case IPL_TYPE_UNKNOWN:
-       default:
-               /* We have no info to copy */
-               break;
-       }
-}
-
 struct ipl_info ipl_info;
 EXPORT_SYMBOL_GPL(ipl_info);
 
-static ssize_t ipl_type_show(struct kset *kset, char *page)
+static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
+                            char *page)
 {
        return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
 }
 
-static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
+static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
 
-static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
+static ssize_t sys_ipl_device_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *page)
 {
        struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
@@ -292,7 +279,7 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
        }
 }
 
-static struct subsys_attribute sys_ipl_device_attr =
+static struct kobj_attribute sys_ipl_device_attr =
        __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
 
 static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
@@ -367,7 +354,8 @@ static struct attribute_group ipl_fcp_attr_group = {
 
 /* CCW ipl device attributes */
 
-static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
+static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
+                                    struct kobj_attribute *attr, char *page)
 {
        char loadparm[LOADPARM_LEN + 1] = {};
 
@@ -379,7 +367,7 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
        return sprintf(page, "%s\n", loadparm);
 }
 
-static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
+static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
        __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
 
 static struct attribute *ipl_ccw_attrs[] = {
@@ -418,10 +406,76 @@ static struct attribute_group ipl_unknown_attr_group = {
        .attrs = ipl_unknown_attrs,
 };
 
-static decl_subsys(ipl, NULL, NULL);
+static struct kset *ipl_kset;
+
+static int __init ipl_register_fcp_files(void)
+{
+       int rc;
+
+       rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
+       if (rc)
+               goto out;
+       rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
+       if (rc)
+               goto out_ipl_parm;
+       rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr);
+       if (!rc)
+               goto out;
+
+       sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
+
+out_ipl_parm:
+       sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
+out:
+       return rc;
+}
+
+static void ipl_run(struct shutdown_trigger *trigger)
+{
+       diag308(DIAG308_IPL, NULL);
+       if (MACHINE_IS_VM)
+               __cpcmd("IPL", NULL, 0, NULL);
+       else if (ipl_info.type == IPL_TYPE_CCW)
+               reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
+}
+
+static int ipl_init(void)
+{
+       int rc;
+
+       ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
+       if (!ipl_kset) {
+               rc = -ENOMEM;
+               goto out;
+       }
+       switch (ipl_info.type) {
+       case IPL_TYPE_CCW:
+               rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
+               break;
+       case IPL_TYPE_FCP:
+       case IPL_TYPE_FCP_DUMP:
+               rc = ipl_register_fcp_files();
+               break;
+       case IPL_TYPE_NSS:
+               rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
+               break;
+       default:
+               rc = sysfs_create_group(&ipl_kset->kobj,
+                                       &ipl_unknown_attr_group);
+               break;
+       }
+out:
+       if (rc)
+               panic("ipl_init failed: rc = %i\n", rc);
+
+       return 0;
+}
+
+static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
+                                           ipl_init};
 
 /*
- * reipl section
+ * reipl shutdown action: Reboot Linux on shutdown.
  */
 
 /* FCP reipl device attributes */
@@ -465,7 +519,8 @@ static void reipl_get_ascii_loadparm(char *loadparm)
        strstrip(loadparm);
 }
 
-static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
+static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr, char *page)
 {
        char buf[LOADPARM_LEN + 1];
 
@@ -473,7 +528,8 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
        return sprintf(page, "%s\n", buf);
 }
 
-static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
+static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
                                        const char *buf, size_t len)
 {
        int i, lp_len;
@@ -500,7 +556,7 @@ static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
        return len;
 }
 
-static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
+static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
        __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
               reipl_ccw_loadparm_store);
 
@@ -539,7 +595,9 @@ static int reipl_set_type(enum ipl_type type)
 
        switch(type) {
        case IPL_TYPE_CCW:
-               if (MACHINE_IS_VM)
+               if (diag308_set_works)
+                       reipl_method = REIPL_METHOD_CCW_DIAG;
+               else if (MACHINE_IS_VM)
                        reipl_method = REIPL_METHOD_CCW_VM;
                else
                        reipl_method = REIPL_METHOD_CCW_CIO;
@@ -568,13 +626,15 @@ static int reipl_set_type(enum ipl_type type)
        return 0;
 }
 
-static ssize_t reipl_type_show(struct kset *kset, char *page)
+static ssize_t reipl_type_show(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *page)
 {
        return sprintf(page, "%s\n", ipl_type_str(reipl_type));
 }
 
-static ssize_t reipl_type_store(struct kset *kset, const char *buf,
-                               size_t len)
+static ssize_t reipl_type_store(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               const char *buf, size_t len)
 {
        int rc = -EINVAL;
 
@@ -587,140 +647,12 @@ static ssize_t reipl_type_store(struct kset *kset, const char *buf,
        return (rc != 0) ? rc : len;
 }
 
-static struct subsys_attribute reipl_type_attr =
-               __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
-
-static decl_subsys(reipl, NULL, NULL);
-
-/*
- * dump section
- */
-
-/* FCP dump device attributes */
-
-DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
-                  dump_block_fcp->ipl_info.fcp.wwpn);
-DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
-                  dump_block_fcp->ipl_info.fcp.lun);
-DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
-                  dump_block_fcp->ipl_info.fcp.bootprog);
-DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
-                  dump_block_fcp->ipl_info.fcp.br_lba);
-DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
-                  dump_block_fcp->ipl_info.fcp.devno);
-
-static struct attribute *dump_fcp_attrs[] = {
-       &sys_dump_fcp_device_attr.attr,
-       &sys_dump_fcp_wwpn_attr.attr,
-       &sys_dump_fcp_lun_attr.attr,
-       &sys_dump_fcp_bootprog_attr.attr,
-       &sys_dump_fcp_br_lba_attr.attr,
-       NULL,
-};
-
-static struct attribute_group dump_fcp_attr_group = {
-       .name  = IPL_FCP_STR,
-       .attrs = dump_fcp_attrs,
-};
-
-/* CCW dump device attributes */
-
-DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
-                  dump_block_ccw->ipl_info.ccw.devno);
-
-static struct attribute *dump_ccw_attrs[] = {
-       &sys_dump_ccw_device_attr.attr,
-       NULL,
-};
-
-static struct attribute_group dump_ccw_attr_group = {
-       .name  = IPL_CCW_STR,
-       .attrs = dump_ccw_attrs,
-};
-
-/* dump type */
-
-static int dump_set_type(enum dump_type type)
-{
-       if (!(dump_capabilities & type))
-               return -EINVAL;
-       switch(type) {
-       case DUMP_TYPE_CCW:
-               if (MACHINE_IS_VM)
-                       dump_method = DUMP_METHOD_CCW_VM;
-               else if (diag308_set_works)
-                       dump_method = DUMP_METHOD_CCW_DIAG;
-               else
-                       dump_method = DUMP_METHOD_CCW_CIO;
-               break;
-       case DUMP_TYPE_FCP:
-               dump_method = DUMP_METHOD_FCP_DIAG;
-               break;
-       default:
-               dump_method = DUMP_METHOD_NONE;
-       }
-       dump_type = type;
-       return 0;
-}
-
-static ssize_t dump_type_show(struct kset *kset, char *page)
-{
-       return sprintf(page, "%s\n", dump_type_str(dump_type));
-}
-
-static ssize_t dump_type_store(struct kset *kset, const char *buf,
-                              size_t len)
-{
-       int rc = -EINVAL;
-
-       if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
-               rc = dump_set_type(DUMP_TYPE_NONE);
-       else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
-               rc = dump_set_type(DUMP_TYPE_CCW);
-       else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
-               rc = dump_set_type(DUMP_TYPE_FCP);
-       return (rc != 0) ? rc : len;
-}
-
-static struct subsys_attribute dump_type_attr =
-               __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
-
-static decl_subsys(dump, NULL, NULL);
-
-/*
- * Shutdown actions section
- */
-
-static decl_subsys(shutdown_actions, NULL, NULL);
-
-/* on panic */
-
-static ssize_t on_panic_show(struct kset *kset, char *page)
-{
-       return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
-}
-
-static ssize_t on_panic_store(struct kset *kset, const char *buf,
-                             size_t len)
-{
-       if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
-               on_panic_action = SHUTDOWN_REIPL;
-       else if (strncmp(buf, SHUTDOWN_DUMP_STR,
-                        strlen(SHUTDOWN_DUMP_STR)) == 0)
-               on_panic_action = SHUTDOWN_DUMP;
-       else if (strncmp(buf, SHUTDOWN_STOP_STR,
-                        strlen(SHUTDOWN_STOP_STR)) == 0)
-               on_panic_action = SHUTDOWN_STOP;
-       else
-               return -EINVAL;
-
-       return len;
-}
+static struct kobj_attribute reipl_type_attr =
+       __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
 
-static struct subsys_attribute on_panic_attr =
-               __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
+static struct kset *reipl_kset;
 
-void do_reipl(void)
+void reipl_run(struct shutdown_trigger *trigger)
 {
        struct ccw_dev_id devid;
        static char buf[100];
@@ -729,8 +661,6 @@ void do_reipl(void)
        switch (reipl_method) {
        case REIPL_METHOD_CCW_CIO:
                devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
-               if (ipl_info.type == IPL_TYPE_CCW && devid.devno == ipl_devno)
-                       diag308(DIAG308_IPL, NULL);
                devid.ssid  = 0;
                reipl_ccw_dev(&devid);
                break;
@@ -771,134 +701,42 @@ void do_reipl(void)
        default:
                break;
        }
-       signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-static void do_dump(void)
+static void __init reipl_probe(void)
 {
-       struct ccw_dev_id devid;
-       static char buf[100];
+       void *buffer;
 
-       switch (dump_method) {
-       case DUMP_METHOD_CCW_CIO:
-               smp_send_stop();
-               devid.devno = dump_block_ccw->ipl_info.ccw.devno;
-               devid.ssid  = 0;
-               reipl_ccw_dev(&devid);
-               break;
-       case DUMP_METHOD_CCW_VM:
-               smp_send_stop();
-               sprintf(buf, "STORE STATUS");
-               __cpcmd(buf, NULL, 0, NULL);
-               sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
-               __cpcmd(buf, NULL, 0, NULL);
-               break;
-       case DUMP_METHOD_CCW_DIAG:
-               diag308(DIAG308_SET, dump_block_ccw);
-               diag308(DIAG308_DUMP, NULL);
-               break;
-       case DUMP_METHOD_FCP_DIAG:
-               diag308(DIAG308_SET, dump_block_fcp);
-               diag308(DIAG308_DUMP, NULL);
-               break;
-       case DUMP_METHOD_NONE:
-       default:
+       buffer = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!buffer)
                return;
-       }
-       printk(KERN_EMERG "Dump failed!\n");
+       if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
+               diag308_set_works = 1;
+       free_page((unsigned long)buffer);
 }
 
-/* init functions */
-
-static int __init ipl_register_fcp_files(void)
+static int __init reipl_nss_init(void)
 {
        int rc;
 
-       rc = sysfs_create_group(&ipl_subsys.kobj,
-                               &ipl_fcp_attr_group);
-       if (rc)
-               goto out;
-       rc = sysfs_create_bin_file(&ipl_subsys.kobj,
-                                  &ipl_parameter_attr);
+       if (!MACHINE_IS_VM)
+               return 0;
+       rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
        if (rc)
-               goto out_ipl_parm;
-       rc = sysfs_create_bin_file(&ipl_subsys.kobj,
-                                  &ipl_scp_data_attr);
-       if (!rc)
-               goto out;
-
-       sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr);
-
-out_ipl_parm:
-       sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group);
-out:
-       return rc;
+               return rc;
+       strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+       reipl_capabilities |= IPL_TYPE_NSS;
+       return 0;
 }
 
-static int __init ipl_init(void)
-{
-       int rc;
-
-       rc = firmware_register(&ipl_subsys);
-       if (rc)
-               return rc;
-       switch (ipl_info.type) {
-       case IPL_TYPE_CCW:
-               rc = sysfs_create_group(&ipl_subsys.kobj,
-                                       &ipl_ccw_attr_group);
-               break;
-       case IPL_TYPE_FCP:
-       case IPL_TYPE_FCP_DUMP:
-               rc = ipl_register_fcp_files();
-               break;
-       case IPL_TYPE_NSS:
-               rc = sysfs_create_group(&ipl_subsys.kobj,
-                                       &ipl_nss_attr_group);
-               break;
-       default:
-               rc = sysfs_create_group(&ipl_subsys.kobj,
-                                       &ipl_unknown_attr_group);
-               break;
-       }
-       if (rc)
-               firmware_unregister(&ipl_subsys);
-       return rc;
-}
-
-static void __init reipl_probe(void)
-{
-       void *buffer;
-
-       buffer = (void *) get_zeroed_page(GFP_KERNEL);
-       if (!buffer)
-               return;
-       if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
-               diag308_set_works = 1;
-       free_page((unsigned long)buffer);
-}
-
-static int __init reipl_nss_init(void)
-{
-       int rc;
-
-       if (!MACHINE_IS_VM)
-               return 0;
-       rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group);
-       if (rc)
-               return rc;
-       strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
-       reipl_capabilities |= IPL_TYPE_NSS;
-       return 0;
-}
-
-static int __init reipl_ccw_init(void)
+static int __init reipl_ccw_init(void)
 {
        int rc;
 
        reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
        if (!reipl_block_ccw)
                return -ENOMEM;
-       rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group);
+       rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
        if (rc) {
                free_page((unsigned long)reipl_block_ccw);
                return rc;
@@ -907,6 +745,7 @@ static int __init reipl_ccw_init(void)
        reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
        reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
        reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
+       reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
        /* check if read scp info worked and set loadparm */
        if (sclp_ipl_info.is_valid)
                memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
@@ -915,8 +754,7 @@ static int __init reipl_ccw_init(void)
                /* read scp info failed: set empty loadparm (EBCDIC blanks) */
                memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
                       LOADPARM_LEN);
-       /* FIXME: check for diag308_set_works when enabling diag ccw reipl */
-       if (!MACHINE_IS_VM)
+       if (!MACHINE_IS_VM && !diag308_set_works)
                sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
        if (ipl_info.type == IPL_TYPE_CCW)
                reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
@@ -936,7 +774,7 @@ static int __init reipl_fcp_init(void)
        reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
        if (!reipl_block_fcp)
                return -ENOMEM;
-       rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group);
+       rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
        if (rc) {
                free_page((unsigned long)reipl_block_fcp);
                return rc;
@@ -954,16 +792,16 @@ static int __init reipl_fcp_init(void)
        return 0;
 }
 
-static int __init reipl_init(void)
+static int reipl_init(void)
 {
        int rc;
 
-       rc = firmware_register(&reipl_subsys);
-       if (rc)
-               return rc;
-       rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
+       reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
+       if (!reipl_kset)
+               return -ENOMEM;
+       rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
        if (rc) {
-               firmware_unregister(&reipl_subsys);
+               kset_unregister(reipl_kset);
                return rc;
        }
        rc = reipl_ccw_init();
@@ -981,6 +819,140 @@ static int __init reipl_init(void)
        return 0;
 }
 
+static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
+                                             reipl_run, reipl_init};
+
+/*
+ * dump shutdown action: Dump Linux on shutdown.
+ */
+
+/* FCP dump device attributes */
+
+DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
+                  dump_block_fcp->ipl_info.fcp.wwpn);
+DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
+                  dump_block_fcp->ipl_info.fcp.lun);
+DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
+                  dump_block_fcp->ipl_info.fcp.bootprog);
+DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
+                  dump_block_fcp->ipl_info.fcp.br_lba);
+DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
+                  dump_block_fcp->ipl_info.fcp.devno);
+
+static struct attribute *dump_fcp_attrs[] = {
+       &sys_dump_fcp_device_attr.attr,
+       &sys_dump_fcp_wwpn_attr.attr,
+       &sys_dump_fcp_lun_attr.attr,
+       &sys_dump_fcp_bootprog_attr.attr,
+       &sys_dump_fcp_br_lba_attr.attr,
+       NULL,
+};
+
+static struct attribute_group dump_fcp_attr_group = {
+       .name  = IPL_FCP_STR,
+       .attrs = dump_fcp_attrs,
+};
+
+/* CCW dump device attributes */
+
+DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
+                  dump_block_ccw->ipl_info.ccw.devno);
+
+static struct attribute *dump_ccw_attrs[] = {
+       &sys_dump_ccw_device_attr.attr,
+       NULL,
+};
+
+static struct attribute_group dump_ccw_attr_group = {
+       .name  = IPL_CCW_STR,
+       .attrs = dump_ccw_attrs,
+};
+
+/* dump type */
+
+static int dump_set_type(enum dump_type type)
+{
+       if (!(dump_capabilities & type))
+               return -EINVAL;
+       switch (type) {
+       case DUMP_TYPE_CCW:
+               if (diag308_set_works)
+                       dump_method = DUMP_METHOD_CCW_DIAG;
+               else if (MACHINE_IS_VM)
+                       dump_method = DUMP_METHOD_CCW_VM;
+               else
+                       dump_method = DUMP_METHOD_CCW_CIO;
+               break;
+       case DUMP_TYPE_FCP:
+               dump_method = DUMP_METHOD_FCP_DIAG;
+               break;
+       default:
+               dump_method = DUMP_METHOD_NONE;
+       }
+       dump_type = type;
+       return 0;
+}
+
+static ssize_t dump_type_show(struct kobject *kobj,
+                             struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%s\n", dump_type_str(dump_type));
+}
+
+static ssize_t dump_type_store(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              const char *buf, size_t len)
+{
+       int rc = -EINVAL;
+
+       if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
+               rc = dump_set_type(DUMP_TYPE_NONE);
+       else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
+               rc = dump_set_type(DUMP_TYPE_CCW);
+       else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
+               rc = dump_set_type(DUMP_TYPE_FCP);
+       return (rc != 0) ? rc : len;
+}
+
+static struct kobj_attribute dump_type_attr =
+       __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
+
+static struct kset *dump_kset;
+
+static void dump_run(struct shutdown_trigger *trigger)
+{
+       struct ccw_dev_id devid;
+       static char buf[100];
+
+       switch (dump_method) {
+       case DUMP_METHOD_CCW_CIO:
+               smp_send_stop();
+               devid.devno = dump_block_ccw->ipl_info.ccw.devno;
+               devid.ssid  = 0;
+               reipl_ccw_dev(&devid);
+               break;
+       case DUMP_METHOD_CCW_VM:
+               smp_send_stop();
+               sprintf(buf, "STORE STATUS");
+               __cpcmd(buf, NULL, 0, NULL);
+               sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
+               __cpcmd(buf, NULL, 0, NULL);
+               break;
+       case DUMP_METHOD_CCW_DIAG:
+               diag308(DIAG308_SET, dump_block_ccw);
+               diag308(DIAG308_DUMP, NULL);
+               break;
+       case DUMP_METHOD_FCP_DIAG:
+               diag308(DIAG308_SET, dump_block_fcp);
+               diag308(DIAG308_DUMP, NULL);
+               break;
+       case DUMP_METHOD_NONE:
+       default:
+               return;
+       }
+       printk(KERN_EMERG "Dump failed!\n");
+}
+
 static int __init dump_ccw_init(void)
 {
        int rc;
@@ -988,7 +960,7 @@ static int __init dump_ccw_init(void)
        dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
        if (!dump_block_ccw)
                return -ENOMEM;
-       rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group);
+       rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
        if (rc) {
                free_page((unsigned long)dump_block_ccw);
                return rc;
@@ -1012,7 +984,7 @@ static int __init dump_fcp_init(void)
        dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
        if (!dump_block_fcp)
                return -ENOMEM;
-       rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group);
+       rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
        if (rc) {
                free_page((unsigned long)dump_block_fcp);
                return rc;
@@ -1026,33 +998,16 @@ static int __init dump_fcp_init(void)
        return 0;
 }
 
-#define SHUTDOWN_ON_PANIC_PRIO 0
-
-static int shutdown_on_panic_notify(struct notifier_block *self,
-                                   unsigned long event, void *data)
-{
-       if (on_panic_action == SHUTDOWN_DUMP)
-               do_dump();
-       else if (on_panic_action == SHUTDOWN_REIPL)
-               do_reipl();
-       return NOTIFY_OK;
-}
-
-static struct notifier_block shutdown_on_panic_nb = {
-       .notifier_call = shutdown_on_panic_notify,
-       .priority = SHUTDOWN_ON_PANIC_PRIO
-};
-
-static int __init dump_init(void)
+static int dump_init(void)
 {
        int rc;
 
-       rc = firmware_register(&dump_subsys);
-       if (rc)
-               return rc;
-       rc = subsys_create_file(&dump_subsys, &dump_type_attr);
+       dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
+       if (!dump_kset)
+               return -ENOMEM;
+       rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
        if (rc) {
-               firmware_unregister(&dump_subsys);
+               kset_unregister(dump_kset);
                return rc;
        }
        rc = dump_ccw_init();
@@ -1065,46 +1020,381 @@ static int __init dump_init(void)
        return 0;
 }
 
-static int __init shutdown_actions_init(void)
+static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
+                                            dump_run, dump_init};
+
+/*
+ * vmcmd shutdown action: Trigger vm command on shutdown.
+ */
+
+static char vmcmd_on_reboot[128];
+static char vmcmd_on_panic[128];
+static char vmcmd_on_halt[128];
+static char vmcmd_on_poff[128];
+
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
+
+static struct attribute *vmcmd_attrs[] = {
+       &sys_vmcmd_on_reboot_attr.attr,
+       &sys_vmcmd_on_panic_attr.attr,
+       &sys_vmcmd_on_halt_attr.attr,
+       &sys_vmcmd_on_poff_attr.attr,
+       NULL,
+};
+
+static struct attribute_group vmcmd_attr_group = {
+       .attrs = vmcmd_attrs,
+};
+
+static struct kset *vmcmd_kset;
+
+static void vmcmd_run(struct shutdown_trigger *trigger)
 {
-       int rc;
+       char *cmd, *next_cmd;
+
+       if (strcmp(trigger->name, ON_REIPL_STR) == 0)
+               cmd = vmcmd_on_reboot;
+       else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+               cmd = vmcmd_on_panic;
+       else if (strcmp(trigger->name, ON_HALT_STR) == 0)
+               cmd = vmcmd_on_halt;
+       else if (strcmp(trigger->name, ON_POFF_STR) == 0)
+               cmd = vmcmd_on_poff;
+       else
+               return;
 
-       rc = firmware_register(&shutdown_actions_subsys);
-       if (rc)
-               return rc;
-       rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
-       if (rc) {
-               firmware_unregister(&shutdown_actions_subsys);
-               return rc;
+       if (strlen(cmd) == 0)
+               return;
+       do {
+               next_cmd = strchr(cmd, '\n');
+               if (next_cmd) {
+                       next_cmd[0] = 0;
+                       next_cmd += 1;
+               }
+               __cpcmd(cmd, NULL, 0, NULL);
+               cmd = next_cmd;
+       } while (cmd != NULL);
+}
+
+static int vmcmd_init(void)
+{
+       if (!MACHINE_IS_VM)
+               return -ENOTSUPP;
+       vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
+       if (!vmcmd_kset)
+               return -ENOMEM;
+       return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
+}
+
+static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
+                                             vmcmd_run, vmcmd_init};
+
+/*
+ * stop shutdown action: Stop Linux on shutdown.
+ */
+
+static void stop_run(struct shutdown_trigger *trigger)
+{
+       if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+               disabled_wait((unsigned long) __builtin_return_address(0));
+       else {
+               signal_processor(smp_processor_id(), sigp_stop);
+               for (;;);
        }
-       atomic_notifier_chain_register(&panic_notifier_list,
-                                      &shutdown_on_panic_nb);
-       return 0;
 }
 
-static int __init s390_ipl_init(void)
+static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
+                                            stop_run, NULL};
+
+/* action list */
+
+static struct shutdown_action *shutdown_actions_list[] = {
+       &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
+#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
+
+/*
+ * Trigger section
+ */
+
+static struct kset *shutdown_actions_kset;
+
+static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
+                      size_t len)
 {
-       int rc;
+       int i;
+       for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
+               if (!shutdown_actions_list[i])
+                       continue;
+               if (strncmp(buf, shutdown_actions_list[i]->name,
+                           strlen(shutdown_actions_list[i]->name)) == 0) {
+                       trigger->action = shutdown_actions_list[i];
+                       return len;
+               }
+       }
+       return -EINVAL;
+}
 
-       sclp_get_ipl_info(&sclp_ipl_info);
+/* on reipl */
+
+static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
+                                                   &reipl_action};
+
+static ssize_t on_reboot_show(struct kobject *kobj,
+                             struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%s\n", on_reboot_trigger.action->name);
+}
+
+static ssize_t on_reboot_store(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              const char *buf, size_t len)
+{
+       return set_trigger(buf, &on_reboot_trigger, len);
+}
+
+static struct kobj_attribute on_reboot_attr =
+       __ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store);
+
+static void do_machine_restart(char *__unused)
+{
+       smp_send_stop();
+       on_reboot_trigger.action->fn(&on_reboot_trigger);
+       reipl_run(NULL);
+}
+void (*_machine_restart)(char *command) = do_machine_restart;
+
+/* on panic */
+
+static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
+
+static ssize_t on_panic_show(struct kobject *kobj,
+                            struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%s\n", on_panic_trigger.action->name);
+}
+
+static ssize_t on_panic_store(struct kobject *kobj,
+                             struct kobj_attribute *attr,
+                             const char *buf, size_t len)
+{
+       return set_trigger(buf, &on_panic_trigger, len);
+}
+
+static struct kobj_attribute on_panic_attr =
+       __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
+
+static void do_panic(void)
+{
+       on_panic_trigger.action->fn(&on_panic_trigger);
+       stop_run(&on_panic_trigger);
+}
+
+/* on halt */
+
+static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
+
+static ssize_t on_halt_show(struct kobject *kobj,
+                           struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%s\n", on_halt_trigger.action->name);
+}
+
+static ssize_t on_halt_store(struct kobject *kobj,
+                            struct kobj_attribute *attr,
+                            const char *buf, size_t len)
+{
+       return set_trigger(buf, &on_halt_trigger, len);
+}
+
+static struct kobj_attribute on_halt_attr =
+       __ATTR(on_halt, 0644, on_halt_show, on_halt_store);
+
+
+static void do_machine_halt(void)
+{
+       smp_send_stop();
+       on_halt_trigger.action->fn(&on_halt_trigger);
+       stop_run(&on_halt_trigger);
+}
+void (*_machine_halt)(void) = do_machine_halt;
+
+/* on power off */
+
+static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
+
+static ssize_t on_poff_show(struct kobject *kobj,
+                           struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%s\n", on_poff_trigger.action->name);
+}
+
+static ssize_t on_poff_store(struct kobject *kobj,
+                            struct kobj_attribute *attr,
+                            const char *buf, size_t len)
+{
+       return set_trigger(buf, &on_poff_trigger, len);
+}
+
+static struct kobj_attribute on_poff_attr =
+       __ATTR(on_poff, 0644, on_poff_show, on_poff_store);
+
+
+static void do_machine_power_off(void)
+{
+       smp_send_stop();
+       on_poff_trigger.action->fn(&on_poff_trigger);
+       stop_run(&on_poff_trigger);
+}
+void (*_machine_power_off)(void) = do_machine_power_off;
+
+static void __init shutdown_triggers_init(void)
+{
+       shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
+                                                   firmware_kobj);
+       if (!shutdown_actions_kset)
+               goto fail;
+       if (sysfs_create_file(&shutdown_actions_kset->kobj,
+                             &on_reboot_attr.attr))
+               goto fail;
+       if (sysfs_create_file(&shutdown_actions_kset->kobj,
+                             &on_panic_attr.attr))
+               goto fail;
+       if (sysfs_create_file(&shutdown_actions_kset->kobj,
+                             &on_halt_attr.attr))
+               goto fail;
+       if (sysfs_create_file(&shutdown_actions_kset->kobj,
+                             &on_poff_attr.attr))
+               goto fail;
+
+       return;
+fail:
+       panic("shutdown_triggers_init failed\n");
+}
+
+static void __init shutdown_actions_init(void)
+{
+       int i;
+
+       for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
+               if (!shutdown_actions_list[i]->init)
+                       continue;
+               if (shutdown_actions_list[i]->init())
+                       shutdown_actions_list[i] = NULL;
+       }
+}
+
+static int __init s390_ipl_init(void)
+{
        reipl_probe();
-       rc = ipl_init();
-       if (rc)
-               return rc;
-       rc = reipl_init();
-       if (rc)
-               return rc;
-       rc = dump_init();
-       if (rc)
-               return rc;
-       rc = shutdown_actions_init();
-       if (rc)
-               return rc;
+       sclp_get_ipl_info(&sclp_ipl_info);
+       shutdown_actions_init();
+       shutdown_triggers_init();
        return 0;
 }
 
 __initcall(s390_ipl_init);
 
+static void __init strncpy_skip_quote(char *dst, char *src, int n)
+{
+       int sx, dx;
+
+       dx = 0;
+       for (sx = 0; src[sx] != 0; sx++) {
+               if (src[sx] == '"')
+                       continue;
+               dst[dx++] = src[sx];
+               if (dx >= n)
+                       break;
+       }
+}
+
+static int __init vmcmd_on_reboot_setup(char *str)
+{
+       if (!MACHINE_IS_VM)
+               return 1;
+       strncpy_skip_quote(vmcmd_on_reboot, str, 127);
+       vmcmd_on_reboot[127] = 0;
+       on_reboot_trigger.action = &vmcmd_action;
+       return 1;
+}
+__setup("vmreboot=", vmcmd_on_reboot_setup);
+
+static int __init vmcmd_on_panic_setup(char *str)
+{
+       if (!MACHINE_IS_VM)
+               return 1;
+       strncpy_skip_quote(vmcmd_on_panic, str, 127);
+       vmcmd_on_panic[127] = 0;
+       on_panic_trigger.action = &vmcmd_action;
+       return 1;
+}
+__setup("vmpanic=", vmcmd_on_panic_setup);
+
+static int __init vmcmd_on_halt_setup(char *str)
+{
+       if (!MACHINE_IS_VM)
+               return 1;
+       strncpy_skip_quote(vmcmd_on_halt, str, 127);
+       vmcmd_on_halt[127] = 0;
+       on_halt_trigger.action = &vmcmd_action;
+       return 1;
+}
+__setup("vmhalt=", vmcmd_on_halt_setup);
+
+static int __init vmcmd_on_poff_setup(char *str)
+{
+       if (!MACHINE_IS_VM)
+               return 1;
+       strncpy_skip_quote(vmcmd_on_poff, str, 127);
+       vmcmd_on_poff[127] = 0;
+       on_poff_trigger.action = &vmcmd_action;
+       return 1;
+}
+__setup("vmpoff=", vmcmd_on_poff_setup);
+
+static int on_panic_notify(struct notifier_block *self,
+                          unsigned long event, void *data)
+{
+       do_panic();
+       return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+       .notifier_call = on_panic_notify,
+       .priority = 0,
+};
+
+void __init setup_ipl(void)
+{
+       ipl_info.type = get_ipl_type();
+       switch (ipl_info.type) {
+       case IPL_TYPE_CCW:
+               ipl_info.data.ccw.dev_id.devno = ipl_devno;
+               ipl_info.data.ccw.dev_id.ssid = 0;
+               break;
+       case IPL_TYPE_FCP:
+       case IPL_TYPE_FCP_DUMP:
+               ipl_info.data.fcp.dev_id.devno =
+                       IPL_PARMBLOCK_START->ipl_info.fcp.devno;
+               ipl_info.data.fcp.dev_id.ssid = 0;
+               ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
+               ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
+               break;
+       case IPL_TYPE_NSS:
+               strncpy(ipl_info.data.nss.name, kernel_nss_name,
+                       sizeof(ipl_info.data.nss.name));
+               break;
+       case IPL_TYPE_UNKNOWN:
+       default:
+               /* We have no info to copy */
+               break;
+       }
+       atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+}
+
 void __init ipl_save_parameters(void)
 {
        struct cio_iplinfo iplinfo;
@@ -1185,3 +1475,4 @@ void s390_reset_system(void)
 
        do_reset_calls();
 }
+
index 29f7884b4ffad57c3f709f714959dc8c52c7f3f1..0e7aca0393070d3ca19538c130b1b5491bdb4681 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
-
+#include <linux/utsname.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -182,13 +182,15 @@ void cpu_idle(void)
 
 void show_regs(struct pt_regs *regs)
 {
-       struct task_struct *tsk = current;
-
-        printk("CPU:    %d    %s\n", task_thread_info(tsk)->cpu, print_tainted());
-        printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
-              current->comm, task_pid_nr(current), (void *) tsk,
-              (void *) tsk->thread.ksp);
-
+       print_modules();
+       printk("CPU: %d %s %s %.*s\n",
+              task_thread_info(current)->cpu, print_tainted(),
+              init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+       printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+              current->comm, current->pid, current,
+              (void *) current->thread.ksp);
        show_registers(regs);
        /* Show stack backtrace if pt_regs is from kernel mode */
        if (!(regs->psw.mask & PSW_MASK_PSTATE))
index 1d81bf9488aec20b968e305b2acf57fcd6d0bd85..6e036bae987534d0c46e05159e6de1f310cc41bd 100644 (file)
@@ -86,13 +86,13 @@ FixPerRegisters(struct task_struct *task)
                per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }
 
-static void set_single_step(struct task_struct *task)
+void user_enable_single_step(struct task_struct *task)
 {
        task->thread.per_info.single_step = 1;
        FixPerRegisters(task);
 }
 
-static void clear_single_step(struct task_struct *task)
+void user_disable_single_step(struct task_struct *task)
 {
        task->thread.per_info.single_step = 0;
        FixPerRegisters(task);
@@ -107,7 +107,7 @@ void
 ptrace_disable(struct task_struct *child)
 {
        /* make sure the single step bit is not set. */
-       clear_single_step(child);
+       user_disable_single_step(child);
 }
 
 #ifndef CONFIG_64BIT
@@ -651,7 +651,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                child->exit_code = data;
                /* make sure the single step bit is not set. */
-               clear_single_step(child);
+               user_disable_single_step(child);
                wake_up_process(child);
                return 0;
 
@@ -665,7 +665,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
                        return 0;
                child->exit_code = SIGKILL;
                /* make sure the single step bit is not set. */
-               clear_single_step(child);
+               user_disable_single_step(child);
                wake_up_process(child);
                return 0;
 
@@ -675,10 +675,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
                        return -EIO;
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                child->exit_code = data;
-               if (data)
-                       set_tsk_thread_flag(child, TIF_SINGLE_STEP);
-               else
-                       set_single_step(child);
+               user_enable_single_step(child);
                /* give it a chance to run. */
                wake_up_process(child);
                return 0;
index 577aa7dd660eba1371d39fe33e8847cc6de815a3..766c783bd7a726e25c8a9f0ba243067a1a296344 100644 (file)
@@ -125,75 +125,6 @@ void __cpuinit cpu_init(void)
         enter_lazy_tlb(&init_mm, current);
 }
 
-/*
- * VM halt and poweroff setup routines
- */
-char vmhalt_cmd[128] = "";
-char vmpoff_cmd[128] = "";
-static char vmpanic_cmd[128] = "";
-
-static void strncpy_skip_quote(char *dst, char *src, int n)
-{
-        int sx, dx;
-
-        dx = 0;
-        for (sx = 0; src[sx] != 0; sx++) {
-                if (src[sx] == '"') continue;
-                dst[dx++] = src[sx];
-                if (dx >= n) break;
-        }
-}
-
-static int __init vmhalt_setup(char *str)
-{
-        strncpy_skip_quote(vmhalt_cmd, str, 127);
-        vmhalt_cmd[127] = 0;
-        return 1;
-}
-
-__setup("vmhalt=", vmhalt_setup);
-
-static int __init vmpoff_setup(char *str)
-{
-        strncpy_skip_quote(vmpoff_cmd, str, 127);
-        vmpoff_cmd[127] = 0;
-        return 1;
-}
-
-__setup("vmpoff=", vmpoff_setup);
-
-static int vmpanic_notify(struct notifier_block *self, unsigned long event,
-                         void *data)
-{
-       if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
-               cpcmd(vmpanic_cmd, NULL, 0, NULL);
-
-       return NOTIFY_OK;
-}
-
-#define PANIC_PRI_VMPANIC      0
-
-static struct notifier_block vmpanic_nb = {
-       .notifier_call = vmpanic_notify,
-       .priority = PANIC_PRI_VMPANIC
-};
-
-static int __init vmpanic_setup(char *str)
-{
-       static int register_done __initdata = 0;
-
-       strncpy_skip_quote(vmpanic_cmd, str, 127);
-       vmpanic_cmd[127] = 0;
-       if (!register_done) {
-               register_done = 1;
-               atomic_notifier_chain_register(&panic_notifier_list,
-                                              &vmpanic_nb);
-       }
-       return 1;
-}
-
-__setup("vmpanic=", vmpanic_setup);
-
 /*
  * condev= and conmode= setup parameter.
  */
@@ -308,38 +239,6 @@ static void __init setup_zfcpdump(unsigned int console_devno)
 static inline void setup_zfcpdump(unsigned int console_devno) {}
 #endif /* CONFIG_ZFCPDUMP */
 
-#ifdef CONFIG_SMP
-void (*_machine_restart)(char *command) = machine_restart_smp;
-void (*_machine_halt)(void) = machine_halt_smp;
-void (*_machine_power_off)(void) = machine_power_off_smp;
-#else
-/*
- * Reboot, halt and power_off routines for non SMP.
- */
-static void do_machine_restart_nonsmp(char * __unused)
-{
-       do_reipl();
-}
-
-static void do_machine_halt_nonsmp(void)
-{
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-               __cpcmd(vmhalt_cmd, NULL, 0, NULL);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-}
-
-static void do_machine_power_off_nonsmp(void)
-{
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-               __cpcmd(vmpoff_cmd, NULL, 0, NULL);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-}
-
-void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
-void (*_machine_halt)(void) = do_machine_halt_nonsmp;
-void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
-#endif
-
  /*
  * Reboot, halt and power_off stubs. They just call _machine_restart,
  * _machine_halt or _machine_power_off. 
@@ -559,7 +458,9 @@ setup_resources(void)
        data_resource.start = (unsigned long) &_etext;
        data_resource.end = (unsigned long) &_edata - 1;
 
-       for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+       for (i = 0; i < MEMORY_CHUNKS; i++) {
+               if (!memory_chunk[i].size)
+                       continue;
                res = alloc_bootmem_low(sizeof(struct resource));
                res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
                switch (memory_chunk[i].type) {
@@ -617,7 +518,7 @@ EXPORT_SYMBOL_GPL(real_memory_size);
 static void __init setup_memory_end(void)
 {
        unsigned long memory_size;
-       unsigned long max_mem, max_phys;
+       unsigned long max_mem;
        int i;
 
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
@@ -625,10 +526,31 @@ static void __init setup_memory_end(void)
                memory_end = ZFCPDUMP_HSA_SIZE;
 #endif
        memory_size = 0;
-       max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
        memory_end &= PAGE_MASK;
 
-       max_mem = memory_end ? min(max_phys, memory_end) : max_phys;
+       max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
+       memory_end = min(max_mem, memory_end);
+
+       /*
+        * Make sure all chunks are MAX_ORDER aligned so we don't need the
+        * extra checks that HOLES_IN_ZONE would require.
+        */
+       for (i = 0; i < MEMORY_CHUNKS; i++) {
+               unsigned long start, end;
+               struct mem_chunk *chunk;
+               unsigned long align;
+
+               chunk = &memory_chunk[i];
+               align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
+               start = (chunk->addr + align - 1) & ~(align - 1);
+               end = (chunk->addr + chunk->size) & ~(align - 1);
+               if (start >= end)
+                       memset(chunk, 0, sizeof(*chunk));
+               else {
+                       chunk->addr = start;
+                       chunk->size = end - start;
+               }
+       }
 
        for (i = 0; i < MEMORY_CHUNKS; i++) {
                struct mem_chunk *chunk = &memory_chunk[i];
@@ -890,7 +812,7 @@ setup_arch(char **cmdline_p)
 
        parse_early_param();
 
-       setup_ipl_info();
+       setup_ipl();
        setup_memory_end();
        setup_addressing_mode();
        setup_memory();
@@ -899,7 +821,6 @@ setup_arch(char **cmdline_p)
 
         cpu_init();
         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
-       smp_setup_cpu_possible_map();
 
        /*
         * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
@@ -920,7 +841,7 @@ setup_arch(char **cmdline_p)
 
 void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
 {
-   printk("cpu %d "
+   printk(KERN_INFO "cpu %d "
 #ifdef CONFIG_SMP
            "phys_idx=%d "
 #endif
@@ -996,7 +917,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 static void c_stop(struct seq_file *m, void *v)
 {
 }
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
        .start  = c_start,
        .next   = c_next,
        .stop   = c_stop,
index d264671c1b71e996b38563a398e7109cb9946028..4449bf32cbf1e976e414518cee77998587ba18a3 100644 (file)
@@ -471,6 +471,7 @@ void do_signal(struct pt_regs *regs)
 
        if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
+               int ret;
 #ifdef CONFIG_COMPAT
                if (test_thread_flag(TIF_31BIT)) {
                        extern int handle_signal32(unsigned long sig,
@@ -478,15 +479,12 @@ void do_signal(struct pt_regs *regs)
                                                   siginfo_t *info,
                                                   sigset_t *oldset,
                                                   struct pt_regs *regs);
-                       if (handle_signal32(
-                                   signr, &ka, &info, oldset, regs) == 0) {
-                               if (test_thread_flag(TIF_RESTORE_SIGMASK))
-                                       clear_thread_flag(TIF_RESTORE_SIGMASK);
-                       }
-                       return;
+                       ret = handle_signal32(signr, &ka, &info, oldset, regs);
                }
+               else
 #endif
-               if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+                       ret = handle_signal(signr, &ka, &info, oldset, regs);
+               if (!ret) {
                        /*
                         * A signal was successfully delivered; the saved
                         * sigmask will have been stored in the signal frame,
@@ -495,6 +493,14 @@ void do_signal(struct pt_regs *regs)
                         */
                        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                                clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+                       /*
+                        * If we would have taken a single-step trap
+                        * for a normal instruction, act like we took
+                        * one for the handler setup.
+                        */
+                       if (current->thread.per_info.single_step)
+                               set_thread_flag(TIF_SINGLE_STEP);
                }
                return;
        }
index 264ea906db4c1cb2b8c5258b4d448e18e9293de9..aa37fa154512eb2323064bf2c9dc7ba44ec6be8e 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
 #include <asm/lowcore.h>
+#include <asm/sclp.h>
 #include <asm/cpu.h>
 
 /*
@@ -53,11 +54,27 @@ EXPORT_SYMBOL(lowcore_ptr);
 cpumask_t cpu_online_map = CPU_MASK_NONE;
 EXPORT_SYMBOL(cpu_online_map);
 
-cpumask_t cpu_possible_map = CPU_MASK_NONE;
+cpumask_t cpu_possible_map = CPU_MASK_ALL;
 EXPORT_SYMBOL(cpu_possible_map);
 
 static struct task_struct *current_set[NR_CPUS];
 
+static u8 smp_cpu_type;
+static int smp_use_sigp_detection;
+
+enum s390_cpu_state {
+       CPU_STATE_STANDBY,
+       CPU_STATE_CONFIGURED,
+};
+
+#ifdef CONFIG_HOTPLUG_CPU
+static DEFINE_MUTEX(smp_cpu_state_mutex);
+#endif
+static int smp_cpu_state[NR_CPUS];
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+
 static void smp_ext_bitcall(int, ec_bit_sig);
 
 /*
@@ -193,6 +210,33 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
 }
 EXPORT_SYMBOL(smp_call_function_single);
 
+/**
+ * smp_call_function_mask(): Run a function on a set of other CPUs.
+ * @mask: The set of cpus to run on.  Must not include the current cpu.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int
+smp_call_function_mask(cpumask_t mask,
+                       void (*func)(void *), void *info,
+                       int wait)
+{
+       preempt_disable();
+       __smp_call_function_map(func, info, 0, wait, mask);
+       preempt_enable();
+       return 0;
+}
+EXPORT_SYMBOL(smp_call_function_mask);
+
 void smp_send_stop(void)
 {
        int cpu, rc;
@@ -216,33 +260,6 @@ void smp_send_stop(void)
        }
 }
 
-/*
- * Reboot, halt and power_off routines for SMP.
- */
-void machine_restart_smp(char *__unused)
-{
-       smp_send_stop();
-       do_reipl();
-}
-
-void machine_halt_smp(void)
-{
-       smp_send_stop();
-       if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-               __cpcmd(vmhalt_cmd, NULL, 0, NULL);
-       signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-       for (;;);
-}
-
-void machine_power_off_smp(void)
-{
-       smp_send_stop();
-       if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-               __cpcmd(vmpoff_cmd, NULL, 0, NULL);
-       signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-       for (;;);
-}
-
 /*
  * This is the main routine where commands issued by other
  * cpus are handled.
@@ -355,6 +372,13 @@ void smp_ctl_clear_bit(int cr, int bit)
 }
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 
+/*
+ * In early ipl state a temp. logically cpu number is needed, so the sigp
+ * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on
+ * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1.
+ */
+#define CPU_INIT_NO    1
+
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
 
 /*
@@ -375,9 +399,10 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
                       "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS);
                return;
        }
-       zfcpdump_save_areas[cpu] = alloc_bootmem(sizeof(union save_area));
-       __cpu_logical_map[1] = (__u16) phy_cpu;
-       while (signal_processor(1, sigp_stop_and_store_status) == sigp_busy)
+       zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL);
+       __cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu;
+       while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) ==
+              sigp_busy)
                cpu_relax();
        memcpy(zfcpdump_save_areas[cpu],
               (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
@@ -397,32 +422,155 @@ static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
 
 #endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */
 
-/*
- * Lets check how many CPUs we have.
- */
-static unsigned int __init smp_count_cpus(void)
+static int cpu_stopped(int cpu)
 {
-       unsigned int cpu, num_cpus;
-       __u16 boot_cpu_addr;
+       __u32 status;
 
-       /*
-        * cpu 0 is the boot cpu. See smp_prepare_boot_cpu.
-        */
+       /* Check for stopped state */
+       if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
+           sigp_status_stored) {
+               if (status & 0x40)
+                       return 1;
+       }
+       return 0;
+}
+
+static int cpu_known(int cpu_id)
+{
+       int cpu;
+
+       for_each_present_cpu(cpu) {
+               if (__cpu_logical_map[cpu] == cpu_id)
+                       return 1;
+       }
+       return 0;
+}
+
+static int smp_rescan_cpus_sigp(cpumask_t avail)
+{
+       int cpu_id, logical_cpu;
+
+       logical_cpu = first_cpu(avail);
+       if (logical_cpu == NR_CPUS)
+               return 0;
+       for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
+               if (cpu_known(cpu_id))
+                       continue;
+               __cpu_logical_map[logical_cpu] = cpu_id;
+               if (!cpu_stopped(logical_cpu))
+                       continue;
+               cpu_set(logical_cpu, cpu_present_map);
+               smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
+               logical_cpu = next_cpu(logical_cpu, avail);
+               if (logical_cpu == NR_CPUS)
+                       break;
+       }
+       return 0;
+}
+
+static int smp_rescan_cpus_sclp(cpumask_t avail)
+{
+       struct sclp_cpu_info *info;
+       int cpu_id, logical_cpu, cpu;
+       int rc;
+
+       logical_cpu = first_cpu(avail);
+       if (logical_cpu == NR_CPUS)
+               return 0;
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       rc = sclp_get_cpu_info(info);
+       if (rc)
+               goto out;
+       for (cpu = 0; cpu < info->combined; cpu++) {
+               if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+                       continue;
+               cpu_id = info->cpu[cpu].address;
+               if (cpu_known(cpu_id))
+                       continue;
+               __cpu_logical_map[logical_cpu] = cpu_id;
+               cpu_set(logical_cpu, cpu_present_map);
+               if (cpu >= info->configured)
+                       smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
+               else
+                       smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
+               logical_cpu = next_cpu(logical_cpu, avail);
+               if (logical_cpu == NR_CPUS)
+                       break;
+       }
+out:
+       kfree(info);
+       return rc;
+}
+
+static int smp_rescan_cpus(void)
+{
+       cpumask_t avail;
+
+       cpus_xor(avail, cpu_possible_map, cpu_present_map);
+       if (smp_use_sigp_detection)
+               return smp_rescan_cpus_sigp(avail);
+       else
+               return smp_rescan_cpus_sclp(avail);
+}
+
+static void __init smp_detect_cpus(void)
+{
+       unsigned int cpu, c_cpus, s_cpus;
+       struct sclp_cpu_info *info;
+       u16 boot_cpu_addr, cpu_addr;
+
+       c_cpus = 1;
+       s_cpus = 0;
        boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
-       current_thread_info()->cpu = 0;
-       num_cpus = 1;
-       for (cpu = 0; cpu <= 65535; cpu++) {
-               if ((__u16) cpu == boot_cpu_addr)
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               panic("smp_detect_cpus failed to allocate memory\n");
+       /* Use sigp detection algorithm if sclp doesn't work. */
+       if (sclp_get_cpu_info(info)) {
+               smp_use_sigp_detection = 1;
+               for (cpu = 0; cpu <= 65535; cpu++) {
+                       if (cpu == boot_cpu_addr)
+                               continue;
+                       __cpu_logical_map[CPU_INIT_NO] = cpu;
+                       if (!cpu_stopped(CPU_INIT_NO))
+                               continue;
+                       smp_get_save_area(c_cpus, cpu);
+                       c_cpus++;
+               }
+               goto out;
+       }
+
+       if (info->has_cpu_type) {
+               for (cpu = 0; cpu < info->combined; cpu++) {
+                       if (info->cpu[cpu].address == boot_cpu_addr) {
+                               smp_cpu_type = info->cpu[cpu].type;
+                               break;
+                       }
+               }
+       }
+
+       for (cpu = 0; cpu < info->combined; cpu++) {
+               if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+                       continue;
+               cpu_addr = info->cpu[cpu].address;
+               if (cpu_addr == boot_cpu_addr)
                        continue;
-               __cpu_logical_map[1] = (__u16) cpu;
-               if (signal_processor(1, sigp_sense) == sigp_not_operational)
+               __cpu_logical_map[CPU_INIT_NO] = cpu_addr;
+               if (!cpu_stopped(CPU_INIT_NO)) {
+                       s_cpus++;
                        continue;
-               smp_get_save_area(num_cpus, cpu);
-               num_cpus++;
+               }
+               smp_get_save_area(c_cpus, cpu_addr);
+               c_cpus++;
        }
-       printk("Detected %d CPU's\n", (int) num_cpus);
-       printk("Boot cpu address %2X\n", boot_cpu_addr);
-       return num_cpus;
+out:
+       kfree(info);
+       printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
+       get_online_cpus();
+       smp_rescan_cpus();
+       put_online_cpus();
 }
 
 /*
@@ -453,8 +601,6 @@ int __cpuinit start_secondary(void *cpuvoid)
        return 0;
 }
 
-DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
-
 static void __init smp_create_idle(unsigned int cpu)
 {
        struct task_struct *p;
@@ -470,37 +616,82 @@ static void __init smp_create_idle(unsigned int cpu)
        spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
 }
 
-static int cpu_stopped(int cpu)
+static int __cpuinit smp_alloc_lowcore(int cpu)
 {
-       __u32 status;
+       unsigned long async_stack, panic_stack;
+       struct _lowcore *lowcore;
+       int lc_order;
+
+       lc_order = sizeof(long) == 8 ? 1 : 0;
+       lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order);
+       if (!lowcore)
+               return -ENOMEM;
+       async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+       if (!async_stack)
+               goto out_async_stack;
+       panic_stack = __get_free_page(GFP_KERNEL);
+       if (!panic_stack)
+               goto out_panic_stack;
+
+       *lowcore = S390_lowcore;
+       lowcore->async_stack = async_stack + ASYNC_SIZE;
+       lowcore->panic_stack = panic_stack + PAGE_SIZE;
 
-       /* Check for stopped state */
-       if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
-           sigp_status_stored) {
-               if (status & 0x40)
-                       return 1;
+#ifndef CONFIG_64BIT
+       if (MACHINE_HAS_IEEE) {
+               unsigned long save_area;
+
+               save_area = get_zeroed_page(GFP_KERNEL);
+               if (!save_area)
+                       goto out_save_area;
+               lowcore->extended_save_area_addr = (u32) save_area;
        }
+#endif
+       lowcore_ptr[cpu] = lowcore;
        return 0;
+
+#ifndef CONFIG_64BIT
+out_save_area:
+       free_page(panic_stack);
+#endif
+out_panic_stack:
+       free_pages(async_stack, ASYNC_ORDER);
+out_async_stack:
+       free_pages((unsigned long) lowcore, lc_order);
+       return -ENOMEM;
 }
 
-/* Upping and downing of CPUs */
+#ifdef CONFIG_HOTPLUG_CPU
+static void smp_free_lowcore(int cpu)
+{
+       struct _lowcore *lowcore;
+       int lc_order;
+
+       lc_order = sizeof(long) == 8 ? 1 : 0;
+       lowcore = lowcore_ptr[cpu];
+#ifndef CONFIG_64BIT
+       if (MACHINE_HAS_IEEE)
+               free_page((unsigned long) lowcore->extended_save_area_addr);
+#endif
+       free_page(lowcore->panic_stack - PAGE_SIZE);
+       free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER);
+       free_pages((unsigned long) lowcore, lc_order);
+       lowcore_ptr[cpu] = NULL;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
-int __cpu_up(unsigned int cpu)
+/* Upping and downing of CPUs */
+int __cpuinit __cpu_up(unsigned int cpu)
 {
        struct task_struct *idle;
        struct _lowcore *cpu_lowcore;
        struct stack_frame *sf;
        sigp_ccode ccode;
-       int curr_cpu;
 
-       for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) {
-               __cpu_logical_map[cpu] = (__u16) curr_cpu;
-               if (cpu_stopped(cpu))
-                       break;
-       }
-
-       if (!cpu_stopped(cpu))
-               return -ENODEV;
+       if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
+               return -EIO;
+       if (smp_alloc_lowcore(cpu))
+               return -ENOMEM;
 
        ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
                                   cpu, sigp_set_prefix);
@@ -515,6 +706,7 @@ int __cpu_up(unsigned int cpu)
        cpu_lowcore = lowcore_ptr[cpu];
        cpu_lowcore->kernel_stack = (unsigned long)
                task_stack_page(idle) + THREAD_SIZE;
+       cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle);
        sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
                                     - sizeof(struct pt_regs)
                                     - sizeof(struct stack_frame));
@@ -528,6 +720,8 @@ int __cpu_up(unsigned int cpu)
        cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
        cpu_lowcore->current_task = (unsigned long) idle;
        cpu_lowcore->cpu_data.cpu_nr = cpu;
+       cpu_lowcore->softirq_pending = 0;
+       cpu_lowcore->ext_call_fast = 0;
        eieio();
 
        while (signal_processor(cpu, sigp_restart) == sigp_busy)
@@ -538,44 +732,20 @@ int __cpu_up(unsigned int cpu)
        return 0;
 }
 
-static unsigned int __initdata additional_cpus;
-static unsigned int __initdata possible_cpus;
-
-void __init smp_setup_cpu_possible_map(void)
+static int __init setup_possible_cpus(char *s)
 {
-       unsigned int phy_cpus, pos_cpus, cpu;
-
-       phy_cpus = smp_count_cpus();
-       pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS);
-
-       if (possible_cpus)
-               pos_cpus = min(possible_cpus, (unsigned int) NR_CPUS);
+       int pcpus, cpu;
 
-       for (cpu = 0; cpu < pos_cpus; cpu++)
+       pcpus = simple_strtoul(s, NULL, 0);
+       cpu_possible_map = cpumask_of_cpu(0);
+       for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++)
                cpu_set(cpu, cpu_possible_map);
-
-       phy_cpus = min(phy_cpus, pos_cpus);
-
-       for (cpu = 0; cpu < phy_cpus; cpu++)
-               cpu_set(cpu, cpu_present_map);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-static int __init setup_additional_cpus(char *s)
-{
-       additional_cpus = simple_strtoul(s, NULL, 0);
-       return 0;
-}
-early_param("additional_cpus", setup_additional_cpus);
-
-static int __init setup_possible_cpus(char *s)
-{
-       possible_cpus = simple_strtoul(s, NULL, 0);
        return 0;
 }
 early_param("possible_cpus", setup_possible_cpus);
 
+#ifdef CONFIG_HOTPLUG_CPU
+
 int __cpu_disable(void)
 {
        struct ec_creg_mask_parms cr_parms;
@@ -612,7 +782,8 @@ void __cpu_die(unsigned int cpu)
        /* Wait until target cpu is down */
        while (!smp_cpu_not_running(cpu))
                cpu_relax();
-       printk("Processor %d spun down\n", cpu);
+       smp_free_lowcore(cpu);
+       printk(KERN_INFO "Processor %d spun down\n", cpu);
 }
 
 void cpu_die(void)
@@ -625,49 +796,19 @@ void cpu_die(void)
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
-/*
- *     Cycle through the processors and setup structures.
- */
-
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       unsigned long stack;
        unsigned int cpu;
-       int i;
+
+       smp_detect_cpus();
 
        /* request the 0x1201 emergency signal external interrupt */
        if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
                panic("Couldn't request external interrupt 0x1201");
        memset(lowcore_ptr, 0, sizeof(lowcore_ptr));
-       /*
-        *  Initialize prefix pages and stacks for all possible cpus
-        */
        print_cpu_info(&S390_lowcore.cpu_data);
+       smp_alloc_lowcore(smp_processor_id());
 
-       for_each_possible_cpu(i) {
-               lowcore_ptr[i] = (struct _lowcore *)
-                       __get_free_pages(GFP_KERNEL | GFP_DMA,
-                                        sizeof(void*) == 8 ? 1 : 0);
-               stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
-               if (!lowcore_ptr[i] || !stack)
-                       panic("smp_boot_cpus failed to allocate memory\n");
-
-               *(lowcore_ptr[i]) = S390_lowcore;
-               lowcore_ptr[i]->async_stack = stack + ASYNC_SIZE;
-               stack = __get_free_pages(GFP_KERNEL, 0);
-               if (!stack)
-                       panic("smp_boot_cpus failed to allocate memory\n");
-               lowcore_ptr[i]->panic_stack = stack + PAGE_SIZE;
-#ifndef CONFIG_64BIT
-               if (MACHINE_HAS_IEEE) {
-                       lowcore_ptr[i]->extended_save_area_addr =
-                               (__u32) __get_free_pages(GFP_KERNEL, 0);
-                       if (!lowcore_ptr[i]->extended_save_area_addr)
-                               panic("smp_boot_cpus failed to "
-                                     "allocate memory\n");
-               }
-#endif
-       }
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE)
                ctl_set_bit(14, 29); /* enable extended save area */
@@ -683,15 +824,17 @@ void __init smp_prepare_boot_cpu(void)
 {
        BUG_ON(smp_processor_id() != 0);
 
+       current_thread_info()->cpu = 0;
+       cpu_set(0, cpu_present_map);
        cpu_set(0, cpu_online_map);
        S390_lowcore.percpu_offset = __per_cpu_offset[0];
        current_set[0] = current;
+       smp_cpu_state[0] = CPU_STATE_CONFIGURED;
        spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
-       cpu_present_map = cpu_possible_map;
 }
 
 /*
@@ -705,7 +848,79 @@ int setup_profiling_timer(unsigned int multiplier)
        return 0;
 }
 
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t cpu_configure_show(struct sys_device *dev, char *buf)
+{
+       ssize_t count;
+
+       mutex_lock(&smp_cpu_state_mutex);
+       count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]);
+       mutex_unlock(&smp_cpu_state_mutex);
+       return count;
+}
+
+static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf,
+                                  size_t count)
+{
+       int cpu = dev->id;
+       int val, rc;
+       char delim;
+
+       if (sscanf(buf, "%d %c", &val, &delim) != 1)
+               return -EINVAL;
+       if (val != 0 && val != 1)
+               return -EINVAL;
+
+       mutex_lock(&smp_cpu_state_mutex);
+       get_online_cpus();
+       rc = -EBUSY;
+       if (cpu_online(cpu))
+               goto out;
+       rc = 0;
+       switch (val) {
+       case 0:
+               if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) {
+                       rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]);
+                       if (!rc)
+                               smp_cpu_state[cpu] = CPU_STATE_STANDBY;
+               }
+               break;
+       case 1:
+               if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) {
+                       rc = sclp_cpu_configure(__cpu_logical_map[cpu]);
+                       if (!rc)
+                               smp_cpu_state[cpu] = CPU_STATE_CONFIGURED;
+               }
+               break;
+       default:
+               break;
+       }
+out:
+       put_online_cpus();
+       mutex_unlock(&smp_cpu_state_mutex);
+       return rc ? rc : count;
+}
+static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static ssize_t show_cpu_address(struct sys_device *dev, char *buf)
+{
+       return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]);
+}
+static SYSDEV_ATTR(address, 0444, show_cpu_address, NULL);
+
+
+static struct attribute *cpu_common_attrs[] = {
+#ifdef CONFIG_HOTPLUG_CPU
+       &attr_configure.attr,
+#endif
+       &attr_address.attr,
+       NULL,
+};
+
+static struct attribute_group cpu_common_attr_group = {
+       .attrs = cpu_common_attrs,
+};
 
 static ssize_t show_capability(struct sys_device *dev, char *buf)
 {
@@ -750,15 +965,15 @@ static ssize_t show_idle_time(struct sys_device *dev, char *buf)
 }
 static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL);
 
-static struct attribute *cpu_attrs[] = {
+static struct attribute *cpu_online_attrs[] = {
        &attr_capability.attr,
        &attr_idle_count.attr,
        &attr_idle_time_us.attr,
        NULL,
 };
 
-static struct attribute_group cpu_attr_group = {
-       .attrs = cpu_attrs,
+static struct attribute_group cpu_online_attr_group = {
+       .attrs = cpu_online_attrs,
 };
 
 static int __cpuinit smp_cpu_notify(struct notifier_block *self,
@@ -778,12 +993,12 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
                idle->idle_time = 0;
                idle->idle_count = 0;
                spin_unlock_irq(&idle->lock);
-               if (sysfs_create_group(&s->kobj, &cpu_attr_group))
+               if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
                        return NOTIFY_BAD;
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               sysfs_remove_group(&s->kobj, &cpu_attr_group);
+               sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
                break;
        }
        return NOTIFY_OK;
@@ -793,6 +1008,62 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
        .notifier_call = smp_cpu_notify,
 };
 
+static int smp_add_present_cpu(int cpu)
+{
+       struct cpu *c = &per_cpu(cpu_devices, cpu);
+       struct sys_device *s = &c->sysdev;
+       int rc;
+
+       c->hotpluggable = 1;
+       rc = register_cpu(c, cpu);
+       if (rc)
+               goto out;
+       rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
+       if (rc)
+               goto out_cpu;
+       if (!cpu_online(cpu))
+               goto out;
+       rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
+       if (!rc)
+               return 0;
+       sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
+out_cpu:
+#ifdef CONFIG_HOTPLUG_CPU
+       unregister_cpu(c);
+#endif
+out:
+       return rc;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t rescan_store(struct sys_device *dev, const char *buf,
+                           size_t count)
+{
+       cpumask_t newcpus;
+       int cpu;
+       int rc;
+
+       mutex_lock(&smp_cpu_state_mutex);
+       get_online_cpus();
+       newcpus = cpu_present_map;
+       rc = smp_rescan_cpus();
+       if (rc)
+               goto out;
+       cpus_andnot(newcpus, cpu_present_map, newcpus);
+       for_each_cpu_mask(cpu, newcpus) {
+               rc = smp_add_present_cpu(cpu);
+               if (rc)
+                       cpu_clear(cpu, cpu_present_map);
+       }
+       rc = 0;
+out:
+       put_online_cpus();
+       mutex_unlock(&smp_cpu_state_mutex);
+       return rc ? rc : count;
+}
+static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store);
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init topology_init(void)
 {
        int cpu;
@@ -800,16 +1071,14 @@ static int __init topology_init(void)
 
        register_cpu_notifier(&smp_cpu_nb);
 
-       for_each_possible_cpu(cpu) {
-               struct cpu *c = &per_cpu(cpu_devices, cpu);
-               struct sys_device *s = &c->sysdev;
-
-               c->hotpluggable = 1;
-               register_cpu(c, cpu);
-               if (!cpu_online(cpu))
-                       continue;
-               s = &c->sysdev;
-               rc = sysfs_create_group(&s->kobj, &cpu_attr_group);
+#ifdef CONFIG_HOTPLUG_CPU
+       rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+                              &attr_rescan.attr);
+       if (rc)
+               return rc;
+#endif
+       for_each_present_cpu(cpu) {
+               rc = smp_add_present_cpu(cpu);
                if (rc)
                        return rc;
        }
index 22b800ce2126d0fed3c47400229ef95f4060310b..3bbac1293be45d020ffbb703f74c8c8272ff70ad 100644 (file)
@@ -1145,7 +1145,7 @@ static void etr_work_fn(struct work_struct *work)
  * Sysfs interface functions
  */
 static struct sysdev_class etr_sysclass = {
-       set_kset_name("etr")
+       .name   = "etr",
 };
 
 static struct sys_device etr_port0_dev = {
index 8ed16a83fba756932ee6bf16aa3d3b927cdcca89..52b8342c6bf265e9facd1e18a4f3512d56c2357a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/reboot.h>
 #include <linux/kprobes.h>
 #include <linux/bug.h>
+#include <linux/utsname.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -168,9 +169,16 @@ void show_stack(struct task_struct *task, unsigned long *sp)
  */
 void dump_stack(void)
 {
+       printk("CPU: %d %s %s %.*s\n",
+              task_thread_info(current)->cpu, print_tainted(),
+              init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+       printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+              current->comm, current->pid, current,
+              (void *) current->thread.ksp);
        show_stack(NULL, NULL);
 }
-
 EXPORT_SYMBOL(dump_stack);
 
 static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
@@ -258,8 +266,14 @@ void die(const char * str, struct pt_regs * regs, long err)
        console_verbose();
        spin_lock_irq(&die_lock);
        bust_spinlocks(1);
-       printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-       print_modules();
+       printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP");
+#endif
+       printk("\n");
        notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
        show_regs(regs);
        bust_spinlocks(0);
index 849120e3e28a0b6e7c2dddaa16c82e09dc086bc9..936159199346520387f895c7fec5f6ffcba33345 100644 (file)
@@ -17,6 +17,12 @@ ENTRY(_start)
 jiffies = jiffies_64;
 #endif
 
+PHDRS {
+       text PT_LOAD FLAGS(5);  /* R_E */
+       data PT_LOAD FLAGS(7);  /* RWE */
+       note PT_NOTE FLAGS(0);  /* ___ */
+}
+
 SECTIONS
 {
        . = 0x00000000;
@@ -33,6 +39,9 @@ SECTIONS
 
        _etext = .;             /* End of text section */
 
+       NOTES :text :note
+       BUG_TABLE :text
+
        RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
@@ -49,9 +58,6 @@ SECTIONS
                __stop___ex_table = .;
        }
 
-       NOTES
-       BUG_TABLE
-
        .data : {               /* Data */
                DATA_DATA
                CONSTRUCTORS
index 8d76403fcf89b5900f02f6084312049791b8dc4e..e41f4008afc501927a5c3b08fda18891c1afc887 100644 (file)
@@ -39,7 +39,7 @@ static inline void _raw_yield_cpu(int cpu)
                _raw_yield();
 }
 
-void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
+void _raw_spin_lock_wait(raw_spinlock_t *lp)
 {
        int count = spin_retry;
        unsigned int cpu = ~smp_processor_id();
@@ -53,15 +53,36 @@ void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
                }
                if (__raw_spin_is_locked(lp))
                        continue;
-               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
-                       lp->owner_pc = pc;
+               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
                        return;
-               }
        }
 }
 EXPORT_SYMBOL(_raw_spin_lock_wait);
 
-int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
+void _raw_spin_lock_wait_flags(raw_spinlock_t *lp, unsigned long flags)
+{
+       int count = spin_retry;
+       unsigned int cpu = ~smp_processor_id();
+
+       local_irq_restore(flags);
+       while (1) {
+               if (count-- <= 0) {
+                       unsigned int owner = lp->owner_cpu;
+                       if (owner != 0)
+                               _raw_yield_cpu(~owner);
+                       count = spin_retry;
+               }
+               if (__raw_spin_is_locked(lp))
+                       continue;
+               local_irq_disable();
+               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+                       return;
+               local_irq_restore(flags);
+       }
+}
+EXPORT_SYMBOL(_raw_spin_lock_wait_flags);
+
+int _raw_spin_trylock_retry(raw_spinlock_t *lp)
 {
        unsigned int cpu = ~smp_processor_id();
        int count;
@@ -69,10 +90,8 @@ int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
        for (count = spin_retry; count > 0; count--) {
                if (__raw_spin_is_locked(lp))
                        continue;
-               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
-                       lp->owner_pc = pc;
+               if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
                        return 1;
-               }
        }
        return 0;
 }
index 394980b05e6fd91aaea02bacca57f81062690ad4..880b0ebf894b43e466c4936c9646d288c3bdb811 100644 (file)
@@ -83,7 +83,7 @@ struct dcss_segment {
 };
 
 static DEFINE_MUTEX(dcss_lock);
-static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list);
+static LIST_HEAD(dcss_list);
 static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
                                        "EW/EN-MIXED" };
 
index fb9c5a85aa563b745fafbf096fdd5d239603da8e..79d13a166a3dac765df9c7af68c18b0cf58bd253 100644 (file)
 #include <asm/setup.h>
 #include <asm/tlbflush.h>
 
-unsigned long vmalloc_end;
-EXPORT_SYMBOL(vmalloc_end);
-
-static struct page *vmem_map;
 static DEFINE_MUTEX(vmem_mutex);
 
 struct memory_segment {
@@ -188,8 +184,8 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
        pte_t  pte;
        int ret = -ENOMEM;
 
-       map_start = vmem_map + PFN_DOWN(start);
-       map_end = vmem_map + PFN_DOWN(start + size);
+       map_start = VMEM_MAP + PFN_DOWN(start);
+       map_end = VMEM_MAP + PFN_DOWN(start + size);
 
        start_addr = (unsigned long) map_start & PAGE_MASK;
        end_addr = PFN_ALIGN((unsigned long) map_end);
@@ -240,10 +236,10 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
 {
        int ret;
 
-       ret = vmem_add_range(start, size);
+       ret = vmem_add_mem_map(start, size);
        if (ret)
                return ret;
-       return vmem_add_mem_map(start, size);
+       return vmem_add_range(start, size);
 }
 
 /*
@@ -254,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg)
 {
        struct memory_segment *tmp;
 
-       if (PFN_DOWN(seg->start + seg->size) > max_pfn ||
+       if (seg->start + seg->size >= VMALLOC_START ||
            seg->start + seg->size < seg->start)
                return -ERANGE;
 
@@ -357,17 +353,15 @@ out:
 
 /*
  * map whole physical memory to virtual memory (identity mapping)
+ * we reserve enough space in the vmalloc area for vmemmap to hotplug
+ * additional memory segments.
  */
 void __init vmem_map_init(void)
 {
-       unsigned long map_size;
        int i;
 
-       map_size = ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page);
-       vmalloc_end = PFN_ALIGN(VMALLOC_END_INIT) - PFN_ALIGN(map_size);
-       vmem_map = (struct page *) vmalloc_end;
-       NODE_DATA(0)->node_mem_map = vmem_map;
-
+       BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
+       NODE_DATA(0)->node_mem_map = VMEM_MAP;
        for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
                vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
 }
@@ -382,7 +376,7 @@ static int __init vmem_convert_memory_chunk(void)
        int i;
 
        mutex_lock(&vmem_mutex);
-       for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+       for (i = 0; i < MEMORY_CHUNKS; i++) {
                if (!memory_chunk[i].size)
                        continue;
                seg = kzalloc(sizeof(*seg), GFP_KERNEL);
index eebcd4768bbf01a12ecbfd2cd6b06b0e60f3c5d8..51b57c0d1a3c01f98d99e4bb5071cdb1478b89d3 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/dma.h>
 
 static struct sysdev_class dma_sysclass = {
-       set_kset_name("dma"),
+       .name = "dma",
 };
 EXPORT_SYMBOL(dma_sysclass);
 
index b22a78c807e6bb012ba2f4289673176c598e8453..3008c00eea6b6c269e7fa6bde3e2e43ca4d0f4b8 100644 (file)
@@ -341,17 +341,18 @@ static int __devinit sq_sysdev_add(struct sys_device *sysdev)
 {
        unsigned int cpu = sysdev->id;
        struct kobject *kobj;
+       int error;
 
        sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
        if (unlikely(!sq_kobject[cpu]))
                return -ENOMEM;
 
        kobj = sq_kobject[cpu];
-       kobj->parent = &sysdev->kobj;
-       kobject_set_name(kobj, "%s", "sq");
-       kobj->ktype = &ktype_percpu_entry;
-
-       return kobject_register(kobj);
+       error = kobject_init_and_add(kobj, &ktype_percpu_entry, &sysdev->kobj,
+                                    "%s", "sq");
+       if (!error)
+               kobject_uevent(kobj, KOBJ_ADD);
+       return error;
 }
 
 static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
@@ -359,7 +360,7 @@ static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
        unsigned int cpu = sysdev->id;
        struct kobject *kobj = sq_kobject[cpu];
 
-       kobject_unregister(kobj);
+       kobject_put(kobj);
        return 0;
 }
 
index a3a67d151e520285b08c7fd58cc93d618e079fe6..2bc04bfee73891045e92df6506287aa5ce1e102b 100644 (file)
@@ -174,7 +174,7 @@ int timer_resume(struct sys_device *dev)
 #endif
 
 static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer"),
+       .name    = "timer",
        .suspend = timer_suspend,
        .resume  = timer_resume,
 };
index f8228383895ac9f38c51709c9af3c76ac13d2ba1..d07bc74773aa4c2bfa063a8090a0b0efe95dda52 100644 (file)
@@ -379,7 +379,7 @@ static void c_stop(struct seq_file *m, void *v)
 {
 }
 
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
        .start =c_start,
        .next = c_next,
        .stop = c_stop,
index 45cb7c5286d7cb327d19d057de0ab07e77fbe2ce..00b393c3a4a09edcde2b89e283c9642199c09670 100644 (file)
@@ -436,7 +436,14 @@ void __init time_init(void)
 
 static inline unsigned long do_gettimeoffset(void)
 {
-       return (*master_l10_counter >> 10) & 0x1fffff;
+       unsigned long val = *master_l10_counter;
+       unsigned long usec = (val >> 10) & 0x1fffff;
+
+       /* Limit hit?  */
+       if (val & 0x80000000)
+               usec += 1000000 / HZ;
+
+       return usec;
 }
 
 /* Ok, my cute asm atomicity trick doesn't work anymore.
index 964527d2ffa0f974b2ee7cfe4c6d16bf04e97e0c..cef8defcd7a931785acf4a8ccb8f978ee42d86bf 100644 (file)
@@ -1,6 +1,6 @@
 /* arch/sparc64/kernel/ktlb.S: Kernel mapping TLB miss handling.
  *
- * Copyright (C) 1995, 1997, 2005 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 1995, 1997, 2005, 2008 David S. Miller <davem@davemloft.net>
  * Copyright (C) 1996 Eddie C. Dost        (ecd@brainaid.de)
  * Copyright (C) 1996 Miguel de Icaza      (miguel@nuclecu.unam.mx)
  * Copyright (C) 1996,98,99 Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -226,6 +226,7 @@ kvmap_dtlb_load:
        ba,pt           %xcc, sun4v_dtlb_load
         mov            %g5, %g3
 
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
 kvmap_vmemmap:
        sub             %g4, %g5, %g5
        srlx            %g5, 22, %g5
@@ -234,6 +235,7 @@ kvmap_vmemmap:
        or              %g1, %lo(vmemmap_table), %g1
        ba,pt           %xcc, kvmap_dtlb_load
         ldx            [%g1 + %g5], %g5
+#endif
 
 kvmap_dtlb_nonlinear:
        /* Catch kernel NULL pointer derefs.  */
@@ -242,12 +244,14 @@ kvmap_dtlb_nonlinear:
        bleu,pn         %xcc, kvmap_dtlb_longpath
         nop
 
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
        /* Do not use the TSB for vmemmap.  */
        mov             (VMEMMAP_BASE >> 24), %g5
        sllx            %g5, 24, %g5
        cmp             %g4,%g5
        bgeu,pn         %xcc, kvmap_vmemmap
         nop
+#endif
 
        KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
 
index fef3b37487bf4fc92f850afc2053afbd22c6cad2..7571ed563147295623c41fce6f9def73d0dc8993 100644 (file)
@@ -30,7 +30,7 @@
                               "i" (ASI_PHYS_BYPASS_EC_E) \
                             : "memory")
 
-static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_fire_scan_bus(struct pci_pbm_info *pbm)
 {
        pbm->pci_bus = pci_scan_one_pbm(pbm);
 
@@ -434,8 +434,8 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
        fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
 }
 
-static int pci_fire_pbm_init(struct pci_controller_info *p,
-                            struct device_node *dp, u32 portid)
+static int __init pci_fire_pbm_init(struct pci_controller_info *p,
+                                   struct device_node *dp, u32 portid)
 {
        const struct linux_prom64_registers *regs;
        struct pci_pbm_info *pbm;
@@ -488,7 +488,7 @@ static inline int portid_compare(u32 x, u32 y)
        return 0;
 }
 
-void fire_pci_init(struct device_node *dp, const char *model_name)
+void __init fire_pci_init(struct device_node *dp, const char *model_name)
 {
        struct pci_controller_info *p;
        u32 portid = of_getintprop_default(dp, "portid", 0xff);
index d27ee5d528a2d6bfb3ef79f64aa7e225f5caa330..0bad96e5d184a3d6d983e31d90f743e43275111d 100644 (file)
@@ -801,7 +801,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void psycho_scan_bus(struct pci_pbm_info *pbm)
+static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable = 0;
@@ -965,7 +965,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
 #define PSYCHO_MEMSPACE_B      0x180000000UL
 #define PSYCHO_MEMSPACE_SIZE   0x07fffffffUL
 
-static void psycho_pbm_init(struct pci_controller_info *p,
+static void __init psycho_pbm_init(struct pci_controller_info *p,
                            struct device_node *dp, int is_pbm_a)
 {
        struct property *prop;
@@ -1012,7 +1012,7 @@ static void psycho_pbm_init(struct pci_controller_info *p,
 
 #define PSYCHO_CONFIGSPACE     0x001000000UL
 
-void psycho_init(struct device_node *dp, char *model_name)
+void __init psycho_init(struct device_node *dp, char *model_name)
 {
        struct linux_prom64_registers *pr_regs;
        struct pci_controller_info *p;
index fba67c3d880928e00d9332e9f1e5099f26d5171b..1c5f5fa2339f30de8504ced049d6f393020b030b 100644 (file)
@@ -633,7 +633,7 @@ static void apb_init(struct pci_bus *sabre_bus)
        }
 }
 
-static void sabre_scan_bus(struct pci_pbm_info *pbm)
+static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
 {
        static int once;
 
@@ -731,7 +731,8 @@ static int sabre_iommu_init(struct pci_pbm_info *pbm,
        return 0;
 }
 
-static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
+static void __init sabre_pbm_init(struct pci_controller_info *p,
+                                 struct pci_pbm_info *pbm, struct device_node *dp)
 {
        pbm->name = dp->full_name;
        printk("%s: SABRE PCI Bus Module\n", pbm->name);
@@ -750,7 +751,7 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *p
        pci_determine_mem_io_space(pbm);
 }
 
-void sabre_init(struct device_node *dp, char *model_name)
+void __init sabre_init(struct device_node *dp, char *model_name)
 {
        const struct linux_prom64_registers *pr_regs;
        struct pci_controller_info *p;
index e752e75cce83a14388a431bcbd2663f8b9ab42af..e306093623222a645900c559ad3286f5e90071df 100644 (file)
@@ -1084,7 +1084,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable =
@@ -1333,9 +1333,9 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
        }
 }
 
-static int schizo_pbm_init(struct pci_controller_info *p,
-                          struct device_node *dp, u32 portid,
-                          int chip_type)
+static int __init schizo_pbm_init(struct pci_controller_info *p,
+                                 struct device_node *dp, u32 portid,
+                                 int chip_type)
 {
        const struct linux_prom64_registers *regs;
        struct pci_pbm_info *pbm;
@@ -1430,7 +1430,8 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
        return (x == y);
 }
 
-static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
+static void __init __schizo_init(struct device_node *dp, char *model_name,
+                                int chip_type)
 {
        struct pci_controller_info *p;
        struct pci_pbm_info *pbm;
@@ -1474,17 +1475,17 @@ fatal_memory_error:
        prom_halt();
 }
 
-void schizo_init(struct device_node *dp, char *model_name)
+void __init schizo_init(struct device_node *dp, char *model_name)
 {
        __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
 }
 
-void schizo_plus_init(struct device_node *dp, char *model_name)
+void __init schizo_plus_init(struct device_node *dp, char *model_name)
 {
        __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
 }
 
-void tomatillo_init(struct device_node *dp, char *model_name)
+void __init tomatillo_init(struct device_node *dp, char *model_name)
 {
        __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
 }
index e587a372f3fee55918b92755dbc37794257763e2..1aa8e044b1057c5d8a2d34ae56447787faac4773 100644 (file)
@@ -612,7 +612,7 @@ const struct dma_ops sun4v_dma_ops = {
        .sync_sg_for_cpu                = dma_4v_sync_sg_for_cpu,
 };
 
-static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
 {
        struct property *prop;
        struct device_node *dp;
@@ -960,7 +960,8 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
+                                     struct device_node *dp, u32 devhandle)
 {
        struct pci_pbm_info *pbm;
 
index 0f5be828ee92614c8465055552a192e042274d47..a813441b358f1355d9a732a530e7ef5160dcfba9 100644 (file)
@@ -421,7 +421,7 @@ static void c_stop(struct seq_file *m, void *v)
 {
 }
 
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
        .start =c_start,
        .next = c_next,
        .stop = c_stop,
index 9871dbb1ab42579a10e22e892a4049711bb3e941..fd9430562e0be4c20f558fd9a903db6e2f212013 100644 (file)
@@ -215,6 +215,7 @@ sun4v_itlb_error:
 
 1:     ba,pt   %xcc, etrap
 2:      or     %g7, %lo(2b), %g7
+       mov     %l4, %o1
        call    sun4v_itlb_error_report
         add    %sp, PTREGS_OFF, %o0
 
@@ -241,6 +242,7 @@ sun4v_dtlb_error:
 
 1:     ba,pt   %xcc, etrap
 2:      or     %g7, %lo(2b), %g7
+       mov     %l4, %o1
        call    sun4v_dtlb_error_report
         add    %sp, PTREGS_OFF, %o0
 
index 04998388259fcfe7597843c0dd9cb72166b448db..2b6abf633343f3e76df9d08711e8593b9507d604 100644 (file)
@@ -1950,6 +1950,8 @@ void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
        printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
               regs->tpc, tl);
        print_symbol(KERN_EMERG "SUN4V-ITLB: TPC<%s>\n", regs->tpc);
+       printk(KERN_EMERG "SUN4V-ITLB: O7[%lx]\n", regs->u_regs[UREG_I7]);
+       print_symbol(KERN_EMERG "SUN4V-ITLB: O7<%s>\n", regs->u_regs[UREG_I7]);
        printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] "
               "pte[%lx] error[%lx]\n",
               sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
@@ -1971,6 +1973,8 @@ void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
        printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
               regs->tpc, tl);
        print_symbol(KERN_EMERG "SUN4V-DTLB: TPC<%s>\n", regs->tpc);
+       printk(KERN_EMERG "SUN4V-DTLB: O7[%lx]\n", regs->u_regs[UREG_I7]);
+       print_symbol(KERN_EMERG "SUN4V-DTLB: O7<%s>\n", regs->u_regs[UREG_I7]);
        printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] "
               "pte[%lx] error[%lx]\n",
               sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
index 0c1ee619d814c1f1e2330ef276c6271356fbe5c5..e78b3517940b6a252a13d36b544c371341f1aae0 100644 (file)
@@ -131,7 +131,7 @@ void vio_unregister_driver(struct vio_driver *viodrv)
 }
 EXPORT_SYMBOL(vio_unregister_driver);
 
-static void __devinit vio_dev_release(struct device *dev)
+static void vio_dev_release(struct device *dev)
 {
        kfree(to_vio_dev(dev));
 }
index 46bb609e2444a50cd9c5b2370d5febe0df90cbce..3874c2de54036e125a7f4772d93f37fa277e5c11 100644 (file)
@@ -4,12 +4,16 @@
 
 obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
+obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
+obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
 
-aes-i586-y := aes-i586-asm_32.o aes_32.o
-twofish-i586-y := twofish-i586-asm_32.o twofish_32.o
+aes-i586-y := aes-i586-asm_32.o aes_glue.o
+twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
+salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
 
-aes-x86_64-y := aes-x86_64-asm_64.o aes_64.o
-twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o
+aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
+twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
+salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
index f942f0c8f6306d19875b069a419743efe010c979..1093bede3e0a75378c6dde1bfa9a9f2fafce4cff 100644 (file)
@@ -46,9 +46,9 @@
 #define in_blk 16
 
 /* offsets in crypto_tfm structure */
-#define ekey (crypto_tfm_ctx_offset + 0)
-#define nrnd (crypto_tfm_ctx_offset + 256)
-#define dkey (crypto_tfm_ctx_offset + 260)
+#define klen (crypto_tfm_ctx_offset + 0)
+#define ekey (crypto_tfm_ctx_offset + 4)
+#define dkey (crypto_tfm_ctx_offset + 244)
 
 // register mapping for encrypt and decrypt subroutines
 
 
 .global  aes_enc_blk
 
-.extern  ft_tab
-.extern  fl_tab
+.extern  crypto_ft_tab
+.extern  crypto_fl_tab
 
 .align 4
 
@@ -236,7 +236,7 @@ aes_enc_blk:
 1:     push    %ebx
        mov     in_blk+4(%esp),%r2
        push    %esi
-       mov     nrnd(%ebp),%r3   // number of rounds
+       mov     klen(%ebp),%r3   // key size
        push    %edi
 #if ekey != 0
        lea     ekey(%ebp),%ebp  // key pointer
@@ -255,26 +255,26 @@ aes_enc_blk:
 
        sub     $8,%esp         // space for register saves on stack
        add     $16,%ebp        // increment to next round key
-       cmp     $12,%r3
+       cmp     $24,%r3
        jb      4f              // 10 rounds for 128-bit key
        lea     32(%ebp),%ebp
        je      3f              // 12 rounds for 192-bit key
        lea     32(%ebp),%ebp
 
-2:     fwd_rnd1( -64(%ebp) ,ft_tab)    // 14 rounds for 256-bit key
-       fwd_rnd2( -48(%ebp) ,ft_tab)
-3:     fwd_rnd1( -32(%ebp) ,ft_tab)    // 12 rounds for 192-bit key
-       fwd_rnd2( -16(%ebp) ,ft_tab)
-4:     fwd_rnd1(    (%ebp) ,ft_tab)    // 10 rounds for 128-bit key
-       fwd_rnd2( +16(%ebp) ,ft_tab)
-       fwd_rnd1( +32(%ebp) ,ft_tab)
-       fwd_rnd2( +48(%ebp) ,ft_tab)
-       fwd_rnd1( +64(%ebp) ,ft_tab)
-       fwd_rnd2( +80(%ebp) ,ft_tab)
-       fwd_rnd1( +96(%ebp) ,ft_tab)
-       fwd_rnd2(+112(%ebp) ,ft_tab)
-       fwd_rnd1(+128(%ebp) ,ft_tab)
-       fwd_rnd2(+144(%ebp) ,fl_tab)    // last round uses a different table
+2:     fwd_rnd1( -64(%ebp), crypto_ft_tab)     // 14 rounds for 256-bit key
+       fwd_rnd2( -48(%ebp), crypto_ft_tab)
+3:     fwd_rnd1( -32(%ebp), crypto_ft_tab)     // 12 rounds for 192-bit key
+       fwd_rnd2( -16(%ebp), crypto_ft_tab)
+4:     fwd_rnd1(    (%ebp), crypto_ft_tab)     // 10 rounds for 128-bit key
+       fwd_rnd2( +16(%ebp), crypto_ft_tab)
+       fwd_rnd1( +32(%ebp), crypto_ft_tab)
+       fwd_rnd2( +48(%ebp), crypto_ft_tab)
+       fwd_rnd1( +64(%ebp), crypto_ft_tab)
+       fwd_rnd2( +80(%ebp), crypto_ft_tab)
+       fwd_rnd1( +96(%ebp), crypto_ft_tab)
+       fwd_rnd2(+112(%ebp), crypto_ft_tab)
+       fwd_rnd1(+128(%ebp), crypto_ft_tab)
+       fwd_rnd2(+144(%ebp), crypto_fl_tab)     // last round uses a different table
 
 // move final values to the output array.  CAUTION: the 
 // order of these assigns rely on the register mappings
@@ -297,8 +297,8 @@ aes_enc_blk:
 
 .global  aes_dec_blk
 
-.extern  it_tab
-.extern  il_tab
+.extern  crypto_it_tab
+.extern  crypto_il_tab
 
 .align 4
 
@@ -312,14 +312,11 @@ aes_dec_blk:
 1:     push    %ebx
        mov     in_blk+4(%esp),%r2
        push    %esi
-       mov     nrnd(%ebp),%r3   // number of rounds
+       mov     klen(%ebp),%r3   // key size
        push    %edi
 #if dkey != 0
        lea     dkey(%ebp),%ebp  // key pointer
 #endif
-       mov     %r3,%r0
-       shl     $4,%r0
-       add     %r0,%ebp
        
 // input four columns and xor in first round key
 
@@ -333,27 +330,27 @@ aes_dec_blk:
        xor     12(%ebp),%r5
 
        sub     $8,%esp         // space for register saves on stack
-       sub     $16,%ebp        // increment to next round key
-       cmp     $12,%r3
+       add     $16,%ebp        // increment to next round key
+       cmp     $24,%r3
        jb      4f              // 10 rounds for 128-bit key
-       lea     -32(%ebp),%ebp
+       lea     32(%ebp),%ebp
        je      3f              // 12 rounds for 192-bit key
-       lea     -32(%ebp),%ebp
-
-2:     inv_rnd1( +64(%ebp), it_tab)    // 14 rounds for 256-bit key
-       inv_rnd2( +48(%ebp), it_tab)
-3:     inv_rnd1( +32(%ebp), it_tab)    // 12 rounds for 192-bit key
-       inv_rnd2( +16(%ebp), it_tab)
-4:     inv_rnd1(    (%ebp), it_tab)    // 10 rounds for 128-bit key
-       inv_rnd2( -16(%ebp), it_tab)
-       inv_rnd1( -32(%ebp), it_tab)
-       inv_rnd2( -48(%ebp), it_tab)
-       inv_rnd1( -64(%ebp), it_tab)
-       inv_rnd2( -80(%ebp), it_tab)
-       inv_rnd1( -96(%ebp), it_tab)
-       inv_rnd2(-112(%ebp), it_tab)
-       inv_rnd1(-128(%ebp), it_tab)
-       inv_rnd2(-144(%ebp), il_tab)    // last round uses a different table
+       lea     32(%ebp),%ebp
+
+2:     inv_rnd1( -64(%ebp), crypto_it_tab)     // 14 rounds for 256-bit key
+       inv_rnd2( -48(%ebp), crypto_it_tab)
+3:     inv_rnd1( -32(%ebp), crypto_it_tab)     // 12 rounds for 192-bit key
+       inv_rnd2( -16(%ebp), crypto_it_tab)
+4:     inv_rnd1(    (%ebp), crypto_it_tab)     // 10 rounds for 128-bit key
+       inv_rnd2( +16(%ebp), crypto_it_tab)
+       inv_rnd1( +32(%ebp), crypto_it_tab)
+       inv_rnd2( +48(%ebp), crypto_it_tab)
+       inv_rnd1( +64(%ebp), crypto_it_tab)
+       inv_rnd2( +80(%ebp), crypto_it_tab)
+       inv_rnd1( +96(%ebp), crypto_it_tab)
+       inv_rnd2(+112(%ebp), crypto_it_tab)
+       inv_rnd1(+128(%ebp), crypto_it_tab)
+       inv_rnd2(+144(%ebp), crypto_il_tab)     // last round uses a different table
 
 // move final values to the output array.  CAUTION: the 
 // order of these assigns rely on the register mappings
index 26b40de4d0b0299939591aead1d6652e296f60f7..a120f526c3df9d9c547b996867f1b035b44b006b 100644 (file)
@@ -8,10 +8,10 @@
  * including this sentence is retained in full.
  */
 
-.extern aes_ft_tab
-.extern aes_it_tab
-.extern aes_fl_tab
-.extern aes_il_tab
+.extern crypto_ft_tab
+.extern crypto_it_tab
+.extern crypto_fl_tab
+.extern crypto_il_tab
 
 .text
 
        .align  8;                      \
 FUNC:  movq    r1,r2;                  \
        movq    r3,r4;                  \
-       leaq    BASE+KEY+52(r8),r9;     \
+       leaq    BASE+KEY+48+4(r8),r9;   \
        movq    r10,r11;                \
        movl    (r7),r5 ## E;           \
        movl    4(r7),r1 ## E;          \
        movl    8(r7),r6 ## E;          \
        movl    12(r7),r7 ## E;         \
-       movl    BASE(r8),r10 ## E;      \
+       movl    BASE+0(r8),r10 ## E;    \
        xorl    -48(r9),r5 ## E;        \
        xorl    -44(r9),r1 ## E;        \
        xorl    -40(r9),r6 ## E;        \
@@ -154,37 +154,37 @@ FUNC:     movq    r1,r2;                  \
 /* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */
 
        entry(aes_enc_blk,0,enc128,enc192)
-       encrypt_round(aes_ft_tab,-96)
-       encrypt_round(aes_ft_tab,-80)
-enc192:        encrypt_round(aes_ft_tab,-64)
-       encrypt_round(aes_ft_tab,-48)
-enc128:        encrypt_round(aes_ft_tab,-32)
-       encrypt_round(aes_ft_tab,-16)
-       encrypt_round(aes_ft_tab,  0)
-       encrypt_round(aes_ft_tab, 16)
-       encrypt_round(aes_ft_tab, 32)
-       encrypt_round(aes_ft_tab, 48)
-       encrypt_round(aes_ft_tab, 64)
-       encrypt_round(aes_ft_tab, 80)
-       encrypt_round(aes_ft_tab, 96)
-       encrypt_final(aes_fl_tab,112)
+       encrypt_round(crypto_ft_tab,-96)
+       encrypt_round(crypto_ft_tab,-80)
+enc192:        encrypt_round(crypto_ft_tab,-64)
+       encrypt_round(crypto_ft_tab,-48)
+enc128:        encrypt_round(crypto_ft_tab,-32)
+       encrypt_round(crypto_ft_tab,-16)
+       encrypt_round(crypto_ft_tab,  0)
+       encrypt_round(crypto_ft_tab, 16)
+       encrypt_round(crypto_ft_tab, 32)
+       encrypt_round(crypto_ft_tab, 48)
+       encrypt_round(crypto_ft_tab, 64)
+       encrypt_round(crypto_ft_tab, 80)
+       encrypt_round(crypto_ft_tab, 96)
+       encrypt_final(crypto_fl_tab,112)
        return
 
 /* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */
 
        entry(aes_dec_blk,240,dec128,dec192)
-       decrypt_round(aes_it_tab,-96)
-       decrypt_round(aes_it_tab,-80)
-dec192:        decrypt_round(aes_it_tab,-64)
-       decrypt_round(aes_it_tab,-48)
-dec128:        decrypt_round(aes_it_tab,-32)
-       decrypt_round(aes_it_tab,-16)
-       decrypt_round(aes_it_tab,  0)
-       decrypt_round(aes_it_tab, 16)
-       decrypt_round(aes_it_tab, 32)
-       decrypt_round(aes_it_tab, 48)
-       decrypt_round(aes_it_tab, 64)
-       decrypt_round(aes_it_tab, 80)
-       decrypt_round(aes_it_tab, 96)
-       decrypt_final(aes_il_tab,112)
+       decrypt_round(crypto_it_tab,-96)
+       decrypt_round(crypto_it_tab,-80)
+dec192:        decrypt_round(crypto_it_tab,-64)
+       decrypt_round(crypto_it_tab,-48)
+dec128:        decrypt_round(crypto_it_tab,-32)
+       decrypt_round(crypto_it_tab,-16)
+       decrypt_round(crypto_it_tab,  0)
+       decrypt_round(crypto_it_tab, 16)
+       decrypt_round(crypto_it_tab, 32)
+       decrypt_round(crypto_it_tab, 48)
+       decrypt_round(crypto_it_tab, 64)
+       decrypt_round(crypto_it_tab, 80)
+       decrypt_round(crypto_it_tab, 96)
+       decrypt_final(crypto_il_tab,112)
        return
diff --git a/arch/x86/crypto/aes_32.c b/arch/x86/crypto/aes_32.c
deleted file mode 100644 (file)
index 49aad93..0000000
+++ /dev/null
@@ -1,515 +0,0 @@
-/* 
- * 
- * Glue Code for optimized 586 assembler version of AES
- *
- * Copyright (c) 2002, Dr Brian Gladman <>, Worcester, UK.
- * All rights reserved.
- *
- * LICENSE TERMS
- *
- * The free distribution and use of this software in both source and binary
- * form is allowed (with or without changes) provided that:
- *
- *   1. distributions of this source code include the above copyright
- *      notice, this list of conditions and the following disclaimer;
- *
- *   2. distributions in binary form include the above copyright
- *      notice, this list of conditions and the following disclaimer
- *      in the documentation and/or other associated materials;
- *
- *   3. the copyright holder's name is not used to endorse products
- *      built using this software without specific written permission.
- *
- * ALTERNATIVELY, provided that this notice is retained in full, this product
- * may be distributed under the terms of the GNU General Public License (GPL),
- * in which case the provisions of the GPL apply INSTEAD OF those given above.
- *
- * DISCLAIMER
- *
- * This software is provided 'as is' with no explicit or implied warranties
- * in respect of its properties, including, but not limited to, correctness
- * and/or fitness for purpose.
- *
- * Copyright (c) 2003, Adam J. Richter <adam@yggdrasil.com> (conversion to
- * 2.5 API).
- * Copyright (c) 2003, 2004 Fruhwirth Clemens <clemens@endorphin.org>
- * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
- *
- */
-
-#include <asm/byteorder.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-#include <linux/linkage.h>
-
-asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-#define AES_MIN_KEY_SIZE       16
-#define AES_MAX_KEY_SIZE       32
-#define AES_BLOCK_SIZE         16
-#define AES_KS_LENGTH          4 * AES_BLOCK_SIZE
-#define RC_LENGTH              29
-
-struct aes_ctx {
-       u32 ekey[AES_KS_LENGTH];
-       u32 rounds;
-       u32 dkey[AES_KS_LENGTH];
-};
-
-#define WPOLY 0x011b
-#define bytes2word(b0, b1, b2, b3)  \
-       (((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0))
-
-/* define the finite field multiplies required for Rijndael */
-#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
-#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
-#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
-#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
-#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
-#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
-#define fi(x) ((x) ?   pow[255 - log[x]]: 0)
-
-static inline u32 upr(u32 x, int n)
-{
-       return (x << 8 * n) | (x >> (32 - 8 * n));
-}
-
-static inline u8 bval(u32 x, int n)
-{
-       return x >> 8 * n;
-}
-
-/* The forward and inverse affine transformations used in the S-box */
-#define fwd_affine(x) \
-       (w = (u32)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(u8)(w^(w>>8)))
-
-#define inv_affine(x) \
-       (w = (u32)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(u8)(w^(w>>8)))
-
-static u32 rcon_tab[RC_LENGTH];
-
-u32 ft_tab[4][256];
-u32 fl_tab[4][256];
-static u32 im_tab[4][256];
-u32 il_tab[4][256];
-u32 it_tab[4][256];
-
-static void gen_tabs(void)
-{
-       u32 i, w;
-       u8 pow[512], log[256];
-
-       /*
-        * log and power tables for GF(2^8) finite field with
-        * WPOLY as modular polynomial - the simplest primitive
-        * root is 0x03, used here to generate the tables.
-        */
-       i = 0; w = 1; 
-       
-       do {
-               pow[i] = (u8)w;
-               pow[i + 255] = (u8)w;
-               log[w] = (u8)i++;
-               w ^=  (w << 1) ^ (w & 0x80 ? WPOLY : 0);
-       } while (w != 1);
-       
-       for(i = 0, w = 1; i < RC_LENGTH; ++i) {
-               rcon_tab[i] = bytes2word(w, 0, 0, 0);
-               w = f2(w);
-       }
-
-       for(i = 0; i < 256; ++i) {
-               u8 b;
-               
-               b = fwd_affine(fi((u8)i));
-               w = bytes2word(f2(b), b, b, f3(b));
-
-               /* tables for a normal encryption round */
-               ft_tab[0][i] = w;
-               ft_tab[1][i] = upr(w, 1);
-               ft_tab[2][i] = upr(w, 2);
-               ft_tab[3][i] = upr(w, 3);
-               w = bytes2word(b, 0, 0, 0);
-               
-               /*
-                * tables for last encryption round
-                * (may also be used in the key schedule)
-                */
-               fl_tab[0][i] = w;
-               fl_tab[1][i] = upr(w, 1);
-               fl_tab[2][i] = upr(w, 2);
-               fl_tab[3][i] = upr(w, 3);
-               
-               b = fi(inv_affine((u8)i));
-               w = bytes2word(fe(b), f9(b), fd(b), fb(b));
-
-               /* tables for the inverse mix column operation  */
-               im_tab[0][b] = w;
-               im_tab[1][b] = upr(w, 1);
-               im_tab[2][b] = upr(w, 2);
-               im_tab[3][b] = upr(w, 3);
-
-               /* tables for a normal decryption round */
-               it_tab[0][i] = w;
-               it_tab[1][i] = upr(w,1);
-               it_tab[2][i] = upr(w,2);
-               it_tab[3][i] = upr(w,3);
-
-               w = bytes2word(b, 0, 0, 0);
-               
-               /* tables for last decryption round */
-               il_tab[0][i] = w;
-               il_tab[1][i] = upr(w,1);
-               il_tab[2][i] = upr(w,2);
-               il_tab[3][i] = upr(w,3);
-    }
-}
-
-#define four_tables(x,tab,vf,rf,c)             \
-(      tab[0][bval(vf(x,0,c),rf(0,c))] ^       \
-       tab[1][bval(vf(x,1,c),rf(1,c))] ^       \
-       tab[2][bval(vf(x,2,c),rf(2,c))] ^       \
-       tab[3][bval(vf(x,3,c),rf(3,c))]         \
-)
-
-#define vf1(x,r,c)  (x)
-#define rf1(r,c)    (r)
-#define rf2(r,c)    ((r-c)&3)
-
-#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0)
-#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c)
-
-#define ff(x) inv_mcol(x)
-
-#define ke4(k,i)                                                       \
-{                                                                      \
-       k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i];            \
-       k[4*(i)+5] = ss[1] ^= ss[0];                                    \
-       k[4*(i)+6] = ss[2] ^= ss[1];                                    \
-       k[4*(i)+7] = ss[3] ^= ss[2];                                    \
-}
-
-#define kel4(k,i)                                                      \
-{                                                                      \
-       k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i];            \
-       k[4*(i)+5] = ss[1] ^= ss[0];                                    \
-       k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2];       \
-}
-
-#define ke6(k,i)                                                       \
-{                                                                      \
-       k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];           \
-       k[6*(i)+ 7] = ss[1] ^= ss[0];                                   \
-       k[6*(i)+ 8] = ss[2] ^= ss[1];                                   \
-       k[6*(i)+ 9] = ss[3] ^= ss[2];                                   \
-       k[6*(i)+10] = ss[4] ^= ss[3];                                   \
-       k[6*(i)+11] = ss[5] ^= ss[4];                                   \
-}
-
-#define kel6(k,i)                                                      \
-{                                                                      \
-       k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];           \
-       k[6*(i)+ 7] = ss[1] ^= ss[0];                                   \
-       k[6*(i)+ 8] = ss[2] ^= ss[1];                                   \
-       k[6*(i)+ 9] = ss[3] ^= ss[2];                                   \
-}
-
-#define ke8(k,i)                                                       \
-{                                                                      \
-       k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];           \
-       k[8*(i)+ 9] = ss[1] ^= ss[0];                                   \
-       k[8*(i)+10] = ss[2] ^= ss[1];                                   \
-       k[8*(i)+11] = ss[3] ^= ss[2];                                   \
-       k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0);                         \
-       k[8*(i)+13] = ss[5] ^= ss[4];                                   \
-       k[8*(i)+14] = ss[6] ^= ss[5];                                   \
-       k[8*(i)+15] = ss[7] ^= ss[6];                                   \
-}
-
-#define kel8(k,i)                                                      \
-{                                                                      \
-       k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];           \
-       k[8*(i)+ 9] = ss[1] ^= ss[0];                                   \
-       k[8*(i)+10] = ss[2] ^= ss[1];                                   \
-       k[8*(i)+11] = ss[3] ^= ss[2];                                   \
-}
-
-#define kdf4(k,i)                                                      \
-{                                                                      \
-       ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3];                          \
-       ss[1] = ss[1] ^ ss[3];                                          \
-       ss[2] = ss[2] ^ ss[3];                                          \
-       ss[3] = ss[3];                                                  \
-       ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];                 \
-       ss[i % 4] ^= ss[4];                                             \
-       ss[4] ^= k[4*(i)];                                              \
-       k[4*(i)+4] = ff(ss[4]);                                         \
-       ss[4] ^= k[4*(i)+1];                                            \
-       k[4*(i)+5] = ff(ss[4]);                                         \
-       ss[4] ^= k[4*(i)+2];                                            \
-       k[4*(i)+6] = ff(ss[4]);                                         \
-       ss[4] ^= k[4*(i)+3];                                            \
-       k[4*(i)+7] = ff(ss[4]);                                         \
-}
-
-#define kd4(k,i)                                                       \
-{                                                                      \
-       ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];                 \
-       ss[i % 4] ^= ss[4];                                             \
-       ss[4] = ff(ss[4]);                                              \
-       k[4*(i)+4] = ss[4] ^= k[4*(i)];                                 \
-       k[4*(i)+5] = ss[4] ^= k[4*(i)+1];                               \
-       k[4*(i)+6] = ss[4] ^= k[4*(i)+2];                               \
-       k[4*(i)+7] = ss[4] ^= k[4*(i)+3];                               \
-}
-
-#define kdl4(k,i)                                                      \
-{                                                                      \
-       ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];                 \
-       ss[i % 4] ^= ss[4];                                             \
-       k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3];                  \
-       k[4*(i)+5] = ss[1] ^ ss[3];                                     \
-       k[4*(i)+6] = ss[0];                                             \
-       k[4*(i)+7] = ss[1];                                             \
-}
-
-#define kdf6(k,i)                                                      \
-{                                                                      \
-       ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];                         \
-       k[6*(i)+ 6] = ff(ss[0]);                                        \
-       ss[1] ^= ss[0];                                                 \
-       k[6*(i)+ 7] = ff(ss[1]);                                        \
-       ss[2] ^= ss[1];                                                 \
-       k[6*(i)+ 8] = ff(ss[2]);                                        \
-       ss[3] ^= ss[2];                                                 \
-       k[6*(i)+ 9] = ff(ss[3]);                                        \
-       ss[4] ^= ss[3];                                                 \
-       k[6*(i)+10] = ff(ss[4]);                                        \
-       ss[5] ^= ss[4];                                                 \
-       k[6*(i)+11] = ff(ss[5]);                                        \
-}
-
-#define kd6(k,i)                                                       \
-{                                                                      \
-       ss[6] = ls_box(ss[5],3) ^ rcon_tab[i];                          \
-       ss[0] ^= ss[6]; ss[6] = ff(ss[6]);                              \
-       k[6*(i)+ 6] = ss[6] ^= k[6*(i)];                                \
-       ss[1] ^= ss[0];                                                 \
-       k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1];                             \
-       ss[2] ^= ss[1];                                                 \
-       k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2];                             \
-       ss[3] ^= ss[2];                                                 \
-       k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3];                             \
-       ss[4] ^= ss[3];                                                 \
-       k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4];                             \
-       ss[5] ^= ss[4];                                                 \
-       k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5];                             \
-}
-
-#define kdl6(k,i)                                                      \
-{                                                                      \
-       ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];                         \
-       k[6*(i)+ 6] = ss[0];                                            \
-       ss[1] ^= ss[0];                                                 \
-       k[6*(i)+ 7] = ss[1];                                            \
-       ss[2] ^= ss[1];                                                 \
-       k[6*(i)+ 8] = ss[2];                                            \
-       ss[3] ^= ss[2];                                                 \
-       k[6*(i)+ 9] = ss[3];                                            \
-}
-
-#define kdf8(k,i)                                                      \
-{                                                                      \
-       ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];                         \
-       k[8*(i)+ 8] = ff(ss[0]);                                        \
-       ss[1] ^= ss[0];                                                 \
-       k[8*(i)+ 9] = ff(ss[1]);                                        \
-       ss[2] ^= ss[1];                                                 \
-       k[8*(i)+10] = ff(ss[2]);                                        \
-       ss[3] ^= ss[2];                                                 \
-       k[8*(i)+11] = ff(ss[3]);                                        \
-       ss[4] ^= ls_box(ss[3],0);                                       \
-       k[8*(i)+12] = ff(ss[4]);                                        \
-       ss[5] ^= ss[4];                                                 \
-       k[8*(i)+13] = ff(ss[5]);                                        \
-       ss[6] ^= ss[5];                                                 \
-       k[8*(i)+14] = ff(ss[6]);                                        \
-       ss[7] ^= ss[6];                                                 \
-       k[8*(i)+15] = ff(ss[7]);                                        \
-}
-
-#define kd8(k,i)                                                       \
-{                                                                      \
-       u32 __g = ls_box(ss[7],3) ^ rcon_tab[i];                        \
-       ss[0] ^= __g;                                                   \
-       __g = ff(__g);                                                  \
-       k[8*(i)+ 8] = __g ^= k[8*(i)];                                  \
-       ss[1] ^= ss[0];                                                 \
-       k[8*(i)+ 9] = __g ^= k[8*(i)+ 1];                               \
-       ss[2] ^= ss[1];                                                 \
-       k[8*(i)+10] = __g ^= k[8*(i)+ 2];                               \
-       ss[3] ^= ss[2];                                                 \
-       k[8*(i)+11] = __g ^= k[8*(i)+ 3];                               \
-       __g = ls_box(ss[3],0);                                          \
-       ss[4] ^= __g;                                                   \
-       __g = ff(__g);                                                  \
-       k[8*(i)+12] = __g ^= k[8*(i)+ 4];                               \
-       ss[5] ^= ss[4];                                                 \
-       k[8*(i)+13] = __g ^= k[8*(i)+ 5];                               \
-       ss[6] ^= ss[5];                                                 \
-       k[8*(i)+14] = __g ^= k[8*(i)+ 6];                               \
-       ss[7] ^= ss[6];                                                 \
-       k[8*(i)+15] = __g ^= k[8*(i)+ 7];                               \
-}
-
-#define kdl8(k,i)                                                      \
-{                                                                      \
-       ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];                         \
-       k[8*(i)+ 8] = ss[0];                                            \
-       ss[1] ^= ss[0];                                                 \
-       k[8*(i)+ 9] = ss[1];                                            \
-       ss[2] ^= ss[1];                                                 \
-       k[8*(i)+10] = ss[2];                                            \
-       ss[3] ^= ss[2];                                                 \
-       k[8*(i)+11] = ss[3];                                            \
-}
-
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-                      unsigned int key_len)
-{
-       int i;
-       u32 ss[8];
-       struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
-       const __le32 *key = (const __le32 *)in_key;
-       u32 *flags = &tfm->crt_flags;
-
-       /* encryption schedule */
-       
-       ctx->ekey[0] = ss[0] = le32_to_cpu(key[0]);
-       ctx->ekey[1] = ss[1] = le32_to_cpu(key[1]);
-       ctx->ekey[2] = ss[2] = le32_to_cpu(key[2]);
-       ctx->ekey[3] = ss[3] = le32_to_cpu(key[3]);
-
-       switch(key_len) {
-       case 16:
-               for (i = 0; i < 9; i++)
-                       ke4(ctx->ekey, i);
-               kel4(ctx->ekey, 9);
-               ctx->rounds = 10;
-               break;
-               
-       case 24:
-               ctx->ekey[4] = ss[4] = le32_to_cpu(key[4]);
-               ctx->ekey[5] = ss[5] = le32_to_cpu(key[5]);
-               for (i = 0; i < 7; i++)
-                       ke6(ctx->ekey, i);
-               kel6(ctx->ekey, 7); 
-               ctx->rounds = 12;
-               break;
-
-       case 32:
-               ctx->ekey[4] = ss[4] = le32_to_cpu(key[4]);
-               ctx->ekey[5] = ss[5] = le32_to_cpu(key[5]);
-               ctx->ekey[6] = ss[6] = le32_to_cpu(key[6]);
-               ctx->ekey[7] = ss[7] = le32_to_cpu(key[7]);
-               for (i = 0; i < 6; i++)
-                       ke8(ctx->ekey, i);
-               kel8(ctx->ekey, 6);
-               ctx->rounds = 14;
-               break;
-
-       default:
-               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-               return -EINVAL;
-       }
-       
-       /* decryption schedule */
-       
-       ctx->dkey[0] = ss[0] = le32_to_cpu(key[0]);
-       ctx->dkey[1] = ss[1] = le32_to_cpu(key[1]);
-       ctx->dkey[2] = ss[2] = le32_to_cpu(key[2]);
-       ctx->dkey[3] = ss[3] = le32_to_cpu(key[3]);
-
-       switch (key_len) {
-       case 16:
-               kdf4(ctx->dkey, 0);
-               for (i = 1; i < 9; i++)
-                       kd4(ctx->dkey, i);
-               kdl4(ctx->dkey, 9);
-               break;
-               
-       case 24:
-               ctx->dkey[4] = ff(ss[4] = le32_to_cpu(key[4]));
-               ctx->dkey[5] = ff(ss[5] = le32_to_cpu(key[5]));
-               kdf6(ctx->dkey, 0);
-               for (i = 1; i < 7; i++)
-                       kd6(ctx->dkey, i);
-               kdl6(ctx->dkey, 7);
-               break;
-
-       case 32:
-               ctx->dkey[4] = ff(ss[4] = le32_to_cpu(key[4]));
-               ctx->dkey[5] = ff(ss[5] = le32_to_cpu(key[5]));
-               ctx->dkey[6] = ff(ss[6] = le32_to_cpu(key[6]));
-               ctx->dkey[7] = ff(ss[7] = le32_to_cpu(key[7]));
-               kdf8(ctx->dkey, 0);
-               for (i = 1; i < 6; i++)
-                       kd8(ctx->dkey, i);
-               kdl8(ctx->dkey, 6);
-               break;
-       }
-       return 0;
-}
-
-static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       aes_enc_blk(tfm, dst, src);
-}
-
-static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       aes_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg aes_alg = {
-       .cra_name               =       "aes",
-       .cra_driver_name        =       "aes-i586",
-       .cra_priority           =       200,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       AES_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct aes_ctx),
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =       AES_MIN_KEY_SIZE,
-                       .cia_max_keysize        =       AES_MAX_KEY_SIZE,
-                       .cia_setkey             =       aes_set_key,
-                       .cia_encrypt            =       aes_encrypt,
-                       .cia_decrypt            =       aes_decrypt
-               }
-       }
-};
-
-static int __init aes_init(void)
-{
-       gen_tabs();
-       return crypto_register_alg(&aes_alg);
-}
-
-static void __exit aes_fini(void)
-{
-       crypto_unregister_alg(&aes_alg);
-}
-
-module_init(aes_init);
-module_exit(aes_fini);
-
-MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, i586 asm optimized");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Fruhwirth Clemens, James Morris, Brian Gladman, Adam Richter");
-MODULE_ALIAS("aes");
diff --git a/arch/x86/crypto/aes_64.c b/arch/x86/crypto/aes_64.c
deleted file mode 100644 (file)
index 5cdb13e..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Cryptographic API.
- *
- * AES Cipher Algorithm.
- *
- * Based on Brian Gladman's code.
- *
- * Linux developers:
- *  Alexander Kjeldaas <astor@fast.no>
- *  Herbert Valerio Riedel <hvr@hvrlab.org>
- *  Kyle McMartin <kyle@debian.org>
- *  Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
- *  Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler)
- *
- * 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.
- *
- * ---------------------------------------------------------------------------
- * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
- * All rights reserved.
- *
- * LICENSE TERMS
- *
- * The free distribution and use of this software in both source and binary
- * form is allowed (with or without changes) provided that:
- *
- *   1. distributions of this source code include the above copyright
- *      notice, this list of conditions and the following disclaimer;
- *
- *   2. distributions in binary form include the above copyright
- *      notice, this list of conditions and the following disclaimer
- *      in the documentation and/or other associated materials;
- *
- *   3. the copyright holder's name is not used to endorse products
- *      built using this software without specific written permission.
- *
- * ALTERNATIVELY, provided that this notice is retained in full, this product
- * may be distributed under the terms of the GNU General Public License (GPL),
- * in which case the provisions of the GPL apply INSTEAD OF those given above.
- *
- * DISCLAIMER
- *
- * This software is provided 'as is' with no explicit or implied warranties
- * in respect of its properties, including, but not limited to, correctness
- * and/or fitness for purpose.
- * ---------------------------------------------------------------------------
- */
-
-/* Some changes from the Gladman version:
-    s/RIJNDAEL(e_key)/E_KEY/g
-    s/RIJNDAEL(d_key)/D_KEY/g
-*/
-
-#include <asm/byteorder.h>
-#include <linux/bitops.h>
-#include <linux/crypto.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-#define AES_MIN_KEY_SIZE       16
-#define AES_MAX_KEY_SIZE       32
-
-#define AES_BLOCK_SIZE         16
-
-/*
- * #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))
- */
-static inline u8 byte(const u32 x, const unsigned n)
-{
-       return x >> (n << 3);
-}
-
-struct aes_ctx
-{
-       u32 key_length;
-       u32 buf[120];
-};
-
-#define E_KEY (&ctx->buf[0])
-#define D_KEY (&ctx->buf[60])
-
-static u8 pow_tab[256] __initdata;
-static u8 log_tab[256] __initdata;
-static u8 sbx_tab[256] __initdata;
-static u8 isb_tab[256] __initdata;
-static u32 rco_tab[10];
-u32 aes_ft_tab[4][256];
-u32 aes_it_tab[4][256];
-
-u32 aes_fl_tab[4][256];
-u32 aes_il_tab[4][256];
-
-static inline u8 f_mult(u8 a, u8 b)
-{
-       u8 aa = log_tab[a], cc = aa + log_tab[b];
-
-       return pow_tab[cc + (cc < aa ? 1 : 0)];
-}
-
-#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0)
-
-#define ls_box(x)                              \
-       (aes_fl_tab[0][byte(x, 0)] ^            \
-        aes_fl_tab[1][byte(x, 1)] ^            \
-        aes_fl_tab[2][byte(x, 2)] ^            \
-        aes_fl_tab[3][byte(x, 3)])
-
-static void __init gen_tabs(void)
-{
-       u32 i, t;
-       u8 p, q;
-
-       /* log and power tables for GF(2**8) finite field with
-          0x011b as modular polynomial - the simplest primitive
-          root is 0x03, used here to generate the tables */
-
-       for (i = 0, p = 1; i < 256; ++i) {
-               pow_tab[i] = (u8)p;
-               log_tab[p] = (u8)i;
-
-               p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
-       }
-
-       log_tab[1] = 0;
-
-       for (i = 0, p = 1; i < 10; ++i) {
-               rco_tab[i] = p;
-
-               p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
-       }
-
-       for (i = 0; i < 256; ++i) {
-               p = (i ? pow_tab[255 - log_tab[i]] : 0);
-               q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
-               p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
-               sbx_tab[i] = p;
-               isb_tab[p] = (u8)i;
-       }
-
-       for (i = 0; i < 256; ++i) {
-               p = sbx_tab[i];
-
-               t = p;
-               aes_fl_tab[0][i] = t;
-               aes_fl_tab[1][i] = rol32(t, 8);
-               aes_fl_tab[2][i] = rol32(t, 16);
-               aes_fl_tab[3][i] = rol32(t, 24);
-
-               t = ((u32)ff_mult(2, p)) |
-                   ((u32)p << 8) |
-                   ((u32)p << 16) | ((u32)ff_mult(3, p) << 24);
-
-               aes_ft_tab[0][i] = t;
-               aes_ft_tab[1][i] = rol32(t, 8);
-               aes_ft_tab[2][i] = rol32(t, 16);
-               aes_ft_tab[3][i] = rol32(t, 24);
-
-               p = isb_tab[i];
-
-               t = p;
-               aes_il_tab[0][i] = t;
-               aes_il_tab[1][i] = rol32(t, 8);
-               aes_il_tab[2][i] = rol32(t, 16);
-               aes_il_tab[3][i] = rol32(t, 24);
-
-               t = ((u32)ff_mult(14, p)) |
-                   ((u32)ff_mult(9, p) << 8) |
-                   ((u32)ff_mult(13, p) << 16) |
-                   ((u32)ff_mult(11, p) << 24);
-
-               aes_it_tab[0][i] = t;
-               aes_it_tab[1][i] = rol32(t, 8);
-               aes_it_tab[2][i] = rol32(t, 16);
-               aes_it_tab[3][i] = rol32(t, 24);
-       }
-}
-
-#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
-
-#define imix_col(y, x)                 \
-       u    = star_x(x);               \
-       v    = star_x(u);               \
-       w    = star_x(v);               \
-       t    = w ^ (x);                 \
-       (y)  = u ^ v ^ w;               \
-       (y) ^= ror32(u ^ t,  8) ^       \
-              ror32(v ^ t, 16) ^       \
-              ror32(t, 24)
-
-/* initialise the key schedule from the user supplied key */
-
-#define loop4(i)                                       \
-{                                                      \
-       t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];   \
-       t ^= E_KEY[4 * i];     E_KEY[4 * i + 4] = t;    \
-       t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t;    \
-       t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t;    \
-       t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t;    \
-}
-
-#define loop6(i)                                       \
-{                                                      \
-       t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];   \
-       t ^= E_KEY[6 * i];     E_KEY[6 * i + 6] = t;    \
-       t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t;    \
-       t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t;    \
-       t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t;    \
-       t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t;   \
-       t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t;   \
-}
-
-#define loop8(i)                                       \
-{                                                      \
-       t = ror32(t,  8); ; t = ls_box(t) ^ rco_tab[i]; \
-       t ^= E_KEY[8 * i];     E_KEY[8 * i + 8] = t;    \
-       t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t;    \
-       t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t;   \
-       t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t;   \
-       t  = E_KEY[8 * i + 4] ^ ls_box(t);              \
-       E_KEY[8 * i + 12] = t;                          \
-       t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t;   \
-       t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t;   \
-       t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;   \
-}
-
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-                      unsigned int key_len)
-{
-       struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
-       const __le32 *key = (const __le32 *)in_key;
-       u32 *flags = &tfm->crt_flags;
-       u32 i, j, t, u, v, w;
-
-       if (key_len % 8) {
-               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-               return -EINVAL;
-       }
-
-       ctx->key_length = key_len;
-
-       D_KEY[key_len + 24] = E_KEY[0] = le32_to_cpu(key[0]);
-       D_KEY[key_len + 25] = E_KEY[1] = le32_to_cpu(key[1]);
-       D_KEY[key_len + 26] = E_KEY[2] = le32_to_cpu(key[2]);
-       D_KEY[key_len + 27] = E_KEY[3] = le32_to_cpu(key[3]);
-
-       switch (key_len) {
-       case 16:
-               t = E_KEY[3];
-               for (i = 0; i < 10; ++i)
-                       loop4(i);
-               break;
-
-       case 24:
-               E_KEY[4] = le32_to_cpu(key[4]);
-               t = E_KEY[5] = le32_to_cpu(key[5]);
-               for (i = 0; i < 8; ++i)
-                       loop6 (i);
-               break;
-
-       case 32:
-               E_KEY[4] = le32_to_cpu(key[4]);
-               E_KEY[5] = le32_to_cpu(key[5]);
-               E_KEY[6] = le32_to_cpu(key[6]);
-               t = E_KEY[7] = le32_to_cpu(key[7]);
-               for (i = 0; i < 7; ++i)
-                       loop8(i);
-               break;
-       }
-
-       D_KEY[0] = E_KEY[key_len + 24];
-       D_KEY[1] = E_KEY[key_len + 25];
-       D_KEY[2] = E_KEY[key_len + 26];
-       D_KEY[3] = E_KEY[key_len + 27];
-
-       for (i = 4; i < key_len + 24; ++i) {
-               j = key_len + 24 - (i & ~3) + (i & 3);
-               imix_col(D_KEY[j], E_KEY[i]);
-       }
-
-       return 0;
-}
-
-asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
-asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
-
-static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       aes_enc_blk(tfm, dst, src);
-}
-
-static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       aes_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg aes_alg = {
-       .cra_name               =       "aes",
-       .cra_driver_name        =       "aes-x86_64",
-       .cra_priority           =       200,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       AES_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct aes_ctx),
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =       AES_MIN_KEY_SIZE,
-                       .cia_max_keysize        =       AES_MAX_KEY_SIZE,
-                       .cia_setkey             =       aes_set_key,
-                       .cia_encrypt            =       aes_encrypt,
-                       .cia_decrypt            =       aes_decrypt
-               }
-       }
-};
-
-static int __init aes_init(void)
-{
-       gen_tabs();
-       return crypto_register_alg(&aes_alg);
-}
-
-static void __exit aes_fini(void)
-{
-       crypto_unregister_alg(&aes_alg);
-}
-
-module_init(aes_init);
-module_exit(aes_fini);
-
-MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("aes");
diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c
new file mode 100644 (file)
index 0000000..71f4578
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Glue Code for the asm optimized version of the AES Cipher Algorithm
+ *
+ */
+
+#include <crypto/aes.h>
+
+asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       aes_enc_blk(tfm, dst, src);
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       aes_dec_blk(tfm, dst, src);
+}
+
+static struct crypto_alg aes_alg = {
+       .cra_name               = "aes",
+       .cra_driver_name        = "aes-asm",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct crypto_aes_ctx),
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(aes_alg.cra_list),
+       .cra_u  = {
+               .cipher = {
+                       .cia_min_keysize        = AES_MIN_KEY_SIZE,
+                       .cia_max_keysize        = AES_MAX_KEY_SIZE,
+                       .cia_setkey             = crypto_aes_set_key,
+                       .cia_encrypt            = aes_encrypt,
+                       .cia_decrypt            = aes_decrypt
+               }
+       }
+};
+
+static int __init aes_init(void)
+{
+       return crypto_register_alg(&aes_alg);
+}
+
+static void __exit aes_fini(void)
+{
+       crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, asm optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("aes");
+MODULE_ALIAS("aes-asm");
diff --git a/arch/x86/crypto/salsa20-i586-asm_32.S b/arch/x86/crypto/salsa20-i586-asm_32.S
new file mode 100644 (file)
index 0000000..72eb306
--- /dev/null
@@ -0,0 +1,1114 @@
+# salsa20_pm.s version 20051229
+# D. J. Bernstein
+# Public domain.
+
+# enter ECRYPT_encrypt_bytes
+.text
+.p2align 5
+.globl ECRYPT_encrypt_bytes
+ECRYPT_encrypt_bytes:
+       mov     %esp,%eax
+       and     $31,%eax
+       add     $256,%eax
+       sub     %eax,%esp
+       # eax_stack = eax
+       movl    %eax,80(%esp)
+       # ebx_stack = ebx
+       movl    %ebx,84(%esp)
+       # esi_stack = esi
+       movl    %esi,88(%esp)
+       # edi_stack = edi
+       movl    %edi,92(%esp)
+       # ebp_stack = ebp
+       movl    %ebp,96(%esp)
+       # x = arg1
+       movl    4(%esp,%eax),%edx
+       # m = arg2
+       movl    8(%esp,%eax),%esi
+       # out = arg3
+       movl    12(%esp,%eax),%edi
+       # bytes = arg4
+       movl    16(%esp,%eax),%ebx
+       # bytes -= 0
+       sub     $0,%ebx
+       # goto done if unsigned<=
+       jbe     ._done
+._start:
+       # in0 = *(uint32 *) (x + 0)
+       movl    0(%edx),%eax
+       # in1 = *(uint32 *) (x + 4)
+       movl    4(%edx),%ecx
+       # in2 = *(uint32 *) (x + 8)
+       movl    8(%edx),%ebp
+       # j0 = in0
+       movl    %eax,164(%esp)
+       # in3 = *(uint32 *) (x + 12)
+       movl    12(%edx),%eax
+       # j1 = in1
+       movl    %ecx,168(%esp)
+       # in4 = *(uint32 *) (x + 16)
+       movl    16(%edx),%ecx
+       # j2 = in2
+       movl    %ebp,172(%esp)
+       # in5 = *(uint32 *) (x + 20)
+       movl    20(%edx),%ebp
+       # j3 = in3
+       movl    %eax,176(%esp)
+       # in6 = *(uint32 *) (x + 24)
+       movl    24(%edx),%eax
+       # j4 = in4
+       movl    %ecx,180(%esp)
+       # in7 = *(uint32 *) (x + 28)
+       movl    28(%edx),%ecx
+       # j5 = in5
+       movl    %ebp,184(%esp)
+       # in8 = *(uint32 *) (x + 32)
+       movl    32(%edx),%ebp
+       # j6 = in6
+       movl    %eax,188(%esp)
+       # in9 = *(uint32 *) (x + 36)
+       movl    36(%edx),%eax
+       # j7 = in7
+       movl    %ecx,192(%esp)
+       # in10 = *(uint32 *) (x + 40)
+       movl    40(%edx),%ecx
+       # j8 = in8
+       movl    %ebp,196(%esp)
+       # in11 = *(uint32 *) (x + 44)
+       movl    44(%edx),%ebp
+       # j9 = in9
+       movl    %eax,200(%esp)
+       # in12 = *(uint32 *) (x + 48)
+       movl    48(%edx),%eax
+       # j10 = in10
+       movl    %ecx,204(%esp)
+       # in13 = *(uint32 *) (x + 52)
+       movl    52(%edx),%ecx
+       # j11 = in11
+       movl    %ebp,208(%esp)
+       # in14 = *(uint32 *) (x + 56)
+       movl    56(%edx),%ebp
+       # j12 = in12
+       movl    %eax,212(%esp)
+       # in15 = *(uint32 *) (x + 60)
+       movl    60(%edx),%eax
+       # j13 = in13
+       movl    %ecx,216(%esp)
+       # j14 = in14
+       movl    %ebp,220(%esp)
+       # j15 = in15
+       movl    %eax,224(%esp)
+       # x_backup = x
+       movl    %edx,64(%esp)
+._bytesatleast1:
+       #   bytes - 64
+       cmp     $64,%ebx
+       #   goto nocopy if unsigned>=
+       jae     ._nocopy
+       #     ctarget = out
+       movl    %edi,228(%esp)
+       #     out = &tmp
+       leal    0(%esp),%edi
+       #     i = bytes
+       mov     %ebx,%ecx
+       #     while (i) { *out++ = *m++; --i }
+       rep     movsb
+       #     out = &tmp
+       leal    0(%esp),%edi
+       #     m = &tmp
+       leal    0(%esp),%esi
+._nocopy:
+       #   out_backup = out
+       movl    %edi,72(%esp)
+       #   m_backup = m
+       movl    %esi,68(%esp)
+       #   bytes_backup = bytes
+       movl    %ebx,76(%esp)
+       #   in0 = j0
+       movl    164(%esp),%eax
+       #   in1 = j1
+       movl    168(%esp),%ecx
+       #   in2 = j2
+       movl    172(%esp),%edx
+       #   in3 = j3
+       movl    176(%esp),%ebx
+       #   x0 = in0
+       movl    %eax,100(%esp)
+       #   x1 = in1
+       movl    %ecx,104(%esp)
+       #   x2 = in2
+       movl    %edx,108(%esp)
+       #   x3 = in3
+       movl    %ebx,112(%esp)
+       #   in4 = j4
+       movl    180(%esp),%eax
+       #   in5 = j5
+       movl    184(%esp),%ecx
+       #   in6 = j6
+       movl    188(%esp),%edx
+       #   in7 = j7
+       movl    192(%esp),%ebx
+       #   x4 = in4
+       movl    %eax,116(%esp)
+       #   x5 = in5
+       movl    %ecx,120(%esp)
+       #   x6 = in6
+       movl    %edx,124(%esp)
+       #   x7 = in7
+       movl    %ebx,128(%esp)
+       #   in8 = j8
+       movl    196(%esp),%eax
+       #   in9 = j9
+       movl    200(%esp),%ecx
+       #   in10 = j10
+       movl    204(%esp),%edx
+       #   in11 = j11
+       movl    208(%esp),%ebx
+       #   x8 = in8
+       movl    %eax,132(%esp)
+       #   x9 = in9
+       movl    %ecx,136(%esp)
+       #   x10 = in10
+       movl    %edx,140(%esp)
+       #   x11 = in11
+       movl    %ebx,144(%esp)
+       #   in12 = j12
+       movl    212(%esp),%eax
+       #   in13 = j13
+       movl    216(%esp),%ecx
+       #   in14 = j14
+       movl    220(%esp),%edx
+       #   in15 = j15
+       movl    224(%esp),%ebx
+       #   x12 = in12
+       movl    %eax,148(%esp)
+       #   x13 = in13
+       movl    %ecx,152(%esp)
+       #   x14 = in14
+       movl    %edx,156(%esp)
+       #   x15 = in15
+       movl    %ebx,160(%esp)
+       #   i = 20
+       mov     $20,%ebp
+       # p = x0
+       movl    100(%esp),%eax
+       # s = x5
+       movl    120(%esp),%ecx
+       # t = x10
+       movl    140(%esp),%edx
+       # w = x15
+       movl    160(%esp),%ebx
+._mainloop:
+       # x0 = p
+       movl    %eax,100(%esp)
+       #                               x10 = t
+       movl    %edx,140(%esp)
+       # p += x12
+       addl    148(%esp),%eax
+       #               x5 = s
+       movl    %ecx,120(%esp)
+       #                               t += x6
+       addl    124(%esp),%edx
+       #                                               x15 = w
+       movl    %ebx,160(%esp)
+       #               r = x1
+       movl    104(%esp),%esi
+       #               r += s
+       add     %ecx,%esi
+       #                                               v = x11
+       movl    144(%esp),%edi
+       #                                               v += w
+       add     %ebx,%edi
+       # p <<<= 7
+       rol     $7,%eax
+       # p ^= x4
+       xorl    116(%esp),%eax
+       #                               t <<<= 7
+       rol     $7,%edx
+       #                               t ^= x14
+       xorl    156(%esp),%edx
+       #               r <<<= 7
+       rol     $7,%esi
+       #               r ^= x9
+       xorl    136(%esp),%esi
+       #                                               v <<<= 7
+       rol     $7,%edi
+       #                                               v ^= x3
+       xorl    112(%esp),%edi
+       # x4 = p
+       movl    %eax,116(%esp)
+       #                               x14 = t
+       movl    %edx,156(%esp)
+       # p += x0
+       addl    100(%esp),%eax
+       #               x9 = r
+       movl    %esi,136(%esp)
+       #                               t += x10
+       addl    140(%esp),%edx
+       #                                               x3 = v
+       movl    %edi,112(%esp)
+       # p <<<= 9
+       rol     $9,%eax
+       # p ^= x8
+       xorl    132(%esp),%eax
+       #                               t <<<= 9
+       rol     $9,%edx
+       #                               t ^= x2
+       xorl    108(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 9
+       rol     $9,%ecx
+       #               s ^= x13
+       xorl    152(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 9
+       rol     $9,%ebx
+       #                                               w ^= x7
+       xorl    128(%esp),%ebx
+       # x8 = p
+       movl    %eax,132(%esp)
+       #                               x2 = t
+       movl    %edx,108(%esp)
+       # p += x4
+       addl    116(%esp),%eax
+       #               x13 = s
+       movl    %ecx,152(%esp)
+       #                               t += x14
+       addl    156(%esp),%edx
+       #                                               x7 = w
+       movl    %ebx,128(%esp)
+       # p <<<= 13
+       rol     $13,%eax
+       # p ^= x12
+       xorl    148(%esp),%eax
+       #                               t <<<= 13
+       rol     $13,%edx
+       #                               t ^= x6
+       xorl    124(%esp),%edx
+       #               r += s
+       add     %ecx,%esi
+       #               r <<<= 13
+       rol     $13,%esi
+       #               r ^= x1
+       xorl    104(%esp),%esi
+       #                                               v += w
+       add     %ebx,%edi
+       #                                               v <<<= 13
+       rol     $13,%edi
+       #                                               v ^= x11
+       xorl    144(%esp),%edi
+       # x12 = p
+       movl    %eax,148(%esp)
+       #                               x6 = t
+       movl    %edx,124(%esp)
+       # p += x8
+       addl    132(%esp),%eax
+       #               x1 = r
+       movl    %esi,104(%esp)
+       #                               t += x2
+       addl    108(%esp),%edx
+       #                                               x11 = v
+       movl    %edi,144(%esp)
+       # p <<<= 18
+       rol     $18,%eax
+       # p ^= x0
+       xorl    100(%esp),%eax
+       #                               t <<<= 18
+       rol     $18,%edx
+       #                               t ^= x10
+       xorl    140(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 18
+       rol     $18,%ecx
+       #               s ^= x5
+       xorl    120(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 18
+       rol     $18,%ebx
+       #                                               w ^= x15
+       xorl    160(%esp),%ebx
+       # x0 = p
+       movl    %eax,100(%esp)
+       #                               x10 = t
+       movl    %edx,140(%esp)
+       # p += x3
+       addl    112(%esp),%eax
+       # p <<<= 7
+       rol     $7,%eax
+       #               x5 = s
+       movl    %ecx,120(%esp)
+       #                               t += x9
+       addl    136(%esp),%edx
+       #                                               x15 = w
+       movl    %ebx,160(%esp)
+       #               r = x4
+       movl    116(%esp),%esi
+       #               r += s
+       add     %ecx,%esi
+       #                                               v = x14
+       movl    156(%esp),%edi
+       #                                               v += w
+       add     %ebx,%edi
+       # p ^= x1
+       xorl    104(%esp),%eax
+       #                               t <<<= 7
+       rol     $7,%edx
+       #                               t ^= x11
+       xorl    144(%esp),%edx
+       #               r <<<= 7
+       rol     $7,%esi
+       #               r ^= x6
+       xorl    124(%esp),%esi
+       #                                               v <<<= 7
+       rol     $7,%edi
+       #                                               v ^= x12
+       xorl    148(%esp),%edi
+       # x1 = p
+       movl    %eax,104(%esp)
+       #                               x11 = t
+       movl    %edx,144(%esp)
+       # p += x0
+       addl    100(%esp),%eax
+       #               x6 = r
+       movl    %esi,124(%esp)
+       #                               t += x10
+       addl    140(%esp),%edx
+       #                                               x12 = v
+       movl    %edi,148(%esp)
+       # p <<<= 9
+       rol     $9,%eax
+       # p ^= x2
+       xorl    108(%esp),%eax
+       #                               t <<<= 9
+       rol     $9,%edx
+       #                               t ^= x8
+       xorl    132(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 9
+       rol     $9,%ecx
+       #               s ^= x7
+       xorl    128(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 9
+       rol     $9,%ebx
+       #                                               w ^= x13
+       xorl    152(%esp),%ebx
+       # x2 = p
+       movl    %eax,108(%esp)
+       #                               x8 = t
+       movl    %edx,132(%esp)
+       # p += x1
+       addl    104(%esp),%eax
+       #               x7 = s
+       movl    %ecx,128(%esp)
+       #                               t += x11
+       addl    144(%esp),%edx
+       #                                               x13 = w
+       movl    %ebx,152(%esp)
+       # p <<<= 13
+       rol     $13,%eax
+       # p ^= x3
+       xorl    112(%esp),%eax
+       #                               t <<<= 13
+       rol     $13,%edx
+       #                               t ^= x9
+       xorl    136(%esp),%edx
+       #               r += s
+       add     %ecx,%esi
+       #               r <<<= 13
+       rol     $13,%esi
+       #               r ^= x4
+       xorl    116(%esp),%esi
+       #                                               v += w
+       add     %ebx,%edi
+       #                                               v <<<= 13
+       rol     $13,%edi
+       #                                               v ^= x14
+       xorl    156(%esp),%edi
+       # x3 = p
+       movl    %eax,112(%esp)
+       #                               x9 = t
+       movl    %edx,136(%esp)
+       # p += x2
+       addl    108(%esp),%eax
+       #               x4 = r
+       movl    %esi,116(%esp)
+       #                               t += x8
+       addl    132(%esp),%edx
+       #                                               x14 = v
+       movl    %edi,156(%esp)
+       # p <<<= 18
+       rol     $18,%eax
+       # p ^= x0
+       xorl    100(%esp),%eax
+       #                               t <<<= 18
+       rol     $18,%edx
+       #                               t ^= x10
+       xorl    140(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 18
+       rol     $18,%ecx
+       #               s ^= x5
+       xorl    120(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 18
+       rol     $18,%ebx
+       #                                               w ^= x15
+       xorl    160(%esp),%ebx
+       # x0 = p
+       movl    %eax,100(%esp)
+       #                               x10 = t
+       movl    %edx,140(%esp)
+       # p += x12
+       addl    148(%esp),%eax
+       #               x5 = s
+       movl    %ecx,120(%esp)
+       #                               t += x6
+       addl    124(%esp),%edx
+       #                                               x15 = w
+       movl    %ebx,160(%esp)
+       #               r = x1
+       movl    104(%esp),%esi
+       #               r += s
+       add     %ecx,%esi
+       #                                               v = x11
+       movl    144(%esp),%edi
+       #                                               v += w
+       add     %ebx,%edi
+       # p <<<= 7
+       rol     $7,%eax
+       # p ^= x4
+       xorl    116(%esp),%eax
+       #                               t <<<= 7
+       rol     $7,%edx
+       #                               t ^= x14
+       xorl    156(%esp),%edx
+       #               r <<<= 7
+       rol     $7,%esi
+       #               r ^= x9
+       xorl    136(%esp),%esi
+       #                                               v <<<= 7
+       rol     $7,%edi
+       #                                               v ^= x3
+       xorl    112(%esp),%edi
+       # x4 = p
+       movl    %eax,116(%esp)
+       #                               x14 = t
+       movl    %edx,156(%esp)
+       # p += x0
+       addl    100(%esp),%eax
+       #               x9 = r
+       movl    %esi,136(%esp)
+       #                               t += x10
+       addl    140(%esp),%edx
+       #                                               x3 = v
+       movl    %edi,112(%esp)
+       # p <<<= 9
+       rol     $9,%eax
+       # p ^= x8
+       xorl    132(%esp),%eax
+       #                               t <<<= 9
+       rol     $9,%edx
+       #                               t ^= x2
+       xorl    108(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 9
+       rol     $9,%ecx
+       #               s ^= x13
+       xorl    152(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 9
+       rol     $9,%ebx
+       #                                               w ^= x7
+       xorl    128(%esp),%ebx
+       # x8 = p
+       movl    %eax,132(%esp)
+       #                               x2 = t
+       movl    %edx,108(%esp)
+       # p += x4
+       addl    116(%esp),%eax
+       #               x13 = s
+       movl    %ecx,152(%esp)
+       #                               t += x14
+       addl    156(%esp),%edx
+       #                                               x7 = w
+       movl    %ebx,128(%esp)
+       # p <<<= 13
+       rol     $13,%eax
+       # p ^= x12
+       xorl    148(%esp),%eax
+       #                               t <<<= 13
+       rol     $13,%edx
+       #                               t ^= x6
+       xorl    124(%esp),%edx
+       #               r += s
+       add     %ecx,%esi
+       #               r <<<= 13
+       rol     $13,%esi
+       #               r ^= x1
+       xorl    104(%esp),%esi
+       #                                               v += w
+       add     %ebx,%edi
+       #                                               v <<<= 13
+       rol     $13,%edi
+       #                                               v ^= x11
+       xorl    144(%esp),%edi
+       # x12 = p
+       movl    %eax,148(%esp)
+       #                               x6 = t
+       movl    %edx,124(%esp)
+       # p += x8
+       addl    132(%esp),%eax
+       #               x1 = r
+       movl    %esi,104(%esp)
+       #                               t += x2
+       addl    108(%esp),%edx
+       #                                               x11 = v
+       movl    %edi,144(%esp)
+       # p <<<= 18
+       rol     $18,%eax
+       # p ^= x0
+       xorl    100(%esp),%eax
+       #                               t <<<= 18
+       rol     $18,%edx
+       #                               t ^= x10
+       xorl    140(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 18
+       rol     $18,%ecx
+       #               s ^= x5
+       xorl    120(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 18
+       rol     $18,%ebx
+       #                                               w ^= x15
+       xorl    160(%esp),%ebx
+       # x0 = p
+       movl    %eax,100(%esp)
+       #                               x10 = t
+       movl    %edx,140(%esp)
+       # p += x3
+       addl    112(%esp),%eax
+       # p <<<= 7
+       rol     $7,%eax
+       #               x5 = s
+       movl    %ecx,120(%esp)
+       #                               t += x9
+       addl    136(%esp),%edx
+       #                                               x15 = w
+       movl    %ebx,160(%esp)
+       #               r = x4
+       movl    116(%esp),%esi
+       #               r += s
+       add     %ecx,%esi
+       #                                               v = x14
+       movl    156(%esp),%edi
+       #                                               v += w
+       add     %ebx,%edi
+       # p ^= x1
+       xorl    104(%esp),%eax
+       #                               t <<<= 7
+       rol     $7,%edx
+       #                               t ^= x11
+       xorl    144(%esp),%edx
+       #               r <<<= 7
+       rol     $7,%esi
+       #               r ^= x6
+       xorl    124(%esp),%esi
+       #                                               v <<<= 7
+       rol     $7,%edi
+       #                                               v ^= x12
+       xorl    148(%esp),%edi
+       # x1 = p
+       movl    %eax,104(%esp)
+       #                               x11 = t
+       movl    %edx,144(%esp)
+       # p += x0
+       addl    100(%esp),%eax
+       #               x6 = r
+       movl    %esi,124(%esp)
+       #                               t += x10
+       addl    140(%esp),%edx
+       #                                               x12 = v
+       movl    %edi,148(%esp)
+       # p <<<= 9
+       rol     $9,%eax
+       # p ^= x2
+       xorl    108(%esp),%eax
+       #                               t <<<= 9
+       rol     $9,%edx
+       #                               t ^= x8
+       xorl    132(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 9
+       rol     $9,%ecx
+       #               s ^= x7
+       xorl    128(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 9
+       rol     $9,%ebx
+       #                                               w ^= x13
+       xorl    152(%esp),%ebx
+       # x2 = p
+       movl    %eax,108(%esp)
+       #                               x8 = t
+       movl    %edx,132(%esp)
+       # p += x1
+       addl    104(%esp),%eax
+       #               x7 = s
+       movl    %ecx,128(%esp)
+       #                               t += x11
+       addl    144(%esp),%edx
+       #                                               x13 = w
+       movl    %ebx,152(%esp)
+       # p <<<= 13
+       rol     $13,%eax
+       # p ^= x3
+       xorl    112(%esp),%eax
+       #                               t <<<= 13
+       rol     $13,%edx
+       #                               t ^= x9
+       xorl    136(%esp),%edx
+       #               r += s
+       add     %ecx,%esi
+       #               r <<<= 13
+       rol     $13,%esi
+       #               r ^= x4
+       xorl    116(%esp),%esi
+       #                                               v += w
+       add     %ebx,%edi
+       #                                               v <<<= 13
+       rol     $13,%edi
+       #                                               v ^= x14
+       xorl    156(%esp),%edi
+       # x3 = p
+       movl    %eax,112(%esp)
+       #                               x9 = t
+       movl    %edx,136(%esp)
+       # p += x2
+       addl    108(%esp),%eax
+       #               x4 = r
+       movl    %esi,116(%esp)
+       #                               t += x8
+       addl    132(%esp),%edx
+       #                                               x14 = v
+       movl    %edi,156(%esp)
+       # p <<<= 18
+       rol     $18,%eax
+       # p ^= x0
+       xorl    100(%esp),%eax
+       #                               t <<<= 18
+       rol     $18,%edx
+       #                               t ^= x10
+       xorl    140(%esp),%edx
+       #               s += r
+       add     %esi,%ecx
+       #               s <<<= 18
+       rol     $18,%ecx
+       #               s ^= x5
+       xorl    120(%esp),%ecx
+       #                                               w += v
+       add     %edi,%ebx
+       #                                               w <<<= 18
+       rol     $18,%ebx
+       #                                               w ^= x15
+       xorl    160(%esp),%ebx
+       # i -= 4
+       sub     $4,%ebp
+       # goto mainloop if unsigned >
+       ja      ._mainloop
+       # x0 = p
+       movl    %eax,100(%esp)
+       # x5 = s
+       movl    %ecx,120(%esp)
+       # x10 = t
+       movl    %edx,140(%esp)
+       # x15 = w
+       movl    %ebx,160(%esp)
+       #   out = out_backup
+       movl    72(%esp),%edi
+       #   m = m_backup
+       movl    68(%esp),%esi
+       #   in0 = x0
+       movl    100(%esp),%eax
+       #   in1 = x1
+       movl    104(%esp),%ecx
+       #   in0 += j0
+       addl    164(%esp),%eax
+       #   in1 += j1
+       addl    168(%esp),%ecx
+       #   in0 ^= *(uint32 *) (m + 0)
+       xorl    0(%esi),%eax
+       #   in1 ^= *(uint32 *) (m + 4)
+       xorl    4(%esi),%ecx
+       #   *(uint32 *) (out + 0) = in0
+       movl    %eax,0(%edi)
+       #   *(uint32 *) (out + 4) = in1
+       movl    %ecx,4(%edi)
+       #   in2 = x2
+       movl    108(%esp),%eax
+       #   in3 = x3
+       movl    112(%esp),%ecx
+       #   in2 += j2
+       addl    172(%esp),%eax
+       #   in3 += j3
+       addl    176(%esp),%ecx
+       #   in2 ^= *(uint32 *) (m + 8)
+       xorl    8(%esi),%eax
+       #   in3 ^= *(uint32 *) (m + 12)
+       xorl    12(%esi),%ecx
+       #   *(uint32 *) (out + 8) = in2
+       movl    %eax,8(%edi)
+       #   *(uint32 *) (out + 12) = in3
+       movl    %ecx,12(%edi)
+       #   in4 = x4
+       movl    116(%esp),%eax
+       #   in5 = x5
+       movl    120(%esp),%ecx
+       #   in4 += j4
+       addl    180(%esp),%eax
+       #   in5 += j5
+       addl    184(%esp),%ecx
+       #   in4 ^= *(uint32 *) (m + 16)
+       xorl    16(%esi),%eax
+       #   in5 ^= *(uint32 *) (m + 20)
+       xorl    20(%esi),%ecx
+       #   *(uint32 *) (out + 16) = in4
+       movl    %eax,16(%edi)
+       #   *(uint32 *) (out + 20) = in5
+       movl    %ecx,20(%edi)
+       #   in6 = x6
+       movl    124(%esp),%eax
+       #   in7 = x7
+       movl    128(%esp),%ecx
+       #   in6 += j6
+       addl    188(%esp),%eax
+       #   in7 += j7
+       addl    192(%esp),%ecx
+       #   in6 ^= *(uint32 *) (m + 24)
+       xorl    24(%esi),%eax
+       #   in7 ^= *(uint32 *) (m + 28)
+       xorl    28(%esi),%ecx
+       #   *(uint32 *) (out + 24) = in6
+       movl    %eax,24(%edi)
+       #   *(uint32 *) (out + 28) = in7
+       movl    %ecx,28(%edi)
+       #   in8 = x8
+       movl    132(%esp),%eax
+       #   in9 = x9
+       movl    136(%esp),%ecx
+       #   in8 += j8
+       addl    196(%esp),%eax
+       #   in9 += j9
+       addl    200(%esp),%ecx
+       #   in8 ^= *(uint32 *) (m + 32)
+       xorl    32(%esi),%eax
+       #   in9 ^= *(uint32 *) (m + 36)
+       xorl    36(%esi),%ecx
+       #   *(uint32 *) (out + 32) = in8
+       movl    %eax,32(%edi)
+       #   *(uint32 *) (out + 36) = in9
+       movl    %ecx,36(%edi)
+       #   in10 = x10
+       movl    140(%esp),%eax
+       #   in11 = x11
+       movl    144(%esp),%ecx
+       #   in10 += j10
+       addl    204(%esp),%eax
+       #   in11 += j11
+       addl    208(%esp),%ecx
+       #   in10 ^= *(uint32 *) (m + 40)
+       xorl    40(%esi),%eax
+       #   in11 ^= *(uint32 *) (m + 44)
+       xorl    44(%esi),%ecx
+       #   *(uint32 *) (out + 40) = in10
+       movl    %eax,40(%edi)
+       #   *(uint32 *) (out + 44) = in11
+       movl    %ecx,44(%edi)
+       #   in12 = x12
+       movl    148(%esp),%eax
+       #   in13 = x13
+       movl    152(%esp),%ecx
+       #   in12 += j12
+       addl    212(%esp),%eax
+       #   in13 += j13
+       addl    216(%esp),%ecx
+       #   in12 ^= *(uint32 *) (m + 48)
+       xorl    48(%esi),%eax
+       #   in13 ^= *(uint32 *) (m + 52)
+       xorl    52(%esi),%ecx
+       #   *(uint32 *) (out + 48) = in12
+       movl    %eax,48(%edi)
+       #   *(uint32 *) (out + 52) = in13
+       movl    %ecx,52(%edi)
+       #   in14 = x14
+       movl    156(%esp),%eax
+       #   in15 = x15
+       movl    160(%esp),%ecx
+       #   in14 += j14
+       addl    220(%esp),%eax
+       #   in15 += j15
+       addl    224(%esp),%ecx
+       #   in14 ^= *(uint32 *) (m + 56)
+       xorl    56(%esi),%eax
+       #   in15 ^= *(uint32 *) (m + 60)
+       xorl    60(%esi),%ecx
+       #   *(uint32 *) (out + 56) = in14
+       movl    %eax,56(%edi)
+       #   *(uint32 *) (out + 60) = in15
+       movl    %ecx,60(%edi)
+       #   bytes = bytes_backup
+       movl    76(%esp),%ebx
+       #   in8 = j8
+       movl    196(%esp),%eax
+       #   in9 = j9
+       movl    200(%esp),%ecx
+       #   in8 += 1
+       add     $1,%eax
+       #   in9 += 0 + carry
+       adc     $0,%ecx
+       #   j8 = in8
+       movl    %eax,196(%esp)
+       #   j9 = in9
+       movl    %ecx,200(%esp)
+       #   bytes - 64
+       cmp     $64,%ebx
+       #   goto bytesatleast65 if unsigned>
+       ja      ._bytesatleast65
+       #     goto bytesatleast64 if unsigned>=
+       jae     ._bytesatleast64
+       #       m = out
+       mov     %edi,%esi
+       #       out = ctarget
+       movl    228(%esp),%edi
+       #       i = bytes
+       mov     %ebx,%ecx
+       #       while (i) { *out++ = *m++; --i }
+       rep     movsb
+._bytesatleast64:
+       #     x = x_backup
+       movl    64(%esp),%eax
+       #     in8 = j8
+       movl    196(%esp),%ecx
+       #     in9 = j9
+       movl    200(%esp),%edx
+       #     *(uint32 *) (x + 32) = in8
+       movl    %ecx,32(%eax)
+       #     *(uint32 *) (x + 36) = in9
+       movl    %edx,36(%eax)
+._done:
+       #     eax = eax_stack
+       movl    80(%esp),%eax
+       #     ebx = ebx_stack
+       movl    84(%esp),%ebx
+       #     esi = esi_stack
+       movl    88(%esp),%esi
+       #     edi = edi_stack
+       movl    92(%esp),%edi
+       #     ebp = ebp_stack
+       movl    96(%esp),%ebp
+       #     leave
+       add     %eax,%esp
+       ret
+._bytesatleast65:
+       #   bytes -= 64
+       sub     $64,%ebx
+       #   out += 64
+       add     $64,%edi
+       #   m += 64
+       add     $64,%esi
+       # goto bytesatleast1
+       jmp     ._bytesatleast1
+# enter ECRYPT_keysetup
+.text
+.p2align 5
+.globl ECRYPT_keysetup
+ECRYPT_keysetup:
+       mov     %esp,%eax
+       and     $31,%eax
+       add     $256,%eax
+       sub     %eax,%esp
+       #   eax_stack = eax
+       movl    %eax,64(%esp)
+       #   ebx_stack = ebx
+       movl    %ebx,68(%esp)
+       #   esi_stack = esi
+       movl    %esi,72(%esp)
+       #   edi_stack = edi
+       movl    %edi,76(%esp)
+       #   ebp_stack = ebp
+       movl    %ebp,80(%esp)
+       #   k = arg2
+       movl    8(%esp,%eax),%ecx
+       #   kbits = arg3
+       movl    12(%esp,%eax),%edx
+       #   x = arg1
+       movl    4(%esp,%eax),%eax
+       #   in1 = *(uint32 *) (k + 0)
+       movl    0(%ecx),%ebx
+       #   in2 = *(uint32 *) (k + 4)
+       movl    4(%ecx),%esi
+       #   in3 = *(uint32 *) (k + 8)
+       movl    8(%ecx),%edi
+       #   in4 = *(uint32 *) (k + 12)
+       movl    12(%ecx),%ebp
+       #   *(uint32 *) (x + 4) = in1
+       movl    %ebx,4(%eax)
+       #   *(uint32 *) (x + 8) = in2
+       movl    %esi,8(%eax)
+       #   *(uint32 *) (x + 12) = in3
+       movl    %edi,12(%eax)
+       #   *(uint32 *) (x + 16) = in4
+       movl    %ebp,16(%eax)
+       #   kbits - 256
+       cmp     $256,%edx
+       #   goto kbits128 if unsigned<
+       jb      ._kbits128
+._kbits256:
+       #     in11 = *(uint32 *) (k + 16)
+       movl    16(%ecx),%edx
+       #     in12 = *(uint32 *) (k + 20)
+       movl    20(%ecx),%ebx
+       #     in13 = *(uint32 *) (k + 24)
+       movl    24(%ecx),%esi
+       #     in14 = *(uint32 *) (k + 28)
+       movl    28(%ecx),%ecx
+       #     *(uint32 *) (x + 44) = in11
+       movl    %edx,44(%eax)
+       #     *(uint32 *) (x + 48) = in12
+       movl    %ebx,48(%eax)
+       #     *(uint32 *) (x + 52) = in13
+       movl    %esi,52(%eax)
+       #     *(uint32 *) (x + 56) = in14
+       movl    %ecx,56(%eax)
+       #     in0 = 1634760805
+       mov     $1634760805,%ecx
+       #     in5 = 857760878
+       mov     $857760878,%edx
+       #     in10 = 2036477234
+       mov     $2036477234,%ebx
+       #     in15 = 1797285236
+       mov     $1797285236,%esi
+       #     *(uint32 *) (x + 0) = in0
+       movl    %ecx,0(%eax)
+       #     *(uint32 *) (x + 20) = in5
+       movl    %edx,20(%eax)
+       #     *(uint32 *) (x + 40) = in10
+       movl    %ebx,40(%eax)
+       #     *(uint32 *) (x + 60) = in15
+       movl    %esi,60(%eax)
+       #   goto keysetupdone
+       jmp     ._keysetupdone
+._kbits128:
+       #     in11 = *(uint32 *) (k + 0)
+       movl    0(%ecx),%edx
+       #     in12 = *(uint32 *) (k + 4)
+       movl    4(%ecx),%ebx
+       #     in13 = *(uint32 *) (k + 8)
+       movl    8(%ecx),%esi
+       #     in14 = *(uint32 *) (k + 12)
+       movl    12(%ecx),%ecx
+       #     *(uint32 *) (x + 44) = in11
+       movl    %edx,44(%eax)
+       #     *(uint32 *) (x + 48) = in12
+       movl    %ebx,48(%eax)
+       #     *(uint32 *) (x + 52) = in13
+       movl    %esi,52(%eax)
+       #     *(uint32 *) (x + 56) = in14
+       movl    %ecx,56(%eax)
+       #     in0 = 1634760805
+       mov     $1634760805,%ecx
+       #     in5 = 824206446
+       mov     $824206446,%edx
+       #     in10 = 2036477238
+       mov     $2036477238,%ebx
+       #     in15 = 1797285236
+       mov     $1797285236,%esi
+       #     *(uint32 *) (x + 0) = in0
+       movl    %ecx,0(%eax)
+       #     *(uint32 *) (x + 20) = in5
+       movl    %edx,20(%eax)
+       #     *(uint32 *) (x + 40) = in10
+       movl    %ebx,40(%eax)
+       #     *(uint32 *) (x + 60) = in15
+       movl    %esi,60(%eax)
+._keysetupdone:
+       #   eax = eax_stack
+       movl    64(%esp),%eax
+       #   ebx = ebx_stack
+       movl    68(%esp),%ebx
+       #   esi = esi_stack
+       movl    72(%esp),%esi
+       #   edi = edi_stack
+       movl    76(%esp),%edi
+       #   ebp = ebp_stack
+       movl    80(%esp),%ebp
+       # leave
+       add     %eax,%esp
+       ret
+# enter ECRYPT_ivsetup
+.text
+.p2align 5
+.globl ECRYPT_ivsetup
+ECRYPT_ivsetup:
+       mov     %esp,%eax
+       and     $31,%eax
+       add     $256,%eax
+       sub     %eax,%esp
+       #   eax_stack = eax
+       movl    %eax,64(%esp)
+       #   ebx_stack = ebx
+       movl    %ebx,68(%esp)
+       #   esi_stack = esi
+       movl    %esi,72(%esp)
+       #   edi_stack = edi
+       movl    %edi,76(%esp)
+       #   ebp_stack = ebp
+       movl    %ebp,80(%esp)
+       #   iv = arg2
+       movl    8(%esp,%eax),%ecx
+       #   x = arg1
+       movl    4(%esp,%eax),%eax
+       #   in6 = *(uint32 *) (iv + 0)
+       movl    0(%ecx),%edx
+       #   in7 = *(uint32 *) (iv + 4)
+       movl    4(%ecx),%ecx
+       #   in8 = 0
+       mov     $0,%ebx
+       #   in9 = 0
+       mov     $0,%esi
+       #   *(uint32 *) (x + 24) = in6
+       movl    %edx,24(%eax)
+       #   *(uint32 *) (x + 28) = in7
+       movl    %ecx,28(%eax)
+       #   *(uint32 *) (x + 32) = in8
+       movl    %ebx,32(%eax)
+       #   *(uint32 *) (x + 36) = in9
+       movl    %esi,36(%eax)
+       #   eax = eax_stack
+       movl    64(%esp),%eax
+       #   ebx = ebx_stack
+       movl    68(%esp),%ebx
+       #   esi = esi_stack
+       movl    72(%esp),%esi
+       #   edi = edi_stack
+       movl    76(%esp),%edi
+       #   ebp = ebp_stack
+       movl    80(%esp),%ebp
+       # leave
+       add     %eax,%esp
+       ret
diff --git a/arch/x86/crypto/salsa20-x86_64-asm_64.S b/arch/x86/crypto/salsa20-x86_64-asm_64.S
new file mode 100644 (file)
index 0000000..6214a9b
--- /dev/null
@@ -0,0 +1,920 @@
+# enter ECRYPT_encrypt_bytes
+.text
+.p2align 5
+.globl ECRYPT_encrypt_bytes
+ECRYPT_encrypt_bytes:
+       mov     %rsp,%r11
+       and     $31,%r11
+       add     $256,%r11
+       sub     %r11,%rsp
+       # x = arg1
+       mov     %rdi,%r8
+       # m = arg2
+       mov     %rsi,%rsi
+       # out = arg3
+       mov     %rdx,%rdi
+       # bytes = arg4
+       mov     %rcx,%rdx
+       #               unsigned>? bytes - 0
+       cmp     $0,%rdx
+       # comment:fp stack unchanged by jump
+       # goto done if !unsigned>
+       jbe     ._done
+       # comment:fp stack unchanged by fallthrough
+# start:
+._start:
+       # r11_stack = r11
+       movq    %r11,0(%rsp)
+       # r12_stack = r12
+       movq    %r12,8(%rsp)
+       # r13_stack = r13
+       movq    %r13,16(%rsp)
+       # r14_stack = r14
+       movq    %r14,24(%rsp)
+       # r15_stack = r15
+       movq    %r15,32(%rsp)
+       # rbx_stack = rbx
+       movq    %rbx,40(%rsp)
+       # rbp_stack = rbp
+       movq    %rbp,48(%rsp)
+       # in0 = *(uint64 *) (x + 0)
+       movq    0(%r8),%rcx
+       # in2 = *(uint64 *) (x + 8)
+       movq    8(%r8),%r9
+       # in4 = *(uint64 *) (x + 16)
+       movq    16(%r8),%rax
+       # in6 = *(uint64 *) (x + 24)
+       movq    24(%r8),%r10
+       # in8 = *(uint64 *) (x + 32)
+       movq    32(%r8),%r11
+       # in10 = *(uint64 *) (x + 40)
+       movq    40(%r8),%r12
+       # in12 = *(uint64 *) (x + 48)
+       movq    48(%r8),%r13
+       # in14 = *(uint64 *) (x + 56)
+       movq    56(%r8),%r14
+       # j0 = in0
+       movq    %rcx,56(%rsp)
+       # j2 = in2
+       movq    %r9,64(%rsp)
+       # j4 = in4
+       movq    %rax,72(%rsp)
+       # j6 = in6
+       movq    %r10,80(%rsp)
+       # j8 = in8
+       movq    %r11,88(%rsp)
+       # j10 = in10
+       movq    %r12,96(%rsp)
+       # j12 = in12
+       movq    %r13,104(%rsp)
+       # j14 = in14
+       movq    %r14,112(%rsp)
+       # x_backup = x
+       movq    %r8,120(%rsp)
+# bytesatleast1:
+._bytesatleast1:
+       #                   unsigned<? bytes - 64
+       cmp     $64,%rdx
+       # comment:fp stack unchanged by jump
+       #   goto nocopy if !unsigned<
+       jae     ._nocopy
+       #     ctarget = out
+       movq    %rdi,128(%rsp)
+       #     out = &tmp
+       leaq    192(%rsp),%rdi
+       #     i = bytes
+       mov     %rdx,%rcx
+       #     while (i) { *out++ = *m++; --i }
+       rep     movsb
+       #     out = &tmp
+       leaq    192(%rsp),%rdi
+       #     m = &tmp
+       leaq    192(%rsp),%rsi
+       # comment:fp stack unchanged by fallthrough
+#   nocopy:
+._nocopy:
+       #   out_backup = out
+       movq    %rdi,136(%rsp)
+       #   m_backup = m
+       movq    %rsi,144(%rsp)
+       #   bytes_backup = bytes
+       movq    %rdx,152(%rsp)
+       #   x1 = j0
+       movq    56(%rsp),%rdi
+       #   x0 = x1
+       mov     %rdi,%rdx
+       #   (uint64) x1 >>= 32
+       shr     $32,%rdi
+       #               x3 = j2
+       movq    64(%rsp),%rsi
+       #               x2 = x3
+       mov     %rsi,%rcx
+       #               (uint64) x3 >>= 32
+       shr     $32,%rsi
+       #   x5 = j4
+       movq    72(%rsp),%r8
+       #   x4 = x5
+       mov     %r8,%r9
+       #   (uint64) x5 >>= 32
+       shr     $32,%r8
+       #   x5_stack = x5
+       movq    %r8,160(%rsp)
+       #               x7 = j6
+       movq    80(%rsp),%r8
+       #               x6 = x7
+       mov     %r8,%rax
+       #               (uint64) x7 >>= 32
+       shr     $32,%r8
+       #   x9 = j8
+       movq    88(%rsp),%r10
+       #   x8 = x9
+       mov     %r10,%r11
+       #   (uint64) x9 >>= 32
+       shr     $32,%r10
+       #               x11 = j10
+       movq    96(%rsp),%r12
+       #               x10 = x11
+       mov     %r12,%r13
+       #               x10_stack = x10
+       movq    %r13,168(%rsp)
+       #               (uint64) x11 >>= 32
+       shr     $32,%r12
+       #   x13 = j12
+       movq    104(%rsp),%r13
+       #   x12 = x13
+       mov     %r13,%r14
+       #   (uint64) x13 >>= 32
+       shr     $32,%r13
+       #               x15 = j14
+       movq    112(%rsp),%r15
+       #               x14 = x15
+       mov     %r15,%rbx
+       #               (uint64) x15 >>= 32
+       shr     $32,%r15
+       #               x15_stack = x15
+       movq    %r15,176(%rsp)
+       #   i = 20
+       mov     $20,%r15
+#   mainloop:
+._mainloop:
+       #   i_backup = i
+       movq    %r15,184(%rsp)
+       #               x5 = x5_stack
+       movq    160(%rsp),%r15
+       # a = x12 + x0
+       lea     (%r14,%rdx),%rbp
+       # (uint32) a <<<= 7
+       rol     $7,%ebp
+       # x4 ^= a
+       xor     %rbp,%r9
+       #               b = x1 + x5
+       lea     (%rdi,%r15),%rbp
+       #               (uint32) b <<<= 7
+       rol     $7,%ebp
+       #               x9 ^= b
+       xor     %rbp,%r10
+       # a = x0 + x4
+       lea     (%rdx,%r9),%rbp
+       # (uint32) a <<<= 9
+       rol     $9,%ebp
+       # x8 ^= a
+       xor     %rbp,%r11
+       #               b = x5 + x9
+       lea     (%r15,%r10),%rbp
+       #               (uint32) b <<<= 9
+       rol     $9,%ebp
+       #               x13 ^= b
+       xor     %rbp,%r13
+       # a = x4 + x8
+       lea     (%r9,%r11),%rbp
+       # (uint32) a <<<= 13
+       rol     $13,%ebp
+       # x12 ^= a
+       xor     %rbp,%r14
+       #               b = x9 + x13
+       lea     (%r10,%r13),%rbp
+       #               (uint32) b <<<= 13
+       rol     $13,%ebp
+       #               x1 ^= b
+       xor     %rbp,%rdi
+       # a = x8 + x12
+       lea     (%r11,%r14),%rbp
+       # (uint32) a <<<= 18
+       rol     $18,%ebp
+       # x0 ^= a
+       xor     %rbp,%rdx
+       #               b = x13 + x1
+       lea     (%r13,%rdi),%rbp
+       #               (uint32) b <<<= 18
+       rol     $18,%ebp
+       #               x5 ^= b
+       xor     %rbp,%r15
+       #                               x10 = x10_stack
+       movq    168(%rsp),%rbp
+       #               x5_stack = x5
+       movq    %r15,160(%rsp)
+       #                               c = x6 + x10
+       lea     (%rax,%rbp),%r15
+       #                               (uint32) c <<<= 7
+       rol     $7,%r15d
+       #                               x14 ^= c
+       xor     %r15,%rbx
+       #                               c = x10 + x14
+       lea     (%rbp,%rbx),%r15
+       #                               (uint32) c <<<= 9
+       rol     $9,%r15d
+       #                               x2 ^= c
+       xor     %r15,%rcx
+       #                               c = x14 + x2
+       lea     (%rbx,%rcx),%r15
+       #                               (uint32) c <<<= 13
+       rol     $13,%r15d
+       #                               x6 ^= c
+       xor     %r15,%rax
+       #                               c = x2 + x6
+       lea     (%rcx,%rax),%r15
+       #                               (uint32) c <<<= 18
+       rol     $18,%r15d
+       #                               x10 ^= c
+       xor     %r15,%rbp
+       #                                               x15 = x15_stack
+       movq    176(%rsp),%r15
+       #                               x10_stack = x10
+       movq    %rbp,168(%rsp)
+       #                                               d = x11 + x15
+       lea     (%r12,%r15),%rbp
+       #                                               (uint32) d <<<= 7
+       rol     $7,%ebp
+       #                                               x3 ^= d
+       xor     %rbp,%rsi
+       #                                               d = x15 + x3
+       lea     (%r15,%rsi),%rbp
+       #                                               (uint32) d <<<= 9
+       rol     $9,%ebp
+       #                                               x7 ^= d
+       xor     %rbp,%r8
+       #                                               d = x3 + x7
+       lea     (%rsi,%r8),%rbp
+       #                                               (uint32) d <<<= 13
+       rol     $13,%ebp
+       #                                               x11 ^= d
+       xor     %rbp,%r12
+       #                                               d = x7 + x11
+       lea     (%r8,%r12),%rbp
+       #                                               (uint32) d <<<= 18
+       rol     $18,%ebp
+       #                                               x15 ^= d
+       xor     %rbp,%r15
+       #                                               x15_stack = x15
+       movq    %r15,176(%rsp)
+       #               x5 = x5_stack
+       movq    160(%rsp),%r15
+       # a = x3 + x0
+       lea     (%rsi,%rdx),%rbp
+       # (uint32) a <<<= 7
+       rol     $7,%ebp
+       # x1 ^= a
+       xor     %rbp,%rdi
+       #               b = x4 + x5
+       lea     (%r9,%r15),%rbp
+       #               (uint32) b <<<= 7
+       rol     $7,%ebp
+       #               x6 ^= b
+       xor     %rbp,%rax
+       # a = x0 + x1
+       lea     (%rdx,%rdi),%rbp
+       # (uint32) a <<<= 9
+       rol     $9,%ebp
+       # x2 ^= a
+       xor     %rbp,%rcx
+       #               b = x5 + x6
+       lea     (%r15,%rax),%rbp
+       #               (uint32) b <<<= 9
+       rol     $9,%ebp
+       #               x7 ^= b
+       xor     %rbp,%r8
+       # a = x1 + x2
+       lea     (%rdi,%rcx),%rbp
+       # (uint32) a <<<= 13
+       rol     $13,%ebp
+       # x3 ^= a
+       xor     %rbp,%rsi
+       #               b = x6 + x7
+       lea     (%rax,%r8),%rbp
+       #               (uint32) b <<<= 13
+       rol     $13,%ebp
+       #               x4 ^= b
+       xor     %rbp,%r9
+       # a = x2 + x3
+       lea     (%rcx,%rsi),%rbp
+       # (uint32) a <<<= 18
+       rol     $18,%ebp
+       # x0 ^= a
+       xor     %rbp,%rdx
+       #               b = x7 + x4
+       lea     (%r8,%r9),%rbp
+       #               (uint32) b <<<= 18
+       rol     $18,%ebp
+       #               x5 ^= b
+       xor     %rbp,%r15
+       #                               x10 = x10_stack
+       movq    168(%rsp),%rbp
+       #               x5_stack = x5
+       movq    %r15,160(%rsp)
+       #                               c = x9 + x10
+       lea     (%r10,%rbp),%r15
+       #                               (uint32) c <<<= 7
+       rol     $7,%r15d
+       #                               x11 ^= c
+       xor     %r15,%r12
+       #                               c = x10 + x11
+       lea     (%rbp,%r12),%r15
+       #                               (uint32) c <<<= 9
+       rol     $9,%r15d
+       #                               x8 ^= c
+       xor     %r15,%r11
+       #                               c = x11 + x8
+       lea     (%r12,%r11),%r15
+       #                               (uint32) c <<<= 13
+       rol     $13,%r15d
+       #                               x9 ^= c
+       xor     %r15,%r10
+       #                               c = x8 + x9
+       lea     (%r11,%r10),%r15
+       #                               (uint32) c <<<= 18
+       rol     $18,%r15d
+       #                               x10 ^= c
+       xor     %r15,%rbp
+       #                                               x15 = x15_stack
+       movq    176(%rsp),%r15
+       #                               x10_stack = x10
+       movq    %rbp,168(%rsp)
+       #                                               d = x14 + x15
+       lea     (%rbx,%r15),%rbp
+       #                                               (uint32) d <<<= 7
+       rol     $7,%ebp
+       #                                               x12 ^= d
+       xor     %rbp,%r14
+       #                                               d = x15 + x12
+       lea     (%r15,%r14),%rbp
+       #                                               (uint32) d <<<= 9
+       rol     $9,%ebp
+       #                                               x13 ^= d
+       xor     %rbp,%r13
+       #                                               d = x12 + x13
+       lea     (%r14,%r13),%rbp
+       #                                               (uint32) d <<<= 13
+       rol     $13,%ebp
+       #                                               x14 ^= d
+       xor     %rbp,%rbx
+       #                                               d = x13 + x14
+       lea     (%r13,%rbx),%rbp
+       #                                               (uint32) d <<<= 18
+       rol     $18,%ebp
+       #                                               x15 ^= d
+       xor     %rbp,%r15
+       #                                               x15_stack = x15
+       movq    %r15,176(%rsp)
+       #               x5 = x5_stack
+       movq    160(%rsp),%r15
+       # a = x12 + x0
+       lea     (%r14,%rdx),%rbp
+       # (uint32) a <<<= 7
+       rol     $7,%ebp
+       # x4 ^= a
+       xor     %rbp,%r9
+       #               b = x1 + x5
+       lea     (%rdi,%r15),%rbp
+       #               (uint32) b <<<= 7
+       rol     $7,%ebp
+       #               x9 ^= b
+       xor     %rbp,%r10
+       # a = x0 + x4
+       lea     (%rdx,%r9),%rbp
+       # (uint32) a <<<= 9
+       rol     $9,%ebp
+       # x8 ^= a
+       xor     %rbp,%r11
+       #               b = x5 + x9
+       lea     (%r15,%r10),%rbp
+       #               (uint32) b <<<= 9
+       rol     $9,%ebp
+       #               x13 ^= b
+       xor     %rbp,%r13
+       # a = x4 + x8
+       lea     (%r9,%r11),%rbp
+       # (uint32) a <<<= 13
+       rol     $13,%ebp
+       # x12 ^= a
+       xor     %rbp,%r14
+       #               b = x9 + x13
+       lea     (%r10,%r13),%rbp
+       #               (uint32) b <<<= 13
+       rol     $13,%ebp
+       #               x1 ^= b
+       xor     %rbp,%rdi
+       # a = x8 + x12
+       lea     (%r11,%r14),%rbp
+       # (uint32) a <<<= 18
+       rol     $18,%ebp
+       # x0 ^= a
+       xor     %rbp,%rdx
+       #               b = x13 + x1
+       lea     (%r13,%rdi),%rbp
+       #               (uint32) b <<<= 18
+       rol     $18,%ebp
+       #               x5 ^= b
+       xor     %rbp,%r15
+       #                               x10 = x10_stack
+       movq    168(%rsp),%rbp
+       #               x5_stack = x5
+       movq    %r15,160(%rsp)
+       #                               c = x6 + x10
+       lea     (%rax,%rbp),%r15
+       #                               (uint32) c <<<= 7
+       rol     $7,%r15d
+       #                               x14 ^= c
+       xor     %r15,%rbx
+       #                               c = x10 + x14
+       lea     (%rbp,%rbx),%r15
+       #                               (uint32) c <<<= 9
+       rol     $9,%r15d
+       #                               x2 ^= c
+       xor     %r15,%rcx
+       #                               c = x14 + x2
+       lea     (%rbx,%rcx),%r15
+       #                               (uint32) c <<<= 13
+       rol     $13,%r15d
+       #                               x6 ^= c
+       xor     %r15,%rax
+       #                               c = x2 + x6
+       lea     (%rcx,%rax),%r15
+       #                               (uint32) c <<<= 18
+       rol     $18,%r15d
+       #                               x10 ^= c
+       xor     %r15,%rbp
+       #                                               x15 = x15_stack
+       movq    176(%rsp),%r15
+       #                               x10_stack = x10
+       movq    %rbp,168(%rsp)
+       #                                               d = x11 + x15
+       lea     (%r12,%r15),%rbp
+       #                                               (uint32) d <<<= 7
+       rol     $7,%ebp
+       #                                               x3 ^= d
+       xor     %rbp,%rsi
+       #                                               d = x15 + x3
+       lea     (%r15,%rsi),%rbp
+       #                                               (uint32) d <<<= 9
+       rol     $9,%ebp
+       #                                               x7 ^= d
+       xor     %rbp,%r8
+       #                                               d = x3 + x7
+       lea     (%rsi,%r8),%rbp
+       #                                               (uint32) d <<<= 13
+       rol     $13,%ebp
+       #                                               x11 ^= d
+       xor     %rbp,%r12
+       #                                               d = x7 + x11
+       lea     (%r8,%r12),%rbp
+       #                                               (uint32) d <<<= 18
+       rol     $18,%ebp
+       #                                               x15 ^= d
+       xor     %rbp,%r15
+       #                                               x15_stack = x15
+       movq    %r15,176(%rsp)
+       #               x5 = x5_stack
+       movq    160(%rsp),%r15
+       # a = x3 + x0
+       lea     (%rsi,%rdx),%rbp
+       # (uint32) a <<<= 7
+       rol     $7,%ebp
+       # x1 ^= a
+       xor     %rbp,%rdi
+       #               b = x4 + x5
+       lea     (%r9,%r15),%rbp
+       #               (uint32) b <<<= 7
+       rol     $7,%ebp
+       #               x6 ^= b
+       xor     %rbp,%rax
+       # a = x0 + x1
+       lea     (%rdx,%rdi),%rbp
+       # (uint32) a <<<= 9
+       rol     $9,%ebp
+       # x2 ^= a
+       xor     %rbp,%rcx
+       #               b = x5 + x6
+       lea     (%r15,%rax),%rbp
+       #               (uint32) b <<<= 9
+       rol     $9,%ebp
+       #               x7 ^= b
+       xor     %rbp,%r8
+       # a = x1 + x2
+       lea     (%rdi,%rcx),%rbp
+       # (uint32) a <<<= 13
+       rol     $13,%ebp
+       # x3 ^= a
+       xor     %rbp,%rsi
+       #               b = x6 + x7
+       lea     (%rax,%r8),%rbp
+       #               (uint32) b <<<= 13
+       rol     $13,%ebp
+       #               x4 ^= b
+       xor     %rbp,%r9
+       # a = x2 + x3
+       lea     (%rcx,%rsi),%rbp
+       # (uint32) a <<<= 18
+       rol     $18,%ebp
+       # x0 ^= a
+       xor     %rbp,%rdx
+       #               b = x7 + x4
+       lea     (%r8,%r9),%rbp
+       #               (uint32) b <<<= 18
+       rol     $18,%ebp
+       #               x5 ^= b
+       xor     %rbp,%r15
+       #                               x10 = x10_stack
+       movq    168(%rsp),%rbp
+       #               x5_stack = x5
+       movq    %r15,160(%rsp)
+       #                               c = x9 + x10
+       lea     (%r10,%rbp),%r15
+       #                               (uint32) c <<<= 7
+       rol     $7,%r15d
+       #                               x11 ^= c
+       xor     %r15,%r12
+       #                               c = x10 + x11
+       lea     (%rbp,%r12),%r15
+       #                               (uint32) c <<<= 9
+       rol     $9,%r15d
+       #                               x8 ^= c
+       xor     %r15,%r11
+       #                               c = x11 + x8
+       lea     (%r12,%r11),%r15
+       #                               (uint32) c <<<= 13
+       rol     $13,%r15d
+       #                               x9 ^= c
+       xor     %r15,%r10
+       #                               c = x8 + x9
+       lea     (%r11,%r10),%r15
+       #                               (uint32) c <<<= 18
+       rol     $18,%r15d
+       #                               x10 ^= c
+       xor     %r15,%rbp
+       #                                               x15 = x15_stack
+       movq    176(%rsp),%r15
+       #                               x10_stack = x10
+       movq    %rbp,168(%rsp)
+       #                                               d = x14 + x15
+       lea     (%rbx,%r15),%rbp
+       #                                               (uint32) d <<<= 7
+       rol     $7,%ebp
+       #                                               x12 ^= d
+       xor     %rbp,%r14
+       #                                               d = x15 + x12
+       lea     (%r15,%r14),%rbp
+       #                                               (uint32) d <<<= 9
+       rol     $9,%ebp
+       #                                               x13 ^= d
+       xor     %rbp,%r13
+       #                                               d = x12 + x13
+       lea     (%r14,%r13),%rbp
+       #                                               (uint32) d <<<= 13
+       rol     $13,%ebp
+       #                                               x14 ^= d
+       xor     %rbp,%rbx
+       #                                               d = x13 + x14
+       lea     (%r13,%rbx),%rbp
+       #                                               (uint32) d <<<= 18
+       rol     $18,%ebp
+       #                                               x15 ^= d
+       xor     %rbp,%r15
+       #                                               x15_stack = x15
+       movq    %r15,176(%rsp)
+       #   i = i_backup
+       movq    184(%rsp),%r15
+       #                  unsigned>? i -= 4
+       sub     $4,%r15
+       # comment:fp stack unchanged by jump
+       # goto mainloop if unsigned>
+       ja      ._mainloop
+       #   (uint32) x2 += j2
+       addl    64(%rsp),%ecx
+       #   x3 <<= 32
+       shl     $32,%rsi
+       #   x3 += j2
+       addq    64(%rsp),%rsi
+       #   (uint64) x3 >>= 32
+       shr     $32,%rsi
+       #   x3 <<= 32
+       shl     $32,%rsi
+       #   x2 += x3
+       add     %rsi,%rcx
+       #   (uint32) x6 += j6
+       addl    80(%rsp),%eax
+       #   x7 <<= 32
+       shl     $32,%r8
+       #   x7 += j6
+       addq    80(%rsp),%r8
+       #   (uint64) x7 >>= 32
+       shr     $32,%r8
+       #   x7 <<= 32
+       shl     $32,%r8
+       #   x6 += x7
+       add     %r8,%rax
+       #   (uint32) x8 += j8
+       addl    88(%rsp),%r11d
+       #   x9 <<= 32
+       shl     $32,%r10
+       #   x9 += j8
+       addq    88(%rsp),%r10
+       #   (uint64) x9 >>= 32
+       shr     $32,%r10
+       #   x9 <<= 32
+       shl     $32,%r10
+       #   x8 += x9
+       add     %r10,%r11
+       #   (uint32) x12 += j12
+       addl    104(%rsp),%r14d
+       #   x13 <<= 32
+       shl     $32,%r13
+       #   x13 += j12
+       addq    104(%rsp),%r13
+       #   (uint64) x13 >>= 32
+       shr     $32,%r13
+       #   x13 <<= 32
+       shl     $32,%r13
+       #   x12 += x13
+       add     %r13,%r14
+       #   (uint32) x0 += j0
+       addl    56(%rsp),%edx
+       #   x1 <<= 32
+       shl     $32,%rdi
+       #   x1 += j0
+       addq    56(%rsp),%rdi
+       #   (uint64) x1 >>= 32
+       shr     $32,%rdi
+       #   x1 <<= 32
+       shl     $32,%rdi
+       #   x0 += x1
+       add     %rdi,%rdx
+       #   x5 = x5_stack
+       movq    160(%rsp),%rdi
+       #   (uint32) x4 += j4
+       addl    72(%rsp),%r9d
+       #   x5 <<= 32
+       shl     $32,%rdi
+       #   x5 += j4
+       addq    72(%rsp),%rdi
+       #   (uint64) x5 >>= 32
+       shr     $32,%rdi
+       #   x5 <<= 32
+       shl     $32,%rdi
+       #   x4 += x5
+       add     %rdi,%r9
+       #   x10 = x10_stack
+       movq    168(%rsp),%r8
+       #   (uint32) x10 += j10
+       addl    96(%rsp),%r8d
+       #   x11 <<= 32
+       shl     $32,%r12
+       #   x11 += j10
+       addq    96(%rsp),%r12
+       #   (uint64) x11 >>= 32
+       shr     $32,%r12
+       #   x11 <<= 32
+       shl     $32,%r12
+       #   x10 += x11
+       add     %r12,%r8
+       #   x15 = x15_stack
+       movq    176(%rsp),%rdi
+       #   (uint32) x14 += j14
+       addl    112(%rsp),%ebx
+       #   x15 <<= 32
+       shl     $32,%rdi
+       #   x15 += j14
+       addq    112(%rsp),%rdi
+       #   (uint64) x15 >>= 32
+       shr     $32,%rdi
+       #   x15 <<= 32
+       shl     $32,%rdi
+       #   x14 += x15
+       add     %rdi,%rbx
+       #   out = out_backup
+       movq    136(%rsp),%rdi
+       #   m = m_backup
+       movq    144(%rsp),%rsi
+       #   x0 ^= *(uint64 *) (m + 0)
+       xorq    0(%rsi),%rdx
+       #   *(uint64 *) (out + 0) = x0
+       movq    %rdx,0(%rdi)
+       #   x2 ^= *(uint64 *) (m + 8)
+       xorq    8(%rsi),%rcx
+       #   *(uint64 *) (out + 8) = x2
+       movq    %rcx,8(%rdi)
+       #   x4 ^= *(uint64 *) (m + 16)
+       xorq    16(%rsi),%r9
+       #   *(uint64 *) (out + 16) = x4
+       movq    %r9,16(%rdi)
+       #   x6 ^= *(uint64 *) (m + 24)
+       xorq    24(%rsi),%rax
+       #   *(uint64 *) (out + 24) = x6
+       movq    %rax,24(%rdi)
+       #   x8 ^= *(uint64 *) (m + 32)
+       xorq    32(%rsi),%r11
+       #   *(uint64 *) (out + 32) = x8
+       movq    %r11,32(%rdi)
+       #   x10 ^= *(uint64 *) (m + 40)
+       xorq    40(%rsi),%r8
+       #   *(uint64 *) (out + 40) = x10
+       movq    %r8,40(%rdi)
+       #   x12 ^= *(uint64 *) (m + 48)
+       xorq    48(%rsi),%r14
+       #   *(uint64 *) (out + 48) = x12
+       movq    %r14,48(%rdi)
+       #   x14 ^= *(uint64 *) (m + 56)
+       xorq    56(%rsi),%rbx
+       #   *(uint64 *) (out + 56) = x14
+       movq    %rbx,56(%rdi)
+       #   bytes = bytes_backup
+       movq    152(%rsp),%rdx
+       #   in8 = j8
+       movq    88(%rsp),%rcx
+       #   in8 += 1
+       add     $1,%rcx
+       #   j8 = in8
+       movq    %rcx,88(%rsp)
+       #                          unsigned>? unsigned<? bytes - 64
+       cmp     $64,%rdx
+       # comment:fp stack unchanged by jump
+       #   goto bytesatleast65 if unsigned>
+       ja      ._bytesatleast65
+       # comment:fp stack unchanged by jump
+       #     goto bytesatleast64 if !unsigned<
+       jae     ._bytesatleast64
+       #       m = out
+       mov     %rdi,%rsi
+       #       out = ctarget
+       movq    128(%rsp),%rdi
+       #       i = bytes
+       mov     %rdx,%rcx
+       #       while (i) { *out++ = *m++; --i }
+       rep     movsb
+       # comment:fp stack unchanged by fallthrough
+#     bytesatleast64:
+._bytesatleast64:
+       #     x = x_backup
+       movq    120(%rsp),%rdi
+       #     in8 = j8
+       movq    88(%rsp),%rsi
+       #     *(uint64 *) (x + 32) = in8
+       movq    %rsi,32(%rdi)
+       #     r11 = r11_stack
+       movq    0(%rsp),%r11
+       #     r12 = r12_stack
+       movq    8(%rsp),%r12
+       #     r13 = r13_stack
+       movq    16(%rsp),%r13
+       #     r14 = r14_stack
+       movq    24(%rsp),%r14
+       #     r15 = r15_stack
+       movq    32(%rsp),%r15
+       #     rbx = rbx_stack
+       movq    40(%rsp),%rbx
+       #     rbp = rbp_stack
+       movq    48(%rsp),%rbp
+       # comment:fp stack unchanged by fallthrough
+#     done:
+._done:
+       #     leave
+       add     %r11,%rsp
+       mov     %rdi,%rax
+       mov     %rsi,%rdx
+       ret
+#   bytesatleast65:
+._bytesatleast65:
+       #   bytes -= 64
+       sub     $64,%rdx
+       #   out += 64
+       add     $64,%rdi
+       #   m += 64
+       add     $64,%rsi
+       # comment:fp stack unchanged by jump
+       # goto bytesatleast1
+       jmp     ._bytesatleast1
+# enter ECRYPT_keysetup
+.text
+.p2align 5
+.globl ECRYPT_keysetup
+ECRYPT_keysetup:
+       mov     %rsp,%r11
+       and     $31,%r11
+       add     $256,%r11
+       sub     %r11,%rsp
+       #   k = arg2
+       mov     %rsi,%rsi
+       #   kbits = arg3
+       mov     %rdx,%rdx
+       #   x = arg1
+       mov     %rdi,%rdi
+       #   in0 = *(uint64 *) (k + 0)
+       movq    0(%rsi),%r8
+       #   in2 = *(uint64 *) (k + 8)
+       movq    8(%rsi),%r9
+       #   *(uint64 *) (x + 4) = in0
+       movq    %r8,4(%rdi)
+       #   *(uint64 *) (x + 12) = in2
+       movq    %r9,12(%rdi)
+       #                    unsigned<? kbits - 256
+       cmp     $256,%rdx
+       # comment:fp stack unchanged by jump
+       #   goto kbits128 if unsigned<
+       jb      ._kbits128
+#   kbits256:
+._kbits256:
+       #     in10 = *(uint64 *) (k + 16)
+       movq    16(%rsi),%rdx
+       #     in12 = *(uint64 *) (k + 24)
+       movq    24(%rsi),%rsi
+       #     *(uint64 *) (x + 44) = in10
+       movq    %rdx,44(%rdi)
+       #     *(uint64 *) (x + 52) = in12
+       movq    %rsi,52(%rdi)
+       #     in0 = 1634760805
+       mov     $1634760805,%rsi
+       #     in4 = 857760878
+       mov     $857760878,%rdx
+       #     in10 = 2036477234
+       mov     $2036477234,%rcx
+       #     in14 = 1797285236
+       mov     $1797285236,%r8
+       #     *(uint32 *) (x + 0) = in0
+       movl    %esi,0(%rdi)
+       #     *(uint32 *) (x + 20) = in4
+       movl    %edx,20(%rdi)
+       #     *(uint32 *) (x + 40) = in10
+       movl    %ecx,40(%rdi)
+       #     *(uint32 *) (x + 60) = in14
+       movl    %r8d,60(%rdi)
+       # comment:fp stack unchanged by jump
+       #   goto keysetupdone
+       jmp     ._keysetupdone
+#   kbits128:
+._kbits128:
+       #     in10 = *(uint64 *) (k + 0)
+       movq    0(%rsi),%rdx
+       #     in12 = *(uint64 *) (k + 8)
+       movq    8(%rsi),%rsi
+       #     *(uint64 *) (x + 44) = in10
+       movq    %rdx,44(%rdi)
+       #     *(uint64 *) (x + 52) = in12
+       movq    %rsi,52(%rdi)
+       #     in0 = 1634760805
+       mov     $1634760805,%rsi
+       #     in4 = 824206446
+       mov     $824206446,%rdx
+       #     in10 = 2036477238
+       mov     $2036477238,%rcx
+       #     in14 = 1797285236
+       mov     $1797285236,%r8
+       #     *(uint32 *) (x + 0) = in0
+       movl    %esi,0(%rdi)
+       #     *(uint32 *) (x + 20) = in4
+       movl    %edx,20(%rdi)
+       #     *(uint32 *) (x + 40) = in10
+       movl    %ecx,40(%rdi)
+       #     *(uint32 *) (x + 60) = in14
+       movl    %r8d,60(%rdi)
+#   keysetupdone:
+._keysetupdone:
+       # leave
+       add     %r11,%rsp
+       mov     %rdi,%rax
+       mov     %rsi,%rdx
+       ret
+# enter ECRYPT_ivsetup
+.text
+.p2align 5
+.globl ECRYPT_ivsetup
+ECRYPT_ivsetup:
+       mov     %rsp,%r11
+       and     $31,%r11
+       add     $256,%r11
+       sub     %r11,%rsp
+       #   iv = arg2
+       mov     %rsi,%rsi
+       #   x = arg1
+       mov     %rdi,%rdi
+       #   in6 = *(uint64 *) (iv + 0)
+       movq    0(%rsi),%rsi
+       #   in8 = 0
+       mov     $0,%r8
+       #   *(uint64 *) (x + 24) = in6
+       movq    %rsi,24(%rdi)
+       #   *(uint64 *) (x + 32) = in8
+       movq    %r8,32(%rdi)
+       # leave
+       add     %r11,%rsp
+       mov     %rdi,%rax
+       mov     %rsi,%rdx
+       ret
diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c
new file mode 100644 (file)
index 0000000..bccb76d
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Glue code for optimized assembly version of  Salsa20.
+ *
+ * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com>
+ *
+ * The assembly codes are public domain assembly codes written by Daniel. J.
+ * Bernstein <djb@cr.yp.to>. The codes are modified to include indentation
+ * and to remove extraneous comments and functions that are not needed.
+ * - i586 version, renamed as salsa20-i586-asm_32.S
+ *   available from <http://cr.yp.to/snuffle/salsa20/x86-pm/salsa20.s>
+ * - x86-64 version, renamed as salsa20-x86_64-asm_64.S
+ *   available from <http://cr.yp.to/snuffle/salsa20/amd64-3/salsa20.s>
+ *
+ * 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 <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+
+#define SALSA20_IV_SIZE        8U
+#define SALSA20_MIN_KEY_SIZE  16U
+#define SALSA20_MAX_KEY_SIZE  32U
+
+// use the ECRYPT_* function names
+#define salsa20_keysetup        ECRYPT_keysetup
+#define salsa20_ivsetup         ECRYPT_ivsetup
+#define salsa20_encrypt_bytes   ECRYPT_encrypt_bytes
+
+struct salsa20_ctx
+{
+       u32 input[16];
+};
+
+asmlinkage void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k,
+                                u32 keysize, u32 ivsize);
+asmlinkage void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv);
+asmlinkage void salsa20_encrypt_bytes(struct salsa20_ctx *ctx,
+                                     const u8 *src, u8 *dst, u32 bytes);
+
+static int setkey(struct crypto_tfm *tfm, const u8 *key,
+                 unsigned int keysize)
+{
+       struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm);
+       salsa20_keysetup(ctx, key, keysize*8, SALSA20_IV_SIZE*8);
+       return 0;
+}
+
+static int encrypt(struct blkcipher_desc *desc,
+                  struct scatterlist *dst, struct scatterlist *src,
+                  unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       struct crypto_blkcipher *tfm = desc->tfm;
+       struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm);
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, 64);
+
+       salsa20_ivsetup(ctx, walk.iv);
+
+       if (likely(walk.nbytes == nbytes))
+       {
+               salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
+                                     walk.dst.virt.addr, nbytes);
+               return blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       while (walk.nbytes >= 64) {
+               salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
+                                     walk.dst.virt.addr,
+                                     walk.nbytes - (walk.nbytes % 64));
+               err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64);
+       }
+
+       if (walk.nbytes) {
+               salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
+                                     walk.dst.virt.addr, walk.nbytes);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+static struct crypto_alg alg = {
+       .cra_name           =   "salsa20",
+       .cra_driver_name    =   "salsa20-asm",
+       .cra_priority       =   200,
+       .cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_type           =   &crypto_blkcipher_type,
+       .cra_blocksize      =   1,
+       .cra_ctxsize        =   sizeof(struct salsa20_ctx),
+       .cra_alignmask      =   3,
+       .cra_module         =   THIS_MODULE,
+       .cra_list           =   LIST_HEAD_INIT(alg.cra_list),
+       .cra_u              =   {
+               .blkcipher = {
+                       .setkey         =   setkey,
+                       .encrypt        =   encrypt,
+                       .decrypt        =   encrypt,
+                       .min_keysize    =   SALSA20_MIN_KEY_SIZE,
+                       .max_keysize    =   SALSA20_MAX_KEY_SIZE,
+                       .ivsize         =   SALSA20_IV_SIZE,
+               }
+       }
+};
+
+static int __init init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm (optimized assembly version)");
+MODULE_ALIAS("salsa20");
+MODULE_ALIAS("salsa20-asm");
diff --git a/arch/x86/crypto/twofish_32.c b/arch/x86/crypto/twofish_32.c
deleted file mode 100644 (file)
index e3004df..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *  Glue Code for optimized 586 assembler version of TWOFISH
- *
- * Originally Twofish for GPG
- * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
- * 256-bit key length added March 20, 1999
- * Some modifications to reduce the text size by Werner Koch, April, 1998
- * Ported to the kerneli patch by Marc Mutz <Marc@Mutz.com>
- * Ported to CryptoAPI by Colin Slater <hoho@tacomeat.net>
- *
- * The original author has disclaimed all copyright interest in this
- * code and thus put it in the public domain. The subsequent authors
- * have put this under the GNU General Public License.
- *
- * 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
- *
- * This code is a "clean room" implementation, written from the paper
- * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
- * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
- * through http://www.counterpane.com/twofish.html
- *
- * For background information on multiplication in finite fields, used for
- * the matrix operations in the key schedule, see the book _Contemporary
- * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
- * Third Edition.
- */
-
-#include <crypto/twofish.h>
-#include <linux/crypto.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-
-asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       twofish_enc_blk(tfm, dst, src);
-}
-
-static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       twofish_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg alg = {
-       .cra_name               =       "twofish",
-       .cra_driver_name        =       "twofish-i586",
-       .cra_priority           =       200,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       TF_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct twofish_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =       TF_MIN_KEY_SIZE,
-                       .cia_max_keysize        =       TF_MAX_KEY_SIZE,
-                       .cia_setkey             =       twofish_setkey,
-                       .cia_encrypt            =       twofish_encrypt,
-                       .cia_decrypt            =       twofish_decrypt
-               }
-       }
-};
-
-static int __init init(void)
-{
-       return crypto_register_alg(&alg);
-}
-
-static void __exit fini(void)
-{
-       crypto_unregister_alg(&alg);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION ("Twofish Cipher Algorithm, i586 asm optimized");
-MODULE_ALIAS("twofish");
diff --git a/arch/x86/crypto/twofish_64.c b/arch/x86/crypto/twofish_64.c
deleted file mode 100644 (file)
index 182d91d..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Glue Code for optimized x86_64 assembler version of TWOFISH
- *
- * Originally Twofish for GPG
- * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
- * 256-bit key length added March 20, 1999
- * Some modifications to reduce the text size by Werner Koch, April, 1998
- * Ported to the kerneli patch by Marc Mutz <Marc@Mutz.com>
- * Ported to CryptoAPI by Colin Slater <hoho@tacomeat.net>
- *
- * The original author has disclaimed all copyright interest in this
- * code and thus put it in the public domain. The subsequent authors
- * have put this under the GNU General Public License.
- *
- * 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
- *
- * This code is a "clean room" implementation, written from the paper
- * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
- * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
- * through http://www.counterpane.com/twofish.html
- *
- * For background information on multiplication in finite fields, used for
- * the matrix operations in the key schedule, see the book _Contemporary
- * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
- * Third Edition.
- */
-
-#include <crypto/twofish.h>
-#include <linux/crypto.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       twofish_enc_blk(tfm, dst, src);
-}
-
-static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       twofish_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg alg = {
-       .cra_name               =       "twofish",
-       .cra_driver_name        =       "twofish-x86_64",
-       .cra_priority           =       200,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       TF_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct twofish_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =       TF_MIN_KEY_SIZE,
-                       .cia_max_keysize        =       TF_MAX_KEY_SIZE,
-                       .cia_setkey             =       twofish_setkey,
-                       .cia_encrypt            =       twofish_encrypt,
-                       .cia_decrypt            =       twofish_decrypt
-               }
-       }
-};
-
-static int __init init(void)
-{
-       return crypto_register_alg(&alg);
-}
-
-static void __exit fini(void)
-{
-       crypto_unregister_alg(&alg);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION ("Twofish Cipher Algorithm, x86_64 asm optimized");
-MODULE_ALIAS("twofish");
diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c
new file mode 100644 (file)
index 0000000..cefaf8b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Glue Code for assembler optimized version of TWOFISH
+ *
+ * Originally Twofish for GPG
+ * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
+ * 256-bit key length added March 20, 1999
+ * Some modifications to reduce the text size by Werner Koch, April, 1998
+ * Ported to the kerneli patch by Marc Mutz <Marc@Mutz.com>
+ * Ported to CryptoAPI by Colin Slater <hoho@tacomeat.net>
+ *
+ * The original author has disclaimed all copyright interest in this
+ * code and thus put it in the public domain. The subsequent authors
+ * have put this under the GNU General Public License.
+ *
+ * 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
+ *
+ * This code is a "clean room" implementation, written from the paper
+ * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
+ * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
+ * through http://www.counterpane.com/twofish.html
+ *
+ * For background information on multiplication in finite fields, used for
+ * the matrix operations in the key schedule, see the book _Contemporary
+ * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
+ * Third Edition.
+ */
+
+#include <crypto/twofish.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+
+static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       twofish_enc_blk(tfm, dst, src);
+}
+
+static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       twofish_dec_blk(tfm, dst, src);
+}
+
+static struct crypto_alg alg = {
+       .cra_name               =       "twofish",
+       .cra_driver_name        =       "twofish-asm",
+       .cra_priority           =       200,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       TF_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct twofish_ctx),
+       .cra_alignmask          =       3,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       TF_MIN_KEY_SIZE,
+                       .cia_max_keysize        =       TF_MAX_KEY_SIZE,
+                       .cia_setkey             =       twofish_setkey,
+                       .cia_encrypt            =       twofish_encrypt,
+                       .cia_decrypt            =       twofish_decrypt
+               }
+       }
+};
+
+static int __init init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("Twofish Cipher Algorithm, asm optimized");
+MODULE_ALIAS("twofish");
+MODULE_ALIAS("twofish-asm");
index edb5108e5d0e057f24dabe50ae1fde323b9fed56..a56c782653be7dc17474e133518d75f299659945 100644 (file)
@@ -1530,7 +1530,7 @@ static int lapic_resume(struct sys_device *dev)
  */
 
 static struct sysdev_class lapic_sysclass = {
-       set_kset_name("lapic"),
+       .name           = "lapic",
        .resume         = lapic_resume,
        .suspend        = lapic_suspend,
 };
index f28ccb588fbab8996cd76512d2c1bae24e4b1a2c..fa6cdee6d303a9dbd29b9f198fd2742140ebc0d8 100644 (file)
@@ -639,7 +639,7 @@ static int lapic_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class lapic_sysclass = {
-       set_kset_name("lapic"),
+       .name           = "lapic",
        .resume         = lapic_resume,
        .suspend        = lapic_suspend,
 };
index 17089a041028d5447f2c20503b10dd1058b030d5..af045ca0f653e7587fdd39dac737877ba0ebe17f 100644 (file)
@@ -2256,14 +2256,12 @@ static int __init apm_init(void)
                apm_info.disabled = 1;
                return -ENODEV;
        }
-       if (PM_IS_ACTIVE()) {
+       if (pm_flags & PM_ACPI) {
                printk(KERN_NOTICE "apm: overridden by ACPI.\n");
                apm_info.disabled = 1;
                return -ENODEV;
        }
-#ifdef CONFIG_PM_LEGACY
-       pm_active = 1;
-#endif
+       pm_flags |= PM_APM;
 
        /*
         * Set up a segment that references the real mode segment 0x40
@@ -2366,9 +2364,7 @@ static void __exit apm_exit(void)
                kthread_stop(kapmd_task);
                kapmd_task = NULL;
        }
-#ifdef CONFIG_PM_LEGACY
-       pm_active = 0;
-#endif
+       pm_flags &= ~PM_APM;
 }
 
 module_init(apm_init);
index 9f530ff43c213ec3def93623fe36c11658721734..8b4507b8469b18ed09f906e35b94ba6649e75b8a 100644 (file)
@@ -733,10 +733,8 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
        if (unlikely(retval < 0))
                return retval;
 
-       cache_kobject[cpu]->parent = &sys_dev->kobj;
-       kobject_set_name(cache_kobject[cpu], "%s", "cache");
-       cache_kobject[cpu]->ktype = &ktype_percpu_entry;
-       retval = kobject_register(cache_kobject[cpu]);
+       retval = kobject_init_and_add(cache_kobject[cpu], &ktype_percpu_entry,
+                                     &sys_dev->kobj, "%s", "cache");
        if (retval < 0) {
                cpuid4_cache_sysfs_exit(cpu);
                return retval;
@@ -746,23 +744,23 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
                this_object = INDEX_KOBJECT_PTR(cpu,i);
                this_object->cpu = cpu;
                this_object->index = i;
-               this_object->kobj.parent = cache_kobject[cpu];
-               kobject_set_name(&(this_object->kobj), "index%1lu", i);
-               this_object->kobj.ktype = &ktype_cache;
-               retval = kobject_register(&(this_object->kobj));
+               retval = kobject_init_and_add(&(this_object->kobj),
+                                             &ktype_cache, cache_kobject[cpu],
+                                             "index%1lu", i);
                if (unlikely(retval)) {
                        for (j = 0; j < i; j++) {
-                               kobject_unregister(
-                                       &(INDEX_KOBJECT_PTR(cpu,j)->kobj));
+                               kobject_put(&(INDEX_KOBJECT_PTR(cpu,j)->kobj));
                        }
-                       kobject_unregister(cache_kobject[cpu]);
+                       kobject_put(cache_kobject[cpu]);
                        cpuid4_cache_sysfs_exit(cpu);
                        break;
                }
+               kobject_uevent(&(this_object->kobj), KOBJ_ADD);
        }
        if (!retval)
                cpu_set(cpu, cache_dev_map);
 
+       kobject_uevent(cache_kobject[cpu], KOBJ_ADD);
        return retval;
 }
 
@@ -778,8 +776,8 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
        cpu_clear(cpu, cache_dev_map);
 
        for (i = 0; i < num_cache_leaves; i++)
-               kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
-       kobject_unregister(cache_kobject[cpu]);
+               kobject_put(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
+       kobject_put(cache_kobject[cpu]);
        cpuid4_cache_sysfs_exit(cpu);
 }
 
index 4b21d29fb5aa575b6146132db6dadd319ac5ca4a..242e8668dbeb2a6904b9b15feee00f827e099d5f 100644 (file)
@@ -745,7 +745,7 @@ static void mce_restart(void)
 
 static struct sysdev_class mce_sysclass = {
        .resume = mce_resume,
-       set_kset_name("machinecheck"),
+       .name = "machinecheck",
 };
 
 DEFINE_PER_CPU(struct sys_device, device_mce);
index 752fb16a817d7187ac1732e66c426a12a19ff352..753588755feeb6d76d079cefe64d39236438a86e 100644 (file)
@@ -65,7 +65,7 @@ static struct threshold_block threshold_defaults = {
 };
 
 struct threshold_bank {
-       struct kobject kobj;
+       struct kobject *kobj;
        struct threshold_block *blocks;
        cpumask_t cpus;
 };
@@ -432,10 +432,9 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
        else
                per_cpu(threshold_banks, cpu)[bank]->blocks = b;
 
-       kobject_set_name(&b->kobj, "misc%i", block);
-       b->kobj.parent = &per_cpu(threshold_banks, cpu)[bank]->kobj;
-       b->kobj.ktype = &threshold_ktype;
-       err = kobject_register(&b->kobj);
+       err = kobject_init_and_add(&b->kobj, &threshold_ktype,
+                                  per_cpu(threshold_banks, cpu)[bank]->kobj,
+                                  "misc%i", block);
        if (err)
                goto out_free;
 recurse:
@@ -451,11 +450,13 @@ recurse:
        if (err)
                goto out_free;
 
+       kobject_uevent(&b->kobj, KOBJ_ADD);
+
        return err;
 
 out_free:
        if (b) {
-               kobject_unregister(&b->kobj);
+               kobject_put(&b->kobj);
                kfree(b);
        }
        return err;
@@ -489,7 +490,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                        goto out;
 
                err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj,
-                                       &b->kobj, name);
+                                       b->kobj, name);
                if (err)
                        goto out;
 
@@ -505,16 +506,15 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                goto out;
        }
 
-       kobject_set_name(&b->kobj, "threshold_bank%i", bank);
-       b->kobj.parent = &per_cpu(device_mce, cpu).kobj;
+       b->kobj = kobject_create_and_add(name, &per_cpu(device_mce, cpu).kobj);
+       if (!b->kobj)
+               goto out_free;
+
 #ifndef CONFIG_SMP
        b->cpus = CPU_MASK_ALL;
 #else
        b->cpus = per_cpu(cpu_core_map, cpu);
 #endif
-       err = kobject_register(&b->kobj);
-       if (err)
-               goto out_free;
 
        per_cpu(threshold_banks, cpu)[bank] = b;
 
@@ -531,7 +531,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                        continue;
 
                err = sysfs_create_link(&per_cpu(device_mce, i).kobj,
-                                       &b->kobj, name);
+                                       b->kobj, name);
                if (err)
                        goto out;
 
@@ -581,7 +581,7 @@ static void deallocate_threshold_block(unsigned int cpu,
                return;
 
        list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) {
-               kobject_unregister(&pos->kobj);
+               kobject_put(&pos->kobj);
                list_del(&pos->miscj);
                kfree(pos);
        }
@@ -627,7 +627,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
        deallocate_threshold_block(cpu, bank);
 
 free_out:
-       kobject_unregister(&b->kobj);
+       kobject_put(b->kobj);
        kfree(b);
        per_cpu(threshold_banks, cpu)[bank] = NULL;
 }
index 3b20613325dcbf88ef7cd7c3626d8a744b12ca4a..beb45c9c08357911a78af58f24640556b0a19240 100644 (file)
@@ -349,7 +349,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
        replace = -1;
 
        /* No CPU hotplug when we change MTRR entries */
-       lock_cpu_hotplug();
+       get_online_cpus();
        /*  Search for existing MTRR  */
        mutex_lock(&mtrr_mutex);
        for (i = 0; i < num_var_ranges; ++i) {
@@ -405,7 +405,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
        error = i;
  out:
        mutex_unlock(&mtrr_mutex);
-       unlock_cpu_hotplug();
+       put_online_cpus();
        return error;
 }
 
@@ -495,7 +495,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
 
        max = num_var_ranges;
        /* No CPU hotplug when we change MTRR entries */
-       lock_cpu_hotplug();
+       get_online_cpus();
        mutex_lock(&mtrr_mutex);
        if (reg < 0) {
                /*  Search for existing MTRR  */
@@ -536,7 +536,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
        error = reg;
  out:
        mutex_unlock(&mtrr_mutex);
-       unlock_cpu_hotplug();
+       put_online_cpus();
        return error;
 }
 /**
index 05c9936a16ccc50c015dae4c3af81552d4564fa7..d387c770c518e179413f4d2f891cbb86403ce45b 100644 (file)
@@ -157,15 +157,15 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
-       case CPU_UP_PREPARE_FROZEN:
                err = cpuid_device_create(cpu);
                break;
        case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
                cpuid_device_destroy(cpu);
                break;
+       case CPU_UP_CANCELED_FROZEN:
+               destroy_suspended_device(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
+               break;
        }
        return err ? NOTIFY_BAD : NOTIFY_OK;
 }
index 3a058bb16409329f9ee255c57e81ff1cefb8cf2a..e70f3881d7e486f1ec55c14bcea41065506aaff2 100644 (file)
@@ -283,7 +283,7 @@ sysret_careful:
 sysret_signal:
        TRACE_IRQS_ON
        sti
-       testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
+       testl $_TIF_DO_NOTIFY_MASK,%edx
        jz    1f
 
        /* Really a signal */
@@ -377,7 +377,7 @@ int_very_careful:
        jmp int_restore_rest
        
 int_signal:
-       testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
+       testl $_TIF_DO_NOTIFY_MASK,%edx
        jz 1f
        movq %rsp,%rdi          # &ptregs -> arg1
        xorl %esi,%esi          # oldset -> arg2
@@ -603,7 +603,7 @@ retint_careful:
        jmp retint_check
        
 retint_signal:
-       testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
+       testl $_TIF_DO_NOTIFY_MASK,%edx
        jz    retint_swapgs
        TRACE_IRQS_ON
        sti
index ac0637a6d71cc75637cff60888c78cbfb5a504b1..fbad51fce672b25f4f30cf24ca81da8bc628a574 100644 (file)
@@ -196,7 +196,7 @@ default_entry:
        /* Do an early initialization of the fixmap area */
        movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
        movl $(swapper_pg_pmd - __PAGE_OFFSET), %eax
-       addl $0x007, %eax                       /* 0x007 = PRESENT+RW+USER */
+       addl $0x67, %eax                        /* 0x67 == _PAGE_TABLE */
        movl %eax, 4092(%edx)
 
        xorl %ebx,%ebx                          /* This is the boot CPU (BSP) */
index 4a86ffd67ec5e23ecec8c9ed42d9f00ecc051631..2f99ee206b9527c3cad6250caa95e2a3ceac9268 100644 (file)
@@ -657,7 +657,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
                hpet_pie_count = 0;
        }
 
-       if (hpet_rtc_flags & RTC_PIE &&
+       if (hpet_rtc_flags & RTC_AIE &&
            (curr_time.tm_sec == hpet_alarm_time.tm_sec) &&
            (curr_time.tm_min == hpet_alarm_time.tm_min) &&
            (curr_time.tm_hour == hpet_alarm_time.tm_hour))
index 29313832df0c082409641e1e06f234320d72b254..dbd6c1d1b638bcd739747e54eac08f639d304242 100644 (file)
@@ -51,7 +51,7 @@ static int i8237A_suspend(struct sys_device *dev, pm_message_t state)
 }
 
 static struct sysdev_class i8237_sysdev_class = {
-       set_kset_name("i8237"),
+       .name = "i8237",
        .suspend = i8237A_suspend,
        .resume = i8237A_resume,
 };
index f634fc715c99b455d3973645d4d16c3a80e13361..5f3496d0198403023f652a2e4d0a8a21816887ea 100644 (file)
@@ -258,7 +258,7 @@ static int i8259A_shutdown(struct sys_device *dev)
 }
 
 static struct sysdev_class i8259_sysdev_class = {
-       set_kset_name("i8259"),
+       .name = "i8259",
        .suspend = i8259A_suspend,
        .resume = i8259A_resume,
        .shutdown = i8259A_shutdown,
index 3f27ea0b9816fddb9a98d2587fd5c235b1e123ca..ba6d57286f5648ff299d10e9a2dcb88d0c563ceb 100644 (file)
@@ -370,7 +370,7 @@ static int i8259A_shutdown(struct sys_device *dev)
 }
 
 static struct sysdev_class i8259_sysdev_class = {
-       set_kset_name("i8259"),
+       .name = "i8259",
        .suspend = i8259A_suspend,
        .resume = i8259A_resume,
        .shutdown = i8259A_shutdown,
index c3a565bba106e5058d1465462b3656b0ee8e05a8..ab77f1905469592b724ce9c6bdd7c3ea70f0e408 100644 (file)
@@ -2169,14 +2169,10 @@ static inline void __init check_timer(void)
 {
        int apic1, pin1, apic2, pin2;
        int vector;
-       unsigned int ver;
        unsigned long flags;
 
        local_irq_save(flags);
 
-       ver = apic_read(APIC_LVR);
-       ver = GET_APIC_VERSION(ver);
-
        /*
         * get/set the timer IRQ vector:
         */
@@ -2189,15 +2185,11 @@ static inline void __init check_timer(void)
         * mode for the 8259A whenever interrupts are routed
         * through I/O APICs.  Also IRQ0 has to be enabled in
         * the 8259A which implies the virtual wire has to be
-        * disabled in the local APIC.  Finally timer interrupts
-        * need to be acknowledged manually in the 8259A for
-        * timer_interrupt() and for the i82489DX when using
-        * the NMI watchdog.
+        * disabled in the local APIC.
         */
        apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
        init_8259A(1);
-       timer_ack = !cpu_has_tsc;
-       timer_ack |= (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
+       timer_ack = 1;
        if (timer_over_8254 > 0)
                enable_8259A_irq(0);
 
@@ -2409,7 +2401,7 @@ static int ioapic_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class ioapic_sysdev_class = {
-       set_kset_name("ioapic"),
+       .name = "ioapic",
        .suspend = ioapic_suspend,
        .resume = ioapic_resume,
 };
index cbac1670c7c36ec4ee8c268618b4a8014859c2f3..23a3ac06a23ea1dc68d6d79f6cf7eb3f9f215f96 100644 (file)
@@ -1850,7 +1850,7 @@ static int ioapic_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class ioapic_sysdev_class = {
-       set_kset_name("ioapic"),
+       .name = "ioapic",
        .suspend = ioapic_suspend,
        .resume = ioapic_resume,
 };
index 0ab680f2d9db9af7885e9d5eedc9c02b79cd72d2..3960ab7e149773aa1c3dd4b7f3160cf9b76d944b 100644 (file)
@@ -278,12 +278,12 @@ static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
 
 static irqreturn_t mfgpt_tick(int irq, void *dev_id)
 {
+       /* Turn off the clock (and clear the event) */
+       mfgpt_disable_timer(mfgpt_event_clock);
+
        if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
                return IRQ_HANDLED;
 
-       /* Turn off the clock */
-       mfgpt_disable_timer(mfgpt_event_clock);
-
        /* Clear the counter */
        geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
 
@@ -319,10 +319,6 @@ static int __init mfgpt_timer_setup(void)
        }
 
        mfgpt_event_clock = timer;
-       /* Set the clock scale and enable the event mode for CMP2 */
-       val = MFGPT_SCALE | (3 << 8);
-
-       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
 
        /* Set up the IRQ on the MFGPT side */
        if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
@@ -339,6 +335,11 @@ static int __init mfgpt_timer_setup(void)
                goto err;
        }
 
+       /* Set the clock scale and enable the event mode for CMP2 */
+       val = MFGPT_SCALE | (3 << 8);
+
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
+
        /* Set up the clock event */
        mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
        mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
index 09c315214a5ec87fdddd00f039255d69f3c01b9a..40cfd5488719b96fd6ccd8d3a890e54761d0c6c0 100644 (file)
@@ -436,7 +436,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
                return -EINVAL;
        }
 
-       lock_cpu_hotplug();
+       get_online_cpus();
        mutex_lock(&microcode_mutex);
 
        user_buffer = (void __user *) buf;
@@ -447,7 +447,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
                ret = (ssize_t)len;
 
        mutex_unlock(&microcode_mutex);
-       unlock_cpu_hotplug();
+       put_online_cpus();
 
        return ret;
 }
@@ -658,14 +658,14 @@ static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz)
 
                old = current->cpus_allowed;
 
-               lock_cpu_hotplug();
+               get_online_cpus();
                set_cpus_allowed(current, cpumask_of_cpu(cpu));
 
                mutex_lock(&microcode_mutex);
                if (uci->valid)
                        err = cpu_request_microcode(cpu);
                mutex_unlock(&microcode_mutex);
-               unlock_cpu_hotplug();
+               put_online_cpus();
                set_cpus_allowed(current, old);
        }
        if (err)
@@ -817,9 +817,9 @@ static int __init microcode_init (void)
                return PTR_ERR(microcode_pdev);
        }
 
-       lock_cpu_hotplug();
+       get_online_cpus();
        error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
-       unlock_cpu_hotplug();
+       put_online_cpus();
        if (error) {
                microcode_dev_exit();
                platform_device_unregister(microcode_pdev);
@@ -839,9 +839,9 @@ static void __exit microcode_exit (void)
 
        unregister_hotcpu_notifier(&mc_cpu_notifier);
 
-       lock_cpu_hotplug();
+       get_online_cpus();
        sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
-       unlock_cpu_hotplug();
+       put_online_cpus();
 
        platform_device_unregister(microcode_pdev);
 }
index ee6eba4ecfeaadee33e8875be5a4f3b1ccd253d0..21f6e3c0be185c657d307042168fef4509073798 100644 (file)
@@ -155,15 +155,15 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
-       case CPU_UP_PREPARE_FROZEN:
                err = msr_device_create(cpu);
                break;
        case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
                msr_device_destroy(cpu);
                break;
+       case CPU_UP_CANCELED_FROZEN:
+               destroy_suspended_device(msr_class, MKDEV(MSR_MAJOR, cpu));
+               break;
        }
        return err ? NOTIFY_BAD : NOTIFY_OK;
 }
index 80ca72e5ac29f4fc9e3f41da4d428f31ea658896..4f4bfd3a88b6f89bb6bf080bb1e69787e320f2e7 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <asm/smp.h>
 #include <asm/nmi.h>
-#include <asm/timer.h>
 
 #include "mach_traps.h"
 
@@ -84,7 +83,7 @@ static int __init check_nmi_watchdog(void)
 
        prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
        if (!prev_nmi_count)
-               goto error;
+               return -1;
 
        printk(KERN_INFO "Testing NMI watchdog ... ");
 
@@ -119,7 +118,7 @@ static int __init check_nmi_watchdog(void)
        if (!atomic_read(&nmi_active)) {
                kfree(prev_nmi_count);
                atomic_set(&nmi_active, -1);
-               goto error;
+               return -1;
        }
        printk("OK.\n");
 
@@ -130,10 +129,6 @@ static int __init check_nmi_watchdog(void)
 
        kfree(prev_nmi_count);
        return 0;
-error:
-       timer_ack = !cpu_has_tsc;
-
-       return -1;
 }
 /* This needs to happen later in boot so counters are working */
 late_initcall(check_nmi_watchdog);
@@ -181,7 +176,7 @@ static int lapic_nmi_resume(struct sys_device *dev)
 
 
 static struct sysdev_class nmi_sysclass = {
-       set_kset_name("lapic_nmi"),
+       .name           = "lapic_nmi",
        .resume         = lapic_nmi_resume,
        .suspend        = lapic_nmi_suspend,
 };
index 4253c4e8849cd3abb29c519dc2d4d36d6b6627c3..c3d1476b6a1170673b6ab03a991c320f70af8ec8 100644 (file)
@@ -211,7 +211,7 @@ static int lapic_nmi_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class nmi_sysclass = {
-       set_kset_name("lapic_nmi"),
+       .name           = "lapic_nmi",
        .resume         = lapic_nmi_resume,
        .suspend        = lapic_nmi_suspend,
 };
index 9663c2a74830efcfdb1268bc862d9bac082e7f1c..46d391d49de8a82b750647787e0cd80186533e68 100644 (file)
@@ -204,6 +204,10 @@ void cpu_idle(void)
        }
 }
 
+static void do_nothing(void *unused)
+{
+}
+
 void cpu_idle_wait(void)
 {
        unsigned int cpu, this_cpu = get_cpu();
@@ -228,6 +232,13 @@ void cpu_idle_wait(void)
                                cpu_clear(cpu, map);
                }
                cpus_and(map, map, cpu_online_map);
+               /*
+                * We waited 1 sec, if a CPU still did not call idle
+                * it may be because it is in idle and not waking up
+                * because it has nothing to do.
+                * Give all the remaining CPUS a kick.
+                */
+               smp_call_function_mask(map, do_nothing, 0, 0);
        } while (!cpus_empty(map));
 
        set_cpus_allowed(current, tmp);
index 6309b275cb9c176f61133fa7fc2b5585c9063fd4..ab79e1dfa02311bb75c81c44aa137ddd450c5922 100644 (file)
@@ -135,6 +135,10 @@ static void poll_idle (void)
        cpu_relax();
 }
 
+static void do_nothing(void *unused)
+{
+}
+
 void cpu_idle_wait(void)
 {
        unsigned int cpu, this_cpu = get_cpu();
@@ -160,6 +164,13 @@ void cpu_idle_wait(void)
                                cpu_clear(cpu, map);
                }
                cpus_and(map, map, cpu_online_map);
+               /*
+                * We waited 1 sec, if a CPU still did not call idle
+                * it may be because it is in idle and not waking up
+                * because it has nothing to do.
+                * Give all the remaining CPUS a kick.
+                */
+               smp_call_function_mask(map, do_nothing, 0, 0);
        } while (!cpus_empty(map));
 
        set_cpus_allowed(current, tmp);
index 9bdd83022f5f1659588409a2704d6a157f13e23e..20f29e4c1d332ea682e14acbc570ddfa19924ff7 100644 (file)
@@ -658,6 +658,9 @@ void do_notify_resume(struct pt_regs *regs, void *_unused,
        /* deal with pending signal delivery */
        if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs);
+
+       if (thread_info_flags & _TIF_HRTICK_RESCHED)
+               hrtick_resched();
        
        clear_thread_flag(TIF_IRET);
 }
index ab086b0357fc7cc977378a97f3525ad47f105095..38d806467c0f3ee8ad7e1935a7a5e0b18de9cd26 100644 (file)
@@ -480,6 +480,9 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
        /* deal with pending signal delivery */
        if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
                do_signal(regs);
+
+       if (thread_info_flags & _TIF_HRTICK_RESCHED)
+               hrtick_resched();
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
index 500670c93d81d278e0402289803f5881946226b5..aaf4e1291217ef120d98cb3d7d98e55dd0debb79 100644 (file)
@@ -526,7 +526,7 @@ struct create_idle {
        int cpu;
 };
 
-void do_fork_idle(struct work_struct *work)
+static void __cpuinit do_fork_idle(struct work_struct *work)
 {
        struct create_idle *c_idle =
                container_of(work, struct create_idle, work);
index 6fa6cf036c7065bf1ead1ba9f668f07bbab834cd..55771fd7e545c2875c64ad274ed8609f1298931a 100644 (file)
@@ -33,6 +33,19 @@ static void save_stack_address(void *data, unsigned long addr)
                trace->entries[trace->nr_entries++] = addr;
 }
 
+static void save_stack_address_nosched(void *data, unsigned long addr)
+{
+       struct stack_trace *trace = (struct stack_trace *)data;
+       if (in_sched_functions(addr))
+               return;
+       if (trace->skip > 0) {
+               trace->skip--;
+               return;
+       }
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = addr;
+}
+
 static const struct stacktrace_ops save_stack_ops = {
        .warning = save_stack_warning,
        .warning_symbol = save_stack_warning_symbol,
@@ -40,6 +53,13 @@ static const struct stacktrace_ops save_stack_ops = {
        .address = save_stack_address,
 };
 
+static const struct stacktrace_ops save_stack_ops_nosched = {
+       .warning = save_stack_warning,
+       .warning_symbol = save_stack_warning_symbol,
+       .stack = save_stack_stack,
+       .address = save_stack_address_nosched,
+};
+
 /*
  * Save stack-backtrace addresses into a stack_trace buffer.
  */
@@ -50,3 +70,10 @@ void save_stack_trace(struct stack_trace *trace)
                trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
 EXPORT_SYMBOL(save_stack_trace);
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
index c88bbffcaa03ed9485dddc721f6bf611c6982ae2..02d1e1e58e819211fed1813113d945b0baeb0e9d 100644 (file)
@@ -541,6 +541,7 @@ fastcall void do_##name(struct pt_regs * regs, long error_code) \
        info.si_errno = 0; \
        info.si_code = sicode; \
        info.si_addr = (void __user *)siaddr; \
+       trace_hardirqs_fixup(); \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
                                                == NOTIFY_STOP) \
                return; \
index d11525ad81b40676cd99736cf729329993b580ab..cc68b92316cd3813fc049874562f28eed81d9c60 100644 (file)
@@ -635,6 +635,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
        info.si_errno = 0; \
        info.si_code = sicode; \
        info.si_addr = (void __user *)siaddr; \
+       trace_hardirqs_fixup(); \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
                                                        == NOTIFY_STOP) \
                return; \
index c7d19471261dc7050244bd3f0f0883bdac8c3ccb..3c76d194fd2ccef4df106a2f47fe9b02a3057264 100644 (file)
@@ -321,8 +321,13 @@ extern void set_highmem_pages_init(int);
 static void __init set_highmem_pages_init(int bad_ppro)
 {
        int pfn;
-       for (pfn = highstart_pfn; pfn < highend_pfn; pfn++)
-               add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
+       for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) {
+               /*
+                * Holes under sparsemem might not have no mem_map[]:
+                */
+               if (pfn_valid(pfn))
+                       add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
+       }
        totalram_pages += totalhigh_pages;
 }
 #endif /* CONFIG_FLATMEM */
index 2d0eeac7251f7bc3bca55b4b5b990ab5234d6917..c8ab79ef42761f1df1cfffc2b53a205e5a5282ce 100644 (file)
@@ -51,7 +51,7 @@ static int nmi_resume(struct sys_device *dev)
 
 
 static struct sysdev_class oprofile_sysclass = {
-       set_kset_name("oprofile"),
+       .name           = "oprofile",
        .resume         = nmi_resume,
        .suspend        = nmi_suspend,
 };
@@ -380,7 +380,7 @@ static int __init ppro_init(char ** cpu_type)
 
        if (cpu_model == 14)
                *cpu_type = "i386/core";
-       else if (cpu_model == 15)
+       else if (cpu_model == 15 || cpu_model == 23)
                *cpu_type = "i386/core_2";
        else if (cpu_model > 0xd)
                return 0;
index b6af3ea43c7308b3e513272ccb5c9c0f6c224717..79ad1525215016aeafa3526daa8834d453950d40 100644 (file)
@@ -95,7 +95,7 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
  *
  * 0: not available, 1: available
  */
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement = 0;
 
 static void __init xen_vcpu_setup(int cpu)
 {
index 498a0a54a6aa664f27edce4a32d2fb2d37f4c110..9b4da4ae3c7dcce3dc9964adb5ecf2c570017e8a 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/time.h>
 #include <asm/uaccess.h>
 
-static DEFINE_PER_CPU(unsigned long long, blk_trace_cpu_offset) = { 0, };
 static unsigned int blktrace_seq __read_mostly = 1;
 
 /*
@@ -41,7 +40,7 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action,
                const int cpu = smp_processor_id();
 
                t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
-               t->time = cpu_clock(cpu) - per_cpu(blk_trace_cpu_offset, cpu);
+               t->time = ktime_to_ns(ktime_get());
                t->device = bt->dev;
                t->action = action;
                t->pid = pid;
@@ -159,7 +158,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
 
                t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
                t->sequence = ++(*sequence);
-               t->time = cpu_clock(cpu) - per_cpu(blk_trace_cpu_offset, cpu);
+               t->time = ktime_to_ns(ktime_get());
                t->sector = sector;
                t->bytes = bytes;
                t->action = what;
@@ -179,7 +178,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
 EXPORT_SYMBOL_GPL(__blk_add_trace);
 
 static struct dentry *blk_tree_root;
-static struct mutex blk_tree_mutex;
+static DEFINE_MUTEX(blk_tree_mutex);
 static unsigned int root_users;
 
 static inline void blk_remove_root(void)
@@ -505,77 +504,3 @@ void blk_trace_shutdown(struct request_queue *q)
                blk_trace_remove(q);
        }
 }
-
-/*
- * Average offset over two calls to cpu_clock() with a gettimeofday()
- * in the middle
- */
-static void blk_check_time(unsigned long long *t, int this_cpu)
-{
-       unsigned long long a, b;
-       struct timeval tv;
-
-       a = cpu_clock(this_cpu);
-       do_gettimeofday(&tv);
-       b = cpu_clock(this_cpu);
-
-       *t = tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
-       *t -= (a + b) / 2;
-}
-
-/*
- * calibrate our inter-CPU timings
- */
-static void blk_trace_check_cpu_time(void *data)
-{
-       unsigned long long *t;
-       int this_cpu = get_cpu();
-
-       t = &per_cpu(blk_trace_cpu_offset, this_cpu);
-
-       /*
-        * Just call it twice, hopefully the second call will be cache hot
-        * and a little more precise
-        */
-       blk_check_time(t, this_cpu);
-       blk_check_time(t, this_cpu);
-
-       put_cpu();
-}
-
-static void blk_trace_set_ht_offsets(void)
-{
-#if defined(CONFIG_SCHED_SMT)
-       int cpu, i;
-
-       /*
-        * now make sure HT siblings have the same time offset
-        */
-       preempt_disable();
-       for_each_online_cpu(cpu) {
-               unsigned long long *cpu_off, *sibling_off;
-
-               for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu)) {
-                       if (i == cpu)
-                               continue;
-
-                       cpu_off = &per_cpu(blk_trace_cpu_offset, cpu);
-                       sibling_off = &per_cpu(blk_trace_cpu_offset, i);
-                       *sibling_off = *cpu_off;
-               }
-       }
-       preempt_enable();
-#endif
-}
-
-static __init int blk_trace_init(void)
-{
-       mutex_init(&blk_tree_mutex);
-       on_each_cpu(blk_trace_check_cpu_time, NULL, 1, 1);
-       blk_trace_set_ht_offsets();
-
-       return 0;
-}
-
-module_init(blk_trace_init);
-
index 8e181ab3afb9a515f38195b450145002a2be044d..69b0a9d333064c782676a4f84fd79e4006c2c879 100644 (file)
@@ -445,6 +445,15 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
        else
                hdr->dout_resid = rq->data_len;
 
+       /*
+        * If the request generated a negative error number, return it
+        * (providing we aren't already returning an error); if it's
+        * just a protocol response (i.e. non negative), that gets
+        * processed above.
+        */
+       if (!ret && rq->errors < 0)
+               ret = rq->errors;
+
        blk_rq_unmap_user(bio);
        blk_put_request(rq);
 
@@ -837,6 +846,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct bsg_device *bd = file->private_data;
        int __user *uarg = (int __user *) arg;
+       int ret;
 
        switch (cmd) {
                /*
@@ -889,12 +899,12 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                if (rq->next_rq)
                        bidi_bio = rq->next_rq->bio;
                blk_execute_rq(bd->queue, NULL, rq, 0);
-               blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
+               ret = blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
 
                if (copy_to_user(uarg, &hdr, sizeof(hdr)))
                        return -EFAULT;
 
-               return 0;
+               return ret;
        }
        /*
         * block device ioctls
index e452deb803957c1f71d71901ef669a630036363b..f9736fbdab0308f7121694df2faa3ffa68258994 100644 (file)
@@ -185,9 +185,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
 
        eq->ops = &e->ops;
        eq->elevator_type = e;
-       kobject_init(&eq->kobj);
-       kobject_set_name(&eq->kobj, "%s", "iosched");
-       eq->kobj.ktype = &elv_ktype;
+       kobject_init(&eq->kobj, &elv_ktype);
        mutex_init(&eq->sysfs_lock);
 
        eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES,
@@ -931,9 +929,7 @@ int elv_register_queue(struct request_queue *q)
        elevator_t *e = q->elevator;
        int error;
 
-       e->kobj.parent = &q->kobj;
-
-       error = kobject_add(&e->kobj);
+       error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
        if (!error) {
                struct elv_fs_entry *attr = e->elevator_type->elevator_attrs;
                if (attr) {
index f2ac914160d1a96e7258bd86949caef3dcdec6a3..5e4ab4b37d9f4f94e05a8c741693cafd177d28f0 100644 (file)
 #include <linux/buffer_head.h>
 #include <linux/mutex.h>
 
-struct kset block_subsys;
-static DEFINE_MUTEX(block_subsys_lock);
+static DEFINE_MUTEX(block_class_lock);
+#ifndef CONFIG_SYSFS_DEPRECATED
+struct kobject *block_depr;
+#endif
 
 /*
  * Can be deleted altogether. Later.
@@ -37,19 +39,17 @@ static inline int major_to_index(int major)
 }
 
 #ifdef CONFIG_PROC_FS
-
 void blkdev_show(struct seq_file *f, off_t offset)
 {
        struct blk_major_name *dp;
 
        if (offset < BLKDEV_MAJOR_HASH_SIZE) {
-               mutex_lock(&block_subsys_lock);
+               mutex_lock(&block_class_lock);
                for (dp = major_names[offset]; dp; dp = dp->next)
                        seq_printf(f, "%3d %s\n", dp->major, dp->name);
-               mutex_unlock(&block_subsys_lock);
+               mutex_unlock(&block_class_lock);
        }
 }
-
 #endif /* CONFIG_PROC_FS */
 
 int register_blkdev(unsigned int major, const char *name)
@@ -57,7 +57,7 @@ int register_blkdev(unsigned int major, const char *name)
        struct blk_major_name **n, *p;
        int index, ret = 0;
 
-       mutex_lock(&block_subsys_lock);
+       mutex_lock(&block_class_lock);
 
        /* temporary */
        if (major == 0) {
@@ -102,7 +102,7 @@ int register_blkdev(unsigned int major, const char *name)
                kfree(p);
        }
 out:
-       mutex_unlock(&block_subsys_lock);
+       mutex_unlock(&block_class_lock);
        return ret;
 }
 
@@ -114,7 +114,7 @@ void unregister_blkdev(unsigned int major, const char *name)
        struct blk_major_name *p = NULL;
        int index = major_to_index(major);
 
-       mutex_lock(&block_subsys_lock);
+       mutex_lock(&block_class_lock);
        for (n = &major_names[index]; *n; n = &(*n)->next)
                if ((*n)->major == major)
                        break;
@@ -124,7 +124,7 @@ void unregister_blkdev(unsigned int major, const char *name)
                p = *n;
                *n = p->next;
        }
-       mutex_unlock(&block_subsys_lock);
+       mutex_unlock(&block_class_lock);
        kfree(p);
 }
 
@@ -137,29 +137,30 @@ static struct kobj_map *bdev_map;
  * range must be nonzero
  * The hash chain is sorted on range, so that subranges can override.
  */
-void blk_register_region(dev_t dev, unsigned long range, struct module *module,
+void blk_register_region(dev_t devt, unsigned long range, struct module *module,
                         struct kobject *(*probe)(dev_t, int *, void *),
                         int (*lock)(dev_t, void *), void *data)
 {
-       kobj_map(bdev_map, dev, range, module, probe, lock, data);
+       kobj_map(bdev_map, devt, range, module, probe, lock, data);
 }
 
 EXPORT_SYMBOL(blk_register_region);
 
-void blk_unregister_region(dev_t dev, unsigned long range)
+void blk_unregister_region(dev_t devt, unsigned long range)
 {
-       kobj_unmap(bdev_map, dev, range);
+       kobj_unmap(bdev_map, devt, range);
 }
 
 EXPORT_SYMBOL(blk_unregister_region);
 
-static struct kobject *exact_match(dev_t dev, int *part, void *data)
+static struct kobject *exact_match(dev_t devt, int *part, void *data)
 {
        struct gendisk *p = data;
-       return &p->kobj;
+
+       return &p->dev.kobj;
 }
 
-static int exact_lock(dev_t dev, void *data)
+static int exact_lock(dev_t devt, void *data)
 {
        struct gendisk *p = data;
 
@@ -194,8 +195,6 @@ void unlink_gendisk(struct gendisk *disk)
                              disk->minors);
 }
 
-#define to_disk(obj) container_of(obj,struct gendisk,kobj)
-
 /**
  * get_gendisk - get partitioning information for a given device
  * @dev: device to get partitioning information for
@@ -203,10 +202,12 @@ void unlink_gendisk(struct gendisk *disk)
  * This function gets the structure containing partitioning
  * information for the given device @dev.
  */
-struct gendisk *get_gendisk(dev_t dev, int *part)
+struct gendisk *get_gendisk(dev_t devt, int *part)
 {
-       struct kobject *kobj = kobj_lookup(bdev_map, dev, part);
-       return  kobj ? to_disk(kobj) : NULL;
+       struct kobject *kobj = kobj_lookup(bdev_map, devt, part);
+       struct device *dev = kobj_to_dev(kobj);
+
+       return  kobj ? dev_to_disk(dev) : NULL;
 }
 
 /*
@@ -216,13 +217,17 @@ struct gendisk *get_gendisk(dev_t dev, int *part)
  */
 void __init printk_all_partitions(void)
 {
-       int n;
+       struct device *dev;
        struct gendisk *sgp;
+       char buf[BDEVNAME_SIZE];
+       int n;
 
-       mutex_lock(&block_subsys_lock);
+       mutex_lock(&block_class_lock);
        /* For each block device... */
-       list_for_each_entry(sgp, &block_subsys.list, kobj.entry) {
-               char buf[BDEVNAME_SIZE];
+       list_for_each_entry(dev, &block_class.devices, node) {
+               if (dev->type != &disk_type)
+                       continue;
+               sgp = dev_to_disk(dev);
                /*
                 * Don't show empty devices or things that have been surpressed
                 */
@@ -255,38 +260,46 @@ void __init printk_all_partitions(void)
                                sgp->major, n + 1 + sgp->first_minor,
                                (unsigned long long)sgp->part[n]->nr_sects >> 1,
                                disk_name(sgp, n + 1, buf));
-               } /* partition subloop */
-       } /* Block device loop */
+               }
+       }
 
-       mutex_unlock(&block_subsys_lock);
-       return;
+       mutex_unlock(&block_class_lock);
 }
 
 #ifdef CONFIG_PROC_FS
 /* iterator */
 static void *part_start(struct seq_file *part, loff_t *pos)
 {
-       struct list_head *p;
-       loff_t l = *pos;
+       loff_t k = *pos;
+       struct device *dev;
 
-       mutex_lock(&block_subsys_lock);
-       list_for_each(p, &block_subsys.list)
-               if (!l--)
-                       return list_entry(p, struct gendisk, kobj.entry);
+       mutex_lock(&block_class_lock);
+       list_for_each_entry(dev, &block_class.devices, node) {
+               if (dev->type != &disk_type)
+                       continue;
+               if (!k--)
+                       return dev_to_disk(dev);
+       }
        return NULL;
 }
 
 static void *part_next(struct seq_file *part, void *v, loff_t *pos)
 {
-       struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
+       struct gendisk *gp = v;
+       struct device *dev;
        ++*pos;
-       return p==&block_subsys.list ? NULL :
-               list_entry(p, struct gendisk, kobj.entry);
+       list_for_each_entry(dev, &gp->dev.node, node) {
+               if (&dev->node == &block_class.devices)
+                       return NULL;
+               if (dev->type == &disk_type)
+                       return dev_to_disk(dev);
+       }
+       return NULL;
 }
 
 static void part_stop(struct seq_file *part, void *v)
 {
-       mutex_unlock(&block_subsys_lock);
+       mutex_unlock(&block_class_lock);
 }
 
 static int show_partition(struct seq_file *part, void *v)
@@ -295,7 +308,7 @@ static int show_partition(struct seq_file *part, void *v)
        int n;
        char buf[BDEVNAME_SIZE];
 
-       if (&sgp->kobj.entry == block_subsys.list.next)
+       if (&sgp->dev.node == block_class.devices.next)
                seq_puts(part, "major minor  #blocks  name\n\n");
 
        /* Don't show non-partitionable removeable devices or empty devices */
@@ -325,110 +338,81 @@ static int show_partition(struct seq_file *part, void *v)
 }
 
 struct seq_operations partitions_op = {
-       .start =part_start,
-       .next = part_next,
-       .stop = part_stop,
-       .show = show_partition
+       .start  = part_start,
+       .next   = part_next,
+       .stop   = part_stop,
+       .show   = show_partition
 };
 #endif
 
 
 extern int blk_dev_init(void);
 
-static struct kobject *base_probe(dev_t dev, int *part, void *data)
+static struct kobject *base_probe(dev_t devt, int *part, void *data)
 {
-       if (request_module("block-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)
+       if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
                /* Make old-style 2.4 aliases work */
-               request_module("block-major-%d", MAJOR(dev));
+               request_module("block-major-%d", MAJOR(devt));
        return NULL;
 }
 
 static int __init genhd_device_init(void)
 {
-       int err;
-
-       bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
+       class_register(&block_class);
+       bdev_map = kobj_map_init(base_probe, &block_class_lock);
        blk_dev_init();
-       err = subsystem_register(&block_subsys);
-       if (err < 0)
-               printk(KERN_WARNING "%s: subsystem_register error: %d\n",
-                       __FUNCTION__, err);
-       return err;
+
+#ifndef CONFIG_SYSFS_DEPRECATED
+       /* create top-level block dir */
+       block_depr = kobject_create_and_add("block", NULL);
+#endif
+       return 0;
 }
 
 subsys_initcall(genhd_device_init);
 
-
-
-/*
- * kobject & sysfs bindings for block devices
- */
-static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
-                             char *page)
+static ssize_t disk_range_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
 {
-       struct gendisk *disk = to_disk(kobj);
-       struct disk_attribute *disk_attr =
-               container_of(attr,struct disk_attribute,attr);
-       ssize_t ret = -EIO;
+       struct gendisk *disk = dev_to_disk(dev);
 
-       if (disk_attr->show)
-               ret = disk_attr->show(disk,page);
-       return ret;
+       return sprintf(buf, "%d\n", disk->minors);
 }
 
-static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr,
-                              const char *page, size_t count)
+static ssize_t disk_removable_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
 {
-       struct gendisk *disk = to_disk(kobj);
-       struct disk_attribute *disk_attr =
-               container_of(attr,struct disk_attribute,attr);
-       ssize_t ret = 0;
+       struct gendisk *disk = dev_to_disk(dev);
 
-       if (disk_attr->store)
-               ret = disk_attr->store(disk, page, count);
-       return ret;
+       return sprintf(buf, "%d\n",
+                      (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
 }
 
-static struct sysfs_ops disk_sysfs_ops = {
-       .show   = &disk_attr_show,
-       .store  = &disk_attr_store,
-};
-
-static ssize_t disk_uevent_store(struct gendisk * disk,
-                                const char *buf, size_t count)
-{
-       kobject_uevent(&disk->kobj, KOBJ_ADD);
-       return count;
-}
-static ssize_t disk_dev_read(struct gendisk * disk, char *page)
-{
-       dev_t base = MKDEV(disk->major, disk->first_minor); 
-       return print_dev_t(page, base);
-}
-static ssize_t disk_range_read(struct gendisk * disk, char *page)
+static ssize_t disk_size_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
-       return sprintf(page, "%d\n", disk->minors);
-}
-static ssize_t disk_removable_read(struct gendisk * disk, char *page)
-{
-       return sprintf(page, "%d\n",
-                      (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
+       struct gendisk *disk = dev_to_disk(dev);
 
+       return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk));
 }
-static ssize_t disk_size_read(struct gendisk * disk, char *page)
-{
-       return sprintf(page, "%llu\n", (unsigned long long)get_capacity(disk));
-}
-static ssize_t disk_capability_read(struct gendisk *disk, char *page)
+
+static ssize_t disk_capability_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
 {
-       return sprintf(page, "%x\n", disk->flags);
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%x\n", disk->flags);
 }
-static ssize_t disk_stats_read(struct gendisk * disk, char *page)
+
+static ssize_t disk_stat_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
+       struct gendisk *disk = dev_to_disk(dev);
+
        preempt_disable();
        disk_round_stats(disk);
        preempt_enable();
-       return sprintf(page,
+       return sprintf(buf,
                "%8lu %8lu %8llu %8u "
                "%8lu %8lu %8llu %8u "
                "%8u %8u %8u"
@@ -445,40 +429,21 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page)
                jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
                jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
 }
-static struct disk_attribute disk_attr_uevent = {
-       .attr = {.name = "uevent", .mode = S_IWUSR },
-       .store  = disk_uevent_store
-};
-static struct disk_attribute disk_attr_dev = {
-       .attr = {.name = "dev", .mode = S_IRUGO },
-       .show   = disk_dev_read
-};
-static struct disk_attribute disk_attr_range = {
-       .attr = {.name = "range", .mode = S_IRUGO },
-       .show   = disk_range_read
-};
-static struct disk_attribute disk_attr_removable = {
-       .attr = {.name = "removable", .mode = S_IRUGO },
-       .show   = disk_removable_read
-};
-static struct disk_attribute disk_attr_size = {
-       .attr = {.name = "size", .mode = S_IRUGO },
-       .show   = disk_size_read
-};
-static struct disk_attribute disk_attr_capability = {
-       .attr = {.name = "capability", .mode = S_IRUGO },
-       .show   = disk_capability_read
-};
-static struct disk_attribute disk_attr_stat = {
-       .attr = {.name = "stat", .mode = S_IRUGO },
-       .show   = disk_stats_read
-};
 
 #ifdef CONFIG_FAIL_MAKE_REQUEST
+static ssize_t disk_fail_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
+}
 
-static ssize_t disk_fail_store(struct gendisk * disk,
+static ssize_t disk_fail_store(struct device *dev,
+                              struct device_attribute *attr,
                               const char *buf, size_t count)
 {
+       struct gendisk *disk = dev_to_disk(dev);
        int i;
 
        if (count > 0 && sscanf(buf, "%d", &i) > 0) {
@@ -490,136 +455,100 @@ static ssize_t disk_fail_store(struct gendisk * disk,
 
        return count;
 }
-static ssize_t disk_fail_read(struct gendisk * disk, char *page)
-{
-       return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
-}
-static struct disk_attribute disk_attr_fail = {
-       .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
-       .store  = disk_fail_store,
-       .show   = disk_fail_read
-};
 
 #endif
 
-static struct attribute * default_attrs[] = {
-       &disk_attr_uevent.attr,
-       &disk_attr_dev.attr,
-       &disk_attr_range.attr,
-       &disk_attr_removable.attr,
-       &disk_attr_size.attr,
-       &disk_attr_stat.attr,
-       &disk_attr_capability.attr,
+static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
+static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
+static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL);
+static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
+static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+static struct device_attribute dev_attr_fail =
+       __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store);
+#endif
+
+static struct attribute *disk_attrs[] = {
+       &dev_attr_range.attr,
+       &dev_attr_removable.attr,
+       &dev_attr_size.attr,
+       &dev_attr_capability.attr,
+       &dev_attr_stat.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
-       &disk_attr_fail.attr,
+       &dev_attr_fail.attr,
 #endif
-       NULL,
+       NULL
+};
+
+static struct attribute_group disk_attr_group = {
+       .attrs = disk_attrs,
 };
 
-static void disk_release(struct kobject * kobj)
+static struct attribute_group *disk_attr_groups[] = {
+       &disk_attr_group,
+       NULL
+};
+
+static void disk_release(struct device *dev)
 {
-       struct gendisk *disk = to_disk(kobj);
+       struct gendisk *disk = dev_to_disk(dev);
+
        kfree(disk->random);
        kfree(disk->part);
        free_disk_stats(disk);
        kfree(disk);
 }
-
-static struct kobj_type ktype_block = {
-       .release        = disk_release,
-       .sysfs_ops      = &disk_sysfs_ops,
-       .default_attrs  = default_attrs,
+struct class block_class = {
+       .name           = "block",
 };
 
-extern struct kobj_type ktype_part;
-
-static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
-{
-       struct kobj_type *ktype = get_ktype(kobj);
-
-       return ((ktype == &ktype_block) || (ktype == &ktype_part));
-}
-
-static int block_uevent(struct kset *kset, struct kobject *kobj,
-                       struct kobj_uevent_env *env)
-{
-       struct kobj_type *ktype = get_ktype(kobj);
-       struct device *physdev;
-       struct gendisk *disk;
-       struct hd_struct *part;
-
-       if (ktype == &ktype_block) {
-               disk = container_of(kobj, struct gendisk, kobj);
-               add_uevent_var(env, "MINOR=%u", disk->first_minor);
-       } else if (ktype == &ktype_part) {
-               disk = container_of(kobj->parent, struct gendisk, kobj);
-               part = container_of(kobj, struct hd_struct, kobj);
-               add_uevent_var(env, "MINOR=%u",
-                              disk->first_minor + part->partno);
-       } else
-               return 0;
-
-       add_uevent_var(env, "MAJOR=%u", disk->major);
-
-       /* add physical device, backing this device  */
-       physdev = disk->driverfs_dev;
-       if (physdev) {
-               char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
-
-               add_uevent_var(env, "PHYSDEVPATH=%s", path);
-               kfree(path);
-
-               if (physdev->bus)
-                       add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);
-
-               if (physdev->driver)
-                       add_uevent_var(env, physdev->driver->name);
-       }
-
-       return 0;
-}
-
-static struct kset_uevent_ops block_uevent_ops = {
-       .filter         = block_uevent_filter,
-       .uevent         = block_uevent,
+struct device_type disk_type = {
+       .name           = "disk",
+       .groups         = disk_attr_groups,
+       .release        = disk_release,
 };
 
-decl_subsys(block, &ktype_block, &block_uevent_ops);
-
 /*
  * aggregate disk stat collector.  Uses the same stats that the sysfs
  * entries do, above, but makes them available through one seq_file.
- * Watching a few disks may be efficient through sysfs, but watching
- * all of them will be more efficient through this interface.
  *
  * The output looks suspiciously like /proc/partitions with a bunch of
  * extra fields.
  */
 
-/* iterator */
 static void *diskstats_start(struct seq_file *part, loff_t *pos)
 {
        loff_t k = *pos;
-       struct list_head *p;
+       struct device *dev;
 
-       mutex_lock(&block_subsys_lock);
-       list_for_each(p, &block_subsys.list)
+       mutex_lock(&block_class_lock);
+       list_for_each_entry(dev, &block_class.devices, node) {
+               if (dev->type != &disk_type)
+                       continue;
                if (!k--)
-                       return list_entry(p, struct gendisk, kobj.entry);
+                       return dev_to_disk(dev);
+       }
        return NULL;
 }
 
 static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
 {
-       struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
+       struct gendisk *gp = v;
+       struct device *dev;
+
        ++*pos;
-       return p==&block_subsys.list ? NULL :
-               list_entry(p, struct gendisk, kobj.entry);
+       list_for_each_entry(dev, &gp->dev.node, node) {
+               if (&dev->node == &block_class.devices)
+                       return NULL;
+               if (dev->type == &disk_type)
+                       return dev_to_disk(dev);
+       }
+       return NULL;
 }
 
 static void diskstats_stop(struct seq_file *part, void *v)
 {
-       mutex_unlock(&block_subsys_lock);
+       mutex_unlock(&block_class_lock);
 }
 
 static int diskstats_show(struct seq_file *s, void *v)
@@ -629,7 +558,7 @@ static int diskstats_show(struct seq_file *s, void *v)
        int n = 0;
 
        /*
-       if (&sgp->kobj.entry == block_subsys.kset.list.next)
+       if (&gp->dev.kobj.entry == block_class.devices.next)
                seq_puts(s,     "major minor name"
                                "     rio rmerge rsect ruse wio wmerge "
                                "wsect wuse running use aveq"
@@ -683,7 +612,7 @@ static void media_change_notify_thread(struct work_struct *work)
         * set enviroment vars to indicate which event this is for
         * so that user space will know to go check the media status.
         */
-       kobject_uevent_env(&gd->kobj, KOBJ_CHANGE, envp);
+       kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp);
        put_device(gd->driverfs_dev);
 }
 
@@ -694,6 +623,25 @@ void genhd_media_change_notify(struct gendisk *disk)
 }
 EXPORT_SYMBOL_GPL(genhd_media_change_notify);
 
+dev_t blk_lookup_devt(const char *name)
+{
+       struct device *dev;
+       dev_t devt = MKDEV(0, 0);
+
+       mutex_lock(&block_class_lock);
+       list_for_each_entry(dev, &block_class.devices, node) {
+               if (strcmp(dev->bus_id, name) == 0) {
+                       devt = dev->devt;
+                       break;
+               }
+       }
+       mutex_unlock(&block_class_lock);
+
+       return devt;
+}
+
+EXPORT_SYMBOL(blk_lookup_devt);
+
 struct gendisk *alloc_disk(int minors)
 {
        return alloc_disk_node(minors, -1);
@@ -721,9 +669,10 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
                        }
                }
                disk->minors = minors;
-               kobj_set_kset_s(disk,block_subsys);
-               kobject_init(&disk->kobj);
                rand_initialize_disk(disk);
+               disk->dev.class = &block_class;
+               disk->dev.type = &disk_type;
+               device_initialize(&disk->dev);
                INIT_WORK(&disk->async_notify,
                        media_change_notify_thread);
        }
@@ -743,7 +692,7 @@ struct kobject *get_disk(struct gendisk *disk)
        owner = disk->fops->owner;
        if (owner && !try_module_get(owner))
                return NULL;
-       kobj = kobject_get(&disk->kobj);
+       kobj = kobject_get(&disk->dev.kobj);
        if (kobj == NULL) {
                module_put(owner);
                return NULL;
@@ -757,7 +706,7 @@ EXPORT_SYMBOL(get_disk);
 void put_disk(struct gendisk *disk)
 {
        if (disk)
-               kobject_put(&disk->kobj);
+               kobject_put(&disk->dev.kobj);
 }
 
 EXPORT_SYMBOL(put_disk);
index 8b919940b2abdb37119cd9927b6f45dbec66aa31..3d0422f48453c0019ad8d1de25eaa4643bb379fe 100644 (file)
@@ -759,6 +759,30 @@ void blk_queue_dma_alignment(struct request_queue *q, int mask)
 
 EXPORT_SYMBOL(blk_queue_dma_alignment);
 
+/**
+ * blk_queue_update_dma_alignment - update dma length and memory alignment
+ * @q:     the request queue for the device
+ * @mask:  alignment mask
+ *
+ * description:
+ *    update required memory and length aligment for direct dma transactions.
+ *    If the requested alignment is larger than the current alignment, then
+ *    the current queue alignment is updated to the new value, otherwise it
+ *    is left alone.  The design of this is to allow multiple objects
+ *    (driver, device, transport etc) to set their respective
+ *    alignments without having them interfere.
+ *
+ **/
+void blk_queue_update_dma_alignment(struct request_queue *q, int mask)
+{
+       BUG_ON(mask > PAGE_SIZE);
+
+       if (mask > q->dma_alignment)
+               q->dma_alignment = mask;
+}
+
+EXPORT_SYMBOL(blk_queue_update_dma_alignment);
+
 /**
  * blk_queue_find_tag - find a request by its tag and queue
  * @q:  The request queue for the device
@@ -1862,9 +1886,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 
        init_timer(&q->unplug_timer);
 
-       kobject_set_name(&q->kobj, "%s", "queue");
-       q->kobj.ktype = &queue_ktype;
-       kobject_init(&q->kobj);
+       kobject_init(&q->kobj, &queue_ktype);
 
        mutex_init(&q->sysfs_lock);
 
@@ -4182,9 +4204,8 @@ int blk_register_queue(struct gendisk *disk)
        if (!q || !q->request_fn)
                return -ENXIO;
 
-       q->kobj.parent = kobject_get(&disk->kobj);
-
-       ret = kobject_add(&q->kobj);
+       ret = kobject_add(&q->kobj, kobject_get(&disk->dev.kobj),
+                         "%s", "queue");
        if (ret < 0)
                return ret;
 
@@ -4209,6 +4230,6 @@ void blk_unregister_queue(struct gendisk *disk)
 
                kobject_uevent(&q->kobj, KOBJ_REMOVE);
                kobject_del(&q->kobj);
-               kobject_put(&disk->kobj);
+               kobject_put(&disk->dev.kobj);
        }
 }
index 083d2e1dfc21640e67f6e6f85671323b2f954a97..c3166a1a5bb6da630f7861581b96a6a5f5a19073 100644 (file)
@@ -24,10 +24,6 @@ config CRYPTO_ALGAPI
        help
          This option provides the API for cryptographic algorithms.
 
-config CRYPTO_ABLKCIPHER
-       tristate
-       select CRYPTO_BLKCIPHER
-
 config CRYPTO_AEAD
        tristate
        select CRYPTO_ALGAPI
@@ -36,6 +32,15 @@ config CRYPTO_BLKCIPHER
        tristate
        select CRYPTO_ALGAPI
 
+config CRYPTO_SEQIV
+       tristate "Sequence Number IV Generator"
+       select CRYPTO_AEAD
+       select CRYPTO_BLKCIPHER
+       help
+         This IV generator generates an IV based on a sequence number by
+         xoring it with a salt.  This algorithm is mainly useful for CTR
+         and similar modes.
+
 config CRYPTO_HASH
        tristate
        select CRYPTO_ALGAPI
@@ -91,7 +96,7 @@ config CRYPTO_SHA1
          SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
 config CRYPTO_SHA256
-       tristate "SHA256 digest algorithm"
+       tristate "SHA224 and SHA256 digest algorithm"
        select CRYPTO_ALGAPI
        help
          SHA256 secure hash standard (DFIPS 180-2).
@@ -99,6 +104,9 @@ config CRYPTO_SHA256
          This version of SHA implements a 256 bit hash with 128 bits of
          security against collision attacks.
 
+          This code also includes SHA-224, a 224 bit hash with 112 bits
+          of security against collision attacks.
+
 config CRYPTO_SHA512
        tristate "SHA384 and SHA512 digest algorithms"
        select CRYPTO_ALGAPI
@@ -195,9 +203,34 @@ config CRYPTO_XTS
          key size 256, 384 or 512 bits. This implementation currently
          can't handle a sectorsize which is not a multiple of 16 bytes.
 
+config CRYPTO_CTR
+       tristate "CTR support"
+       select CRYPTO_BLKCIPHER
+       select CRYPTO_SEQIV
+       select CRYPTO_MANAGER
+       help
+         CTR: Counter mode
+         This block cipher algorithm is required for IPSec.
+
+config CRYPTO_GCM
+       tristate "GCM/GMAC support"
+       select CRYPTO_CTR
+       select CRYPTO_AEAD
+       select CRYPTO_GF128MUL
+       help
+         Support for Galois/Counter Mode (GCM) and Galois Message
+         Authentication Code (GMAC). Required for IPSec.
+
+config CRYPTO_CCM
+       tristate "CCM support"
+       select CRYPTO_CTR
+       select CRYPTO_AEAD
+       help
+         Support for Counter with CBC MAC. Required for IPsec.
+
 config CRYPTO_CRYPTD
        tristate "Software async crypto daemon"
-       select CRYPTO_ABLKCIPHER
+       select CRYPTO_BLKCIPHER
        select CRYPTO_MANAGER
        help
          This is a generic software asynchronous crypto daemon that
@@ -320,6 +353,7 @@ config CRYPTO_AES_586
        tristate "AES cipher algorithms (i586)"
        depends on (X86 || UML_X86) && !64BIT
        select CRYPTO_ALGAPI
+       select CRYPTO_AES
        help
          AES cipher algorithms (FIPS-197). AES uses the Rijndael 
          algorithm.
@@ -341,6 +375,7 @@ config CRYPTO_AES_X86_64
        tristate "AES cipher algorithms (x86_64)"
        depends on (X86 || UML_X86) && 64BIT
        select CRYPTO_ALGAPI
+       select CRYPTO_AES
        help
          AES cipher algorithms (FIPS-197). AES uses the Rijndael 
          algorithm.
@@ -441,6 +476,46 @@ config CRYPTO_SEED
          See also:
          <http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp>
 
+config CRYPTO_SALSA20
+       tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       select CRYPTO_BLKCIPHER
+       help
+         Salsa20 stream cipher algorithm.
+
+         Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT
+         Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/>
+
+         The Salsa20 stream cipher algorithm is designed by Daniel J.
+         Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
+
+config CRYPTO_SALSA20_586
+       tristate "Salsa20 stream cipher algorithm (i586) (EXPERIMENTAL)"
+       depends on (X86 || UML_X86) && !64BIT
+       depends on EXPERIMENTAL
+       select CRYPTO_BLKCIPHER
+       help
+         Salsa20 stream cipher algorithm.
+
+         Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT
+         Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/>
+
+         The Salsa20 stream cipher algorithm is designed by Daniel J.
+         Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
+
+config CRYPTO_SALSA20_X86_64
+       tristate "Salsa20 stream cipher algorithm (x86_64) (EXPERIMENTAL)"
+       depends on (X86 || UML_X86) && 64BIT
+       depends on EXPERIMENTAL
+       select CRYPTO_BLKCIPHER
+       help
+         Salsa20 stream cipher algorithm.
+
+         Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT
+         Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/>
+
+         The Salsa20 stream cipher algorithm is designed by Daniel J.
+         Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
 
 config CRYPTO_DEFLATE
        tristate "Deflate compression algorithm"
@@ -491,6 +566,7 @@ config CRYPTO_TEST
        tristate "Testing module"
        depends on m
        select CRYPTO_ALGAPI
+       select CRYPTO_AEAD
        help
          Quick & dirty crypto test module.
 
@@ -498,10 +574,19 @@ config CRYPTO_AUTHENC
        tristate "Authenc support"
        select CRYPTO_AEAD
        select CRYPTO_MANAGER
+       select CRYPTO_HASH
        help
          Authenc: Combined mode wrapper for IPsec.
          This is required for IPSec.
 
+config CRYPTO_LZO
+       tristate "LZO compression algorithm"
+       select CRYPTO_ALGAPI
+       select LZO_COMPRESS
+       select LZO_DECOMPRESS
+       help
+         This is the LZO algorithm.
+
 source "drivers/crypto/Kconfig"
 
 endif  # if CRYPTO
index 43c2a0dc99365faf07d960dfe6ffbf4cc1c816b1..48c7583799541045751655aa6de6af80fed70ae9 100644 (file)
@@ -8,9 +8,14 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o
 crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y)
 obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
 
-obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o
 obj-$(CONFIG_CRYPTO_AEAD) += aead.o
-obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
+
+crypto_blkcipher-objs := ablkcipher.o
+crypto_blkcipher-objs += blkcipher.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
+obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
 
 crypto_hash-objs := hash.o
 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
@@ -32,6 +37,9 @@ obj-$(CONFIG_CRYPTO_CBC) += cbc.o
 obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_XTS) += xts.o
+obj-$(CONFIG_CRYPTO_CTR) += ctr.o
+obj-$(CONFIG_CRYPTO_GCM) += gcm.o
+obj-$(CONFIG_CRYPTO_CCM) += ccm.o
 obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
 obj-$(CONFIG_CRYPTO_DES) += des_generic.o
 obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
@@ -48,10 +56,12 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
 obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_SEED) += seed.o
+obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
+obj-$(CONFIG_CRYPTO_LZO) += lzo.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
index 2731acb86e7d53755bbfd3d7cdc98926844ca887..3bcb099b4a85bd779d752f7d42868c48cb07d87a 100644 (file)
  *
  */
 
-#include <crypto/algapi.h>
-#include <linux/errno.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 
+#include "internal.h"
+
 static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key,
                            unsigned int keylen)
 {
@@ -66,6 +70,16 @@ static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type,
        return alg->cra_ctxsize;
 }
 
+int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req)
+{
+       return crypto_ablkcipher_encrypt(&req->creq);
+}
+
+int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req)
+{
+       return crypto_ablkcipher_decrypt(&req->creq);
+}
+
 static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
                                      u32 mask)
 {
@@ -78,6 +92,11 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
        crt->setkey = setkey;
        crt->encrypt = alg->encrypt;
        crt->decrypt = alg->decrypt;
+       if (!alg->ivsize) {
+               crt->givencrypt = skcipher_null_givencrypt;
+               crt->givdecrypt = skcipher_null_givdecrypt;
+       }
+       crt->base = __crypto_ablkcipher_cast(tfm);
        crt->ivsize = alg->ivsize;
 
        return 0;
@@ -90,10 +109,13 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
        struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
 
        seq_printf(m, "type         : ablkcipher\n");
+       seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+                                            "yes" : "no");
        seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
        seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
        seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
        seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
+       seq_printf(m, "geniv        : %s\n", ablkcipher->geniv ?: "<default>");
 }
 
 const struct crypto_type crypto_ablkcipher_type = {
@@ -105,5 +127,220 @@ const struct crypto_type crypto_ablkcipher_type = {
 };
 EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);
 
+static int no_givdecrypt(struct skcipher_givcrypt_request *req)
+{
+       return -ENOSYS;
+}
+
+static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type,
+                                     u32 mask)
+{
+       struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher;
+       struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
+
+       if (alg->ivsize > PAGE_SIZE / 8)
+               return -EINVAL;
+
+       crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
+                     alg->setkey : setkey;
+       crt->encrypt = alg->encrypt;
+       crt->decrypt = alg->decrypt;
+       crt->givencrypt = alg->givencrypt;
+       crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt;
+       crt->base = __crypto_ablkcipher_cast(tfm);
+       crt->ivsize = alg->ivsize;
+
+       return 0;
+}
+
+static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
+       __attribute__ ((unused));
+static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
+{
+       struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
+
+       seq_printf(m, "type         : givcipher\n");
+       seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+                                            "yes" : "no");
+       seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+       seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
+       seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
+       seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
+       seq_printf(m, "geniv        : %s\n", ablkcipher->geniv ?: "<built-in>");
+}
+
+const struct crypto_type crypto_givcipher_type = {
+       .ctxsize = crypto_ablkcipher_ctxsize,
+       .init = crypto_init_givcipher_ops,
+#ifdef CONFIG_PROC_FS
+       .show = crypto_givcipher_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_givcipher_type);
+
+const char *crypto_default_geniv(const struct crypto_alg *alg)
+{
+       return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv";
+}
+
+static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
+{
+       struct rtattr *tb[3];
+       struct {
+               struct rtattr attr;
+               struct crypto_attr_type data;
+       } ptype;
+       struct {
+               struct rtattr attr;
+               struct crypto_attr_alg data;
+       } palg;
+       struct crypto_template *tmpl;
+       struct crypto_instance *inst;
+       struct crypto_alg *larval;
+       const char *geniv;
+       int err;
+
+       larval = crypto_larval_lookup(alg->cra_driver_name,
+                                     CRYPTO_ALG_TYPE_GIVCIPHER,
+                                     CRYPTO_ALG_TYPE_MASK);
+       err = PTR_ERR(larval);
+       if (IS_ERR(larval))
+               goto out;
+
+       err = -EAGAIN;
+       if (!crypto_is_larval(larval))
+               goto drop_larval;
+
+       ptype.attr.rta_len = sizeof(ptype);
+       ptype.attr.rta_type = CRYPTOA_TYPE;
+       ptype.data.type = type | CRYPTO_ALG_GENIV;
+       /* GENIV tells the template that we're making a default geniv. */
+       ptype.data.mask = mask | CRYPTO_ALG_GENIV;
+       tb[0] = &ptype.attr;
+
+       palg.attr.rta_len = sizeof(palg);
+       palg.attr.rta_type = CRYPTOA_ALG;
+       /* Must use the exact name to locate ourselves. */
+       memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME);
+       tb[1] = &palg.attr;
+
+       tb[2] = NULL;
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_BLKCIPHER)
+               geniv = alg->cra_blkcipher.geniv;
+       else
+               geniv = alg->cra_ablkcipher.geniv;
+
+       if (!geniv)
+               geniv = crypto_default_geniv(alg);
+
+       tmpl = crypto_lookup_template(geniv);
+       err = -ENOENT;
+       if (!tmpl)
+               goto kill_larval;
+
+       inst = tmpl->alloc(tb);
+       err = PTR_ERR(inst);
+       if (IS_ERR(inst))
+               goto put_tmpl;
+
+       if ((err = crypto_register_instance(tmpl, inst))) {
+               tmpl->free(inst);
+               goto put_tmpl;
+       }
+
+       /* Redo the lookup to use the instance we just registered. */
+       err = -EAGAIN;
+
+put_tmpl:
+       crypto_tmpl_put(tmpl);
+kill_larval:
+       crypto_larval_kill(larval);
+drop_larval:
+       crypto_mod_put(larval);
+out:
+       crypto_mod_put(alg);
+       return err;
+}
+
+static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type,
+                                                u32 mask)
+{
+       struct crypto_alg *alg;
+
+       alg = crypto_alg_mod_lookup(name, type, mask);
+       if (IS_ERR(alg))
+               return alg;
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_GIVCIPHER)
+               return alg;
+
+       if (!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+             CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+                                         alg->cra_ablkcipher.ivsize))
+               return alg;
+
+       return ERR_PTR(crypto_givcipher_default(alg, type, mask));
+}
+
+int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
+                        u32 type, u32 mask)
+{
+       struct crypto_alg *alg;
+       int err;
+
+       type = crypto_skcipher_type(type);
+       mask = crypto_skcipher_mask(mask);
+
+       alg = crypto_lookup_skcipher(name, type, mask);
+       if (IS_ERR(alg))
+               return PTR_ERR(alg);
+
+       err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+       crypto_mod_put(alg);
+       return err;
+}
+EXPORT_SYMBOL_GPL(crypto_grab_skcipher);
+
+struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name,
+                                                 u32 type, u32 mask)
+{
+       struct crypto_tfm *tfm;
+       int err;
+
+       type = crypto_skcipher_type(type);
+       mask = crypto_skcipher_mask(mask);
+
+       for (;;) {
+               struct crypto_alg *alg;
+
+               alg = crypto_lookup_skcipher(alg_name, type, mask);
+               if (IS_ERR(alg)) {
+                       err = PTR_ERR(alg);
+                       goto err;
+               }
+
+               tfm = __crypto_alloc_tfm(alg, type, mask);
+               if (!IS_ERR(tfm))
+                       return __crypto_ablkcipher_cast(tfm);
+
+               crypto_mod_put(alg);
+               err = PTR_ERR(tfm);
+
+err:
+               if (err != -EAGAIN)
+                       break;
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+       }
+
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous block chaining cipher type");
index 84a3501fb478bf8bb9d12c2586e925c59eb46135..3a6f3f52c7c71911ac6cd7506493fb24ccd8eb50 100644 (file)
  *
  */
 
-#include <crypto/algapi.h>
-#include <linux/errno.h>
+#include <crypto/internal/aead.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 
+#include "internal.h"
+
 static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
                            unsigned int keylen)
 {
@@ -53,25 +56,54 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
        return aead->setkey(tfm, key, keylen);
 }
 
+int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+       struct aead_tfm *crt = crypto_aead_crt(tfm);
+       int err;
+
+       if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+               return -EINVAL;
+
+       if (crypto_aead_alg(tfm)->setauthsize) {
+               err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize);
+               if (err)
+                       return err;
+       }
+
+       crypto_aead_crt(crt->base)->authsize = authsize;
+       crt->authsize = authsize;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
+
 static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type,
                                        u32 mask)
 {
        return alg->cra_ctxsize;
 }
 
+static int no_givcrypt(struct aead_givcrypt_request *req)
+{
+       return -ENOSYS;
+}
+
 static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 {
        struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
        struct aead_tfm *crt = &tfm->crt_aead;
 
-       if (max(alg->authsize, alg->ivsize) > PAGE_SIZE / 8)
+       if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
                return -EINVAL;
 
-       crt->setkey = setkey;
+       crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
+                     alg->setkey : setkey;
        crt->encrypt = alg->encrypt;
        crt->decrypt = alg->decrypt;
+       crt->givencrypt = alg->givencrypt ?: no_givcrypt;
+       crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;
+       crt->base = __crypto_aead_cast(tfm);
        crt->ivsize = alg->ivsize;
-       crt->authsize = alg->authsize;
+       crt->authsize = alg->maxauthsize;
 
        return 0;
 }
@@ -83,9 +115,12 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
        struct aead_alg *aead = &alg->cra_aead;
 
        seq_printf(m, "type         : aead\n");
+       seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+                                            "yes" : "no");
        seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
        seq_printf(m, "ivsize       : %u\n", aead->ivsize);
-       seq_printf(m, "authsize     : %u\n", aead->authsize);
+       seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
+       seq_printf(m, "geniv        : %s\n", aead->geniv ?: "<built-in>");
 }
 
 const struct crypto_type crypto_aead_type = {
@@ -97,5 +132,358 @@ const struct crypto_type crypto_aead_type = {
 };
 EXPORT_SYMBOL_GPL(crypto_aead_type);
 
+static int aead_null_givencrypt(struct aead_givcrypt_request *req)
+{
+       return crypto_aead_encrypt(&req->areq);
+}
+
+static int aead_null_givdecrypt(struct aead_givcrypt_request *req)
+{
+       return crypto_aead_decrypt(&req->areq);
+}
+
+static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+       struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
+       struct aead_tfm *crt = &tfm->crt_aead;
+
+       if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
+               return -EINVAL;
+
+       crt->setkey = setkey;
+       crt->encrypt = alg->encrypt;
+       crt->decrypt = alg->decrypt;
+       if (!alg->ivsize) {
+               crt->givencrypt = aead_null_givencrypt;
+               crt->givdecrypt = aead_null_givdecrypt;
+       }
+       crt->base = __crypto_aead_cast(tfm);
+       crt->ivsize = alg->ivsize;
+       crt->authsize = alg->maxauthsize;
+
+       return 0;
+}
+
+static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
+       __attribute__ ((unused));
+static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
+{
+       struct aead_alg *aead = &alg->cra_aead;
+
+       seq_printf(m, "type         : nivaead\n");
+       seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+                                            "yes" : "no");
+       seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+       seq_printf(m, "ivsize       : %u\n", aead->ivsize);
+       seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
+       seq_printf(m, "geniv        : %s\n", aead->geniv);
+}
+
+const struct crypto_type crypto_nivaead_type = {
+       .ctxsize = crypto_aead_ctxsize,
+       .init = crypto_init_nivaead_ops,
+#ifdef CONFIG_PROC_FS
+       .show = crypto_nivaead_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_nivaead_type);
+
+static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn,
+                              const char *name, u32 type, u32 mask)
+{
+       struct crypto_alg *alg;
+       int err;
+
+       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       type |= CRYPTO_ALG_TYPE_AEAD;
+       mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV;
+
+       alg = crypto_alg_mod_lookup(name, type, mask);
+       if (IS_ERR(alg))
+               return PTR_ERR(alg);
+
+       err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+       crypto_mod_put(alg);
+       return err;
+}
+
+struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
+                                        struct rtattr **tb, u32 type,
+                                        u32 mask)
+{
+       const char *name;
+       struct crypto_aead_spawn *spawn;
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) &
+           algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(name);
+       if (IS_ERR(name))
+               return ERR_PTR(err);
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       spawn = crypto_instance_ctx(inst);
+
+       /* Ignore async algorithms if necessary. */
+       mask |= crypto_requires_sync(algt->type, algt->mask);
+
+       crypto_set_aead_spawn(spawn, inst);
+       err = crypto_grab_nivaead(spawn, name, type, mask);
+       if (err)
+               goto err_free_inst;
+
+       alg = crypto_aead_spawn_alg(spawn);
+
+       err = -EINVAL;
+       if (!alg->cra_aead.ivsize)
+               goto err_drop_alg;
+
+       /*
+        * This is only true if we're constructing an algorithm with its
+        * default IV generator.  For the default generator we elide the
+        * template name and double-check the IV generator.
+        */
+       if (algt->mask & CRYPTO_ALG_GENIV) {
+               if (strcmp(tmpl->name, alg->cra_aead.geniv))
+                       goto err_drop_alg;
+
+               memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+               memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
+                      CRYPTO_MAX_ALG_NAME);
+       } else {
+               err = -ENAMETOOLONG;
+               if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+                            "%s(%s)", tmpl->name, alg->cra_name) >=
+                   CRYPTO_MAX_ALG_NAME)
+                       goto err_drop_alg;
+               if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                            "%s(%s)", tmpl->name, alg->cra_driver_name) >=
+                   CRYPTO_MAX_ALG_NAME)
+                       goto err_drop_alg;
+       }
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV;
+       inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = alg->cra_blocksize;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = &crypto_aead_type;
+
+       inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
+       inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
+       inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
+
+       inst->alg.cra_aead.setkey = alg->cra_aead.setkey;
+       inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
+       inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt;
+       inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt;
+
+out:
+       return inst;
+
+err_drop_alg:
+       crypto_drop_aead(spawn);
+err_free_inst:
+       kfree(inst);
+       inst = ERR_PTR(err);
+       goto out;
+}
+EXPORT_SYMBOL_GPL(aead_geniv_alloc);
+
+void aead_geniv_free(struct crypto_instance *inst)
+{
+       crypto_drop_aead(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+EXPORT_SYMBOL_GPL(aead_geniv_free);
+
+int aead_geniv_init(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct crypto_aead *aead;
+
+       aead = crypto_spawn_aead(crypto_instance_ctx(inst));
+       if (IS_ERR(aead))
+               return PTR_ERR(aead);
+
+       tfm->crt_aead.base = aead;
+       tfm->crt_aead.reqsize += crypto_aead_reqsize(aead);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(aead_geniv_init);
+
+void aead_geniv_exit(struct crypto_tfm *tfm)
+{
+       crypto_free_aead(tfm->crt_aead.base);
+}
+EXPORT_SYMBOL_GPL(aead_geniv_exit);
+
+static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask)
+{
+       struct rtattr *tb[3];
+       struct {
+               struct rtattr attr;
+               struct crypto_attr_type data;
+       } ptype;
+       struct {
+               struct rtattr attr;
+               struct crypto_attr_alg data;
+       } palg;
+       struct crypto_template *tmpl;
+       struct crypto_instance *inst;
+       struct crypto_alg *larval;
+       const char *geniv;
+       int err;
+
+       larval = crypto_larval_lookup(alg->cra_driver_name,
+                                     CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV,
+                                     CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       err = PTR_ERR(larval);
+       if (IS_ERR(larval))
+               goto out;
+
+       err = -EAGAIN;
+       if (!crypto_is_larval(larval))
+               goto drop_larval;
+
+       ptype.attr.rta_len = sizeof(ptype);
+       ptype.attr.rta_type = CRYPTOA_TYPE;
+       ptype.data.type = type | CRYPTO_ALG_GENIV;
+       /* GENIV tells the template that we're making a default geniv. */
+       ptype.data.mask = mask | CRYPTO_ALG_GENIV;
+       tb[0] = &ptype.attr;
+
+       palg.attr.rta_len = sizeof(palg);
+       palg.attr.rta_type = CRYPTOA_ALG;
+       /* Must use the exact name to locate ourselves. */
+       memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME);
+       tb[1] = &palg.attr;
+
+       tb[2] = NULL;
+
+       geniv = alg->cra_aead.geniv;
+
+       tmpl = crypto_lookup_template(geniv);
+       err = -ENOENT;
+       if (!tmpl)
+               goto kill_larval;
+
+       inst = tmpl->alloc(tb);
+       err = PTR_ERR(inst);
+       if (IS_ERR(inst))
+               goto put_tmpl;
+
+       if ((err = crypto_register_instance(tmpl, inst))) {
+               tmpl->free(inst);
+               goto put_tmpl;
+       }
+
+       /* Redo the lookup to use the instance we just registered. */
+       err = -EAGAIN;
+
+put_tmpl:
+       crypto_tmpl_put(tmpl);
+kill_larval:
+       crypto_larval_kill(larval);
+drop_larval:
+       crypto_mod_put(larval);
+out:
+       crypto_mod_put(alg);
+       return err;
+}
+
+static struct crypto_alg *crypto_lookup_aead(const char *name, u32 type,
+                                            u32 mask)
+{
+       struct crypto_alg *alg;
+
+       alg = crypto_alg_mod_lookup(name, type, mask);
+       if (IS_ERR(alg))
+               return alg;
+
+       if (alg->cra_type == &crypto_aead_type)
+               return alg;
+
+       if (!alg->cra_aead.ivsize)
+               return alg;
+
+       return ERR_PTR(crypto_nivaead_default(alg, type, mask));
+}
+
+int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
+                    u32 type, u32 mask)
+{
+       struct crypto_alg *alg;
+       int err;
+
+       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       type |= CRYPTO_ALG_TYPE_AEAD;
+       mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       mask |= CRYPTO_ALG_TYPE_MASK;
+
+       alg = crypto_lookup_aead(name, type, mask);
+       if (IS_ERR(alg))
+               return PTR_ERR(alg);
+
+       err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+       crypto_mod_put(alg);
+       return err;
+}
+EXPORT_SYMBOL_GPL(crypto_grab_aead);
+
+struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
+{
+       struct crypto_tfm *tfm;
+       int err;
+
+       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       type |= CRYPTO_ALG_TYPE_AEAD;
+       mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       mask |= CRYPTO_ALG_TYPE_MASK;
+
+       for (;;) {
+               struct crypto_alg *alg;
+
+               alg = crypto_lookup_aead(alg_name, type, mask);
+               if (IS_ERR(alg)) {
+                       err = PTR_ERR(alg);
+                       goto err;
+               }
+
+               tfm = __crypto_alloc_tfm(alg, type, mask);
+               if (!IS_ERR(tfm))
+                       return __crypto_aead_cast(tfm);
+
+               crypto_mod_put(alg);
+               err = PTR_ERR(tfm);
+
+err:
+               if (err != -EAGAIN)
+                       break;
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+       }
+
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_aead);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
index 9401dca85e87c9a5c3908ef6cfbd78fa9a20db89..cf30af74480f4519b50e3b1fcf0e9f7ebb21ac34 100644 (file)
  * ---------------------------------------------------------------------------
  */
 
-/* Some changes from the Gladman version:
-    s/RIJNDAEL(e_key)/E_KEY/g
-    s/RIJNDAEL(d_key)/D_KEY/g
-*/
-
+#include <crypto/aes.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/crypto.h>
 #include <asm/byteorder.h>
 
-#define AES_MIN_KEY_SIZE       16
-#define AES_MAX_KEY_SIZE       32
-
-#define AES_BLOCK_SIZE         16
-
-/*
- * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) 
- */
-static inline u8
-byte(const u32 x, const unsigned n)
+static inline u8 byte(const u32 x, const unsigned n)
 {
        return x >> (n << 3);
 }
 
-struct aes_ctx {
-       int key_length;
-       u32 buf[120];
-};
-
-#define E_KEY (&ctx->buf[0])
-#define D_KEY (&ctx->buf[60])
-
 static u8 pow_tab[256] __initdata;
 static u8 log_tab[256] __initdata;
 static u8 sbx_tab[256] __initdata;
 static u8 isb_tab[256] __initdata;
 static u32 rco_tab[10];
-static u32 ft_tab[4][256];
-static u32 it_tab[4][256];
 
-static u32 fl_tab[4][256];
-static u32 il_tab[4][256];
+u32 crypto_ft_tab[4][256];
+u32 crypto_fl_tab[4][256];
+u32 crypto_it_tab[4][256];
+u32 crypto_il_tab[4][256];
 
-static inline u8 __init
-f_mult (u8 a, u8 b)
+EXPORT_SYMBOL_GPL(crypto_ft_tab);
+EXPORT_SYMBOL_GPL(crypto_fl_tab);
+EXPORT_SYMBOL_GPL(crypto_it_tab);
+EXPORT_SYMBOL_GPL(crypto_il_tab);
+
+static inline u8 __init f_mult(u8 a, u8 b)
 {
        u8 aa = log_tab[a], cc = aa + log_tab[b];
 
        return pow_tab[cc + (cc < aa ? 1 : 0)];
 }
 
-#define ff_mult(a,b)    (a && b ? f_mult(a, b) : 0)
-
-#define f_rn(bo, bi, n, k)                                     \
-    bo[n] =  ft_tab[0][byte(bi[n],0)] ^                                \
-             ft_tab[1][byte(bi[(n + 1) & 3],1)] ^              \
-             ft_tab[2][byte(bi[(n + 2) & 3],2)] ^              \
-             ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-
-#define i_rn(bo, bi, n, k)                                     \
-    bo[n] =  it_tab[0][byte(bi[n],0)] ^                                \
-             it_tab[1][byte(bi[(n + 3) & 3],1)] ^              \
-             it_tab[2][byte(bi[(n + 2) & 3],2)] ^              \
-             it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-
-#define ls_box(x)                              \
-    ( fl_tab[0][byte(x, 0)] ^                  \
-      fl_tab[1][byte(x, 1)] ^                  \
-      fl_tab[2][byte(x, 2)] ^                  \
-      fl_tab[3][byte(x, 3)] )
-
-#define f_rl(bo, bi, n, k)                                     \
-    bo[n] =  fl_tab[0][byte(bi[n],0)] ^                                \
-             fl_tab[1][byte(bi[(n + 1) & 3],1)] ^              \
-             fl_tab[2][byte(bi[(n + 2) & 3],2)] ^              \
-             fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-
-#define i_rl(bo, bi, n, k)                                     \
-    bo[n] =  il_tab[0][byte(bi[n],0)] ^                                \
-             il_tab[1][byte(bi[(n + 3) & 3],1)] ^              \
-             il_tab[2][byte(bi[(n + 2) & 3],2)] ^              \
-             il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-
-static void __init
-gen_tabs (void)
+#define ff_mult(a, b)  (a && b ? f_mult(a, b) : 0)
+
+static void __init gen_tabs(void)
 {
        u32 i, t;
        u8 p, q;
 
-       /* log and power tables for GF(2**8) finite field with
-          0x011b as modular polynomial - the simplest primitive
-          root is 0x03, used here to generate the tables */
+       /*
+        * log and power tables for GF(2**8) finite field with
+        * 0x011b as modular polynomial - the simplest primitive
+        * root is 0x03, used here to generate the tables
+        */
 
        for (i = 0, p = 1; i < 256; ++i) {
                pow_tab[i] = (u8) p;
@@ -169,92 +123,119 @@ gen_tabs (void)
                p = sbx_tab[i];
 
                t = p;
-               fl_tab[0][i] = t;
-               fl_tab[1][i] = rol32(t, 8);
-               fl_tab[2][i] = rol32(t, 16);
-               fl_tab[3][i] = rol32(t, 24);
+               crypto_fl_tab[0][i] = t;
+               crypto_fl_tab[1][i] = rol32(t, 8);
+               crypto_fl_tab[2][i] = rol32(t, 16);
+               crypto_fl_tab[3][i] = rol32(t, 24);
 
-               t = ((u32) ff_mult (2, p)) |
+               t = ((u32) ff_mult(2, p)) |
                    ((u32) p << 8) |
-                   ((u32) p << 16) | ((u32) ff_mult (3, p) << 24);
+                   ((u32) p << 16) | ((u32) ff_mult(3, p) << 24);
 
-               ft_tab[0][i] = t;
-               ft_tab[1][i] = rol32(t, 8);
-               ft_tab[2][i] = rol32(t, 16);
-               ft_tab[3][i] = rol32(t, 24);
+               crypto_ft_tab[0][i] = t;
+               crypto_ft_tab[1][i] = rol32(t, 8);
+               crypto_ft_tab[2][i] = rol32(t, 16);
+               crypto_ft_tab[3][i] = rol32(t, 24);
 
                p = isb_tab[i];
 
                t = p;
-               il_tab[0][i] = t;
-               il_tab[1][i] = rol32(t, 8);
-               il_tab[2][i] = rol32(t, 16);
-               il_tab[3][i] = rol32(t, 24);
-
-               t = ((u32) ff_mult (14, p)) |
-                   ((u32) ff_mult (9, p) << 8) |
-                   ((u32) ff_mult (13, p) << 16) |
-                   ((u32) ff_mult (11, p) << 24);
-
-               it_tab[0][i] = t;
-               it_tab[1][i] = rol32(t, 8);
-               it_tab[2][i] = rol32(t, 16);
-               it_tab[3][i] = rol32(t, 24);
+               crypto_il_tab[0][i] = t;
+               crypto_il_tab[1][i] = rol32(t, 8);
+               crypto_il_tab[2][i] = rol32(t, 16);
+               crypto_il_tab[3][i] = rol32(t, 24);
+
+               t = ((u32) ff_mult(14, p)) |
+                   ((u32) ff_mult(9, p) << 8) |
+                   ((u32) ff_mult(13, p) << 16) |
+                   ((u32) ff_mult(11, p) << 24);
+
+               crypto_it_tab[0][i] = t;
+               crypto_it_tab[1][i] = rol32(t, 8);
+               crypto_it_tab[2][i] = rol32(t, 16);
+               crypto_it_tab[3][i] = rol32(t, 24);
        }
 }
 
-#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
-
-#define imix_col(y,x)       \
-    u   = star_x(x);        \
-    v   = star_x(u);        \
-    w   = star_x(v);        \
-    t   = w ^ (x);          \
-   (y)  = u ^ v ^ w;        \
-   (y) ^= ror32(u ^ t,  8) ^ \
-          ror32(v ^ t, 16) ^ \
-          ror32(t,24)
-
 /* initialise the key schedule from the user supplied key */
 
-#define loop4(i)                                    \
-{   t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];    \
-    t ^= E_KEY[4 * i];     E_KEY[4 * i + 4] = t;    \
-    t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t;    \
-    t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t;    \
-    t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t;    \
-}
-
-#define loop6(i)                                    \
-{   t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];    \
-    t ^= E_KEY[6 * i];     E_KEY[6 * i + 6] = t;    \
-    t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t;    \
-    t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t;    \
-    t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t;    \
-    t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t;   \
-    t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t;   \
-}
-
-#define loop8(i)                                    \
-{   t = ror32(t,  8); ; t = ls_box(t) ^ rco_tab[i];  \
-    t ^= E_KEY[8 * i];     E_KEY[8 * i + 8] = t;    \
-    t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t;    \
-    t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t;   \
-    t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t;   \
-    t  = E_KEY[8 * i + 4] ^ ls_box(t);    \
-    E_KEY[8 * i + 12] = t;                \
-    t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t;   \
-    t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t;   \
-    t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;   \
-}
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
 
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-                      unsigned int key_len)
+#define imix_col(y,x)  do {            \
+       u       = star_x(x);            \
+       v       = star_x(u);            \
+       w       = star_x(v);            \
+       t       = w ^ (x);              \
+       (y)     = u ^ v ^ w;            \
+       (y)     ^= ror32(u ^ t, 8) ^    \
+               ror32(v ^ t, 16) ^      \
+               ror32(t, 24);           \
+} while (0)
+
+#define ls_box(x)              \
+       crypto_fl_tab[0][byte(x, 0)] ^  \
+       crypto_fl_tab[1][byte(x, 1)] ^  \
+       crypto_fl_tab[2][byte(x, 2)] ^  \
+       crypto_fl_tab[3][byte(x, 3)]
+
+#define loop4(i)       do {            \
+       t = ror32(t, 8);                \
+       t = ls_box(t) ^ rco_tab[i];     \
+       t ^= ctx->key_enc[4 * i];               \
+       ctx->key_enc[4 * i + 4] = t;            \
+       t ^= ctx->key_enc[4 * i + 1];           \
+       ctx->key_enc[4 * i + 5] = t;            \
+       t ^= ctx->key_enc[4 * i + 2];           \
+       ctx->key_enc[4 * i + 6] = t;            \
+       t ^= ctx->key_enc[4 * i + 3];           \
+       ctx->key_enc[4 * i + 7] = t;            \
+} while (0)
+
+#define loop6(i)       do {            \
+       t = ror32(t, 8);                \
+       t = ls_box(t) ^ rco_tab[i];     \
+       t ^= ctx->key_enc[6 * i];               \
+       ctx->key_enc[6 * i + 6] = t;            \
+       t ^= ctx->key_enc[6 * i + 1];           \
+       ctx->key_enc[6 * i + 7] = t;            \
+       t ^= ctx->key_enc[6 * i + 2];           \
+       ctx->key_enc[6 * i + 8] = t;            \
+       t ^= ctx->key_enc[6 * i + 3];           \
+       ctx->key_enc[6 * i + 9] = t;            \
+       t ^= ctx->key_enc[6 * i + 4];           \
+       ctx->key_enc[6 * i + 10] = t;           \
+       t ^= ctx->key_enc[6 * i + 5];           \
+       ctx->key_enc[6 * i + 11] = t;           \
+} while (0)
+
+#define loop8(i)       do {                    \
+       t = ror32(t, 8);                        \
+       t = ls_box(t) ^ rco_tab[i];             \
+       t ^= ctx->key_enc[8 * i];                       \
+       ctx->key_enc[8 * i + 8] = t;                    \
+       t ^= ctx->key_enc[8 * i + 1];                   \
+       ctx->key_enc[8 * i + 9] = t;                    \
+       t ^= ctx->key_enc[8 * i + 2];                   \
+       ctx->key_enc[8 * i + 10] = t;                   \
+       t ^= ctx->key_enc[8 * i + 3];                   \
+       ctx->key_enc[8 * i + 11] = t;                   \
+       t  = ctx->key_enc[8 * i + 4] ^ ls_box(t);       \
+       ctx->key_enc[8 * i + 12] = t;                   \
+       t ^= ctx->key_enc[8 * i + 5];                   \
+       ctx->key_enc[8 * i + 13] = t;                   \
+       t ^= ctx->key_enc[8 * i + 6];                   \
+       ctx->key_enc[8 * i + 14] = t;                   \
+       t ^= ctx->key_enc[8 * i + 7];                   \
+       ctx->key_enc[8 * i + 15] = t;                   \
+} while (0)
+
+int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+               unsigned int key_len)
 {
-       struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
        const __le32 *key = (const __le32 *)in_key;
        u32 *flags = &tfm->crt_flags;
-       u32 i, t, u, v, w;
+       u32 i, t, u, v, w, j;
 
        if (key_len % 8) {
                *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -263,95 +244,113 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
        ctx->key_length = key_len;
 
-       E_KEY[0] = le32_to_cpu(key[0]);
-       E_KEY[1] = le32_to_cpu(key[1]);
-       E_KEY[2] = le32_to_cpu(key[2]);
-       E_KEY[3] = le32_to_cpu(key[3]);
+       ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]);
+       ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]);
+       ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]);
+       ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]);
 
        switch (key_len) {
        case 16:
-               t = E_KEY[3];
+               t = ctx->key_enc[3];
                for (i = 0; i < 10; ++i)
-                       loop4 (i);
+                       loop4(i);
                break;
 
        case 24:
-               E_KEY[4] = le32_to_cpu(key[4]);
-               t = E_KEY[5] = le32_to_cpu(key[5]);
+               ctx->key_enc[4] = le32_to_cpu(key[4]);
+               t = ctx->key_enc[5] = le32_to_cpu(key[5]);
                for (i = 0; i < 8; ++i)
-                       loop6 (i);
+                       loop6(i);
                break;
 
        case 32:
-               E_KEY[4] = le32_to_cpu(key[4]);
-               E_KEY[5] = le32_to_cpu(key[5]);
-               E_KEY[6] = le32_to_cpu(key[6]);
-               t = E_KEY[7] = le32_to_cpu(key[7]);
+               ctx->key_enc[4] = le32_to_cpu(key[4]);
+               ctx->key_enc[5] = le32_to_cpu(key[5]);
+               ctx->key_enc[6] = le32_to_cpu(key[6]);
+               t = ctx->key_enc[7] = le32_to_cpu(key[7]);
                for (i = 0; i < 7; ++i)
-                       loop8 (i);
+                       loop8(i);
                break;
        }
 
-       D_KEY[0] = E_KEY[0];
-       D_KEY[1] = E_KEY[1];
-       D_KEY[2] = E_KEY[2];
-       D_KEY[3] = E_KEY[3];
+       ctx->key_dec[0] = ctx->key_enc[key_len + 24];
+       ctx->key_dec[1] = ctx->key_enc[key_len + 25];
+       ctx->key_dec[2] = ctx->key_enc[key_len + 26];
+       ctx->key_dec[3] = ctx->key_enc[key_len + 27];
 
        for (i = 4; i < key_len + 24; ++i) {
-               imix_col (D_KEY[i], E_KEY[i]);
+               j = key_len + 24 - (i & ~3) + (i & 3);
+               imix_col(ctx->key_dec[j], ctx->key_enc[i]);
        }
-
        return 0;
 }
+EXPORT_SYMBOL_GPL(crypto_aes_set_key);
 
 /* encrypt a block of text */
 
-#define f_nround(bo, bi, k) \
-    f_rn(bo, bi, 0, k);     \
-    f_rn(bo, bi, 1, k);     \
-    f_rn(bo, bi, 2, k);     \
-    f_rn(bo, bi, 3, k);     \
-    k += 4
-
-#define f_lround(bo, bi, k) \
-    f_rl(bo, bi, 0, k);     \
-    f_rl(bo, bi, 1, k);     \
-    f_rl(bo, bi, 2, k);     \
-    f_rl(bo, bi, 3, k)
+#define f_rn(bo, bi, n, k)     do {                            \
+       bo[n] = crypto_ft_tab[0][byte(bi[n], 0)] ^                      \
+               crypto_ft_tab[1][byte(bi[(n + 1) & 3], 1)] ^            \
+               crypto_ft_tab[2][byte(bi[(n + 2) & 3], 2)] ^            \
+               crypto_ft_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n);  \
+} while (0)
+
+#define f_nround(bo, bi, k)    do {\
+       f_rn(bo, bi, 0, k);     \
+       f_rn(bo, bi, 1, k);     \
+       f_rn(bo, bi, 2, k);     \
+       f_rn(bo, bi, 3, k);     \
+       k += 4;                 \
+} while (0)
+
+#define f_rl(bo, bi, n, k)     do {                            \
+       bo[n] = crypto_fl_tab[0][byte(bi[n], 0)] ^                      \
+               crypto_fl_tab[1][byte(bi[(n + 1) & 3], 1)] ^            \
+               crypto_fl_tab[2][byte(bi[(n + 2) & 3], 2)] ^            \
+               crypto_fl_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n);  \
+} while (0)
+
+#define f_lround(bo, bi, k)    do {\
+       f_rl(bo, bi, 0, k);     \
+       f_rl(bo, bi, 1, k);     \
+       f_rl(bo, bi, 2, k);     \
+       f_rl(bo, bi, 3, k);     \
+} while (0)
 
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-       const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+       const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
        const __le32 *src = (const __le32 *)in;
        __le32 *dst = (__le32 *)out;
        u32 b0[4], b1[4];
-       const u32 *kp = E_KEY + 4;
+       const u32 *kp = ctx->key_enc + 4;
+       const int key_len = ctx->key_length;
 
-       b0[0] = le32_to_cpu(src[0]) ^ E_KEY[0];
-       b0[1] = le32_to_cpu(src[1]) ^ E_KEY[1];
-       b0[2] = le32_to_cpu(src[2]) ^ E_KEY[2];
-       b0[3] = le32_to_cpu(src[3]) ^ E_KEY[3];
+       b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0];
+       b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1];
+       b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2];
+       b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3];
 
-       if (ctx->key_length > 24) {
-               f_nround (b1, b0, kp);
-               f_nround (b0, b1, kp);
+       if (key_len > 24) {
+               f_nround(b1, b0, kp);
+               f_nround(b0, b1, kp);
        }
 
-       if (ctx->key_length > 16) {
-               f_nround (b1, b0, kp);
-               f_nround (b0, b1, kp);
+       if (key_len > 16) {
+               f_nround(b1, b0, kp);
+               f_nround(b0, b1, kp);
        }
 
-       f_nround (b1, b0, kp);
-       f_nround (b0, b1, kp);
-       f_nround (b1, b0, kp);
-       f_nround (b0, b1, kp);
-       f_nround (b1, b0, kp);
-       f_nround (b0, b1, kp);
-       f_nround (b1, b0, kp);
-       f_nround (b0, b1, kp);
-       f_nround (b1, b0, kp);
-       f_lround (b0, b1, kp);
+       f_nround(b1, b0, kp);
+       f_nround(b0, b1, kp);
+       f_nround(b1, b0, kp);
+       f_nround(b0, b1, kp);
+       f_nround(b1, b0, kp);
+       f_nround(b0, b1, kp);
+       f_nround(b1, b0, kp);
+       f_nround(b0, b1, kp);
+       f_nround(b1, b0, kp);
+       f_lround(b0, b1, kp);
 
        dst[0] = cpu_to_le32(b0[0]);
        dst[1] = cpu_to_le32(b0[1]);
@@ -361,53 +360,69 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 
 /* decrypt a block of text */
 
-#define i_nround(bo, bi, k) \
-    i_rn(bo, bi, 0, k);     \
-    i_rn(bo, bi, 1, k);     \
-    i_rn(bo, bi, 2, k);     \
-    i_rn(bo, bi, 3, k);     \
-    k -= 4
-
-#define i_lround(bo, bi, k) \
-    i_rl(bo, bi, 0, k);     \
-    i_rl(bo, bi, 1, k);     \
-    i_rl(bo, bi, 2, k);     \
-    i_rl(bo, bi, 3, k)
+#define i_rn(bo, bi, n, k)     do {                            \
+       bo[n] = crypto_it_tab[0][byte(bi[n], 0)] ^                      \
+               crypto_it_tab[1][byte(bi[(n + 3) & 3], 1)] ^            \
+               crypto_it_tab[2][byte(bi[(n + 2) & 3], 2)] ^            \
+               crypto_it_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n);  \
+} while (0)
+
+#define i_nround(bo, bi, k)    do {\
+       i_rn(bo, bi, 0, k);     \
+       i_rn(bo, bi, 1, k);     \
+       i_rn(bo, bi, 2, k);     \
+       i_rn(bo, bi, 3, k);     \
+       k += 4;                 \
+} while (0)
+
+#define i_rl(bo, bi, n, k)     do {                    \
+       bo[n] = crypto_il_tab[0][byte(bi[n], 0)] ^              \
+       crypto_il_tab[1][byte(bi[(n + 3) & 3], 1)] ^            \
+       crypto_il_tab[2][byte(bi[(n + 2) & 3], 2)] ^            \
+       crypto_il_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n);  \
+} while (0)
+
+#define i_lround(bo, bi, k)    do {\
+       i_rl(bo, bi, 0, k);     \
+       i_rl(bo, bi, 1, k);     \
+       i_rl(bo, bi, 2, k);     \
+       i_rl(bo, bi, 3, k);     \
+} while (0)
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-       const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+       const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
        const __le32 *src = (const __le32 *)in;
        __le32 *dst = (__le32 *)out;
        u32 b0[4], b1[4];
        const int key_len = ctx->key_length;
-       const u32 *kp = D_KEY + key_len + 20;
+       const u32 *kp = ctx->key_dec + 4;
 
-       b0[0] = le32_to_cpu(src[0]) ^ E_KEY[key_len + 24];
-       b0[1] = le32_to_cpu(src[1]) ^ E_KEY[key_len + 25];
-       b0[2] = le32_to_cpu(src[2]) ^ E_KEY[key_len + 26];
-       b0[3] = le32_to_cpu(src[3]) ^ E_KEY[key_len + 27];
+       b0[0] = le32_to_cpu(src[0]) ^  ctx->key_dec[0];
+       b0[1] = le32_to_cpu(src[1]) ^  ctx->key_dec[1];
+       b0[2] = le32_to_cpu(src[2]) ^  ctx->key_dec[2];
+       b0[3] = le32_to_cpu(src[3]) ^  ctx->key_dec[3];
 
        if (key_len > 24) {
-               i_nround (b1, b0, kp);
-               i_nround (b0, b1, kp);
+               i_nround(b1, b0, kp);
+               i_nround(b0, b1, kp);
        }
 
        if (key_len > 16) {
-               i_nround (b1, b0, kp);
-               i_nround (b0, b1, kp);
+               i_nround(b1, b0, kp);
+               i_nround(b0, b1, kp);
        }
 
-       i_nround (b1, b0, kp);
-       i_nround (b0, b1, kp);
-       i_nround (b1, b0, kp);
-       i_nround (b0, b1, kp);
-       i_nround (b1, b0, kp);
-       i_nround (b0, b1, kp);
-       i_nround (b1, b0, kp);
-       i_nround (b0, b1, kp);
-       i_nround (b1, b0, kp);
-       i_lround (b0, b1, kp);
+       i_nround(b1, b0, kp);
+       i_nround(b0, b1, kp);
+       i_nround(b1, b0, kp);
+       i_nround(b0, b1, kp);
+       i_nround(b1, b0, kp);
+       i_nround(b0, b1, kp);
+       i_nround(b1, b0, kp);
+       i_nround(b0, b1, kp);
+       i_nround(b1, b0, kp);
+       i_lround(b0, b1, kp);
 
        dst[0] = cpu_to_le32(b0[0]);
        dst[1] = cpu_to_le32(b0[1]);
@@ -415,14 +430,13 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
        dst[3] = cpu_to_le32(b0[3]);
 }
 
-
 static struct crypto_alg aes_alg = {
        .cra_name               =       "aes",
        .cra_driver_name        =       "aes-generic",
        .cra_priority           =       100,
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       AES_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct aes_ctx),
+       .cra_ctxsize            =       sizeof(struct crypto_aes_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
@@ -430,9 +444,9 @@ static struct crypto_alg aes_alg = {
                .cipher = {
                        .cia_min_keysize        =       AES_MIN_KEY_SIZE,
                        .cia_max_keysize        =       AES_MAX_KEY_SIZE,
-                       .cia_setkey             =       aes_set_key,
-                       .cia_encrypt            =       aes_encrypt,
-                       .cia_decrypt            =       aes_decrypt
+                       .cia_setkey             =       crypto_aes_set_key,
+                       .cia_encrypt            =       aes_encrypt,
+                       .cia_decrypt            =       aes_decrypt
                }
        }
 };
index 8383282de1ddc39422cd227b7a800a095ad14f67..e65cb50cf4aff8b739130ba7012e383196ef286a 100644 (file)
@@ -472,7 +472,7 @@ int crypto_check_attr_type(struct rtattr **tb, u32 type)
 }
 EXPORT_SYMBOL_GPL(crypto_check_attr_type);
 
-struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+const char *crypto_attr_alg_name(struct rtattr *rta)
 {
        struct crypto_attr_alg *alga;
 
@@ -486,7 +486,21 @@ struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
        alga = RTA_DATA(rta);
        alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
 
-       return crypto_alg_mod_lookup(alga->name, type, mask);
+       return alga->name;
+}
+EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
+
+struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+{
+       const char *name;
+       int err;
+
+       name = crypto_attr_alg_name(rta);
+       err = PTR_ERR(name);
+       if (IS_ERR(name))
+               return ERR_PTR(err);
+
+       return crypto_alg_mod_lookup(name, type, mask);
 }
 EXPORT_SYMBOL_GPL(crypto_attr_alg);
 
@@ -605,6 +619,53 @@ int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
 }
 EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
 
+static inline void crypto_inc_byte(u8 *a, unsigned int size)
+{
+       u8 *b = (a + size);
+       u8 c;
+
+       for (; size; size--) {
+               c = *--b + 1;
+               *b = c;
+               if (c)
+                       break;
+       }
+}
+
+void crypto_inc(u8 *a, unsigned int size)
+{
+       __be32 *b = (__be32 *)(a + size);
+       u32 c;
+
+       for (; size >= 4; size -= 4) {
+               c = be32_to_cpu(*--b) + 1;
+               *b = cpu_to_be32(c);
+               if (c)
+                       return;
+       }
+
+       crypto_inc_byte(a, size);
+}
+EXPORT_SYMBOL_GPL(crypto_inc);
+
+static inline void crypto_xor_byte(u8 *a, const u8 *b, unsigned int size)
+{
+       for (; size; size--)
+               *a++ ^= *b++;
+}
+
+void crypto_xor(u8 *dst, const u8 *src, unsigned int size)
+{
+       u32 *a = (u32 *)dst;
+       u32 *b = (u32 *)src;
+
+       for (; size >= 4; size -= 4)
+               *a++ ^= *b++;
+
+       crypto_xor_byte((u8 *)a, (u8 *)b, size);
+}
+EXPORT_SYMBOL_GPL(crypto_xor);
+
 static int __init crypto_algapi_init(void)
 {
        crypto_init_proc();
index 1f5c724773568acf31f7dde568972f4925f39407..a2496d1bc6d42234dba6477580a9ddafed6759a9 100644 (file)
@@ -137,7 +137,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type,
        return alg;
 }
 
-static void crypto_larval_kill(struct crypto_alg *alg)
+void crypto_larval_kill(struct crypto_alg *alg)
 {
        struct crypto_larval *larval = (void *)alg;
 
@@ -147,6 +147,7 @@ static void crypto_larval_kill(struct crypto_alg *alg)
        complete_all(&larval->completion);
        crypto_alg_put(alg);
 }
+EXPORT_SYMBOL_GPL(crypto_larval_kill);
 
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
 {
@@ -176,11 +177,9 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
        return alg;
 }
 
-struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
 {
        struct crypto_alg *alg;
-       struct crypto_alg *larval;
-       int ok;
 
        if (!name)
                return ERR_PTR(-ENOENT);
@@ -193,7 +192,17 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
        if (alg)
                return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
 
-       larval = crypto_larval_alloc(name, type, mask);
+       return crypto_larval_alloc(name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_larval_lookup);
+
+struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+{
+       struct crypto_alg *alg;
+       struct crypto_alg *larval;
+       int ok;
+
+       larval = crypto_larval_lookup(name, type, mask);
        if (IS_ERR(larval) || !crypto_is_larval(larval))
                return larval;
 
index 126a529b496d5df32959499ff22739767eca52a3..ed8ac5a6fa5ff0bc22fa67fc193a1b0629d4a063 100644 (file)
  *
  */
 
-#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
-#include "scatterwalk.h"
-
 struct authenc_instance_ctx {
        struct crypto_spawn auth;
-       struct crypto_spawn enc;
-
-       unsigned int authsize;
-       unsigned int enckeylen;
+       struct crypto_skcipher_spawn enc;
 };
 
 struct crypto_authenc_ctx {
@@ -37,19 +36,31 @@ struct crypto_authenc_ctx {
 static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
                                 unsigned int keylen)
 {
-       struct authenc_instance_ctx *ictx =
-               crypto_instance_ctx(crypto_aead_alg_instance(authenc));
-       unsigned int enckeylen = ictx->enckeylen;
        unsigned int authkeylen;
+       unsigned int enckeylen;
        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
        struct crypto_hash *auth = ctx->auth;
        struct crypto_ablkcipher *enc = ctx->enc;
+       struct rtattr *rta = (void *)key;
+       struct crypto_authenc_key_param *param;
        int err = -EINVAL;
 
-       if (keylen < enckeylen) {
-               crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
-               goto out;
-       }
+       if (!RTA_OK(rta, keylen))
+               goto badkey;
+       if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+               goto badkey;
+       if (RTA_PAYLOAD(rta) < sizeof(*param))
+               goto badkey;
+
+       param = RTA_DATA(rta);
+       enckeylen = be32_to_cpu(param->enckeylen);
+
+       key += RTA_ALIGN(rta->rta_len);
+       keylen -= RTA_ALIGN(rta->rta_len);
+
+       if (keylen < enckeylen)
+               goto badkey;
+
        authkeylen = keylen - enckeylen;
 
        crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
@@ -71,21 +82,38 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 
 out:
        return err;
+
+badkey:
+       crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
+       goto out;
 }
 
-static int crypto_authenc_hash(struct aead_request *req)
+static void authenc_chain(struct scatterlist *head, struct scatterlist *sg,
+                         int chain)
+{
+       if (chain) {
+               head->length += sg->length;
+               sg = scatterwalk_sg_next(sg);
+       }
+
+       if (sg)
+               scatterwalk_sg_chain(head, 2, sg);
+       else
+               sg_mark_end(head);
+}
+
+static u8 *crypto_authenc_hash(struct aead_request *req, unsigned int flags,
+                              struct scatterlist *cipher,
+                              unsigned int cryptlen)
 {
        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
-       struct authenc_instance_ctx *ictx =
-               crypto_instance_ctx(crypto_aead_alg_instance(authenc));
        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
        struct crypto_hash *auth = ctx->auth;
        struct hash_desc desc = {
                .tfm = auth,
+               .flags = aead_request_flags(req) & flags,
        };
        u8 *hash = aead_request_ctx(req);
-       struct scatterlist *dst = req->dst;
-       unsigned int cryptlen = req->cryptlen;
        int err;
 
        hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), 
@@ -100,7 +128,7 @@ static int crypto_authenc_hash(struct aead_request *req)
        if (err)
                goto auth_unlock;
 
-       err = crypto_hash_update(&desc, dst, cryptlen);
+       err = crypto_hash_update(&desc, cipher, cryptlen);
        if (err)
                goto auth_unlock;
 
@@ -109,17 +137,53 @@ auth_unlock:
        spin_unlock_bh(&ctx->auth_lock);
 
        if (err)
-               return err;
+               return ERR_PTR(err);
+
+       return hash;
+}
 
-       scatterwalk_map_and_copy(hash, dst, cryptlen, ictx->authsize, 1);
+static int crypto_authenc_genicv(struct aead_request *req, u8 *iv,
+                                unsigned int flags)
+{
+       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+       struct scatterlist *dst = req->dst;
+       struct scatterlist cipher[2];
+       struct page *dstp;
+       unsigned int ivsize = crypto_aead_ivsize(authenc);
+       unsigned int cryptlen;
+       u8 *vdst;
+       u8 *hash;
+
+       dstp = sg_page(dst);
+       vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset;
+
+       sg_init_table(cipher, 2);
+       sg_set_buf(cipher, iv, ivsize);
+       authenc_chain(cipher, dst, vdst == iv + ivsize);
+
+       cryptlen = req->cryptlen + ivsize;
+       hash = crypto_authenc_hash(req, flags, cipher, cryptlen);
+       if (IS_ERR(hash))
+               return PTR_ERR(hash);
+
+       scatterwalk_map_and_copy(hash, cipher, cryptlen,
+                                crypto_aead_authsize(authenc), 1);
        return 0;
 }
 
 static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
                                        int err)
 {
-       if (!err)
-               err = crypto_authenc_hash(req->data);
+       if (!err) {
+               struct aead_request *areq = req->data;
+               struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+               struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
+               struct ablkcipher_request *abreq = aead_request_ctx(areq);
+               u8 *iv = (u8 *)(abreq + 1) +
+                        crypto_ablkcipher_reqsize(ctx->enc);
+
+               err = crypto_authenc_genicv(areq, iv, 0);
+       }
 
        aead_request_complete(req->data, err);
 }
@@ -129,72 +193,99 @@ static int crypto_authenc_encrypt(struct aead_request *req)
        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
        struct ablkcipher_request *abreq = aead_request_ctx(req);
+       struct crypto_ablkcipher *enc = ctx->enc;
+       struct scatterlist *dst = req->dst;
+       unsigned int cryptlen = req->cryptlen;
+       u8 *iv = (u8 *)(abreq + 1) + crypto_ablkcipher_reqsize(enc);
        int err;
 
-       ablkcipher_request_set_tfm(abreq, ctx->enc);
+       ablkcipher_request_set_tfm(abreq, enc);
        ablkcipher_request_set_callback(abreq, aead_request_flags(req),
                                        crypto_authenc_encrypt_done, req);
-       ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen,
-                                    req->iv);
+       ablkcipher_request_set_crypt(abreq, req->src, dst, cryptlen, req->iv);
+
+       memcpy(iv, req->iv, crypto_aead_ivsize(authenc));
 
        err = crypto_ablkcipher_encrypt(abreq);
        if (err)
                return err;
 
-       return crypto_authenc_hash(req);
+       return crypto_authenc_genicv(req, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
 }
 
-static int crypto_authenc_verify(struct aead_request *req)
+static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
+                                          int err)
 {
-       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
-       struct authenc_instance_ctx *ictx =
-               crypto_instance_ctx(crypto_aead_alg_instance(authenc));
+       if (!err) {
+               struct aead_givcrypt_request *greq = req->data;
+
+               err = crypto_authenc_genicv(&greq->areq, greq->giv, 0);
+       }
+
+       aead_request_complete(req->data, err);
+}
+
+static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req)
+{
+       struct crypto_aead *authenc = aead_givcrypt_reqtfm(req);
        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
-       struct crypto_hash *auth = ctx->auth;
-       struct hash_desc desc = {
-               .tfm = auth,
-               .flags = aead_request_flags(req),
-       };
-       u8 *ohash = aead_request_ctx(req);
-       u8 *ihash;
-       struct scatterlist *src = req->src;
-       unsigned int cryptlen = req->cryptlen;
-       unsigned int authsize;
+       struct aead_request *areq = &req->areq;
+       struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
+       u8 *iv = req->giv;
        int err;
 
-       ohash = (u8 *)ALIGN((unsigned long)ohash + crypto_hash_alignmask(auth), 
-                           crypto_hash_alignmask(auth) + 1);
-       ihash = ohash + crypto_hash_digestsize(auth);
-
-       spin_lock_bh(&ctx->auth_lock);
-       err = crypto_hash_init(&desc);
-       if (err)
-               goto auth_unlock;
+       skcipher_givcrypt_set_tfm(greq, ctx->enc);
+       skcipher_givcrypt_set_callback(greq, aead_request_flags(areq),
+                                      crypto_authenc_givencrypt_done, areq);
+       skcipher_givcrypt_set_crypt(greq, areq->src, areq->dst, areq->cryptlen,
+                                   areq->iv);
+       skcipher_givcrypt_set_giv(greq, iv, req->seq);
 
-       err = crypto_hash_update(&desc, req->assoc, req->assoclen);
+       err = crypto_skcipher_givencrypt(greq);
        if (err)
-               goto auth_unlock;
+               return err;
 
-       err = crypto_hash_update(&desc, src, cryptlen);
-       if (err)
-               goto auth_unlock;
+       return crypto_authenc_genicv(areq, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
+}
 
-       err = crypto_hash_final(&desc, ohash);
-auth_unlock:
-       spin_unlock_bh(&ctx->auth_lock);
+static int crypto_authenc_verify(struct aead_request *req,
+                                struct scatterlist *cipher,
+                                unsigned int cryptlen)
+{
+       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+       u8 *ohash;
+       u8 *ihash;
+       unsigned int authsize;
 
-       if (err)
-               return err;
+       ohash = crypto_authenc_hash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher,
+                                   cryptlen);
+       if (IS_ERR(ohash))
+               return PTR_ERR(ohash);
 
-       authsize = ictx->authsize;
-       scatterwalk_map_and_copy(ihash, src, cryptlen, authsize, 0);
-       return memcmp(ihash, ohash, authsize) ? -EINVAL : 0;
+       authsize = crypto_aead_authsize(authenc);
+       ihash = ohash + authsize;
+       scatterwalk_map_and_copy(ihash, cipher, cryptlen, authsize, 0);
+       return memcmp(ihash, ohash, authsize) ? -EBADMSG: 0;
 }
 
-static void crypto_authenc_decrypt_done(struct crypto_async_request *req,
-                                       int err)
+static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
+                                 unsigned int cryptlen)
 {
-       aead_request_complete(req->data, err);
+       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+       struct scatterlist *src = req->src;
+       struct scatterlist cipher[2];
+       struct page *srcp;
+       unsigned int ivsize = crypto_aead_ivsize(authenc);
+       u8 *vsrc;
+
+       srcp = sg_page(src);
+       vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset;
+
+       sg_init_table(cipher, 2);
+       sg_set_buf(cipher, iv, ivsize);
+       authenc_chain(cipher, src, vsrc == iv + ivsize);
+
+       return crypto_authenc_verify(req, cipher, cryptlen + ivsize);
 }
 
 static int crypto_authenc_decrypt(struct aead_request *req)
@@ -202,17 +293,23 @@ static int crypto_authenc_decrypt(struct aead_request *req)
        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
        struct ablkcipher_request *abreq = aead_request_ctx(req);
+       unsigned int cryptlen = req->cryptlen;
+       unsigned int authsize = crypto_aead_authsize(authenc);
+       u8 *iv = req->iv;
        int err;
 
-       err = crypto_authenc_verify(req);
+       if (cryptlen < authsize)
+               return -EINVAL;
+       cryptlen -= authsize;
+
+       err = crypto_authenc_iverify(req, iv, cryptlen);
        if (err)
                return err;
 
        ablkcipher_request_set_tfm(abreq, ctx->enc);
        ablkcipher_request_set_callback(abreq, aead_request_flags(req),
-                                       crypto_authenc_decrypt_done, req);
-       ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen,
-                                    req->iv);
+                                       req->base.complete, req->base.data);
+       ablkcipher_request_set_crypt(abreq, req->src, req->dst, cryptlen, iv);
 
        return crypto_ablkcipher_decrypt(abreq);
 }
@@ -224,19 +321,13 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
        struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
        struct crypto_hash *auth;
        struct crypto_ablkcipher *enc;
-       unsigned int digestsize;
        int err;
 
        auth = crypto_spawn_hash(&ictx->auth);
        if (IS_ERR(auth))
                return PTR_ERR(auth);
 
-       err = -EINVAL;
-       digestsize = crypto_hash_digestsize(auth);
-       if (ictx->authsize > digestsize)
-               goto err_free_hash;
-
-       enc = crypto_spawn_ablkcipher(&ictx->enc);
+       enc = crypto_spawn_skcipher(&ictx->enc);
        err = PTR_ERR(enc);
        if (IS_ERR(enc))
                goto err_free_hash;
@@ -246,9 +337,10 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
        tfm->crt_aead.reqsize = max_t(unsigned int,
                                      (crypto_hash_alignmask(auth) &
                                       ~(crypto_tfm_ctx_alignment() - 1)) +
-                                     digestsize * 2,
-                                     sizeof(struct ablkcipher_request) +
-                                     crypto_ablkcipher_reqsize(enc));
+                                     crypto_hash_digestsize(auth) * 2,
+                                     sizeof(struct skcipher_givcrypt_request) +
+                                     crypto_ablkcipher_reqsize(enc) +
+                                     crypto_ablkcipher_ivsize(enc));
 
        spin_lock_init(&ctx->auth_lock);
 
@@ -269,75 +361,74 @@ static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm)
 
 static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 {
+       struct crypto_attr_type *algt;
        struct crypto_instance *inst;
        struct crypto_alg *auth;
        struct crypto_alg *enc;
        struct authenc_instance_ctx *ctx;
-       unsigned int authsize;
-       unsigned int enckeylen;
+       const char *enc_name;
        int err;
 
-       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD);
-       if (err)
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
                return ERR_PTR(err);
 
+       if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+               return ERR_PTR(-EINVAL);
+
        auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
                               CRYPTO_ALG_TYPE_HASH_MASK);
        if (IS_ERR(auth))
                return ERR_PTR(PTR_ERR(auth));
 
-       err = crypto_attr_u32(tb[2], &authsize);
-       inst = ERR_PTR(err);
-       if (err)
-               goto out_put_auth;
-
-       enc = crypto_attr_alg(tb[3], CRYPTO_ALG_TYPE_BLKCIPHER,
-                             CRYPTO_ALG_TYPE_MASK);
-       inst = ERR_PTR(PTR_ERR(enc));
-       if (IS_ERR(enc))
+       enc_name = crypto_attr_alg_name(tb[2]);
+       err = PTR_ERR(enc_name);
+       if (IS_ERR(enc_name))
                goto out_put_auth;
 
-       err = crypto_attr_u32(tb[4], &enckeylen);
-       if (err)
-               goto out_put_enc;
-
        inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
        err = -ENOMEM;
        if (!inst)
-               goto out_put_enc;
-
-       err = -ENAMETOOLONG;
-       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
-                    "authenc(%s,%u,%s,%u)", auth->cra_name, authsize,
-                    enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME)
-               goto err_free_inst;
-
-       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
-                    "authenc(%s,%u,%s,%u)", auth->cra_driver_name,
-                    authsize, enc->cra_driver_name, enckeylen) >=
-           CRYPTO_MAX_ALG_NAME)
-               goto err_free_inst;
+               goto out_put_auth;
 
        ctx = crypto_instance_ctx(inst);
-       ctx->authsize = authsize;
-       ctx->enckeylen = enckeylen;
 
        err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK);
        if (err)
                goto err_free_inst;
 
-       err = crypto_init_spawn(&ctx->enc, enc, inst, CRYPTO_ALG_TYPE_MASK);
+       crypto_set_skcipher_spawn(&ctx->enc, inst);
+       err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
+                                  crypto_requires_sync(algt->type,
+                                                       algt->mask));
        if (err)
                goto err_drop_auth;
 
-       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
+       enc = crypto_skcipher_spawn_alg(&ctx->enc);
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+                    "authenc(%s,%s)", auth->cra_name, enc->cra_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               goto err_drop_enc;
+
+       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "authenc(%s,%s)", auth->cra_driver_name,
+                    enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_drop_enc;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+       inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC;
        inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority;
        inst->alg.cra_blocksize = enc->cra_blocksize;
-       inst->alg.cra_alignmask = max(auth->cra_alignmask, enc->cra_alignmask);
+       inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask;
        inst->alg.cra_type = &crypto_aead_type;
 
-       inst->alg.cra_aead.ivsize = enc->cra_blkcipher.ivsize;
-       inst->alg.cra_aead.authsize = authsize;
+       inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
+       inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ?
+                                        auth->cra_hash.digestsize :
+                                        auth->cra_digest.dia_digestsize;
 
        inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
 
@@ -347,18 +438,19 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
        inst->alg.cra_aead.setkey = crypto_authenc_setkey;
        inst->alg.cra_aead.encrypt = crypto_authenc_encrypt;
        inst->alg.cra_aead.decrypt = crypto_authenc_decrypt;
+       inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt;
 
 out:
-       crypto_mod_put(enc);
-out_put_auth:
        crypto_mod_put(auth);
        return inst;
 
+err_drop_enc:
+       crypto_drop_skcipher(&ctx->enc);
 err_drop_auth:
        crypto_drop_spawn(&ctx->auth);
 err_free_inst:
        kfree(inst);
-out_put_enc:
+out_put_auth:
        inst = ERR_PTR(err);
        goto out;
 }
@@ -367,7 +459,7 @@ static void crypto_authenc_free(struct crypto_instance *inst)
 {
        struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst);
 
-       crypto_drop_spawn(&ctx->enc);
+       crypto_drop_skcipher(&ctx->enc);
        crypto_drop_spawn(&ctx->auth);
        kfree(inst);
 }
index f6c67f9d4e5c2f9085558991a6fc87893e269670..4a7e65c4df4dc3ac6af007efa1d136e1232be053 100644 (file)
@@ -14,7 +14,8 @@
  *
  */
 
-#include <linux/crypto.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
 #include <linux/errno.h>
 #include <linux/hardirq.h>
 #include <linux/kernel.h>
@@ -25,7 +26,6 @@
 #include <linux/string.h>
 
 #include "internal.h"
-#include "scatterwalk.h"
 
 enum {
        BLKCIPHER_WALK_PHYS = 1 << 0,
@@ -433,9 +433,8 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
        struct blkcipher_alg *cipher = &alg->cra_blkcipher;
        unsigned int len = alg->cra_ctxsize;
 
-       type ^= CRYPTO_ALG_ASYNC;
-       mask &= CRYPTO_ALG_ASYNC;
-       if ((type & mask) && cipher->ivsize) {
+       if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK &&
+           cipher->ivsize) {
                len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
                len += cipher->ivsize;
        }
@@ -451,6 +450,11 @@ static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm)
        crt->setkey = async_setkey;
        crt->encrypt = async_encrypt;
        crt->decrypt = async_decrypt;
+       if (!alg->ivsize) {
+               crt->givencrypt = skcipher_null_givencrypt;
+               crt->givdecrypt = skcipher_null_givdecrypt;
+       }
+       crt->base = __crypto_ablkcipher_cast(tfm);
        crt->ivsize = alg->ivsize;
 
        return 0;
@@ -482,9 +486,7 @@ static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
        if (alg->ivsize > PAGE_SIZE / 8)
                return -EINVAL;
 
-       type ^= CRYPTO_ALG_ASYNC;
-       mask &= CRYPTO_ALG_ASYNC;
-       if (type & mask)
+       if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK)
                return crypto_init_blkcipher_ops_sync(tfm);
        else
                return crypto_init_blkcipher_ops_async(tfm);
@@ -499,6 +501,8 @@ static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
        seq_printf(m, "min keysize  : %u\n", alg->cra_blkcipher.min_keysize);
        seq_printf(m, "max keysize  : %u\n", alg->cra_blkcipher.max_keysize);
        seq_printf(m, "ivsize       : %u\n", alg->cra_blkcipher.ivsize);
+       seq_printf(m, "geniv        : %s\n", alg->cra_blkcipher.geniv ?:
+                                            "<default>");
 }
 
 const struct crypto_type crypto_blkcipher_type = {
@@ -510,5 +514,187 @@ const struct crypto_type crypto_blkcipher_type = {
 };
 EXPORT_SYMBOL_GPL(crypto_blkcipher_type);
 
+static int crypto_grab_nivcipher(struct crypto_skcipher_spawn *spawn,
+                               const char *name, u32 type, u32 mask)
+{
+       struct crypto_alg *alg;
+       int err;
+
+       type = crypto_skcipher_type(type);
+       mask = crypto_skcipher_mask(mask) | CRYPTO_ALG_GENIV;
+
+       alg = crypto_alg_mod_lookup(name, type, mask);
+       if (IS_ERR(alg))
+               return PTR_ERR(alg);
+
+       err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+       crypto_mod_put(alg);
+       return err;
+}
+
+struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl,
+                                            struct rtattr **tb, u32 type,
+                                            u32 mask)
+{
+       struct {
+               int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+                             unsigned int keylen);
+               int (*encrypt)(struct ablkcipher_request *req);
+               int (*decrypt)(struct ablkcipher_request *req);
+
+               unsigned int min_keysize;
+               unsigned int max_keysize;
+               unsigned int ivsize;
+
+               const char *geniv;
+       } balg;
+       const char *name;
+       struct crypto_skcipher_spawn *spawn;
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ (CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV)) &
+           algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(name);
+       if (IS_ERR(name))
+               return ERR_PTR(err);
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       spawn = crypto_instance_ctx(inst);
+
+       /* Ignore async algorithms if necessary. */
+       mask |= crypto_requires_sync(algt->type, algt->mask);
+
+       crypto_set_skcipher_spawn(spawn, inst);
+       err = crypto_grab_nivcipher(spawn, name, type, mask);
+       if (err)
+               goto err_free_inst;
+
+       alg = crypto_skcipher_spawn_alg(spawn);
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_BLKCIPHER) {
+               balg.ivsize = alg->cra_blkcipher.ivsize;
+               balg.min_keysize = alg->cra_blkcipher.min_keysize;
+               balg.max_keysize = alg->cra_blkcipher.max_keysize;
+
+               balg.setkey = async_setkey;
+               balg.encrypt = async_encrypt;
+               balg.decrypt = async_decrypt;
+
+               balg.geniv = alg->cra_blkcipher.geniv;
+       } else {
+               balg.ivsize = alg->cra_ablkcipher.ivsize;
+               balg.min_keysize = alg->cra_ablkcipher.min_keysize;
+               balg.max_keysize = alg->cra_ablkcipher.max_keysize;
+
+               balg.setkey = alg->cra_ablkcipher.setkey;
+               balg.encrypt = alg->cra_ablkcipher.encrypt;
+               balg.decrypt = alg->cra_ablkcipher.decrypt;
+
+               balg.geniv = alg->cra_ablkcipher.geniv;
+       }
+
+       err = -EINVAL;
+       if (!balg.ivsize)
+               goto err_drop_alg;
+
+       /*
+        * This is only true if we're constructing an algorithm with its
+        * default IV generator.  For the default generator we elide the
+        * template name and double-check the IV generator.
+        */
+       if (algt->mask & CRYPTO_ALG_GENIV) {
+               if (!balg.geniv)
+                       balg.geniv = crypto_default_geniv(alg);
+               err = -EAGAIN;
+               if (strcmp(tmpl->name, balg.geniv))
+                       goto err_drop_alg;
+
+               memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+               memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
+                      CRYPTO_MAX_ALG_NAME);
+       } else {
+               err = -ENAMETOOLONG;
+               if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+                            "%s(%s)", tmpl->name, alg->cra_name) >=
+                   CRYPTO_MAX_ALG_NAME)
+                       goto err_drop_alg;
+               if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                            "%s(%s)", tmpl->name, alg->cra_driver_name) >=
+                   CRYPTO_MAX_ALG_NAME)
+                       goto err_drop_alg;
+       }
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV;
+       inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = alg->cra_blocksize;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = &crypto_givcipher_type;
+
+       inst->alg.cra_ablkcipher.ivsize = balg.ivsize;
+       inst->alg.cra_ablkcipher.min_keysize = balg.min_keysize;
+       inst->alg.cra_ablkcipher.max_keysize = balg.max_keysize;
+       inst->alg.cra_ablkcipher.geniv = balg.geniv;
+
+       inst->alg.cra_ablkcipher.setkey = balg.setkey;
+       inst->alg.cra_ablkcipher.encrypt = balg.encrypt;
+       inst->alg.cra_ablkcipher.decrypt = balg.decrypt;
+
+out:
+       return inst;
+
+err_drop_alg:
+       crypto_drop_skcipher(spawn);
+err_free_inst:
+       kfree(inst);
+       inst = ERR_PTR(err);
+       goto out;
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_alloc);
+
+void skcipher_geniv_free(struct crypto_instance *inst)
+{
+       crypto_drop_skcipher(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_free);
+
+int skcipher_geniv_init(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct crypto_ablkcipher *cipher;
+
+       cipher = crypto_spawn_skcipher(crypto_instance_ctx(inst));
+       if (IS_ERR(cipher))
+               return PTR_ERR(cipher);
+
+       tfm->crt_ablkcipher.base = cipher;
+       tfm->crt_ablkcipher.reqsize += crypto_ablkcipher_reqsize(cipher);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_init);
+
+void skcipher_geniv_exit(struct crypto_tfm *tfm)
+{
+       crypto_free_ablkcipher(tfm->crt_ablkcipher.base);
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_exit);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic block chaining cipher type");
index 6877ecfd90bb8b2d34f2dce3bab6e6689830830e..493fee7e0a8b46bbd9933d92681e0a7c16d0ab81 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-
-#define CAMELLIA_MIN_KEY_SIZE        16
-#define CAMELLIA_MAX_KEY_SIZE        32
-#define CAMELLIA_BLOCK_SIZE 16
-#define CAMELLIA_TABLE_BYTE_LEN 272
-#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4)
-
-typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN];
-
-
-/* key constants */
-
-#define CAMELLIA_SIGMA1L (0xA09E667FL)
-#define CAMELLIA_SIGMA1R (0x3BCC908BL)
-#define CAMELLIA_SIGMA2L (0xB67AE858L)
-#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
-#define CAMELLIA_SIGMA3L (0xC6EF372FL)
-#define CAMELLIA_SIGMA3R (0xE94F82BEL)
-#define CAMELLIA_SIGMA4L (0x54FF53A5L)
-#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
-#define CAMELLIA_SIGMA5L (0x10E527FAL)
-#define CAMELLIA_SIGMA5R (0xDE682D1DL)
-#define CAMELLIA_SIGMA6L (0xB05688C2L)
-#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
-
-struct camellia_ctx {
-       int key_length;
-       KEY_TABLE_TYPE key_table;
-};
-
-
-/*
- *  macros
- */
-
-
-# define GETU32(pt) (((u32)(pt)[0] << 24)      \
-                    ^ ((u32)(pt)[1] << 16)     \
-                    ^ ((u32)(pt)[2] <<  8)     \
-                    ^ ((u32)(pt)[3]))
-
-#define COPY4WORD(dst, src)                    \
-    do {                                       \
-       (dst)[0]=(src)[0];                      \
-       (dst)[1]=(src)[1];                      \
-       (dst)[2]=(src)[2];                      \
-       (dst)[3]=(src)[3];                      \
-    }while(0)
-
-#define SWAP4WORD(word)                                \
-    do {                                       \
-       CAMELLIA_SWAP4((word)[0]);              \
-       CAMELLIA_SWAP4((word)[1]);              \
-       CAMELLIA_SWAP4((word)[2]);              \
-       CAMELLIA_SWAP4((word)[3]);              \
-    }while(0)
-
-#define XOR4WORD(a, b)/* a = a ^ b */          \
-    do {                                       \
-       (a)[0]^=(b)[0];                         \
-       (a)[1]^=(b)[1];                         \
-       (a)[2]^=(b)[2];                         \
-       (a)[3]^=(b)[3];                         \
-    }while(0)
-
-#define XOR4WORD2(a, b, c)/* a = b ^ c */      \
-    do {                                       \
-       (a)[0]=(b)[0]^(c)[0];                   \
-       (a)[1]=(b)[1]^(c)[1];                   \
-       (a)[2]=(b)[2]^(c)[2];                   \
-       (a)[3]=(b)[3]^(c)[3];                   \
-    }while(0)
-
-#define CAMELLIA_SUBKEY_L(INDEX) (subkey[(INDEX)*2])
-#define CAMELLIA_SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1])
-
-/* rotation right shift 1byte */
-#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24))
-/* rotation left shift 1bit */
-#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31))
-/* rotation left shift 1byte */
-#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24))
-
-#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits)   \
-    do {                                               \
-       w0 = ll;                                        \
-       ll = (ll << bits) + (lr >> (32 - bits));        \
-       lr = (lr << bits) + (rl >> (32 - bits));        \
-       rl = (rl << bits) + (rr >> (32 - bits));        \
-       rr = (rr << bits) + (w0 >> (32 - bits));        \
-    } while(0)
-
-#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits)        \
-    do {                                               \
-       w0 = ll;                                        \
-       w1 = lr;                                        \
-       ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \
-       lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \
-       rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \
-       rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \
-    } while(0)
-
-#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)])
-#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)])
-#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)])
-#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)])
-
-#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)     \
-    do {                                                       \
-       il = xl ^ kl;                                           \
-       ir = xr ^ kr;                                           \
-       t0 = il >> 16;                                          \
-       t1 = ir >> 16;                                          \
-       yl = CAMELLIA_SP1110(ir & 0xff)                         \
-           ^ CAMELLIA_SP0222((t1 >> 8) & 0xff)                 \
-           ^ CAMELLIA_SP3033(t1 & 0xff)                        \
-           ^ CAMELLIA_SP4404((ir >> 8) & 0xff);                \
-       yr = CAMELLIA_SP1110((t0 >> 8) & 0xff)                  \
-           ^ CAMELLIA_SP0222(t0 & 0xff)                        \
-           ^ CAMELLIA_SP3033((il >> 8) & 0xff)                 \
-           ^ CAMELLIA_SP4404(il & 0xff);                       \
-       yl ^= yr;                                               \
-       yr = CAMELLIA_RR8(yr);                                  \
-       yr ^= yl;                                               \
-    } while(0)
-
-
-/*
- * for speed up
- *
- */
-#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
-    do {                                                               \
-       t0 = kll;                                                       \
-       t2 = krr;                                                       \
-       t0 &= ll;                                                       \
-       t2 |= rr;                                                       \
-       rl ^= t2;                                                       \
-       lr ^= CAMELLIA_RL1(t0);                                         \
-       t3 = krl;                                                       \
-       t1 = klr;                                                       \
-       t3 &= rl;                                                       \
-       t1 |= lr;                                                       \
-       ll ^= t1;                                                       \
-       rr ^= CAMELLIA_RL1(t3);                                         \
-    } while(0)
-
-#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)       \
-    do {                                                               \
-       ir =  CAMELLIA_SP1110(xr & 0xff);                               \
-       il =  CAMELLIA_SP1110((xl>>24) & 0xff);                         \
-       ir ^= CAMELLIA_SP0222((xr>>24) & 0xff);                         \
-       il ^= CAMELLIA_SP0222((xl>>16) & 0xff);                         \
-       ir ^= CAMELLIA_SP3033((xr>>16) & 0xff);                         \
-       il ^= CAMELLIA_SP3033((xl>>8) & 0xff);                          \
-       ir ^= CAMELLIA_SP4404((xr>>8) & 0xff);                          \
-       il ^= CAMELLIA_SP4404(xl & 0xff);                               \
-       il ^= kl;                                                       \
-       ir ^= il ^ kr;                                                  \
-       yl ^= ir;                                                       \
-       yr ^= CAMELLIA_RR8(il) ^ ir;                                    \
-    } while(0)
-
-/**
- * Stuff related to the Camellia key schedule
- */
-#define SUBL(x) subL[(x)]
-#define SUBR(x) subR[(x)]
-
-
 static const u32 camellia_sp1110[256] = {
        0x70707000,0x82828200,0x2c2c2c00,0xececec00,
        0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500,
@@ -475,67 +305,348 @@ static const u32 camellia_sp4404[256] = {
 };
 
 
+#define CAMELLIA_MIN_KEY_SIZE        16
+#define CAMELLIA_MAX_KEY_SIZE        32
+#define CAMELLIA_BLOCK_SIZE          16
+#define CAMELLIA_TABLE_BYTE_LEN     272
+
+/*
+ * NB: L and R below stand for 'left' and 'right' as in written numbers.
+ * That is, in (xxxL,xxxR) pair xxxL holds most significant digits,
+ * _not_ least significant ones!
+ */
+
+
+/* key constants */
+
+#define CAMELLIA_SIGMA1L (0xA09E667FL)
+#define CAMELLIA_SIGMA1R (0x3BCC908BL)
+#define CAMELLIA_SIGMA2L (0xB67AE858L)
+#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L (0xC6EF372FL)
+#define CAMELLIA_SIGMA3R (0xE94F82BEL)
+#define CAMELLIA_SIGMA4L (0x54FF53A5L)
+#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L (0x10E527FAL)
+#define CAMELLIA_SIGMA5R (0xDE682D1DL)
+#define CAMELLIA_SIGMA6L (0xB05688C2L)
+#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
+
+/*
+ *  macros
+ */
+#define GETU32(v, pt) \
+    do { \
+       /* latest breed of gcc is clever enough to use move */ \
+       memcpy(&(v), (pt), 4); \
+       (v) = be32_to_cpu(v); \
+    } while(0)
+
+/* rotation right shift 1byte */
+#define ROR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define ROL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define ROL8(x) (((x) << 8) + ((x) >> 24))
+
+#define ROLDQ(ll, lr, rl, rr, w0, w1, bits)            \
+    do {                                               \
+       w0 = ll;                                        \
+       ll = (ll << bits) + (lr >> (32 - bits));        \
+       lr = (lr << bits) + (rl >> (32 - bits));        \
+       rl = (rl << bits) + (rr >> (32 - bits));        \
+       rr = (rr << bits) + (w0 >> (32 - bits));        \
+    } while(0)
+
+#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits)         \
+    do {                                               \
+       w0 = ll;                                        \
+       w1 = lr;                                        \
+       ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \
+       lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \
+       rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \
+       rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \
+    } while(0)
+
+#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)     \
+    do {                                                       \
+       il = xl ^ kl;                                           \
+       ir = xr ^ kr;                                           \
+       t0 = il >> 16;                                          \
+       t1 = ir >> 16;                                          \
+       yl = camellia_sp1110[(u8)(ir     )]                     \
+          ^ camellia_sp0222[    (t1 >> 8)]                     \
+          ^ camellia_sp3033[(u8)(t1     )]                     \
+          ^ camellia_sp4404[(u8)(ir >> 8)];                    \
+       yr = camellia_sp1110[    (t0 >> 8)]                     \
+          ^ camellia_sp0222[(u8)(t0     )]                     \
+          ^ camellia_sp3033[(u8)(il >> 8)]                     \
+          ^ camellia_sp4404[(u8)(il     )];                    \
+       yl ^= yr;                                               \
+       yr = ROR8(yr);                                          \
+       yr ^= yl;                                               \
+    } while(0)
+
+#define SUBKEY_L(INDEX) (subkey[(INDEX)*2])
+#define SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1])
+
+static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
+{
+       u32 dw, tl, tr;
+       u32 kw4l, kw4r;
+       int i;
+
+       /* absorb kw2 to other subkeys */
+       /* round 2 */
+       subL[3] ^= subL[1]; subR[3] ^= subR[1];
+       /* round 4 */
+       subL[5] ^= subL[1]; subR[5] ^= subR[1];
+       /* round 6 */
+       subL[7] ^= subL[1]; subR[7] ^= subR[1];
+       subL[1] ^= subR[1] & ~subR[9];
+       dw = subL[1] & subL[9],
+               subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */
+       /* round 8 */
+       subL[11] ^= subL[1]; subR[11] ^= subR[1];
+       /* round 10 */
+       subL[13] ^= subL[1]; subR[13] ^= subR[1];
+       /* round 12 */
+       subL[15] ^= subL[1]; subR[15] ^= subR[1];
+       subL[1] ^= subR[1] & ~subR[17];
+       dw = subL[1] & subL[17],
+               subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */
+       /* round 14 */
+       subL[19] ^= subL[1]; subR[19] ^= subR[1];
+       /* round 16 */
+       subL[21] ^= subL[1]; subR[21] ^= subR[1];
+       /* round 18 */
+       subL[23] ^= subL[1]; subR[23] ^= subR[1];
+       if (max == 24) {
+               /* kw3 */
+               subL[24] ^= subL[1]; subR[24] ^= subR[1];
+
+       /* absorb kw4 to other subkeys */
+               kw4l = subL[25]; kw4r = subR[25];
+       } else {
+               subL[1] ^= subR[1] & ~subR[25];
+               dw = subL[1] & subL[25],
+                       subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */
+               /* round 20 */
+               subL[27] ^= subL[1]; subR[27] ^= subR[1];
+               /* round 22 */
+               subL[29] ^= subL[1]; subR[29] ^= subR[1];
+               /* round 24 */
+               subL[31] ^= subL[1]; subR[31] ^= subR[1];
+               /* kw3 */
+               subL[32] ^= subL[1]; subR[32] ^= subR[1];
+
+       /* absorb kw4 to other subkeys */
+               kw4l = subL[33]; kw4r = subR[33];
+               /* round 23 */
+               subL[30] ^= kw4l; subR[30] ^= kw4r;
+               /* round 21 */
+               subL[28] ^= kw4l; subR[28] ^= kw4r;
+               /* round 19 */
+               subL[26] ^= kw4l; subR[26] ^= kw4r;
+               kw4l ^= kw4r & ~subR[24];
+               dw = kw4l & subL[24],
+                       kw4r ^= ROL1(dw); /* modified for FL(kl5) */
+       }
+       /* round 17 */
+       subL[22] ^= kw4l; subR[22] ^= kw4r;
+       /* round 15 */
+       subL[20] ^= kw4l; subR[20] ^= kw4r;
+       /* round 13 */
+       subL[18] ^= kw4l; subR[18] ^= kw4r;
+       kw4l ^= kw4r & ~subR[16];
+       dw = kw4l & subL[16],
+               kw4r ^= ROL1(dw); /* modified for FL(kl3) */
+       /* round 11 */
+       subL[14] ^= kw4l; subR[14] ^= kw4r;
+       /* round 9 */
+       subL[12] ^= kw4l; subR[12] ^= kw4r;
+       /* round 7 */
+       subL[10] ^= kw4l; subR[10] ^= kw4r;
+       kw4l ^= kw4r & ~subR[8];
+       dw = kw4l & subL[8],
+               kw4r ^= ROL1(dw); /* modified for FL(kl1) */
+       /* round 5 */
+       subL[6] ^= kw4l; subR[6] ^= kw4r;
+       /* round 3 */
+       subL[4] ^= kw4l; subR[4] ^= kw4r;
+       /* round 1 */
+       subL[2] ^= kw4l; subR[2] ^= kw4r;
+       /* kw1 */
+       subL[0] ^= kw4l; subR[0] ^= kw4r;
+
+       /* key XOR is end of F-function */
+       SUBKEY_L(0) = subL[0] ^ subL[2];/* kw1 */
+       SUBKEY_R(0) = subR[0] ^ subR[2];
+       SUBKEY_L(2) = subL[3];       /* round 1 */
+       SUBKEY_R(2) = subR[3];
+       SUBKEY_L(3) = subL[2] ^ subL[4]; /* round 2 */
+       SUBKEY_R(3) = subR[2] ^ subR[4];
+       SUBKEY_L(4) = subL[3] ^ subL[5]; /* round 3 */
+       SUBKEY_R(4) = subR[3] ^ subR[5];
+       SUBKEY_L(5) = subL[4] ^ subL[6]; /* round 4 */
+       SUBKEY_R(5) = subR[4] ^ subR[6];
+       SUBKEY_L(6) = subL[5] ^ subL[7]; /* round 5 */
+       SUBKEY_R(6) = subR[5] ^ subR[7];
+       tl = subL[10] ^ (subR[10] & ~subR[8]);
+       dw = tl & subL[8],  /* FL(kl1) */
+               tr = subR[10] ^ ROL1(dw);
+       SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
+       SUBKEY_R(7) = subR[6] ^ tr;
+       SUBKEY_L(8) = subL[8];       /* FL(kl1) */
+       SUBKEY_R(8) = subR[8];
+       SUBKEY_L(9) = subL[9];       /* FLinv(kl2) */
+       SUBKEY_R(9) = subR[9];
+       tl = subL[7] ^ (subR[7] & ~subR[9]);
+       dw = tl & subL[9],  /* FLinv(kl2) */
+               tr = subR[7] ^ ROL1(dw);
+       SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
+       SUBKEY_R(10) = tr ^ subR[11];
+       SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
+       SUBKEY_R(11) = subR[10] ^ subR[12];
+       SUBKEY_L(12) = subL[11] ^ subL[13]; /* round 9 */
+       SUBKEY_R(12) = subR[11] ^ subR[13];
+       SUBKEY_L(13) = subL[12] ^ subL[14]; /* round 10 */
+       SUBKEY_R(13) = subR[12] ^ subR[14];
+       SUBKEY_L(14) = subL[13] ^ subL[15]; /* round 11 */
+       SUBKEY_R(14) = subR[13] ^ subR[15];
+       tl = subL[18] ^ (subR[18] & ~subR[16]);
+       dw = tl & subL[16], /* FL(kl3) */
+               tr = subR[18] ^ ROL1(dw);
+       SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
+       SUBKEY_R(15) = subR[14] ^ tr;
+       SUBKEY_L(16) = subL[16];     /* FL(kl3) */
+       SUBKEY_R(16) = subR[16];
+       SUBKEY_L(17) = subL[17];     /* FLinv(kl4) */
+       SUBKEY_R(17) = subR[17];
+       tl = subL[15] ^ (subR[15] & ~subR[17]);
+       dw = tl & subL[17], /* FLinv(kl4) */
+               tr = subR[15] ^ ROL1(dw);
+       SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
+       SUBKEY_R(18) = tr ^ subR[19];
+       SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
+       SUBKEY_R(19) = subR[18] ^ subR[20];
+       SUBKEY_L(20) = subL[19] ^ subL[21]; /* round 15 */
+       SUBKEY_R(20) = subR[19] ^ subR[21];
+       SUBKEY_L(21) = subL[20] ^ subL[22]; /* round 16 */
+       SUBKEY_R(21) = subR[20] ^ subR[22];
+       SUBKEY_L(22) = subL[21] ^ subL[23]; /* round 17 */
+       SUBKEY_R(22) = subR[21] ^ subR[23];
+       if (max == 24) {
+               SUBKEY_L(23) = subL[22];     /* round 18 */
+               SUBKEY_R(23) = subR[22];
+               SUBKEY_L(24) = subL[24] ^ subL[23]; /* kw3 */
+               SUBKEY_R(24) = subR[24] ^ subR[23];
+       } else {
+               tl = subL[26] ^ (subR[26] & ~subR[24]);
+               dw = tl & subL[24], /* FL(kl5) */
+                       tr = subR[26] ^ ROL1(dw);
+               SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
+               SUBKEY_R(23) = subR[22] ^ tr;
+               SUBKEY_L(24) = subL[24];     /* FL(kl5) */
+               SUBKEY_R(24) = subR[24];
+               SUBKEY_L(25) = subL[25];     /* FLinv(kl6) */
+               SUBKEY_R(25) = subR[25];
+               tl = subL[23] ^ (subR[23] & ~subR[25]);
+               dw = tl & subL[25], /* FLinv(kl6) */
+                       tr = subR[23] ^ ROL1(dw);
+               SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
+               SUBKEY_R(26) = tr ^ subR[27];
+               SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
+               SUBKEY_R(27) = subR[26] ^ subR[28];
+               SUBKEY_L(28) = subL[27] ^ subL[29]; /* round 21 */
+               SUBKEY_R(28) = subR[27] ^ subR[29];
+               SUBKEY_L(29) = subL[28] ^ subL[30]; /* round 22 */
+               SUBKEY_R(29) = subR[28] ^ subR[30];
+               SUBKEY_L(30) = subL[29] ^ subL[31]; /* round 23 */
+               SUBKEY_R(30) = subR[29] ^ subR[31];
+               SUBKEY_L(31) = subL[30];     /* round 24 */
+               SUBKEY_R(31) = subR[30];
+               SUBKEY_L(32) = subL[32] ^ subL[31]; /* kw3 */
+               SUBKEY_R(32) = subR[32] ^ subR[31];
+       }
+
+       /* apply the inverse of the last half of P-function */
+       i = 2;
+       do {
+               dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */
+               SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw;
+               dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */
+               SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw;
+               dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */
+               SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw;
+               dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */
+               SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw;
+               dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */
+               SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw;
+               dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */
+               SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw;
+               i += 8;
+       } while (i < max);
+}
 
 static void camellia_setup128(const unsigned char *key, u32 *subkey)
 {
        u32 kll, klr, krl, krr;
        u32 il, ir, t0, t1, w0, w1;
-       u32 kw4l, kw4r, dw, tl, tr;
        u32 subL[26];
        u32 subR[26];
 
        /**
-        *  k == kll || klr || krl || krr (|| is concatination)
-        */
-       kll = GETU32(key     );
-       klr = GETU32(key +  4);
-       krl = GETU32(key +  8);
-       krr = GETU32(key + 12);
-       /**
-        * generate KL dependent subkeys
+        *  k == kll || klr || krl || krr (|| is concatenation)
         */
+       GETU32(kll, key     );
+       GETU32(klr, key +  4);
+       GETU32(krl, key +  8);
+       GETU32(krr, key + 12);
+
+       /* generate KL dependent subkeys */
        /* kw1 */
-       SUBL(0) = kll; SUBR(0) = klr;
+       subL[0] = kll; subR[0] = klr;
        /* kw2 */
-       SUBL(1) = krl; SUBR(1) = krr;
+       subL[1] = krl; subR[1] = krr;
        /* rotation left shift 15bit */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* k3 */
-       SUBL(4) = kll; SUBR(4) = klr;
+       subL[4] = kll; subR[4] = klr;
        /* k4 */
-       SUBL(5) = krl; SUBR(5) = krr;
+       subL[5] = krl; subR[5] = krr;
        /* rotation left shift 15+30bit */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 30);
        /* k7 */
-       SUBL(10) = kll; SUBR(10) = klr;
+       subL[10] = kll; subR[10] = klr;
        /* k8 */
-       SUBL(11) = krl; SUBR(11) = krr;
+       subL[11] = krl; subR[11] = krr;
        /* rotation left shift 15+30+15bit */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* k10 */
-       SUBL(13) = krl; SUBR(13) = krr;
+       subL[13] = krl; subR[13] = krr;
        /* rotation left shift 15+30+15+17 bit */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
        /* kl3 */
-       SUBL(16) = kll; SUBR(16) = klr;
+       subL[16] = kll; subR[16] = klr;
        /* kl4 */
-       SUBL(17) = krl; SUBR(17) = krr;
+       subL[17] = krl; subR[17] = krr;
        /* rotation left shift 15+30+15+17+17 bit */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
        /* k13 */
-       SUBL(18) = kll; SUBR(18) = klr;
+       subL[18] = kll; subR[18] = klr;
        /* k14 */
-       SUBL(19) = krl; SUBR(19) = krr;
+       subL[19] = krl; subR[19] = krr;
        /* rotation left shift 15+30+15+17+17+17 bit */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
        /* k17 */
-       SUBL(22) = kll; SUBR(22) = klr;
+       subL[22] = kll; subR[22] = klr;
        /* k18 */
-       SUBL(23) = krl; SUBR(23) = krr;
+       subL[23] = krl; subR[23] = krr;
 
        /* generate KA */
-       kll = SUBL(0); klr = SUBR(0);
-       krl = SUBL(1); krr = SUBR(1);
+       kll = subL[0]; klr = subR[0];
+       krl = subL[1]; krr = subR[1];
        CAMELLIA_F(kll, klr,
                   CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
                   w0, w1, il, ir, t0, t1);
@@ -555,306 +666,108 @@ static void camellia_setup128(const unsigned char *key, u32 *subkey)
 
        /* generate KA dependent subkeys */
        /* k1, k2 */
-       SUBL(2) = kll; SUBR(2) = klr;
-       SUBL(3) = krl; SUBR(3) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       subL[2] = kll; subR[2] = klr;
+       subL[3] = krl; subR[3] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* k5,k6 */
-       SUBL(6) = kll; SUBR(6) = klr;
-       SUBL(7) = krl; SUBR(7) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       subL[6] = kll; subR[6] = klr;
+       subL[7] = krl; subR[7] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* kl1, kl2 */
-       SUBL(8) = kll; SUBR(8) = klr;
-       SUBL(9) = krl; SUBR(9) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       subL[8] = kll; subR[8] = klr;
+       subL[9] = krl; subR[9] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* k9 */
-       SUBL(12) = kll; SUBR(12) = klr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       subL[12] = kll; subR[12] = klr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* k11, k12 */
-       SUBL(14) = kll; SUBR(14) = klr;
-       SUBL(15) = krl; SUBR(15) = krr;
-       CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+       subL[14] = kll; subR[14] = klr;
+       subL[15] = krl; subR[15] = krr;
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
        /* k15, k16 */
-       SUBL(20) = kll; SUBR(20) = klr;
-       SUBL(21) = krl; SUBR(21) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       subL[20] = kll; subR[20] = klr;
+       subL[21] = krl; subR[21] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
        /* kw3, kw4 */
-       SUBL(24) = kll; SUBR(24) = klr;
-       SUBL(25) = krl; SUBR(25) = krr;
+       subL[24] = kll; subR[24] = klr;
+       subL[25] = krl; subR[25] = krr;
 
-
-       /* absorb kw2 to other subkeys */
-       /* round 2 */
-       SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1);
-       /* round 4 */
-       SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1);
-       /* round 6 */
-       SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1);
-       SUBL(1) ^= SUBR(1) & ~SUBR(9);
-       dw = SUBL(1) & SUBL(9),
-               SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */
-       /* round 8 */
-       SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1);
-       /* round 10 */
-       SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1);
-       /* round 12 */
-       SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1);
-       SUBL(1) ^= SUBR(1) & ~SUBR(17);
-       dw = SUBL(1) & SUBL(17),
-               SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */
-       /* round 14 */
-       SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1);
-       /* round 16 */
-       SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1);
-       /* round 18 */
-       SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1);
-       /* kw3 */
-       SUBL(24) ^= SUBL(1); SUBR(24) ^= SUBR(1);
-
-       /* absorb kw4 to other subkeys */
-       kw4l = SUBL(25); kw4r = SUBR(25);
-       /* round 17 */
-       SUBL(22) ^= kw4l; SUBR(22) ^= kw4r;
-       /* round 15 */
-       SUBL(20) ^= kw4l; SUBR(20) ^= kw4r;
-       /* round 13 */
-       SUBL(18) ^= kw4l; SUBR(18) ^= kw4r;
-       kw4l ^= kw4r & ~SUBR(16);
-       dw = kw4l & SUBL(16),
-               kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */
-       /* round 11 */
-       SUBL(14) ^= kw4l; SUBR(14) ^= kw4r;
-       /* round 9 */
-       SUBL(12) ^= kw4l; SUBR(12) ^= kw4r;
-       /* round 7 */
-       SUBL(10) ^= kw4l; SUBR(10) ^= kw4r;
-       kw4l ^= kw4r & ~SUBR(8);
-       dw = kw4l & SUBL(8),
-               kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */
-       /* round 5 */
-       SUBL(6) ^= kw4l; SUBR(6) ^= kw4r;
-       /* round 3 */
-       SUBL(4) ^= kw4l; SUBR(4) ^= kw4r;
-       /* round 1 */
-       SUBL(2) ^= kw4l; SUBR(2) ^= kw4r;
-       /* kw1 */
-       SUBL(0) ^= kw4l; SUBR(0) ^= kw4r;
-
-
-       /* key XOR is end of F-function */
-       CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */
-       CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2);
-       CAMELLIA_SUBKEY_L(2) = SUBL(3);       /* round 1 */
-       CAMELLIA_SUBKEY_R(2) = SUBR(3);
-       CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */
-       CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4);
-       CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */
-       CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5);
-       CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */
-       CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6);
-       CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */
-       CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7);
-       tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8));
-       dw = tl & SUBL(8),  /* FL(kl1) */
-               tr = SUBR(10) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */
-       CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr;
-       CAMELLIA_SUBKEY_L(8) = SUBL(8);       /* FL(kl1) */
-       CAMELLIA_SUBKEY_R(8) = SUBR(8);
-       CAMELLIA_SUBKEY_L(9) = SUBL(9);       /* FLinv(kl2) */
-       CAMELLIA_SUBKEY_R(9) = SUBR(9);
-       tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9));
-       dw = tl & SUBL(9),  /* FLinv(kl2) */
-               tr = SUBR(7) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */
-       CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11);
-       CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */
-       CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12);
-       CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */
-       CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13);
-       CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */
-       CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14);
-       CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */
-       CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15);
-       tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16));
-       dw = tl & SUBL(16), /* FL(kl3) */
-               tr = SUBR(18) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */
-       CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr;
-       CAMELLIA_SUBKEY_L(16) = SUBL(16);     /* FL(kl3) */
-       CAMELLIA_SUBKEY_R(16) = SUBR(16);
-       CAMELLIA_SUBKEY_L(17) = SUBL(17);     /* FLinv(kl4) */
-       CAMELLIA_SUBKEY_R(17) = SUBR(17);
-       tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17));
-       dw = tl & SUBL(17), /* FLinv(kl4) */
-               tr = SUBR(15) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */
-       CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19);
-       CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */
-       CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20);
-       CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */
-       CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21);
-       CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */
-       CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22);
-       CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */
-       CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23);
-       CAMELLIA_SUBKEY_L(23) = SUBL(22);     /* round 18 */
-       CAMELLIA_SUBKEY_R(23) = SUBR(22);
-       CAMELLIA_SUBKEY_L(24) = SUBL(24) ^ SUBL(23); /* kw3 */
-       CAMELLIA_SUBKEY_R(24) = SUBR(24) ^ SUBR(23);
-
-       /* apply the inverse of the last half of P-function */
-       dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2),
-               dw = CAMELLIA_RL8(dw);/* round 1 */
-       CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw,
-               CAMELLIA_SUBKEY_L(2) = dw;
-       dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3),
-               dw = CAMELLIA_RL8(dw);/* round 2 */
-       CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw,
-               CAMELLIA_SUBKEY_L(3) = dw;
-       dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4),
-               dw = CAMELLIA_RL8(dw);/* round 3 */
-       CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw,
-               CAMELLIA_SUBKEY_L(4) = dw;
-       dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5),
-               dw = CAMELLIA_RL8(dw);/* round 4 */
-       CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw,
-               CAMELLIA_SUBKEY_L(5) = dw;
-       dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6),
-               dw = CAMELLIA_RL8(dw);/* round 5 */
-       CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw,
-               CAMELLIA_SUBKEY_L(6) = dw;
-       dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7),
-               dw = CAMELLIA_RL8(dw);/* round 6 */
-       CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw,
-               CAMELLIA_SUBKEY_L(7) = dw;
-       dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10),
-               dw = CAMELLIA_RL8(dw);/* round 7 */
-       CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw,
-               CAMELLIA_SUBKEY_L(10) = dw;
-       dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11),
-               dw = CAMELLIA_RL8(dw);/* round 8 */
-       CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw,
-               CAMELLIA_SUBKEY_L(11) = dw;
-       dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12),
-               dw = CAMELLIA_RL8(dw);/* round 9 */
-       CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw,
-               CAMELLIA_SUBKEY_L(12) = dw;
-       dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13),
-               dw = CAMELLIA_RL8(dw);/* round 10 */
-       CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw,
-               CAMELLIA_SUBKEY_L(13) = dw;
-       dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14),
-               dw = CAMELLIA_RL8(dw);/* round 11 */
-       CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw,
-               CAMELLIA_SUBKEY_L(14) = dw;
-       dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15),
-               dw = CAMELLIA_RL8(dw);/* round 12 */
-       CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw,
-               CAMELLIA_SUBKEY_L(15) = dw;
-       dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18),
-               dw = CAMELLIA_RL8(dw);/* round 13 */
-       CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw,
-               CAMELLIA_SUBKEY_L(18) = dw;
-       dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19),
-               dw = CAMELLIA_RL8(dw);/* round 14 */
-       CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw,
-               CAMELLIA_SUBKEY_L(19) = dw;
-       dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20),
-               dw = CAMELLIA_RL8(dw);/* round 15 */
-       CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw,
-               CAMELLIA_SUBKEY_L(20) = dw;
-       dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21),
-               dw = CAMELLIA_RL8(dw);/* round 16 */
-       CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw,
-               CAMELLIA_SUBKEY_L(21) = dw;
-       dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22),
-               dw = CAMELLIA_RL8(dw);/* round 17 */
-       CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw,
-               CAMELLIA_SUBKEY_L(22) = dw;
-       dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23),
-               dw = CAMELLIA_RL8(dw);/* round 18 */
-       CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw,
-               CAMELLIA_SUBKEY_L(23) = dw;
-
-       return;
+       camellia_setup_tail(subkey, subL, subR, 24);
 }
 
-
 static void camellia_setup256(const unsigned char *key, u32 *subkey)
 {
-       u32 kll,klr,krl,krr;           /* left half of key */
-       u32 krll,krlr,krrl,krrr;       /* right half of key */
+       u32 kll, klr, krl, krr;        /* left half of key */
+       u32 krll, krlr, krrl, krrr;    /* right half of key */
        u32 il, ir, t0, t1, w0, w1;    /* temporary variables */
-       u32 kw4l, kw4r, dw, tl, tr;
        u32 subL[34];
        u32 subR[34];
 
        /**
         *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
-        *  (|| is concatination)
+        *  (|| is concatenation)
         */
-
-       kll  = GETU32(key     );
-       klr  = GETU32(key +  4);
-       krl  = GETU32(key +  8);
-       krr  = GETU32(key + 12);
-       krll = GETU32(key + 16);
-       krlr = GETU32(key + 20);
-       krrl = GETU32(key + 24);
-       krrr = GETU32(key + 28);
+       GETU32(kll,  key     );
+       GETU32(klr,  key +  4);
+       GETU32(krl,  key +  8);
+       GETU32(krr,  key + 12);
+       GETU32(krll, key + 16);
+       GETU32(krlr, key + 20);
+       GETU32(krrl, key + 24);
+       GETU32(krrr, key + 28);
 
        /* generate KL dependent subkeys */
        /* kw1 */
-       SUBL(0) = kll; SUBR(0) = klr;
+       subL[0] = kll; subR[0] = klr;
        /* kw2 */
-       SUBL(1) = krl; SUBR(1) = krr;
-       CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
+       subL[1] = krl; subR[1] = krr;
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
        /* k9 */
-       SUBL(12) = kll; SUBR(12) = klr;
+       subL[12] = kll; subR[12] = klr;
        /* k10 */
-       SUBL(13) = krl; SUBR(13) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       subL[13] = krl; subR[13] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* kl3 */
-       SUBL(16) = kll; SUBR(16) = klr;
+       subL[16] = kll; subR[16] = klr;
        /* kl4 */
-       SUBL(17) = krl; SUBR(17) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       subL[17] = krl; subR[17] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
        /* k17 */
-       SUBL(22) = kll; SUBR(22) = klr;
+       subL[22] = kll; subR[22] = klr;
        /* k18 */
-       SUBL(23) = krl; SUBR(23) = krr;
-       CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+       subL[23] = krl; subR[23] = krr;
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
        /* k23 */
-       SUBL(30) = kll; SUBR(30) = klr;
+       subL[30] = kll; subR[30] = klr;
        /* k24 */
-       SUBL(31) = krl; SUBR(31) = krr;
+       subL[31] = krl; subR[31] = krr;
 
        /* generate KR dependent subkeys */
-       CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
        /* k3 */
-       SUBL(4) = krll; SUBR(4) = krlr;
+       subL[4] = krll; subR[4] = krlr;
        /* k4 */
-       SUBL(5) = krrl; SUBR(5) = krrr;
-       CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+       subL[5] = krrl; subR[5] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
        /* kl1 */
-       SUBL(8) = krll; SUBR(8) = krlr;
+       subL[8] = krll; subR[8] = krlr;
        /* kl2 */
-       SUBL(9) = krrl; SUBR(9) = krrr;
-       CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+       subL[9] = krrl; subR[9] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
        /* k13 */
-       SUBL(18) = krll; SUBR(18) = krlr;
+       subL[18] = krll; subR[18] = krlr;
        /* k14 */
-       SUBL(19) = krrl; SUBR(19) = krrr;
-       CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+       subL[19] = krrl; subR[19] = krrr;
+       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
        /* k19 */
-       SUBL(26) = krll; SUBR(26) = krlr;
+       subL[26] = krll; subR[26] = krlr;
        /* k20 */
-       SUBL(27) = krrl; SUBR(27) = krrr;
-       CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+       subL[27] = krrl; subR[27] = krrr;
+       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
 
        /* generate KA */
-       kll = SUBL(0) ^ krll; klr = SUBR(0) ^ krlr;
-       krl = SUBL(1) ^ krrl; krr = SUBR(1) ^ krrr;
+       kll = subL[0] ^ krll; klr = subR[0] ^ krlr;
+       krl = subL[1] ^ krrl; krr = subR[1] ^ krrr;
        CAMELLIA_F(kll, klr,
                   CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
                   w0, w1, il, ir, t0, t1);
@@ -885,310 +798,50 @@ static void camellia_setup256(const unsigned char *key, u32 *subkey)
        krll ^= w0; krlr ^= w1;
 
        /* generate KA dependent subkeys */
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
        /* k5 */
-       SUBL(6) = kll; SUBR(6) = klr;
+       subL[6] = kll; subR[6] = klr;
        /* k6 */
-       SUBL(7) = krl; SUBR(7) = krr;
-       CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+       subL[7] = krl; subR[7] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 30);
        /* k11 */
-       SUBL(14) = kll; SUBR(14) = klr;
+       subL[14] = kll; subR[14] = klr;
        /* k12 */
-       SUBL(15) = krl; SUBR(15) = krr;
+       subL[15] = krl; subR[15] = krr;
        /* rotation left shift 32bit */
        /* kl5 */
-       SUBL(24) = klr; SUBR(24) = krl;
+       subL[24] = klr; subR[24] = krl;
        /* kl6 */
-       SUBL(25) = krr; SUBR(25) = kll;
+       subL[25] = krr; subR[25] = kll;
        /* rotation left shift 49 from k11,k12 -> k21,k22 */
-       CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
        /* k21 */
-       SUBL(28) = kll; SUBR(28) = klr;
+       subL[28] = kll; subR[28] = klr;
        /* k22 */
-       SUBL(29) = krl; SUBR(29) = krr;
+       subL[29] = krl; subR[29] = krr;
 
        /* generate KB dependent subkeys */
        /* k1 */
-       SUBL(2) = krll; SUBR(2) = krlr;
+       subL[2] = krll; subR[2] = krlr;
        /* k2 */
-       SUBL(3) = krrl; SUBR(3) = krrr;
-       CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+       subL[3] = krrl; subR[3] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
        /* k7 */
-       SUBL(10) = krll; SUBR(10) = krlr;
+       subL[10] = krll; subR[10] = krlr;
        /* k8 */
-       SUBL(11) = krrl; SUBR(11) = krrr;
-       CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+       subL[11] = krrl; subR[11] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
        /* k15 */
-       SUBL(20) = krll; SUBR(20) = krlr;
+       subL[20] = krll; subR[20] = krlr;
        /* k16 */
-       SUBL(21) = krrl; SUBR(21) = krrr;
-       CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
+       subL[21] = krrl; subR[21] = krrr;
+       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
        /* kw3 */
-       SUBL(32) = krll; SUBR(32) = krlr;
+       subL[32] = krll; subR[32] = krlr;
        /* kw4 */
-       SUBL(33) = krrl; SUBR(33) = krrr;
-
-       /* absorb kw2 to other subkeys */
-       /* round 2 */
-       SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1);
-       /* round 4 */
-       SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1);
-       /* round 6 */
-       SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1);
-       SUBL(1) ^= SUBR(1) & ~SUBR(9);
-       dw = SUBL(1) & SUBL(9),
-               SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */
-       /* round 8 */
-       SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1);
-       /* round 10 */
-       SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1);
-       /* round 12 */
-       SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1);
-       SUBL(1) ^= SUBR(1) & ~SUBR(17);
-       dw = SUBL(1) & SUBL(17),
-               SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */
-       /* round 14 */
-       SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1);
-       /* round 16 */
-       SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1);
-       /* round 18 */
-       SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1);
-       SUBL(1) ^= SUBR(1) & ~SUBR(25);
-       dw = SUBL(1) & SUBL(25),
-               SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl6) */
-       /* round 20 */
-       SUBL(27) ^= SUBL(1); SUBR(27) ^= SUBR(1);
-       /* round 22 */
-       SUBL(29) ^= SUBL(1); SUBR(29) ^= SUBR(1);
-       /* round 24 */
-       SUBL(31) ^= SUBL(1); SUBR(31) ^= SUBR(1);
-       /* kw3 */
-       SUBL(32) ^= SUBL(1); SUBR(32) ^= SUBR(1);
-
-
-       /* absorb kw4 to other subkeys */
-       kw4l = SUBL(33); kw4r = SUBR(33);
-       /* round 23 */
-       SUBL(30) ^= kw4l; SUBR(30) ^= kw4r;
-       /* round 21 */
-       SUBL(28) ^= kw4l; SUBR(28) ^= kw4r;
-       /* round 19 */
-       SUBL(26) ^= kw4l; SUBR(26) ^= kw4r;
-       kw4l ^= kw4r & ~SUBR(24);
-       dw = kw4l & SUBL(24),
-               kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl5) */
-       /* round 17 */
-       SUBL(22) ^= kw4l; SUBR(22) ^= kw4r;
-       /* round 15 */
-       SUBL(20) ^= kw4l; SUBR(20) ^= kw4r;
-       /* round 13 */
-       SUBL(18) ^= kw4l; SUBR(18) ^= kw4r;
-       kw4l ^= kw4r & ~SUBR(16);
-       dw = kw4l & SUBL(16),
-               kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */
-       /* round 11 */
-       SUBL(14) ^= kw4l; SUBR(14) ^= kw4r;
-       /* round 9 */
-       SUBL(12) ^= kw4l; SUBR(12) ^= kw4r;
-       /* round 7 */
-       SUBL(10) ^= kw4l; SUBR(10) ^= kw4r;
-       kw4l ^= kw4r & ~SUBR(8);
-       dw = kw4l & SUBL(8),
-               kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */
-       /* round 5 */
-       SUBL(6) ^= kw4l; SUBR(6) ^= kw4r;
-       /* round 3 */
-       SUBL(4) ^= kw4l; SUBR(4) ^= kw4r;
-       /* round 1 */
-       SUBL(2) ^= kw4l; SUBR(2) ^= kw4r;
-       /* kw1 */
-       SUBL(0) ^= kw4l; SUBR(0) ^= kw4r;
+       subL[33] = krrl; subR[33] = krrr;
 
-       /* key XOR is end of F-function */
-       CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */
-       CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2);
-       CAMELLIA_SUBKEY_L(2) = SUBL(3);       /* round 1 */
-       CAMELLIA_SUBKEY_R(2) = SUBR(3);
-       CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */
-       CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4);
-       CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */
-       CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5);
-       CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */
-       CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6);
-       CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */
-       CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7);
-       tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8));
-       dw = tl & SUBL(8),  /* FL(kl1) */
-               tr = SUBR(10) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */
-       CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr;
-       CAMELLIA_SUBKEY_L(8) = SUBL(8);       /* FL(kl1) */
-       CAMELLIA_SUBKEY_R(8) = SUBR(8);
-       CAMELLIA_SUBKEY_L(9) = SUBL(9);       /* FLinv(kl2) */
-       CAMELLIA_SUBKEY_R(9) = SUBR(9);
-       tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9));
-       dw = tl & SUBL(9),  /* FLinv(kl2) */
-               tr = SUBR(7) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */
-       CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11);
-       CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */
-       CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12);
-       CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */
-       CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13);
-       CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */
-       CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14);
-       CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */
-       CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15);
-       tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16));
-       dw = tl & SUBL(16), /* FL(kl3) */
-               tr = SUBR(18) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */
-       CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr;
-       CAMELLIA_SUBKEY_L(16) = SUBL(16);     /* FL(kl3) */
-       CAMELLIA_SUBKEY_R(16) = SUBR(16);
-       CAMELLIA_SUBKEY_L(17) = SUBL(17);     /* FLinv(kl4) */
-       CAMELLIA_SUBKEY_R(17) = SUBR(17);
-       tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17));
-       dw = tl & SUBL(17), /* FLinv(kl4) */
-               tr = SUBR(15) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */
-       CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19);
-       CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */
-       CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20);
-       CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */
-       CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21);
-       CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */
-       CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22);
-       CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */
-       CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23);
-       tl = SUBL(26) ^ (SUBR(26)
-                        & ~SUBR(24));
-       dw = tl & SUBL(24), /* FL(kl5) */
-               tr = SUBR(26) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(23) = SUBL(22) ^ tl; /* round 18 */
-       CAMELLIA_SUBKEY_R(23) = SUBR(22) ^ tr;
-       CAMELLIA_SUBKEY_L(24) = SUBL(24);     /* FL(kl5) */
-       CAMELLIA_SUBKEY_R(24) = SUBR(24);
-       CAMELLIA_SUBKEY_L(25) = SUBL(25);     /* FLinv(kl6) */
-       CAMELLIA_SUBKEY_R(25) = SUBR(25);
-       tl = SUBL(23) ^ (SUBR(23) &
-                        ~SUBR(25));
-       dw = tl & SUBL(25), /* FLinv(kl6) */
-               tr = SUBR(23) ^ CAMELLIA_RL1(dw);
-       CAMELLIA_SUBKEY_L(26) = tl ^ SUBL(27); /* round 19 */
-       CAMELLIA_SUBKEY_R(26) = tr ^ SUBR(27);
-       CAMELLIA_SUBKEY_L(27) = SUBL(26) ^ SUBL(28); /* round 20 */
-       CAMELLIA_SUBKEY_R(27) = SUBR(26) ^ SUBR(28);
-       CAMELLIA_SUBKEY_L(28) = SUBL(27) ^ SUBL(29); /* round 21 */
-       CAMELLIA_SUBKEY_R(28) = SUBR(27) ^ SUBR(29);
-       CAMELLIA_SUBKEY_L(29) = SUBL(28) ^ SUBL(30); /* round 22 */
-       CAMELLIA_SUBKEY_R(29) = SUBR(28) ^ SUBR(30);
-       CAMELLIA_SUBKEY_L(30) = SUBL(29) ^ SUBL(31); /* round 23 */
-       CAMELLIA_SUBKEY_R(30) = SUBR(29) ^ SUBR(31);
-       CAMELLIA_SUBKEY_L(31) = SUBL(30);     /* round 24 */
-       CAMELLIA_SUBKEY_R(31) = SUBR(30);
-       CAMELLIA_SUBKEY_L(32) = SUBL(32) ^ SUBL(31); /* kw3 */
-       CAMELLIA_SUBKEY_R(32) = SUBR(32) ^ SUBR(31);
-
-       /* apply the inverse of the last half of P-function */
-       dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2),
-               dw = CAMELLIA_RL8(dw);/* round 1 */
-       CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw,
-               CAMELLIA_SUBKEY_L(2) = dw;
-       dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3),
-               dw = CAMELLIA_RL8(dw);/* round 2 */
-       CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw,
-               CAMELLIA_SUBKEY_L(3) = dw;
-       dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4),
-               dw = CAMELLIA_RL8(dw);/* round 3 */
-       CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw,
-               CAMELLIA_SUBKEY_L(4) = dw;
-       dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5),
-               dw = CAMELLIA_RL8(dw);/* round 4 */
-       CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw,
-       CAMELLIA_SUBKEY_L(5) = dw;
-       dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6),
-               dw = CAMELLIA_RL8(dw);/* round 5 */
-       CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw,
-               CAMELLIA_SUBKEY_L(6) = dw;
-       dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7),
-               dw = CAMELLIA_RL8(dw);/* round 6 */
-       CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw,
-               CAMELLIA_SUBKEY_L(7) = dw;
-       dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10),
-               dw = CAMELLIA_RL8(dw);/* round 7 */
-       CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw,
-               CAMELLIA_SUBKEY_L(10) = dw;
-       dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11),
-           dw = CAMELLIA_RL8(dw);/* round 8 */
-       CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw,
-               CAMELLIA_SUBKEY_L(11) = dw;
-       dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12),
-               dw = CAMELLIA_RL8(dw);/* round 9 */
-       CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw,
-               CAMELLIA_SUBKEY_L(12) = dw;
-       dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13),
-               dw = CAMELLIA_RL8(dw);/* round 10 */
-       CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw,
-               CAMELLIA_SUBKEY_L(13) = dw;
-       dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14),
-               dw = CAMELLIA_RL8(dw);/* round 11 */
-       CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw,
-               CAMELLIA_SUBKEY_L(14) = dw;
-       dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15),
-               dw = CAMELLIA_RL8(dw);/* round 12 */
-       CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw,
-               CAMELLIA_SUBKEY_L(15) = dw;
-       dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18),
-               dw = CAMELLIA_RL8(dw);/* round 13 */
-       CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw,
-               CAMELLIA_SUBKEY_L(18) = dw;
-       dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19),
-               dw = CAMELLIA_RL8(dw);/* round 14 */
-       CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw,
-               CAMELLIA_SUBKEY_L(19) = dw;
-       dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20),
-               dw = CAMELLIA_RL8(dw);/* round 15 */
-       CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw,
-               CAMELLIA_SUBKEY_L(20) = dw;
-       dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21),
-               dw = CAMELLIA_RL8(dw);/* round 16 */
-       CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw,
-               CAMELLIA_SUBKEY_L(21) = dw;
-       dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22),
-               dw = CAMELLIA_RL8(dw);/* round 17 */
-       CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw,
-               CAMELLIA_SUBKEY_L(22) = dw;
-       dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23),
-               dw = CAMELLIA_RL8(dw);/* round 18 */
-       CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw,
-               CAMELLIA_SUBKEY_L(23) = dw;
-       dw = CAMELLIA_SUBKEY_L(26) ^ CAMELLIA_SUBKEY_R(26),
-               dw = CAMELLIA_RL8(dw);/* round 19 */
-       CAMELLIA_SUBKEY_R(26) = CAMELLIA_SUBKEY_L(26) ^ dw,
-               CAMELLIA_SUBKEY_L(26) = dw;
-       dw = CAMELLIA_SUBKEY_L(27) ^ CAMELLIA_SUBKEY_R(27),
-               dw = CAMELLIA_RL8(dw);/* round 20 */
-       CAMELLIA_SUBKEY_R(27) = CAMELLIA_SUBKEY_L(27) ^ dw,
-               CAMELLIA_SUBKEY_L(27) = dw;
-       dw = CAMELLIA_SUBKEY_L(28) ^ CAMELLIA_SUBKEY_R(28),
-               dw = CAMELLIA_RL8(dw);/* round 21 */
-       CAMELLIA_SUBKEY_R(28) = CAMELLIA_SUBKEY_L(28) ^ dw,
-               CAMELLIA_SUBKEY_L(28) = dw;
-       dw = CAMELLIA_SUBKEY_L(29) ^ CAMELLIA_SUBKEY_R(29),
-               dw = CAMELLIA_RL8(dw);/* round 22 */
-       CAMELLIA_SUBKEY_R(29) = CAMELLIA_SUBKEY_L(29) ^ dw,
-               CAMELLIA_SUBKEY_L(29) = dw;
-       dw = CAMELLIA_SUBKEY_L(30) ^ CAMELLIA_SUBKEY_R(30),
-               dw = CAMELLIA_RL8(dw);/* round 23 */
-       CAMELLIA_SUBKEY_R(30) = CAMELLIA_SUBKEY_L(30) ^ dw,
-               CAMELLIA_SUBKEY_L(30) = dw;
-       dw = CAMELLIA_SUBKEY_L(31) ^ CAMELLIA_SUBKEY_R(31),
-               dw = CAMELLIA_RL8(dw);/* round 24 */
-       CAMELLIA_SUBKEY_R(31) = CAMELLIA_SUBKEY_L(31) ^ dw,
-               CAMELLIA_SUBKEY_L(31) = dw;
-
-       return;
+       camellia_setup_tail(subkey, subL, subR, 32);
 }
 
 static void camellia_setup192(const unsigned char *key, u32 *subkey)
@@ -1197,482 +850,168 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey)
        u32 krll, krlr, krrl,krrr;
 
        memcpy(kk, key, 24);
-       memcpy((unsigned char *)&krll, key+16,4);
-       memcpy((unsigned char *)&krlr, key+20,4);
+       memcpy((unsigned char *)&krll, key+16, 4);
+       memcpy((unsigned char *)&krlr, key+20, 4);
        krrl = ~krll;
        krrr = ~krlr;
        memcpy(kk+24, (unsigned char *)&krrl, 4);
        memcpy(kk+28, (unsigned char *)&krrr, 4);
        camellia_setup256(kk, subkey);
-       return;
 }
 
 
-/**
- * Stuff related to camellia encryption/decryption
+/*
+ * Encrypt/decrypt
  */
-static void camellia_encrypt128(const u32 *subkey, __be32 *io_text)
-{
-       u32 il,ir,t0,t1;               /* temporary valiables */
-
-       u32 io[4];
-
-       io[0] = be32_to_cpu(io_text[0]);
-       io[1] = be32_to_cpu(io_text[1]);
-       io[2] = be32_to_cpu(io_text[2]);
-       io[3] = be32_to_cpu(io_text[3]);
-
-       /* pre whitening but absorb kw2*/
-       io[0] ^= CAMELLIA_SUBKEY_L(0);
-       io[1] ^= CAMELLIA_SUBKEY_R(0);
-       /* main iteration */
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
-                    CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
-                    CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
-                        io[0],io[1],il,ir,t0,t1);
+#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
+    do {                                                               \
+       t0 = kll;                                                       \
+       t2 = krr;                                                       \
+       t0 &= ll;                                                       \
+       t2 |= rr;                                                       \
+       rl ^= t2;                                                       \
+       lr ^= ROL1(t0);                                                 \
+       t3 = krl;                                                       \
+       t1 = klr;                                                       \
+       t3 &= rl;                                                       \
+       t1 |= lr;                                                       \
+       ll ^= t1;                                                       \
+       rr ^= ROL1(t3);                                                 \
+    } while(0)
 
-       /* post whitening but kw4 */
-       io[2] ^= CAMELLIA_SUBKEY_L(24);
-       io[3] ^= CAMELLIA_SUBKEY_R(24);
-
-       t0 = io[0];
-       t1 = io[1];
-       io[0] = io[2];
-       io[1] = io[3];
-       io[2] = t0;
-       io[3] = t1;
-
-       io_text[0] = cpu_to_be32(io[0]);
-       io_text[1] = cpu_to_be32(io[1]);
-       io_text[2] = cpu_to_be32(io[2]);
-       io_text[3] = cpu_to_be32(io[3]);
-
-       return;
-}
+#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir)               \
+    do {                                                               \
+       ir =  camellia_sp1110[(u8)xr];                                  \
+       il =  camellia_sp1110[    (xl >> 24)];                          \
+       ir ^= camellia_sp0222[    (xr >> 24)];                          \
+       il ^= camellia_sp0222[(u8)(xl >> 16)];                          \
+       ir ^= camellia_sp3033[(u8)(xr >> 16)];                          \
+       il ^= camellia_sp3033[(u8)(xl >> 8)];                           \
+       ir ^= camellia_sp4404[(u8)(xr >> 8)];                           \
+       il ^= camellia_sp4404[(u8)xl];                                  \
+       il ^= kl;                                                       \
+       ir ^= il ^ kr;                                                  \
+       yl ^= ir;                                                       \
+       yr ^= ROR8(il) ^ ir;                                            \
+    } while(0)
 
-static void camellia_decrypt128(const u32 *subkey, __be32 *io_text)
+/* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
+static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max)
 {
-       u32 il,ir,t0,t1;               /* temporary valiables */
+       u32 il,ir,t0,t1;               /* temporary variables */
 
-       u32 io[4];
-
-       io[0] = be32_to_cpu(io_text[0]);
-       io[1] = be32_to_cpu(io_text[1]);
-       io[2] = be32_to_cpu(io_text[2]);
-       io[3] = be32_to_cpu(io_text[3]);
-
-       /* pre whitening but absorb kw2*/
-       io[0] ^= CAMELLIA_SUBKEY_L(24);
-       io[1] ^= CAMELLIA_SUBKEY_R(24);
+       /* pre whitening but absorb kw2 */
+       io[0] ^= SUBKEY_L(0);
+       io[1] ^= SUBKEY_R(0);
 
        /* main iteration */
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
-                    CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
-                    CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
-                        io[0],io[1],il,ir,t0,t1);
-
-       /* post whitening but kw4 */
-       io[2] ^= CAMELLIA_SUBKEY_L(0);
-       io[3] ^= CAMELLIA_SUBKEY_R(0);
-
-       t0 = io[0];
-       t1 = io[1];
-       io[0] = io[2];
-       io[1] = io[3];
-       io[2] = t0;
-       io[3] = t1;
-
-       io_text[0] = cpu_to_be32(io[0]);
-       io_text[1] = cpu_to_be32(io[1]);
-       io_text[2] = cpu_to_be32(io[2]);
-       io_text[3] = cpu_to_be32(io[3]);
-
-       return;
-}
-
-
-/**
- * stuff for 192 and 256bit encryption/decryption
- */
-static void camellia_encrypt256(const u32 *subkey, __be32 *io_text)
-{
-       u32 il,ir,t0,t1;           /* temporary valiables */
-
-       u32 io[4];
-
-       io[0] = be32_to_cpu(io_text[0]);
-       io[1] = be32_to_cpu(io_text[1]);
-       io[2] = be32_to_cpu(io_text[2]);
-       io[3] = be32_to_cpu(io_text[3]);
+#define ROUNDS(i) do { \
+       CAMELLIA_ROUNDSM(io[0],io[1], \
+                        SUBKEY_L(i + 2),SUBKEY_R(i + 2), \
+                        io[2],io[3],il,ir); \
+       CAMELLIA_ROUNDSM(io[2],io[3], \
+                        SUBKEY_L(i + 3),SUBKEY_R(i + 3), \
+                        io[0],io[1],il,ir); \
+       CAMELLIA_ROUNDSM(io[0],io[1], \
+                        SUBKEY_L(i + 4),SUBKEY_R(i + 4), \
+                        io[2],io[3],il,ir); \
+       CAMELLIA_ROUNDSM(io[2],io[3], \
+                        SUBKEY_L(i + 5),SUBKEY_R(i + 5), \
+                        io[0],io[1],il,ir); \
+       CAMELLIA_ROUNDSM(io[0],io[1], \
+                        SUBKEY_L(i + 6),SUBKEY_R(i + 6), \
+                        io[2],io[3],il,ir); \
+       CAMELLIA_ROUNDSM(io[2],io[3], \
+                        SUBKEY_L(i + 7),SUBKEY_R(i + 7), \
+                        io[0],io[1],il,ir); \
+} while (0)
+#define FLS(i) do { \
+       CAMELLIA_FLS(io[0],io[1],io[2],io[3], \
+                    SUBKEY_L(i + 0),SUBKEY_R(i + 0), \
+                    SUBKEY_L(i + 1),SUBKEY_R(i + 1), \
+                    t0,t1,il,ir); \
+} while (0)
+
+       ROUNDS(0);
+       FLS(8);
+       ROUNDS(8);
+       FLS(16);
+       ROUNDS(16);
+       if (max == 32) {
+               FLS(24);
+               ROUNDS(24);
+       }
 
-       /* pre whitening but absorb kw2*/
-       io[0] ^= CAMELLIA_SUBKEY_L(0);
-       io[1] ^= CAMELLIA_SUBKEY_R(0);
-
-       /* main iteration */
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
-                    CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
-                    CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24),
-                    CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31),
-                        io[0],io[1],il,ir,t0,t1);
+#undef ROUNDS
+#undef FLS
 
        /* post whitening but kw4 */
-       io[2] ^= CAMELLIA_SUBKEY_L(32);
-       io[3] ^= CAMELLIA_SUBKEY_R(32);
-
-       t0 = io[0];
-       t1 = io[1];
-       io[0] = io[2];
-       io[1] = io[3];
-       io[2] = t0;
-       io[3] = t1;
-
-       io_text[0] = cpu_to_be32(io[0]);
-       io_text[1] = cpu_to_be32(io[1]);
-       io_text[2] = cpu_to_be32(io[2]);
-       io_text[3] = cpu_to_be32(io[3]);
-
-       return;
+       io[2] ^= SUBKEY_L(max);
+       io[3] ^= SUBKEY_R(max);
+       /* NB: io[0],[1] should be swapped with [2],[3] by caller! */
 }
 
-
-static void camellia_decrypt256(const u32 *subkey, __be32 *io_text)
+static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i)
 {
-       u32 il,ir,t0,t1;           /* temporary valiables */
+       u32 il,ir,t0,t1;               /* temporary variables */
 
-       u32 io[4];
-
-       io[0] = be32_to_cpu(io_text[0]);
-       io[1] = be32_to_cpu(io_text[1]);
-       io[2] = be32_to_cpu(io_text[2]);
-       io[3] = be32_to_cpu(io_text[3]);
-
-       /* pre whitening but absorb kw2*/
-       io[0] ^= CAMELLIA_SUBKEY_L(32);
-       io[1] ^= CAMELLIA_SUBKEY_R(32);
+       /* pre whitening but absorb kw2 */
+       io[0] ^= SUBKEY_L(i);
+       io[1] ^= SUBKEY_R(i);
 
        /* main iteration */
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25),
-                    CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
-                    CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
-                        io[0],io[1],il,ir,t0,t1);
-
-       CAMELLIA_FLS(io[0],io[1],io[2],io[3],
-                    CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
-                    CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
-                    t0,t1,il,ir);
-
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
-                        io[0],io[1],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[0],io[1],
-                        CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
-                        io[2],io[3],il,ir,t0,t1);
-       CAMELLIA_ROUNDSM(io[2],io[3],
-                        CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
-                        io[0],io[1],il,ir,t0,t1);
+#define ROUNDS(i) do { \
+       CAMELLIA_ROUNDSM(io[0],io[1], \
+                        SUBKEY_L(i + 7),SUBKEY_R(i + 7), \
+                        io[2],io[3],il,ir); \
+       CAMELLIA_ROUNDSM(io[2],io[3], \
+                        SUBKEY_L(i + 6),SUBKEY_R(i + 6), \
+                        io[0],io[1],il,ir); \
+       CAMELLIA_ROUNDSM(io[0],io[1], \
+                        SUBKEY_L(i + 5),SUBKEY_R(i + 5), \
+                        io[2],io[3],il,ir); \
+       CAMELLIA_ROUNDSM(io[2],io[3], \
+                        SUBKEY_L(i + 4),SUBKEY_R(i + 4), \
+                        io[0],io[1],il,ir); \
+       CAMELLIA_ROUNDSM(io[0],io[1], \
+                        SUBKEY_L(i + 3),SUBKEY_R(i + 3), \
+                        io[2],io[3],il,ir); \
+       CAMELLIA_ROUNDSM(io[2],io[3], \
+                        SUBKEY_L(i + 2),SUBKEY_R(i + 2), \
+                        io[0],io[1],il,ir); \
+} while (0)
+#define FLS(i) do { \
+       CAMELLIA_FLS(io[0],io[1],io[2],io[3], \
+                    SUBKEY_L(i + 1),SUBKEY_R(i + 1), \
+                    SUBKEY_L(i + 0),SUBKEY_R(i + 0), \
+                    t0,t1,il,ir); \
+} while (0)
+
+       if (i == 32) {
+               ROUNDS(24);
+               FLS(24);
+       }
+       ROUNDS(16);
+       FLS(16);
+       ROUNDS(8);
+       FLS(8);
+       ROUNDS(0);
+
+#undef ROUNDS
+#undef FLS
 
        /* post whitening but kw4 */
-       io[2] ^= CAMELLIA_SUBKEY_L(0);
-       io[3] ^= CAMELLIA_SUBKEY_R(0);
-
-       t0 = io[0];
-       t1 = io[1];
-       io[0] = io[2];
-       io[1] = io[3];
-       io[2] = t0;
-       io[3] = t1;
-
-       io_text[0] = cpu_to_be32(io[0]);
-       io_text[1] = cpu_to_be32(io[1]);
-       io_text[2] = cpu_to_be32(io[2]);
-       io_text[3] = cpu_to_be32(io[3]);
-
-       return;
+       io[2] ^= SUBKEY_L(0);
+       io[3] ^= SUBKEY_R(0);
+       /* NB: 0,1 should be swapped with 2,3 by caller! */
 }
 
 
+struct camellia_ctx {
+       int key_length;
+       u32 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u32)];
+};
+
 static int
 camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
                 unsigned int key_len)
@@ -1688,7 +1027,7 @@ camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
        cctx->key_length = key_len;
 
-       switch(key_len) {
+       switch (key_len) {
        case 16:
                camellia_setup128(key, cctx->key_table);
                break;
@@ -1698,68 +1037,59 @@ camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
        case 32:
                camellia_setup256(key, cctx->key_table);
                break;
-       default:
-               break;
        }
 
        return 0;
 }
 
-
 static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
        const __be32 *src = (const __be32 *)in;
        __be32 *dst = (__be32 *)out;
 
-       __be32 tmp[4];
+       u32 tmp[4];
 
-       memcpy(tmp, src, CAMELLIA_BLOCK_SIZE);
+       tmp[0] = be32_to_cpu(src[0]);
+       tmp[1] = be32_to_cpu(src[1]);
+       tmp[2] = be32_to_cpu(src[2]);
+       tmp[3] = be32_to_cpu(src[3]);
 
-       switch (cctx->key_length) {
-       case 16:
-               camellia_encrypt128(cctx->key_table, tmp);
-               break;
-       case 24:
-               /* fall through */
-       case 32:
-               camellia_encrypt256(cctx->key_table, tmp);
-               break;
-       default:
-               break;
-       }
+       camellia_do_encrypt(cctx->key_table, tmp,
+               cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */
+       );
 
-       memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE);
+       /* do_encrypt returns 0,1 swapped with 2,3 */
+       dst[0] = cpu_to_be32(tmp[2]);
+       dst[1] = cpu_to_be32(tmp[3]);
+       dst[2] = cpu_to_be32(tmp[0]);
+       dst[3] = cpu_to_be32(tmp[1]);
 }
 
-
 static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
        const __be32 *src = (const __be32 *)in;
        __be32 *dst = (__be32 *)out;
 
-       __be32 tmp[4];
+       u32 tmp[4];
 
-       memcpy(tmp, src, CAMELLIA_BLOCK_SIZE);
+       tmp[0] = be32_to_cpu(src[0]);
+       tmp[1] = be32_to_cpu(src[1]);
+       tmp[2] = be32_to_cpu(src[2]);
+       tmp[3] = be32_to_cpu(src[3]);
 
-       switch (cctx->key_length) {
-       case 16:
-               camellia_decrypt128(cctx->key_table, tmp);
-               break;
-       case 24:
-               /* fall through */
-       case 32:
-               camellia_decrypt256(cctx->key_table, tmp);
-               break;
-       default:
-               break;
-       }
+       camellia_do_decrypt(cctx->key_table, tmp,
+               cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */
+       );
 
-       memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE);
+       /* do_decrypt returns 0,1 swapped with 2,3 */
+       dst[0] = cpu_to_be32(tmp[2]);
+       dst[1] = cpu_to_be32(tmp[3]);
+       dst[2] = cpu_to_be32(tmp[0]);
+       dst[3] = cpu_to_be32(tmp[1]);
 }
 
-
 static struct crypto_alg camellia_alg = {
        .cra_name               =       "camellia",
        .cra_driver_name        =       "camellia-generic",
@@ -1786,16 +1116,13 @@ static int __init camellia_init(void)
        return crypto_register_alg(&camellia_alg);
 }
 
-
 static void __exit camellia_fini(void)
 {
        crypto_unregister_alg(&camellia_alg);
 }
 
-
 module_init(camellia_init);
 module_exit(camellia_fini);
 
-
 MODULE_DESCRIPTION("Camellia Cipher Algorithm");
 MODULE_LICENSE("GPL");
index 136ab6dfe8c5661a2f0c6190267cdf2459d37b0e..5fd9420dc58e94098a9da68e0fb4488bac79742d 100644 (file)
@@ -369,7 +369,7 @@ static const u8 Tr[4][8] = {
 };
 
 /* forward octave */
-static inline void W(u32 *key, unsigned int i) {
+static void W(u32 *key, unsigned int i) {
        u32 I;
        key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]);
        key[5] ^= F2(key[6], Tr[i % 4][1], Tm[i][1]);
@@ -428,7 +428,7 @@ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
 }
 
 /*forward quad round*/
-static inline void Q (u32 * block, u8 * Kr, u32 * Km) {
+static void Q (u32 * block, u8 * Kr, u32 * Km) {
        u32 I;
        block[2] ^= F1(block[3], Kr[0], Km[0]);
        block[1] ^= F2(block[2], Kr[1], Km[1]);
@@ -437,7 +437,7 @@ static inline void Q (u32 * block, u8 * Kr, u32 * Km) {
 }
 
 /*reverse quad round*/
-static inline void QBAR (u32 * block, u8 * Kr, u32 * Km) {
+static void QBAR (u32 * block, u8 * Kr, u32 * Km) {
        u32 I;
         block[3] ^= F1(block[0], Kr[3], Km[3]);
         block[0] ^= F3(block[1], Kr[2], Km[2]);
index 1f2649e13b4266ebc1354bd701c6b98d23c83d2e..6affff882cf835bb88f43e0e5aa68951a8e2ac1a 100644 (file)
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 
 struct crypto_cbc_ctx {
        struct crypto_cipher *child;
-       void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
 };
 
 static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key,
@@ -41,9 +41,7 @@ static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key,
 
 static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
                                      struct blkcipher_walk *walk,
-                                     struct crypto_cipher *tfm,
-                                     void (*xor)(u8 *, const u8 *,
-                                                 unsigned int))
+                                     struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_encrypt;
@@ -54,7 +52,7 @@ static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
        u8 *iv = walk->iv;
 
        do {
-               xor(iv, src, bsize);
+               crypto_xor(iv, src, bsize);
                fn(crypto_cipher_tfm(tfm), dst, iv);
                memcpy(iv, dst, bsize);
 
@@ -67,9 +65,7 @@ static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
 
 static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc,
                                      struct blkcipher_walk *walk,
-                                     struct crypto_cipher *tfm,
-                                     void (*xor)(u8 *, const u8 *,
-                                                 unsigned int))
+                                     struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_encrypt;
@@ -79,7 +75,7 @@ static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc,
        u8 *iv = walk->iv;
 
        do {
-               xor(src, iv, bsize);
+               crypto_xor(src, iv, bsize);
                fn(crypto_cipher_tfm(tfm), src, src);
                iv = src;
 
@@ -99,7 +95,6 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
        struct crypto_blkcipher *tfm = desc->tfm;
        struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
        struct crypto_cipher *child = ctx->child;
-       void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
        int err;
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -107,11 +102,9 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
 
        while ((nbytes = walk.nbytes)) {
                if (walk.src.virt.addr == walk.dst.virt.addr)
-                       nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child,
-                                                           xor);
+                       nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child);
                else
-                       nbytes = crypto_cbc_encrypt_segment(desc, &walk, child,
-                                                           xor);
+                       nbytes = crypto_cbc_encrypt_segment(desc, &walk, child);
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
 
@@ -120,9 +113,7 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
 
 static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
                                      struct blkcipher_walk *walk,
-                                     struct crypto_cipher *tfm,
-                                     void (*xor)(u8 *, const u8 *,
-                                                 unsigned int))
+                                     struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_decrypt;
@@ -134,7 +125,7 @@ static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
 
        do {
                fn(crypto_cipher_tfm(tfm), dst, src);
-               xor(dst, iv, bsize);
+               crypto_xor(dst, iv, bsize);
                iv = src;
 
                src += bsize;
@@ -148,34 +139,29 @@ static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
 
 static int crypto_cbc_decrypt_inplace(struct blkcipher_desc *desc,
                                      struct blkcipher_walk *walk,
-                                     struct crypto_cipher *tfm,
-                                     void (*xor)(u8 *, const u8 *,
-                                                 unsigned int))
+                                     struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_decrypt;
        int bsize = crypto_cipher_blocksize(tfm);
-       unsigned long alignmask = crypto_cipher_alignmask(tfm);
        unsigned int nbytes = walk->nbytes;
        u8 *src = walk->src.virt.addr;
-       u8 stack[bsize + alignmask];
-       u8 *first_iv = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
-
-       memcpy(first_iv, walk->iv, bsize);
+       u8 last_iv[bsize];
 
        /* Start of the last block. */
-       src += nbytes - nbytes % bsize - bsize;
-       memcpy(walk->iv, src, bsize);
+       src += nbytes - (nbytes & (bsize - 1)) - bsize;
+       memcpy(last_iv, src, bsize);
 
        for (;;) {
                fn(crypto_cipher_tfm(tfm), src, src);
                if ((nbytes -= bsize) < bsize)
                        break;
-               xor(src, src - bsize, bsize);
+               crypto_xor(src, src - bsize, bsize);
                src -= bsize;
        }
 
-       xor(src, first_iv, bsize);
+       crypto_xor(src, walk->iv, bsize);
+       memcpy(walk->iv, last_iv, bsize);
 
        return nbytes;
 }
@@ -188,7 +174,6 @@ static int crypto_cbc_decrypt(struct blkcipher_desc *desc,
        struct crypto_blkcipher *tfm = desc->tfm;
        struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
        struct crypto_cipher *child = ctx->child;
-       void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
        int err;
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -196,48 +181,15 @@ static int crypto_cbc_decrypt(struct blkcipher_desc *desc,
 
        while ((nbytes = walk.nbytes)) {
                if (walk.src.virt.addr == walk.dst.virt.addr)
-                       nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child,
-                                                           xor);
+                       nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child);
                else
-                       nbytes = crypto_cbc_decrypt_segment(desc, &walk, child,
-                                                           xor);
+                       nbytes = crypto_cbc_decrypt_segment(desc, &walk, child);
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
 
        return err;
 }
 
-static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
-{
-       do {
-               *a++ ^= *b++;
-       } while (--bs);
-}
-
-static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
-{
-       u32 *a = (u32 *)dst;
-       u32 *b = (u32 *)src;
-
-       do {
-               *a++ ^= *b++;
-       } while ((bs -= 4));
-}
-
-static void xor_64(u8 *a, const u8 *b, unsigned int bs)
-{
-       ((u32 *)a)[0] ^= ((u32 *)b)[0];
-       ((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static void xor_128(u8 *a, const u8 *b, unsigned int bs)
-{
-       ((u32 *)a)[0] ^= ((u32 *)b)[0];
-       ((u32 *)a)[1] ^= ((u32 *)b)[1];
-       ((u32 *)a)[2] ^= ((u32 *)b)[2];
-       ((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
 static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_instance *inst = (void *)tfm->__crt_alg;
@@ -245,22 +197,6 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
        struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
        struct crypto_cipher *cipher;
 
-       switch (crypto_tfm_alg_blocksize(tfm)) {
-       case 8:
-               ctx->xor = xor_64;
-               break;
-
-       case 16:
-               ctx->xor = xor_128;
-               break;
-
-       default:
-               if (crypto_tfm_alg_blocksize(tfm) % 4)
-                       ctx->xor = xor_byte;
-               else
-                       ctx->xor = xor_quad;
-       }
-
        cipher = crypto_spawn_cipher(spawn);
        if (IS_ERR(cipher))
                return PTR_ERR(cipher);
@@ -290,6 +226,10 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
        if (IS_ERR(alg))
                return ERR_PTR(PTR_ERR(alg));
 
+       inst = ERR_PTR(-EINVAL);
+       if (!is_power_of_2(alg->cra_blocksize))
+               goto out_put_alg;
+
        inst = crypto_alloc_instance("cbc", alg);
        if (IS_ERR(inst))
                goto out_put_alg;
@@ -300,8 +240,9 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
        inst->alg.cra_alignmask = alg->cra_alignmask;
        inst->alg.cra_type = &crypto_blkcipher_type;
 
-       if (!(alg->cra_blocksize % 4))
-               inst->alg.cra_alignmask |= 3;
+       /* We access the data as u32s when xoring. */
+       inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+
        inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
        inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
        inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
diff --git a/crypto/ccm.c b/crypto/ccm.c
new file mode 100644 (file)
index 0000000..7cf7e5a
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+ * CCM: Counter with CBC-MAC
+ *
+ * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+struct ccm_instance_ctx {
+       struct crypto_skcipher_spawn ctr;
+       struct crypto_spawn cipher;
+};
+
+struct crypto_ccm_ctx {
+       struct crypto_cipher *cipher;
+       struct crypto_ablkcipher *ctr;
+};
+
+struct crypto_rfc4309_ctx {
+       struct crypto_aead *child;
+       u8 nonce[3];
+};
+
+struct crypto_ccm_req_priv_ctx {
+       u8 odata[16];
+       u8 idata[16];
+       u8 auth_tag[16];
+       u32 ilen;
+       u32 flags;
+       struct scatterlist src[2];
+       struct scatterlist dst[2];
+       struct ablkcipher_request abreq;
+};
+
+static inline struct crypto_ccm_req_priv_ctx *crypto_ccm_reqctx(
+       struct aead_request *req)
+{
+       unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
+
+       return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
+}
+
+static int set_msg_len(u8 *block, unsigned int msglen, int csize)
+{
+       __be32 data;
+
+       memset(block, 0, csize);
+       block += csize;
+
+       if (csize >= 4)
+               csize = 4;
+       else if (msglen > (1 << (8 * csize)))
+               return -EOVERFLOW;
+
+       data = cpu_to_be32(msglen);
+       memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+       return 0;
+}
+
+static int crypto_ccm_setkey(struct crypto_aead *aead, const u8 *key,
+                            unsigned int keylen)
+{
+       struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_ablkcipher *ctr = ctx->ctr;
+       struct crypto_cipher *tfm = ctx->cipher;
+       int err = 0;
+
+       crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
+       crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
+                                   CRYPTO_TFM_REQ_MASK);
+       err = crypto_ablkcipher_setkey(ctr, key, keylen);
+       crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
+                             CRYPTO_TFM_RES_MASK);
+       if (err)
+               goto out;
+
+       crypto_cipher_clear_flags(tfm, CRYPTO_TFM_REQ_MASK);
+       crypto_cipher_set_flags(tfm, crypto_aead_get_flags(aead) &
+                                   CRYPTO_TFM_REQ_MASK);
+       err = crypto_cipher_setkey(tfm, key, keylen);
+       crypto_aead_set_flags(aead, crypto_cipher_get_flags(tfm) &
+                             CRYPTO_TFM_RES_MASK);
+
+out:
+       return err;
+}
+
+static int crypto_ccm_setauthsize(struct crypto_aead *tfm,
+                                 unsigned int authsize)
+{
+       switch (authsize) {
+       case 4:
+       case 6:
+       case 8:
+       case 10:
+       case 12:
+       case 14:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int format_input(u8 *info, struct aead_request *req,
+                       unsigned int cryptlen)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       unsigned int lp = req->iv[0];
+       unsigned int l = lp + 1;
+       unsigned int m;
+
+       m = crypto_aead_authsize(aead);
+
+       memcpy(info, req->iv, 16);
+
+       /* format control info per RFC 3610 and
+        * NIST Special Publication 800-38C
+        */
+       *info |= (8 * ((m - 2) / 2));
+       if (req->assoclen)
+               *info |= 64;
+
+       return set_msg_len(info + 16 - l, cryptlen, l);
+}
+
+static int format_adata(u8 *adata, unsigned int a)
+{
+       int len = 0;
+
+       /* add control info for associated data
+        * RFC 3610 and NIST Special Publication 800-38C
+        */
+       if (a < 65280) {
+               *(__be16 *)adata = cpu_to_be16(a);
+               len = 2;
+       } else  {
+               *(__be16 *)adata = cpu_to_be16(0xfffe);
+               *(__be32 *)&adata[2] = cpu_to_be32(a);
+               len = 6;
+       }
+
+       return len;
+}
+
+static void compute_mac(struct crypto_cipher *tfm, u8 *data, int n,
+                      struct crypto_ccm_req_priv_ctx *pctx)
+{
+       unsigned int bs = 16;
+       u8 *odata = pctx->odata;
+       u8 *idata = pctx->idata;
+       int datalen, getlen;
+
+       datalen = n;
+
+       /* first time in here, block may be partially filled. */
+       getlen = bs - pctx->ilen;
+       if (datalen >= getlen) {
+               memcpy(idata + pctx->ilen, data, getlen);
+               crypto_xor(odata, idata, bs);
+               crypto_cipher_encrypt_one(tfm, odata, odata);
+               datalen -= getlen;
+               data += getlen;
+               pctx->ilen = 0;
+       }
+
+       /* now encrypt rest of data */
+       while (datalen >= bs) {
+               crypto_xor(odata, data, bs);
+               crypto_cipher_encrypt_one(tfm, odata, odata);
+
+               datalen -= bs;
+               data += bs;
+       }
+
+       /* check and see if there's leftover data that wasn't
+        * enough to fill a block.
+        */
+       if (datalen) {
+               memcpy(idata + pctx->ilen, data, datalen);
+               pctx->ilen += datalen;
+       }
+}
+
+static void get_data_to_compute(struct crypto_cipher *tfm,
+                              struct crypto_ccm_req_priv_ctx *pctx,
+                              struct scatterlist *sg, unsigned int len)
+{
+       struct scatter_walk walk;
+       u8 *data_src;
+       int n;
+
+       scatterwalk_start(&walk, sg);
+
+       while (len) {
+               n = scatterwalk_clamp(&walk, len);
+               if (!n) {
+                       scatterwalk_start(&walk, sg_next(walk.sg));
+                       n = scatterwalk_clamp(&walk, len);
+               }
+               data_src = scatterwalk_map(&walk, 0);
+
+               compute_mac(tfm, data_src, n, pctx);
+               len -= n;
+
+               scatterwalk_unmap(data_src, 0);
+               scatterwalk_advance(&walk, n);
+               scatterwalk_done(&walk, 0, len);
+               if (len)
+                       crypto_yield(pctx->flags);
+       }
+
+       /* any leftover needs padding and then encrypted */
+       if (pctx->ilen) {
+               int padlen;
+               u8 *odata = pctx->odata;
+               u8 *idata = pctx->idata;
+
+               padlen = 16 - pctx->ilen;
+               memset(idata + pctx->ilen, 0, padlen);
+               crypto_xor(odata, idata, 16);
+               crypto_cipher_encrypt_one(tfm, odata, odata);
+               pctx->ilen = 0;
+       }
+}
+
+static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
+                          unsigned int cryptlen)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+       struct crypto_cipher *cipher = ctx->cipher;
+       unsigned int assoclen = req->assoclen;
+       u8 *odata = pctx->odata;
+       u8 *idata = pctx->idata;
+       int err;
+
+       /* format control data for input */
+       err = format_input(odata, req, cryptlen);
+       if (err)
+               goto out;
+
+       /* encrypt first block to use as start in computing mac  */
+       crypto_cipher_encrypt_one(cipher, odata, odata);
+
+       /* format associated data and compute into mac */
+       if (assoclen) {
+               pctx->ilen = format_adata(idata, assoclen);
+               get_data_to_compute(cipher, pctx, req->assoc, req->assoclen);
+       }
+
+       /* compute plaintext into mac */
+       get_data_to_compute(cipher, pctx, plain, cryptlen);
+
+out:
+       return err;
+}
+
+static void crypto_ccm_encrypt_done(struct crypto_async_request *areq, int err)
+{
+       struct aead_request *req = areq->data;
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+       u8 *odata = pctx->odata;
+
+       if (!err)
+               scatterwalk_map_and_copy(odata, req->dst, req->cryptlen,
+                                        crypto_aead_authsize(aead), 1);
+       aead_request_complete(req, err);
+}
+
+static inline int crypto_ccm_check_iv(const u8 *iv)
+{
+       /* 2 <= L <= 8, so 1 <= L' <= 7. */
+       if (1 > iv[0] || iv[0] > 7)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int crypto_ccm_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+       struct ablkcipher_request *abreq = &pctx->abreq;
+       struct scatterlist *dst;
+       unsigned int cryptlen = req->cryptlen;
+       u8 *odata = pctx->odata;
+       u8 *iv = req->iv;
+       int err;
+
+       err = crypto_ccm_check_iv(iv);
+       if (err)
+               return err;
+
+       pctx->flags = aead_request_flags(req);
+
+       err = crypto_ccm_auth(req, req->src, cryptlen);
+       if (err)
+               return err;
+
+        /* Note: rfc 3610 and NIST 800-38C require counter of
+        * zero to encrypt auth tag.
+        */
+       memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+       sg_init_table(pctx->src, 2);
+       sg_set_buf(pctx->src, odata, 16);
+       scatterwalk_sg_chain(pctx->src, 2, req->src);
+
+       dst = pctx->src;
+       if (req->src != req->dst) {
+               sg_init_table(pctx->dst, 2);
+               sg_set_buf(pctx->dst, odata, 16);
+               scatterwalk_sg_chain(pctx->dst, 2, req->dst);
+               dst = pctx->dst;
+       }
+
+       ablkcipher_request_set_tfm(abreq, ctx->ctr);
+       ablkcipher_request_set_callback(abreq, pctx->flags,
+                                       crypto_ccm_encrypt_done, req);
+       ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv);
+       err = crypto_ablkcipher_encrypt(abreq);
+       if (err)
+               return err;
+
+       /* copy authtag to end of dst */
+       scatterwalk_map_and_copy(odata, req->dst, cryptlen,
+                                crypto_aead_authsize(aead), 1);
+       return err;
+}
+
+static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
+                                  int err)
+{
+       struct aead_request *req = areq->data;
+       struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       unsigned int authsize = crypto_aead_authsize(aead);
+       unsigned int cryptlen = req->cryptlen - authsize;
+
+       if (!err) {
+               err = crypto_ccm_auth(req, req->dst, cryptlen);
+               if (!err && memcmp(pctx->auth_tag, pctx->odata, authsize))
+                       err = -EBADMSG;
+       }
+       aead_request_complete(req, err);
+}
+
+static int crypto_ccm_decrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+       struct ablkcipher_request *abreq = &pctx->abreq;
+       struct scatterlist *dst;
+       unsigned int authsize = crypto_aead_authsize(aead);
+       unsigned int cryptlen = req->cryptlen;
+       u8 *authtag = pctx->auth_tag;
+       u8 *odata = pctx->odata;
+       u8 *iv = req->iv;
+       int err;
+
+       if (cryptlen < authsize)
+               return -EINVAL;
+       cryptlen -= authsize;
+
+       err = crypto_ccm_check_iv(iv);
+       if (err)
+               return err;
+
+       pctx->flags = aead_request_flags(req);
+
+       scatterwalk_map_and_copy(authtag, req->src, cryptlen, authsize, 0);
+
+       memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+       sg_init_table(pctx->src, 2);
+       sg_set_buf(pctx->src, authtag, 16);
+       scatterwalk_sg_chain(pctx->src, 2, req->src);
+
+       dst = pctx->src;
+       if (req->src != req->dst) {
+               sg_init_table(pctx->dst, 2);
+               sg_set_buf(pctx->dst, authtag, 16);
+               scatterwalk_sg_chain(pctx->dst, 2, req->dst);
+               dst = pctx->dst;
+       }
+
+       ablkcipher_request_set_tfm(abreq, ctx->ctr);
+       ablkcipher_request_set_callback(abreq, pctx->flags,
+                                       crypto_ccm_decrypt_done, req);
+       ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv);
+       err = crypto_ablkcipher_decrypt(abreq);
+       if (err)
+               return err;
+
+       err = crypto_ccm_auth(req, req->dst, cryptlen);
+       if (err)
+               return err;
+
+       /* verify */
+       if (memcmp(authtag, odata, authsize))
+               return -EBADMSG;
+
+       return err;
+}
+
+static int crypto_ccm_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct ccm_instance_ctx *ictx = crypto_instance_ctx(inst);
+       struct crypto_ccm_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_cipher *cipher;
+       struct crypto_ablkcipher *ctr;
+       unsigned long align;
+       int err;
+
+       cipher = crypto_spawn_cipher(&ictx->cipher);
+       if (IS_ERR(cipher))
+               return PTR_ERR(cipher);
+
+       ctr = crypto_spawn_skcipher(&ictx->ctr);
+       err = PTR_ERR(ctr);
+       if (IS_ERR(ctr))
+               goto err_free_cipher;
+
+       ctx->cipher = cipher;
+       ctx->ctr = ctr;
+
+       align = crypto_tfm_alg_alignmask(tfm);
+       align &= ~(crypto_tfm_ctx_alignment() - 1);
+       tfm->crt_aead.reqsize = align +
+                               sizeof(struct crypto_ccm_req_priv_ctx) +
+                               crypto_ablkcipher_reqsize(ctr);
+
+       return 0;
+
+err_free_cipher:
+       crypto_free_cipher(cipher);
+       return err;
+}
+
+static void crypto_ccm_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_ccm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_cipher(ctx->cipher);
+       crypto_free_ablkcipher(ctx->ctr);
+}
+
+static struct crypto_instance *crypto_ccm_alloc_common(struct rtattr **tb,
+                                                      const char *full_name,
+                                                      const char *ctr_name,
+                                                      const char *cipher_name)
+{
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_alg *ctr;
+       struct crypto_alg *cipher;
+       struct ccm_instance_ctx *ictx;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       cipher = crypto_alg_mod_lookup(cipher_name,  CRYPTO_ALG_TYPE_CIPHER,
+                                      CRYPTO_ALG_TYPE_MASK);
+       err = PTR_ERR(cipher);
+       if (IS_ERR(cipher))
+               return ERR_PTR(err);
+
+       err = -EINVAL;
+       if (cipher->cra_blocksize != 16)
+               goto out_put_cipher;
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
+       err = -ENOMEM;
+       if (!inst)
+               goto out_put_cipher;
+
+       ictx = crypto_instance_ctx(inst);
+
+       err = crypto_init_spawn(&ictx->cipher, cipher, inst,
+                               CRYPTO_ALG_TYPE_MASK);
+       if (err)
+               goto err_free_inst;
+
+       crypto_set_skcipher_spawn(&ictx->ctr, inst);
+       err = crypto_grab_skcipher(&ictx->ctr, ctr_name, 0,
+                                  crypto_requires_sync(algt->type,
+                                                       algt->mask));
+       if (err)
+               goto err_drop_cipher;
+
+       ctr = crypto_skcipher_spawn_alg(&ictx->ctr);
+
+       /* Not a stream cipher? */
+       err = -EINVAL;
+       if (ctr->cra_blocksize != 1)
+               goto err_drop_ctr;
+
+       /* We want the real thing! */
+       if (ctr->cra_ablkcipher.ivsize != 16)
+               goto err_drop_ctr;
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "ccm_base(%s,%s)", ctr->cra_driver_name,
+                    cipher->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_drop_ctr;
+
+       memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+       inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = cipher->cra_priority + ctr->cra_priority;
+       inst->alg.cra_blocksize = 1;
+       inst->alg.cra_alignmask = cipher->cra_alignmask | ctr->cra_alignmask |
+                                 (__alignof__(u32) - 1);
+       inst->alg.cra_type = &crypto_aead_type;
+       inst->alg.cra_aead.ivsize = 16;
+       inst->alg.cra_aead.maxauthsize = 16;
+       inst->alg.cra_ctxsize = sizeof(struct crypto_ccm_ctx);
+       inst->alg.cra_init = crypto_ccm_init_tfm;
+       inst->alg.cra_exit = crypto_ccm_exit_tfm;
+       inst->alg.cra_aead.setkey = crypto_ccm_setkey;
+       inst->alg.cra_aead.setauthsize = crypto_ccm_setauthsize;
+       inst->alg.cra_aead.encrypt = crypto_ccm_encrypt;
+       inst->alg.cra_aead.decrypt = crypto_ccm_decrypt;
+
+out:
+       crypto_mod_put(cipher);
+       return inst;
+
+err_drop_ctr:
+       crypto_drop_skcipher(&ictx->ctr);
+err_drop_cipher:
+       crypto_drop_spawn(&ictx->cipher);
+err_free_inst:
+       kfree(inst);
+out_put_cipher:
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static struct crypto_instance *crypto_ccm_alloc(struct rtattr **tb)
+{
+       int err;
+       const char *cipher_name;
+       char ctr_name[CRYPTO_MAX_ALG_NAME];
+       char full_name[CRYPTO_MAX_ALG_NAME];
+
+       cipher_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(cipher_name);
+       if (IS_ERR(cipher_name))
+               return ERR_PTR(err);
+
+       if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
+                    cipher_name) >= CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm(%s)", cipher_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       return crypto_ccm_alloc_common(tb, full_name, ctr_name, cipher_name);
+}
+
+static void crypto_ccm_free(struct crypto_instance *inst)
+{
+       struct ccm_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+       crypto_drop_spawn(&ctx->cipher);
+       crypto_drop_skcipher(&ctx->ctr);
+       kfree(inst);
+}
+
+static struct crypto_template crypto_ccm_tmpl = {
+       .name = "ccm",
+       .alloc = crypto_ccm_alloc,
+       .free = crypto_ccm_free,
+       .module = THIS_MODULE,
+};
+
+static struct crypto_instance *crypto_ccm_base_alloc(struct rtattr **tb)
+{
+       int err;
+       const char *ctr_name;
+       const char *cipher_name;
+       char full_name[CRYPTO_MAX_ALG_NAME];
+
+       ctr_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(ctr_name);
+       if (IS_ERR(ctr_name))
+               return ERR_PTR(err);
+
+       cipher_name = crypto_attr_alg_name(tb[2]);
+       err = PTR_ERR(cipher_name);
+       if (IS_ERR(cipher_name))
+               return ERR_PTR(err);
+
+       if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm_base(%s,%s)",
+                    ctr_name, cipher_name) >= CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       return crypto_ccm_alloc_common(tb, full_name, ctr_name, cipher_name);
+}
+
+static struct crypto_template crypto_ccm_base_tmpl = {
+       .name = "ccm_base",
+       .alloc = crypto_ccm_base_alloc,
+       .free = crypto_ccm_free,
+       .module = THIS_MODULE,
+};
+
+static int crypto_rfc4309_setkey(struct crypto_aead *parent, const u8 *key,
+                                unsigned int keylen)
+{
+       struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
+       struct crypto_aead *child = ctx->child;
+       int err;
+
+       if (keylen < 3)
+               return -EINVAL;
+
+       keylen -= 3;
+       memcpy(ctx->nonce, key + keylen, 3);
+
+       crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
+                                    CRYPTO_TFM_REQ_MASK);
+       err = crypto_aead_setkey(child, key, keylen);
+       crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
+                                     CRYPTO_TFM_RES_MASK);
+
+       return err;
+}
+
+static int crypto_rfc4309_setauthsize(struct crypto_aead *parent,
+                                     unsigned int authsize)
+{
+       struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
+
+       switch (authsize) {
+       case 8:
+       case 12:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return crypto_aead_setauthsize(ctx->child, authsize);
+}
+
+static struct aead_request *crypto_rfc4309_crypt(struct aead_request *req)
+{
+       struct aead_request *subreq = aead_request_ctx(req);
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_aead *child = ctx->child;
+       u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
+                          crypto_aead_alignmask(child) + 1);
+
+       /* L' */
+       iv[0] = 3;
+
+       memcpy(iv + 1, ctx->nonce, 3);
+       memcpy(iv + 4, req->iv, 8);
+
+       aead_request_set_tfm(subreq, child);
+       aead_request_set_callback(subreq, req->base.flags, req->base.complete,
+                                 req->base.data);
+       aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
+       aead_request_set_assoc(subreq, req->assoc, req->assoclen);
+
+       return subreq;
+}
+
+static int crypto_rfc4309_encrypt(struct aead_request *req)
+{
+       req = crypto_rfc4309_crypt(req);
+
+       return crypto_aead_encrypt(req);
+}
+
+static int crypto_rfc4309_decrypt(struct aead_request *req)
+{
+       req = crypto_rfc4309_crypt(req);
+
+       return crypto_aead_decrypt(req);
+}
+
+static int crypto_rfc4309_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
+       struct crypto_rfc4309_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_aead *aead;
+       unsigned long align;
+
+       aead = crypto_spawn_aead(spawn);
+       if (IS_ERR(aead))
+               return PTR_ERR(aead);
+
+       ctx->child = aead;
+
+       align = crypto_aead_alignmask(aead);
+       align &= ~(crypto_tfm_ctx_alignment() - 1);
+       tfm->crt_aead.reqsize = sizeof(struct aead_request) +
+                               ALIGN(crypto_aead_reqsize(aead),
+                                     crypto_tfm_ctx_alignment()) +
+                               align + 16;
+
+       return 0;
+}
+
+static void crypto_rfc4309_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_rfc4309_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_aead(ctx->child);
+}
+
+static struct crypto_instance *crypto_rfc4309_alloc(struct rtattr **tb)
+{
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_aead_spawn *spawn;
+       struct crypto_alg *alg;
+       const char *ccm_name;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       ccm_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(ccm_name);
+       if (IS_ERR(ccm_name))
+               return ERR_PTR(err);
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       spawn = crypto_instance_ctx(inst);
+       crypto_set_aead_spawn(spawn, inst);
+       err = crypto_grab_aead(spawn, ccm_name, 0,
+                              crypto_requires_sync(algt->type, algt->mask));
+       if (err)
+               goto out_free_inst;
+
+       alg = crypto_aead_spawn_alg(spawn);
+
+       err = -EINVAL;
+
+       /* We only support 16-byte blocks. */
+       if (alg->cra_aead.ivsize != 16)
+               goto out_drop_alg;
+
+       /* Not a stream cipher? */
+       if (alg->cra_blocksize != 1)
+               goto out_drop_alg;
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+                    "rfc4309(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
+           snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "rfc4309(%s)", alg->cra_driver_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               goto out_drop_alg;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+       inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = 1;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = &crypto_nivaead_type;
+
+       inst->alg.cra_aead.ivsize = 8;
+       inst->alg.cra_aead.maxauthsize = 16;
+
+       inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
+
+       inst->alg.cra_init = crypto_rfc4309_init_tfm;
+       inst->alg.cra_exit = crypto_rfc4309_exit_tfm;
+
+       inst->alg.cra_aead.setkey = crypto_rfc4309_setkey;
+       inst->alg.cra_aead.setauthsize = crypto_rfc4309_setauthsize;
+       inst->alg.cra_aead.encrypt = crypto_rfc4309_encrypt;
+       inst->alg.cra_aead.decrypt = crypto_rfc4309_decrypt;
+
+       inst->alg.cra_aead.geniv = "seqiv";
+
+out:
+       return inst;
+
+out_drop_alg:
+       crypto_drop_aead(spawn);
+out_free_inst:
+       kfree(inst);
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static void crypto_rfc4309_free(struct crypto_instance *inst)
+{
+       crypto_drop_spawn(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+
+static struct crypto_template crypto_rfc4309_tmpl = {
+       .name = "rfc4309",
+       .alloc = crypto_rfc4309_alloc,
+       .free = crypto_rfc4309_free,
+       .module = THIS_MODULE,
+};
+
+static int __init crypto_ccm_module_init(void)
+{
+       int err;
+
+       err = crypto_register_template(&crypto_ccm_base_tmpl);
+       if (err)
+               goto out;
+
+       err = crypto_register_template(&crypto_ccm_tmpl);
+       if (err)
+               goto out_undo_base;
+
+       err = crypto_register_template(&crypto_rfc4309_tmpl);
+       if (err)
+               goto out_undo_ccm;
+
+out:
+       return err;
+
+out_undo_ccm:
+       crypto_unregister_template(&crypto_ccm_tmpl);
+out_undo_base:
+       crypto_unregister_template(&crypto_ccm_base_tmpl);
+       goto out;
+}
+
+static void __exit crypto_ccm_module_exit(void)
+{
+       crypto_unregister_template(&crypto_rfc4309_tmpl);
+       crypto_unregister_template(&crypto_ccm_tmpl);
+       crypto_unregister_template(&crypto_ccm_base_tmpl);
+}
+
+module_init(crypto_ccm_module_init);
+module_exit(crypto_ccm_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Counter with CBC MAC");
+MODULE_ALIAS("ccm_base");
+MODULE_ALIAS("rfc4309");
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
new file mode 100644 (file)
index 0000000..d17fa04
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * chainiv: Chain IV Generator
+ *
+ * Generate IVs simply be using the last block of the previous encryption.
+ * This is mainly useful for CBC with a synchronous algorithm.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
+enum {
+       CHAINIV_STATE_INUSE = 0,
+};
+
+struct chainiv_ctx {
+       spinlock_t lock;
+       char iv[];
+};
+
+struct async_chainiv_ctx {
+       unsigned long state;
+
+       spinlock_t lock;
+       int err;
+
+       struct crypto_queue queue;
+       struct work_struct postponed;
+
+       char iv[];
+};
+
+static int chainiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+       unsigned int ivsize;
+       int err;
+
+       ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+       ablkcipher_request_set_callback(subreq, req->creq.base.flags &
+                                               ~CRYPTO_TFM_REQ_MAY_SLEEP,
+                                       req->creq.base.complete,
+                                       req->creq.base.data);
+       ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
+                                    req->creq.nbytes, req->creq.info);
+
+       spin_lock_bh(&ctx->lock);
+
+       ivsize = crypto_ablkcipher_ivsize(geniv);
+
+       memcpy(req->giv, ctx->iv, ivsize);
+       memcpy(subreq->info, ctx->iv, ivsize);
+
+       err = crypto_ablkcipher_encrypt(subreq);
+       if (err)
+               goto unlock;
+
+       memcpy(ctx->iv, subreq->info, ivsize);
+
+unlock:
+       spin_unlock_bh(&ctx->lock);
+
+       return err;
+}
+
+static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+       spin_lock_bh(&ctx->lock);
+       if (crypto_ablkcipher_crt(geniv)->givencrypt !=
+           chainiv_givencrypt_first)
+               goto unlock;
+
+       crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
+       get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+       spin_unlock_bh(&ctx->lock);
+
+       return chainiv_givencrypt(req);
+}
+
+static int chainiv_init_common(struct crypto_tfm *tfm)
+{
+       tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
+
+       return skcipher_geniv_init(tfm);
+}
+
+static int chainiv_init(struct crypto_tfm *tfm)
+{
+       struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       spin_lock_init(&ctx->lock);
+
+       return chainiv_init_common(tfm);
+}
+
+static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx)
+{
+       int queued;
+
+       if (!ctx->queue.qlen) {
+               smp_mb__before_clear_bit();
+               clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
+
+               if (!ctx->queue.qlen ||
+                   test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+                       goto out;
+       }
+
+       queued = schedule_work(&ctx->postponed);
+       BUG_ON(!queued);
+
+out:
+       return ctx->err;
+}
+
+static int async_chainiv_postpone_request(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       int err;
+
+       spin_lock_bh(&ctx->lock);
+       err = skcipher_enqueue_givcrypt(&ctx->queue, req);
+       spin_unlock_bh(&ctx->lock);
+
+       if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+               return err;
+
+       ctx->err = err;
+       return async_chainiv_schedule_work(ctx);
+}
+
+static int async_chainiv_givencrypt_tail(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+       unsigned int ivsize = crypto_ablkcipher_ivsize(geniv);
+
+       memcpy(req->giv, ctx->iv, ivsize);
+       memcpy(subreq->info, ctx->iv, ivsize);
+
+       ctx->err = crypto_ablkcipher_encrypt(subreq);
+       if (ctx->err)
+               goto out;
+
+       memcpy(ctx->iv, subreq->info, ivsize);
+
+out:
+       return async_chainiv_schedule_work(ctx);
+}
+
+static int async_chainiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+
+       ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+       ablkcipher_request_set_callback(subreq, req->creq.base.flags,
+                                       req->creq.base.complete,
+                                       req->creq.base.data);
+       ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
+                                    req->creq.nbytes, req->creq.info);
+
+       if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+               goto postpone;
+
+       if (ctx->queue.qlen) {
+               clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
+               goto postpone;
+       }
+
+       return async_chainiv_givencrypt_tail(req);
+
+postpone:
+       return async_chainiv_postpone_request(req);
+}
+
+static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+       if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+               goto out;
+
+       if (crypto_ablkcipher_crt(geniv)->givencrypt !=
+           async_chainiv_givencrypt_first)
+               goto unlock;
+
+       crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
+       get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+       clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
+
+out:
+       return async_chainiv_givencrypt(req);
+}
+
+static void async_chainiv_do_postponed(struct work_struct *work)
+{
+       struct async_chainiv_ctx *ctx = container_of(work,
+                                                    struct async_chainiv_ctx,
+                                                    postponed);
+       struct skcipher_givcrypt_request *req;
+       struct ablkcipher_request *subreq;
+
+       /* Only handle one request at a time to avoid hogging keventd. */
+       spin_lock_bh(&ctx->lock);
+       req = skcipher_dequeue_givcrypt(&ctx->queue);
+       spin_unlock_bh(&ctx->lock);
+
+       if (!req) {
+               async_chainiv_schedule_work(ctx);
+               return;
+       }
+
+       subreq = skcipher_givcrypt_reqctx(req);
+       subreq->base.flags |= CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       async_chainiv_givencrypt_tail(req);
+}
+
+static int async_chainiv_init(struct crypto_tfm *tfm)
+{
+       struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       spin_lock_init(&ctx->lock);
+
+       crypto_init_queue(&ctx->queue, 100);
+       INIT_WORK(&ctx->postponed, async_chainiv_do_postponed);
+
+       return chainiv_init_common(tfm);
+}
+
+static void async_chainiv_exit(struct crypto_tfm *tfm)
+{
+       struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       BUG_ON(test_bit(CHAINIV_STATE_INUSE, &ctx->state) || ctx->queue.qlen);
+
+       skcipher_geniv_exit(tfm);
+}
+
+static struct crypto_template chainiv_tmpl;
+
+static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
+{
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0);
+       if (IS_ERR(inst))
+               goto out;
+
+       inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first;
+
+       inst->alg.cra_init = chainiv_init;
+       inst->alg.cra_exit = skcipher_geniv_exit;
+
+       inst->alg.cra_ctxsize = sizeof(struct chainiv_ctx);
+
+       if (!crypto_requires_sync(algt->type, algt->mask)) {
+               inst->alg.cra_flags |= CRYPTO_ALG_ASYNC;
+
+               inst->alg.cra_ablkcipher.givencrypt =
+                       async_chainiv_givencrypt_first;
+
+               inst->alg.cra_init = async_chainiv_init;
+               inst->alg.cra_exit = async_chainiv_exit;
+
+               inst->alg.cra_ctxsize = sizeof(struct async_chainiv_ctx);
+       }
+
+       inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+
+out:
+       return inst;
+}
+
+static struct crypto_template chainiv_tmpl = {
+       .name = "chainiv",
+       .alloc = chainiv_alloc,
+       .free = skcipher_geniv_free,
+       .module = THIS_MODULE,
+};
+
+static int __init chainiv_module_init(void)
+{
+       return crypto_register_template(&chainiv_tmpl);
+}
+
+static void __exit chainiv_module_exit(void)
+{
+       crypto_unregister_template(&chainiv_tmpl);
+}
+
+module_init(chainiv_module_init);
+module_exit(chainiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Chain IV Generator");
index 8bf2da835f7beae4513e164b59622d56e0387a76..074298f2f8e392ef56391db7c2029fe07d1489c2 100644 (file)
@@ -228,7 +228,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
        struct crypto_alg *alg;
 
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
-                                 CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+                                 CRYPTO_ALG_TYPE_MASK);
        if (IS_ERR(alg))
                return ERR_PTR(PTR_ERR(alg));
 
@@ -236,13 +236,15 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
        if (IS_ERR(inst))
                goto out_put_alg;
 
-       inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC;
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
        inst->alg.cra_type = &crypto_ablkcipher_type;
 
        inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize;
        inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
        inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
 
+       inst->alg.cra_ablkcipher.geniv = alg->cra_blkcipher.geniv;
+
        inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx);
 
        inst->alg.cra_init = cryptd_blkcipher_init_tfm;
index 29f77477d701859e5dc34c72035d2c9e39108c67..ff7b3de1bcfdb1bd81742367a5335a6717b0658e 100644 (file)
  * (at your option) any later version.
  *
  */
+
+#include <crypto/internal/skcipher.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
 #include <linux/string.h>
 
 #define NULL_KEY_SIZE          0
 #define NULL_BLOCK_SIZE                1
 #define NULL_DIGEST_SIZE       0
+#define NULL_IV_SIZE           0
 
 static int null_compress(struct crypto_tfm *tfm, const u8 *src,
                         unsigned int slen, u8 *dst, unsigned int *dlen)
@@ -55,6 +57,26 @@ static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
        memcpy(dst, src, NULL_BLOCK_SIZE);
 }
 
+static int skcipher_null_crypt(struct blkcipher_desc *desc,
+                              struct scatterlist *dst,
+                              struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       while (walk.nbytes) {
+               if (walk.src.virt.addr != walk.dst.virt.addr)
+                       memcpy(walk.dst.virt.addr, walk.src.virt.addr,
+                              walk.nbytes);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
 static struct crypto_alg compress_null = {
        .cra_name               =       "compress_null",
        .cra_flags              =       CRYPTO_ALG_TYPE_COMPRESS,
@@ -76,6 +98,7 @@ static struct crypto_alg digest_null = {
        .cra_list               =       LIST_HEAD_INIT(digest_null.cra_list),   
        .cra_u                  =       { .digest = {
        .dia_digestsize         =       NULL_DIGEST_SIZE,
+       .dia_setkey             =       null_setkey,
        .dia_init               =       null_init,
        .dia_update             =       null_update,
        .dia_final              =       null_final } }
@@ -96,6 +119,25 @@ static struct crypto_alg cipher_null = {
        .cia_decrypt            =       null_crypt } }
 };
 
+static struct crypto_alg skcipher_null = {
+       .cra_name               =       "ecb(cipher_null)",
+       .cra_driver_name        =       "ecb-cipher_null",
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       NULL_BLOCK_SIZE,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_ctxsize            =       0,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(skcipher_null.cra_list),
+       .cra_u                  =       { .blkcipher = {
+       .min_keysize            =       NULL_KEY_SIZE,
+       .max_keysize            =       NULL_KEY_SIZE,
+       .ivsize                 =       NULL_IV_SIZE,
+       .setkey                 =       null_setkey,
+       .encrypt                =       skcipher_null_crypt,
+       .decrypt                =       skcipher_null_crypt } }
+};
+
 MODULE_ALIAS("compress_null");
 MODULE_ALIAS("digest_null");
 MODULE_ALIAS("cipher_null");
@@ -108,27 +150,35 @@ static int __init init(void)
        if (ret < 0)
                goto out;
 
+       ret = crypto_register_alg(&skcipher_null);
+       if (ret < 0)
+               goto out_unregister_cipher;
+
        ret = crypto_register_alg(&digest_null);
-       if (ret < 0) {
-               crypto_unregister_alg(&cipher_null);
-               goto out;
-       }
+       if (ret < 0)
+               goto out_unregister_skcipher;
 
        ret = crypto_register_alg(&compress_null);
-       if (ret < 0) {
-               crypto_unregister_alg(&digest_null);
-               crypto_unregister_alg(&cipher_null);
-               goto out;
-       }
+       if (ret < 0)
+               goto out_unregister_digest;
 
 out:   
        return ret;
+
+out_unregister_digest:
+       crypto_unregister_alg(&digest_null);
+out_unregister_skcipher:
+       crypto_unregister_alg(&skcipher_null);
+out_unregister_cipher:
+       crypto_unregister_alg(&cipher_null);
+       goto out;
 }
 
 static void __exit fini(void)
 {
        crypto_unregister_alg(&compress_null);
        crypto_unregister_alg(&digest_null);
+       crypto_unregister_alg(&skcipher_null);
        crypto_unregister_alg(&cipher_null);
 }
 
diff --git a/crypto/ctr.c b/crypto/ctr.c
new file mode 100644 (file)
index 0000000..2d7425f
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * CTR: Counter mode
+ *
+ * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+struct crypto_ctr_ctx {
+       struct crypto_cipher *child;
+};
+
+struct crypto_rfc3686_ctx {
+       struct crypto_blkcipher *child;
+       u8 nonce[CTR_RFC3686_NONCE_SIZE];
+};
+
+static int crypto_ctr_setkey(struct crypto_tfm *parent, const u8 *key,
+                            unsigned int keylen)
+{
+       struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(parent);
+       struct crypto_cipher *child = ctx->child;
+       int err;
+
+       crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+                               CRYPTO_TFM_REQ_MASK);
+       err = crypto_cipher_setkey(child, key, keylen);
+       crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+                            CRYPTO_TFM_RES_MASK);
+
+       return err;
+}
+
+static void crypto_ctr_crypt_final(struct blkcipher_walk *walk,
+                                  struct crypto_cipher *tfm)
+{
+       unsigned int bsize = crypto_cipher_blocksize(tfm);
+       unsigned long alignmask = crypto_cipher_alignmask(tfm);
+       u8 *ctrblk = walk->iv;
+       u8 tmp[bsize + alignmask];
+       u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       crypto_cipher_encrypt_one(tfm, keystream, ctrblk);
+       crypto_xor(keystream, src, nbytes);
+       memcpy(dst, keystream, nbytes);
+
+       crypto_inc(ctrblk, bsize);
+}
+
+static int crypto_ctr_crypt_segment(struct blkcipher_walk *walk,
+                                   struct crypto_cipher *tfm)
+{
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+                  crypto_cipher_alg(tfm)->cia_encrypt;
+       unsigned int bsize = crypto_cipher_blocksize(tfm);
+       u8 *ctrblk = walk->iv;
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       do {
+               /* create keystream */
+               fn(crypto_cipher_tfm(tfm), dst, ctrblk);
+               crypto_xor(dst, src, bsize);
+
+               /* increment counter in counterblock */
+               crypto_inc(ctrblk, bsize);
+
+               src += bsize;
+               dst += bsize;
+       } while ((nbytes -= bsize) >= bsize);
+
+       return nbytes;
+}
+
+static int crypto_ctr_crypt_inplace(struct blkcipher_walk *walk,
+                                   struct crypto_cipher *tfm)
+{
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+                  crypto_cipher_alg(tfm)->cia_encrypt;
+       unsigned int bsize = crypto_cipher_blocksize(tfm);
+       unsigned long alignmask = crypto_cipher_alignmask(tfm);
+       unsigned int nbytes = walk->nbytes;
+       u8 *ctrblk = walk->iv;
+       u8 *src = walk->src.virt.addr;
+       u8 tmp[bsize + alignmask];
+       u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+
+       do {
+               /* create keystream */
+               fn(crypto_cipher_tfm(tfm), keystream, ctrblk);
+               crypto_xor(src, keystream, bsize);
+
+               /* increment counter in counterblock */
+               crypto_inc(ctrblk, bsize);
+
+               src += bsize;
+       } while ((nbytes -= bsize) >= bsize);
+
+       return nbytes;
+}
+
+static int crypto_ctr_crypt(struct blkcipher_desc *desc,
+                             struct scatterlist *dst, struct scatterlist *src,
+                             unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       struct crypto_blkcipher *tfm = desc->tfm;
+       struct crypto_ctr_ctx *ctx = crypto_blkcipher_ctx(tfm);
+       struct crypto_cipher *child = ctx->child;
+       unsigned int bsize = crypto_cipher_blocksize(child);
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, bsize);
+
+       while (walk.nbytes >= bsize) {
+               if (walk.src.virt.addr == walk.dst.virt.addr)
+                       nbytes = crypto_ctr_crypt_inplace(&walk, child);
+               else
+                       nbytes = crypto_ctr_crypt_segment(&walk, child);
+
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       if (walk.nbytes) {
+               crypto_ctr_crypt_final(&walk, child);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+static int crypto_ctr_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+       struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_cipher *cipher;
+
+       cipher = crypto_spawn_cipher(spawn);
+       if (IS_ERR(cipher))
+               return PTR_ERR(cipher);
+
+       ctx->child = cipher;
+
+       return 0;
+}
+
+static void crypto_ctr_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_cipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb)
+{
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+       if (err)
+               return ERR_PTR(err);
+
+       alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
+                                 CRYPTO_ALG_TYPE_MASK);
+       if (IS_ERR(alg))
+               return ERR_PTR(PTR_ERR(alg));
+
+       /* Block size must be >= 4 bytes. */
+       err = -EINVAL;
+       if (alg->cra_blocksize < 4)
+               goto out_put_alg;
+
+       /* If this is false we'd fail the alignment of crypto_inc. */
+       if (alg->cra_blocksize % 4)
+               goto out_put_alg;
+
+       inst = crypto_alloc_instance("ctr", alg);
+       if (IS_ERR(inst))
+               goto out;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = 1;
+       inst->alg.cra_alignmask = alg->cra_alignmask | (__alignof__(u32) - 1);
+       inst->alg.cra_type = &crypto_blkcipher_type;
+
+       inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+       inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
+       inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
+
+       inst->alg.cra_ctxsize = sizeof(struct crypto_ctr_ctx);
+
+       inst->alg.cra_init = crypto_ctr_init_tfm;
+       inst->alg.cra_exit = crypto_ctr_exit_tfm;
+
+       inst->alg.cra_blkcipher.setkey = crypto_ctr_setkey;
+       inst->alg.cra_blkcipher.encrypt = crypto_ctr_crypt;
+       inst->alg.cra_blkcipher.decrypt = crypto_ctr_crypt;
+
+out:
+       crypto_mod_put(alg);
+       return inst;
+
+out_put_alg:
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static void crypto_ctr_free(struct crypto_instance *inst)
+{
+       crypto_drop_spawn(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+
+static struct crypto_template crypto_ctr_tmpl = {
+       .name = "ctr",
+       .alloc = crypto_ctr_alloc,
+       .free = crypto_ctr_free,
+       .module = THIS_MODULE,
+};
+
+static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key,
+                                unsigned int keylen)
+{
+       struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(parent);
+       struct crypto_blkcipher *child = ctx->child;
+       int err;
+
+       /* the nonce is stored in bytes at end of key */
+       if (keylen < CTR_RFC3686_NONCE_SIZE)
+               return -EINVAL;
+
+       memcpy(ctx->nonce, key + (keylen - CTR_RFC3686_NONCE_SIZE),
+              CTR_RFC3686_NONCE_SIZE);
+
+       keylen -= CTR_RFC3686_NONCE_SIZE;
+
+       crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
+                                         CRYPTO_TFM_REQ_MASK);
+       err = crypto_blkcipher_setkey(child, key, keylen);
+       crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
+                                    CRYPTO_TFM_RES_MASK);
+
+       return err;
+}
+
+static int crypto_rfc3686_crypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src, unsigned int nbytes)
+{
+       struct crypto_blkcipher *tfm = desc->tfm;
+       struct crypto_rfc3686_ctx *ctx = crypto_blkcipher_ctx(tfm);
+       struct crypto_blkcipher *child = ctx->child;
+       unsigned long alignmask = crypto_blkcipher_alignmask(tfm);
+       u8 ivblk[CTR_RFC3686_BLOCK_SIZE + alignmask];
+       u8 *iv = PTR_ALIGN(ivblk + 0, alignmask + 1);
+       u8 *info = desc->info;
+       int err;
+
+       /* set up counter block */
+       memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
+       memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
+
+       /* initialize counter portion of counter block */
+       *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
+               cpu_to_be32(1);
+
+       desc->tfm = child;
+       desc->info = iv;
+       err = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+       desc->tfm = tfm;
+       desc->info = info;
+
+       return err;
+}
+
+static int crypto_rfc3686_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+       struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_blkcipher *cipher;
+
+       cipher = crypto_spawn_blkcipher(spawn);
+       if (IS_ERR(cipher))
+               return PTR_ERR(cipher);
+
+       ctx->child = cipher;
+
+       return 0;
+}
+
+static void crypto_rfc3686_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_rfc3686_alloc(struct rtattr **tb)
+{
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+       if (err)
+               return ERR_PTR(err);
+
+       alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
+                                 CRYPTO_ALG_TYPE_MASK);
+       err = PTR_ERR(alg);
+       if (IS_ERR(alg))
+               return ERR_PTR(err);
+
+       /* We only support 16-byte blocks. */
+       err = -EINVAL;
+       if (alg->cra_blkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE)
+               goto out_put_alg;
+
+       /* Not a stream cipher? */
+       if (alg->cra_blocksize != 1)
+               goto out_put_alg;
+
+       inst = crypto_alloc_instance("rfc3686", alg);
+       if (IS_ERR(inst))
+               goto out;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = 1;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = &crypto_blkcipher_type;
+
+       inst->alg.cra_blkcipher.ivsize = CTR_RFC3686_IV_SIZE;
+       inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize
+                                             + CTR_RFC3686_NONCE_SIZE;
+       inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize
+                                             + CTR_RFC3686_NONCE_SIZE;
+
+       inst->alg.cra_blkcipher.geniv = "seqiv";
+
+       inst->alg.cra_ctxsize = sizeof(struct crypto_rfc3686_ctx);
+
+       inst->alg.cra_init = crypto_rfc3686_init_tfm;
+       inst->alg.cra_exit = crypto_rfc3686_exit_tfm;
+
+       inst->alg.cra_blkcipher.setkey = crypto_rfc3686_setkey;
+       inst->alg.cra_blkcipher.encrypt = crypto_rfc3686_crypt;
+       inst->alg.cra_blkcipher.decrypt = crypto_rfc3686_crypt;
+
+out:
+       crypto_mod_put(alg);
+       return inst;
+
+out_put_alg:
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static struct crypto_template crypto_rfc3686_tmpl = {
+       .name = "rfc3686",
+       .alloc = crypto_rfc3686_alloc,
+       .free = crypto_ctr_free,
+       .module = THIS_MODULE,
+};
+
+static int __init crypto_ctr_module_init(void)
+{
+       int err;
+
+       err = crypto_register_template(&crypto_ctr_tmpl);
+       if (err)
+               goto out;
+
+       err = crypto_register_template(&crypto_rfc3686_tmpl);
+       if (err)
+               goto out_drop_ctr;
+
+out:
+       return err;
+
+out_drop_ctr:
+       crypto_unregister_template(&crypto_ctr_tmpl);
+       goto out;
+}
+
+static void __exit crypto_ctr_module_exit(void)
+{
+       crypto_unregister_template(&crypto_rfc3686_tmpl);
+       crypto_unregister_template(&crypto_ctr_tmpl);
+}
+
+module_init(crypto_ctr_module_init);
+module_exit(crypto_ctr_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CTR Counter block mode");
+MODULE_ALIAS("rfc3686");
index 59966d14b8e0dbb672bfff2ebc4ee8de2b752742..355ecb71cb0d737304053960d84b9ef4e982fbf5 100644 (file)
 #include <linux/crypto.h>
 #include <linux/types.h>
 
-#define DES_KEY_SIZE           8
-#define DES_EXPKEY_WORDS       32
-#define DES_BLOCK_SIZE         8
-
-#define DES3_EDE_KEY_SIZE      (3 * DES_KEY_SIZE)
-#define DES3_EDE_EXPKEY_WORDS  (3 * DES_EXPKEY_WORDS)
-#define DES3_EDE_BLOCK_SIZE    DES_BLOCK_SIZE
+#include <crypto/des.h>
 
 #define ROL(x, r) ((x) = rol32((x), (r)))
 #define ROR(x, r) ((x) = ror32((x), (r)))
@@ -634,7 +628,7 @@ static const u32 S8[64] = {
  *   Choice 1 has operated on the key.
  *
  */
-static unsigned long ekey(u32 *pe, const u8 *k)
+unsigned long des_ekey(u32 *pe, const u8 *k)
 {
        /* K&R: long is at least 32 bits */
        unsigned long a, b, c, d, w;
@@ -709,6 +703,7 @@ static unsigned long ekey(u32 *pe, const u8 *k)
        /* Zero if weak key */
        return w;
 }
+EXPORT_SYMBOL_GPL(des_ekey);
 
 /*
  * Decryption key expansion
@@ -792,7 +787,7 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
        int ret;
 
        /* Expand to tmp */
-       ret = ekey(tmp, key);
+       ret = des_ekey(tmp, key);
 
        if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
                *flags |= CRYPTO_TFM_RES_WEAK_KEY;
@@ -879,9 +874,9 @@ static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
                return -EINVAL;
        }
 
-       ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
+       des_ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
        dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
-       ekey(expkey, key);
+       des_ekey(expkey, key);
 
        return 0;
 }
index 8871dec8cae7484a1fe34e68966563ad1d6032b9..6fd43bddd545e788546d868b097e3ad811867e76 100644 (file)
@@ -12,6 +12,7 @@
  *
  */
 
+#include <crypto/scatterwalk.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/hardirq.h>
@@ -20,9 +21,6 @@
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 
-#include "internal.h"
-#include "scatterwalk.h"
-
 static int init(struct hash_desc *desc)
 {
        struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
new file mode 100644 (file)
index 0000000..eb90d27
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * eseqiv: Encrypted Sequence Number IV Generator
+ *
+ * This generator generates an IV based on a sequence number by xoring it
+ * with a salt and then encrypting it with the same key as used to encrypt
+ * the plain text.  This algorithm requires that the block size be equal
+ * to the IV size.  It is mainly useful for CBC.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+struct eseqiv_request_ctx {
+       struct scatterlist src[2];
+       struct scatterlist dst[2];
+       char tail[];
+};
+
+struct eseqiv_ctx {
+       spinlock_t lock;
+       unsigned int reqoff;
+       char salt[];
+};
+
+static void eseqiv_complete2(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req);
+
+       memcpy(req->giv, PTR_ALIGN((u8 *)reqctx->tail,
+                        crypto_ablkcipher_alignmask(geniv) + 1),
+              crypto_ablkcipher_ivsize(geniv));
+}
+
+static void eseqiv_complete(struct crypto_async_request *base, int err)
+{
+       struct skcipher_givcrypt_request *req = base->data;
+
+       if (err)
+               goto out;
+
+       eseqiv_complete2(req);
+
+out:
+       skcipher_givcrypt_complete(req, err);
+}
+
+static void eseqiv_chain(struct scatterlist *head, struct scatterlist *sg,
+                        int chain)
+{
+       if (chain) {
+               head->length += sg->length;
+               sg = scatterwalk_sg_next(sg);
+       }
+
+       if (sg)
+               scatterwalk_sg_chain(head, 2, sg);
+       else
+               sg_mark_end(head);
+}
+
+static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req);
+       struct ablkcipher_request *subreq;
+       crypto_completion_t complete;
+       void *data;
+       struct scatterlist *osrc, *odst;
+       struct scatterlist *dst;
+       struct page *srcp;
+       struct page *dstp;
+       u8 *giv;
+       u8 *vsrc;
+       u8 *vdst;
+       __be64 seq;
+       unsigned int ivsize;
+       unsigned int len;
+       int err;
+
+       subreq = (void *)(reqctx->tail + ctx->reqoff);
+       ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+
+       giv = req->giv;
+       complete = req->creq.base.complete;
+       data = req->creq.base.data;
+
+       osrc = req->creq.src;
+       odst = req->creq.dst;
+       srcp = sg_page(osrc);
+       dstp = sg_page(odst);
+       vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + osrc->offset;
+       vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + odst->offset;
+
+       ivsize = crypto_ablkcipher_ivsize(geniv);
+
+       if (vsrc != giv + ivsize && vdst != giv + ivsize) {
+               giv = PTR_ALIGN((u8 *)reqctx->tail,
+                               crypto_ablkcipher_alignmask(geniv) + 1);
+               complete = eseqiv_complete;
+               data = req;
+       }
+
+       ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
+                                       data);
+
+       sg_init_table(reqctx->src, 2);
+       sg_set_buf(reqctx->src, giv, ivsize);
+       eseqiv_chain(reqctx->src, osrc, vsrc == giv + ivsize);
+
+       dst = reqctx->src;
+       if (osrc != odst) {
+               sg_init_table(reqctx->dst, 2);
+               sg_set_buf(reqctx->dst, giv, ivsize);
+               eseqiv_chain(reqctx->dst, odst, vdst == giv + ivsize);
+
+               dst = reqctx->dst;
+       }
+
+       ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
+                                    req->creq.nbytes, req->creq.info);
+
+       memcpy(req->creq.info, ctx->salt, ivsize);
+
+       len = ivsize;
+       if (ivsize > sizeof(u64)) {
+               memset(req->giv, 0, ivsize - sizeof(u64));
+               len = sizeof(u64);
+       }
+       seq = cpu_to_be64(req->seq);
+       memcpy(req->giv + ivsize - len, &seq, len);
+
+       err = crypto_ablkcipher_encrypt(subreq);
+       if (err)
+               goto out;
+
+       eseqiv_complete2(req);
+
+out:
+       return err;
+}
+
+static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+       spin_lock_bh(&ctx->lock);
+       if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
+               goto unlock;
+
+       crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
+       get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+       spin_unlock_bh(&ctx->lock);
+
+       return eseqiv_givencrypt(req);
+}
+
+static int eseqiv_init(struct crypto_tfm *tfm)
+{
+       struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
+       struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       unsigned long alignmask;
+       unsigned int reqsize;
+
+       spin_lock_init(&ctx->lock);
+
+       alignmask = crypto_tfm_ctx_alignment() - 1;
+       reqsize = sizeof(struct eseqiv_request_ctx);
+
+       if (alignmask & reqsize) {
+               alignmask &= reqsize;
+               alignmask--;
+       }
+
+       alignmask = ~alignmask;
+       alignmask &= crypto_ablkcipher_alignmask(geniv);
+
+       reqsize += alignmask;
+       reqsize += crypto_ablkcipher_ivsize(geniv);
+       reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
+
+       ctx->reqoff = reqsize - sizeof(struct eseqiv_request_ctx);
+
+       tfm->crt_ablkcipher.reqsize = reqsize +
+                                     sizeof(struct ablkcipher_request);
+
+       return skcipher_geniv_init(tfm);
+}
+
+static struct crypto_template eseqiv_tmpl;
+
+static struct crypto_instance *eseqiv_alloc(struct rtattr **tb)
+{
+       struct crypto_instance *inst;
+       int err;
+
+       inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
+       if (IS_ERR(inst))
+               goto out;
+
+       err = -EINVAL;
+       if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
+               goto free_inst;
+
+       inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first;
+
+       inst->alg.cra_init = eseqiv_init;
+       inst->alg.cra_exit = skcipher_geniv_exit;
+
+       inst->alg.cra_ctxsize = sizeof(struct eseqiv_ctx);
+       inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+
+out:
+       return inst;
+
+free_inst:
+       skcipher_geniv_free(inst);
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static struct crypto_template eseqiv_tmpl = {
+       .name = "eseqiv",
+       .alloc = eseqiv_alloc,
+       .free = skcipher_geniv_free,
+       .module = THIS_MODULE,
+};
+
+static int __init eseqiv_module_init(void)
+{
+       return crypto_register_template(&eseqiv_tmpl);
+}
+
+static void __exit eseqiv_module_exit(void)
+{
+       crypto_unregister_template(&eseqiv_tmpl);
+}
+
+module_init(eseqiv_module_init);
+module_exit(eseqiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator");
diff --git a/crypto/gcm.c b/crypto/gcm.c
new file mode 100644 (file)
index 0000000..e70afd0
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+ * GCM: Galois/Counter Mode.
+ *
+ * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
+ *
+ * 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 <crypto/gf128mul.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+struct gcm_instance_ctx {
+       struct crypto_skcipher_spawn ctr;
+};
+
+struct crypto_gcm_ctx {
+       struct crypto_ablkcipher *ctr;
+       struct gf128mul_4k *gf128;
+};
+
+struct crypto_rfc4106_ctx {
+       struct crypto_aead *child;
+       u8 nonce[4];
+};
+
+struct crypto_gcm_ghash_ctx {
+       u32 bytes;
+       u32 flags;
+       struct gf128mul_4k *gf128;
+       u8 buffer[16];
+};
+
+struct crypto_gcm_req_priv_ctx {
+       u8 auth_tag[16];
+       u8 iauth_tag[16];
+       struct scatterlist src[2];
+       struct scatterlist dst[2];
+       struct crypto_gcm_ghash_ctx ghash;
+       struct ablkcipher_request abreq;
+};
+
+struct crypto_gcm_setkey_result {
+       int err;
+       struct completion completion;
+};
+
+static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx(
+       struct aead_request *req)
+{
+       unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
+
+       return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
+}
+
+static void crypto_gcm_ghash_init(struct crypto_gcm_ghash_ctx *ctx, u32 flags,
+                                 struct gf128mul_4k *gf128)
+{
+       ctx->bytes = 0;
+       ctx->flags = flags;
+       ctx->gf128 = gf128;
+       memset(ctx->buffer, 0, 16);
+}
+
+static void crypto_gcm_ghash_update(struct crypto_gcm_ghash_ctx *ctx,
+                                   const u8 *src, unsigned int srclen)
+{
+       u8 *dst = ctx->buffer;
+
+       if (ctx->bytes) {
+               int n = min(srclen, ctx->bytes);
+               u8 *pos = dst + (16 - ctx->bytes);
+
+               ctx->bytes -= n;
+               srclen -= n;
+
+               while (n--)
+                       *pos++ ^= *src++;
+
+               if (!ctx->bytes)
+                       gf128mul_4k_lle((be128 *)dst, ctx->gf128);
+       }
+
+       while (srclen >= 16) {
+               crypto_xor(dst, src, 16);
+               gf128mul_4k_lle((be128 *)dst, ctx->gf128);
+               src += 16;
+               srclen -= 16;
+       }
+
+       if (srclen) {
+               ctx->bytes = 16 - srclen;
+               while (srclen--)
+                       *dst++ ^= *src++;
+       }
+}
+
+static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx,
+                                      struct scatterlist *sg, int len)
+{
+       struct scatter_walk walk;
+       u8 *src;
+       int n;
+
+       if (!len)
+               return;
+
+       scatterwalk_start(&walk, sg);
+
+       while (len) {
+               n = scatterwalk_clamp(&walk, len);
+
+               if (!n) {
+                       scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg));
+                       n = scatterwalk_clamp(&walk, len);
+               }
+
+               src = scatterwalk_map(&walk, 0);
+
+               crypto_gcm_ghash_update(ctx, src, n);
+               len -= n;
+
+               scatterwalk_unmap(src, 0);
+               scatterwalk_advance(&walk, n);
+               scatterwalk_done(&walk, 0, len);
+               if (len)
+                       crypto_yield(ctx->flags);
+       }
+}
+
+static void crypto_gcm_ghash_flush(struct crypto_gcm_ghash_ctx *ctx)
+{
+       u8 *dst = ctx->buffer;
+
+       if (ctx->bytes) {
+               u8 *tmp = dst + (16 - ctx->bytes);
+
+               while (ctx->bytes--)
+                       *tmp++ ^= 0;
+
+               gf128mul_4k_lle((be128 *)dst, ctx->gf128);
+       }
+
+       ctx->bytes = 0;
+}
+
+static void crypto_gcm_ghash_final_xor(struct crypto_gcm_ghash_ctx *ctx,
+                                      unsigned int authlen,
+                                      unsigned int cryptlen, u8 *dst)
+{
+       u8 *buf = ctx->buffer;
+       u128 lengths;
+
+       lengths.a = cpu_to_be64(authlen * 8);
+       lengths.b = cpu_to_be64(cryptlen * 8);
+
+       crypto_gcm_ghash_flush(ctx);
+       crypto_xor(buf, (u8 *)&lengths, 16);
+       gf128mul_4k_lle((be128 *)buf, ctx->gf128);
+       crypto_xor(dst, buf, 16);
+}
+
+static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err)
+{
+       struct crypto_gcm_setkey_result *result = req->data;
+
+       if (err == -EINPROGRESS)
+               return;
+
+       result->err = err;
+       complete(&result->completion);
+}
+
+static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
+                            unsigned int keylen)
+{
+       struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_ablkcipher *ctr = ctx->ctr;
+       struct {
+               be128 hash;
+               u8 iv[8];
+
+               struct crypto_gcm_setkey_result result;
+
+               struct scatterlist sg[1];
+               struct ablkcipher_request req;
+       } *data;
+       int err;
+
+       crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
+       crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
+                                  CRYPTO_TFM_REQ_MASK);
+
+       err = crypto_ablkcipher_setkey(ctr, key, keylen);
+       if (err)
+               return err;
+
+       crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
+                                      CRYPTO_TFM_RES_MASK);
+
+       data = kzalloc(sizeof(*data) + crypto_ablkcipher_reqsize(ctr),
+                      GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       init_completion(&data->result.completion);
+       sg_init_one(data->sg, &data->hash, sizeof(data->hash));
+       ablkcipher_request_set_tfm(&data->req, ctr);
+       ablkcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
+                                                   CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                       crypto_gcm_setkey_done,
+                                       &data->result);
+       ablkcipher_request_set_crypt(&data->req, data->sg, data->sg,
+                                    sizeof(data->hash), data->iv);
+
+       err = crypto_ablkcipher_encrypt(&data->req);
+       if (err == -EINPROGRESS || err == -EBUSY) {
+               err = wait_for_completion_interruptible(
+                       &data->result.completion);
+               if (!err)
+                       err = data->result.err;
+       }
+
+       if (err)
+               goto out;
+
+       if (ctx->gf128 != NULL)
+               gf128mul_free_4k(ctx->gf128);
+
+       ctx->gf128 = gf128mul_init_4k_lle(&data->hash);
+
+       if (ctx->gf128 == NULL)
+               err = -ENOMEM;
+
+out:
+       kfree(data);
+       return err;
+}
+
+static int crypto_gcm_setauthsize(struct crypto_aead *tfm,
+                                 unsigned int authsize)
+{
+       switch (authsize) {
+       case 4:
+       case 8:
+       case 12:
+       case 13:
+       case 14:
+       case 15:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
+                                 struct aead_request *req,
+                                 unsigned int cryptlen)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+       u32 flags = req->base.tfm->crt_flags;
+       struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+       struct scatterlist *dst;
+       __be32 counter = cpu_to_be32(1);
+
+       memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
+       memcpy(req->iv + 12, &counter, 4);
+
+       sg_init_table(pctx->src, 2);
+       sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
+       scatterwalk_sg_chain(pctx->src, 2, req->src);
+
+       dst = pctx->src;
+       if (req->src != req->dst) {
+               sg_init_table(pctx->dst, 2);
+               sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
+               scatterwalk_sg_chain(pctx->dst, 2, req->dst);
+               dst = pctx->dst;
+       }
+
+       ablkcipher_request_set_tfm(ablk_req, ctx->ctr);
+       ablkcipher_request_set_crypt(ablk_req, pctx->src, dst,
+                                    cryptlen + sizeof(pctx->auth_tag),
+                                    req->iv);
+
+       crypto_gcm_ghash_init(ghash, flags, ctx->gf128);
+
+       crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen);
+       crypto_gcm_ghash_flush(ghash);
+}
+
+static int crypto_gcm_hash(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+       u8 *auth_tag = pctx->auth_tag;
+       struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+
+       crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen);
+       crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen,
+                                  auth_tag);
+
+       scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen,
+                                crypto_aead_authsize(aead), 1);
+       return 0;
+}
+
+static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err)
+{
+       struct aead_request *req = areq->data;
+
+       if (!err)
+               err = crypto_gcm_hash(req);
+
+       aead_request_complete(req, err);
+}
+
+static int crypto_gcm_encrypt(struct aead_request *req)
+{
+       struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+       struct ablkcipher_request *abreq = &pctx->abreq;
+       int err;
+
+       crypto_gcm_init_crypt(abreq, req, req->cryptlen);
+       ablkcipher_request_set_callback(abreq, aead_request_flags(req),
+                                       crypto_gcm_encrypt_done, req);
+
+       err = crypto_ablkcipher_encrypt(abreq);
+       if (err)
+               return err;
+
+       return crypto_gcm_hash(req);
+}
+
+static int crypto_gcm_verify(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+       struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+       u8 *auth_tag = pctx->auth_tag;
+       u8 *iauth_tag = pctx->iauth_tag;
+       unsigned int authsize = crypto_aead_authsize(aead);
+       unsigned int cryptlen = req->cryptlen - authsize;
+
+       crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag);
+
+       authsize = crypto_aead_authsize(aead);
+       scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
+       return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
+}
+
+static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err)
+{
+       struct aead_request *req = areq->data;
+
+       if (!err)
+               err = crypto_gcm_verify(req);
+
+       aead_request_complete(req, err);
+}
+
+static int crypto_gcm_decrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+       struct ablkcipher_request *abreq = &pctx->abreq;
+       struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+       unsigned int cryptlen = req->cryptlen;
+       unsigned int authsize = crypto_aead_authsize(aead);
+       int err;
+
+       if (cryptlen < authsize)
+               return -EINVAL;
+       cryptlen -= authsize;
+
+       crypto_gcm_init_crypt(abreq, req, cryptlen);
+       ablkcipher_request_set_callback(abreq, aead_request_flags(req),
+                                       crypto_gcm_decrypt_done, req);
+
+       crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen);
+
+       err = crypto_ablkcipher_decrypt(abreq);
+       if (err)
+               return err;
+
+       return crypto_gcm_verify(req);
+}
+
+static int crypto_gcm_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct gcm_instance_ctx *ictx = crypto_instance_ctx(inst);
+       struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_ablkcipher *ctr;
+       unsigned long align;
+       int err;
+
+       ctr = crypto_spawn_skcipher(&ictx->ctr);
+       err = PTR_ERR(ctr);
+       if (IS_ERR(ctr))
+               return err;
+
+       ctx->ctr = ctr;
+       ctx->gf128 = NULL;
+
+       align = crypto_tfm_alg_alignmask(tfm);
+       align &= ~(crypto_tfm_ctx_alignment() - 1);
+       tfm->crt_aead.reqsize = align +
+                               sizeof(struct crypto_gcm_req_priv_ctx) +
+                               crypto_ablkcipher_reqsize(ctr);
+
+       return 0;
+}
+
+static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (ctx->gf128 != NULL)
+               gf128mul_free_4k(ctx->gf128);
+
+       crypto_free_ablkcipher(ctx->ctr);
+}
+
+static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
+                                                      const char *full_name,
+                                                      const char *ctr_name)
+{
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_alg *ctr;
+       struct gcm_instance_ctx *ctx;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       ctx = crypto_instance_ctx(inst);
+       crypto_set_skcipher_spawn(&ctx->ctr, inst);
+       err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0,
+                                  crypto_requires_sync(algt->type,
+                                                       algt->mask));
+       if (err)
+               goto err_free_inst;
+
+       ctr = crypto_skcipher_spawn_alg(&ctx->ctr);
+
+       /* We only support 16-byte blocks. */
+       if (ctr->cra_ablkcipher.ivsize != 16)
+               goto out_put_ctr;
+
+       /* Not a stream cipher? */
+       err = -EINVAL;
+       if (ctr->cra_blocksize != 1)
+               goto out_put_ctr;
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "gcm_base(%s)", ctr->cra_driver_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               goto out_put_ctr;
+
+       memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+       inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = ctr->cra_priority;
+       inst->alg.cra_blocksize = 1;
+       inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1);
+       inst->alg.cra_type = &crypto_aead_type;
+       inst->alg.cra_aead.ivsize = 16;
+       inst->alg.cra_aead.maxauthsize = 16;
+       inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
+       inst->alg.cra_init = crypto_gcm_init_tfm;
+       inst->alg.cra_exit = crypto_gcm_exit_tfm;
+       inst->alg.cra_aead.setkey = crypto_gcm_setkey;
+       inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize;
+       inst->alg.cra_aead.encrypt = crypto_gcm_encrypt;
+       inst->alg.cra_aead.decrypt = crypto_gcm_decrypt;
+
+out:
+       return inst;
+
+out_put_ctr:
+       crypto_drop_skcipher(&ctx->ctr);
+err_free_inst:
+       kfree(inst);
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb)
+{
+       int err;
+       const char *cipher_name;
+       char ctr_name[CRYPTO_MAX_ALG_NAME];
+       char full_name[CRYPTO_MAX_ALG_NAME];
+
+       cipher_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(cipher_name);
+       if (IS_ERR(cipher_name))
+               return ERR_PTR(err);
+
+       if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       return crypto_gcm_alloc_common(tb, full_name, ctr_name);
+}
+
+static void crypto_gcm_free(struct crypto_instance *inst)
+{
+       struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+       crypto_drop_skcipher(&ctx->ctr);
+       kfree(inst);
+}
+
+static struct crypto_template crypto_gcm_tmpl = {
+       .name = "gcm",
+       .alloc = crypto_gcm_alloc,
+       .free = crypto_gcm_free,
+       .module = THIS_MODULE,
+};
+
+static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
+{
+       int err;
+       const char *ctr_name;
+       char full_name[CRYPTO_MAX_ALG_NAME];
+
+       ctr_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(ctr_name);
+       if (IS_ERR(ctr_name))
+               return ERR_PTR(err);
+
+       if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)",
+                    ctr_name) >= CRYPTO_MAX_ALG_NAME)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       return crypto_gcm_alloc_common(tb, full_name, ctr_name);
+}
+
+static struct crypto_template crypto_gcm_base_tmpl = {
+       .name = "gcm_base",
+       .alloc = crypto_gcm_base_alloc,
+       .free = crypto_gcm_free,
+       .module = THIS_MODULE,
+};
+
+static int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key,
+                                unsigned int keylen)
+{
+       struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
+       struct crypto_aead *child = ctx->child;
+       int err;
+
+       if (keylen < 4)
+               return -EINVAL;
+
+       keylen -= 4;
+       memcpy(ctx->nonce, key + keylen, 4);
+
+       crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
+                                    CRYPTO_TFM_REQ_MASK);
+       err = crypto_aead_setkey(child, key, keylen);
+       crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
+                                     CRYPTO_TFM_RES_MASK);
+
+       return err;
+}
+
+static int crypto_rfc4106_setauthsize(struct crypto_aead *parent,
+                                     unsigned int authsize)
+{
+       struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
+
+       switch (authsize) {
+       case 8:
+       case 12:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return crypto_aead_setauthsize(ctx->child, authsize);
+}
+
+static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req)
+{
+       struct aead_request *subreq = aead_request_ctx(req);
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
+       struct crypto_aead *child = ctx->child;
+       u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
+                          crypto_aead_alignmask(child) + 1);
+
+       memcpy(iv, ctx->nonce, 4);
+       memcpy(iv + 4, req->iv, 8);
+
+       aead_request_set_tfm(subreq, child);
+       aead_request_set_callback(subreq, req->base.flags, req->base.complete,
+                                 req->base.data);
+       aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
+       aead_request_set_assoc(subreq, req->assoc, req->assoclen);
+
+       return subreq;
+}
+
+static int crypto_rfc4106_encrypt(struct aead_request *req)
+{
+       req = crypto_rfc4106_crypt(req);
+
+       return crypto_aead_encrypt(req);
+}
+
+static int crypto_rfc4106_decrypt(struct aead_request *req)
+{
+       req = crypto_rfc4106_crypt(req);
+
+       return crypto_aead_decrypt(req);
+}
+
+static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = (void *)tfm->__crt_alg;
+       struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
+       struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_aead *aead;
+       unsigned long align;
+
+       aead = crypto_spawn_aead(spawn);
+       if (IS_ERR(aead))
+               return PTR_ERR(aead);
+
+       ctx->child = aead;
+
+       align = crypto_aead_alignmask(aead);
+       align &= ~(crypto_tfm_ctx_alignment() - 1);
+       tfm->crt_aead.reqsize = sizeof(struct aead_request) +
+                               ALIGN(crypto_aead_reqsize(aead),
+                                     crypto_tfm_ctx_alignment()) +
+                               align + 16;
+
+       return 0;
+}
+
+static void crypto_rfc4106_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_aead(ctx->child);
+}
+
+static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb)
+{
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_aead_spawn *spawn;
+       struct crypto_alg *alg;
+       const char *ccm_name;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       ccm_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(ccm_name);
+       if (IS_ERR(ccm_name))
+               return ERR_PTR(err);
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       spawn = crypto_instance_ctx(inst);
+       crypto_set_aead_spawn(spawn, inst);
+       err = crypto_grab_aead(spawn, ccm_name, 0,
+                              crypto_requires_sync(algt->type, algt->mask));
+       if (err)
+               goto out_free_inst;
+
+       alg = crypto_aead_spawn_alg(spawn);
+
+       err = -EINVAL;
+
+       /* We only support 16-byte blocks. */
+       if (alg->cra_aead.ivsize != 16)
+               goto out_drop_alg;
+
+       /* Not a stream cipher? */
+       if (alg->cra_blocksize != 1)
+               goto out_drop_alg;
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+                    "rfc4106(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
+           snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "rfc4106(%s)", alg->cra_driver_name) >=
+           CRYPTO_MAX_ALG_NAME)
+               goto out_drop_alg;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+       inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = 1;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = &crypto_nivaead_type;
+
+       inst->alg.cra_aead.ivsize = 8;
+       inst->alg.cra_aead.maxauthsize = 16;
+
+       inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
+
+       inst->alg.cra_init = crypto_rfc4106_init_tfm;
+       inst->alg.cra_exit = crypto_rfc4106_exit_tfm;
+
+       inst->alg.cra_aead.setkey = crypto_rfc4106_setkey;
+       inst->alg.cra_aead.setauthsize = crypto_rfc4106_setauthsize;
+       inst->alg.cra_aead.encrypt = crypto_rfc4106_encrypt;
+       inst->alg.cra_aead.decrypt = crypto_rfc4106_decrypt;
+
+       inst->alg.cra_aead.geniv = "seqiv";
+
+out:
+       return inst;
+
+out_drop_alg:
+       crypto_drop_aead(spawn);
+out_free_inst:
+       kfree(inst);
+       inst = ERR_PTR(err);
+       goto out;
+}
+
+static void crypto_rfc4106_free(struct crypto_instance *inst)
+{
+       crypto_drop_spawn(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+
+static struct crypto_template crypto_rfc4106_tmpl = {
+       .name = "rfc4106",
+       .alloc = crypto_rfc4106_alloc,
+       .free = crypto_rfc4106_free,
+       .module = THIS_MODULE,
+};
+
+static int __init crypto_gcm_module_init(void)
+{
+       int err;
+
+       err = crypto_register_template(&crypto_gcm_base_tmpl);
+       if (err)
+               goto out;
+
+       err = crypto_register_template(&crypto_gcm_tmpl);
+       if (err)
+               goto out_undo_base;
+
+       err = crypto_register_template(&crypto_rfc4106_tmpl);
+       if (err)
+               goto out_undo_gcm;
+
+out:
+       return err;
+
+out_undo_gcm:
+       crypto_unregister_template(&crypto_gcm_tmpl);
+out_undo_base:
+       crypto_unregister_template(&crypto_gcm_base_tmpl);
+       goto out;
+}
+
+static void __exit crypto_gcm_module_exit(void)
+{
+       crypto_unregister_template(&crypto_rfc4106_tmpl);
+       crypto_unregister_template(&crypto_gcm_tmpl);
+       crypto_unregister_template(&crypto_gcm_base_tmpl);
+}
+
+module_init(crypto_gcm_module_init);
+module_exit(crypto_gcm_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Galois/Counter Mode");
+MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>");
+MODULE_ALIAS("gcm_base");
+MODULE_ALIAS("rfc4106");
index 0f05be769c346c71d6ed3a70228d947c4699e50f..a1d016a50e7debd10f6b7030f44d598b6eccedb3 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -160,7 +161,7 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
 
        sg_init_table(sg1, 2);
        sg_set_buf(sg1, ipad, bs);
-       sg_set_page(&sg1[1], (void *) sg, 0, 0);
+       scatterwalk_sg_chain(sg1, 2, sg);
 
        sg_init_table(sg2, 1);
        sg_set_buf(sg2, opad, bs + ds);
index abb01f71f817a80192a449439ed0ecd0565d60c6..32f4c214560315ccc284346499f6b9428bae1d66 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
-#include <asm/kmap_types.h>
 
 /* Crypto notification events. */
 enum {
@@ -50,34 +49,6 @@ extern struct list_head crypto_alg_list;
 extern struct rw_semaphore crypto_alg_sem;
 extern struct blocking_notifier_head crypto_chain;
 
-static inline enum km_type crypto_kmap_type(int out)
-{
-       enum km_type type;
-
-       if (in_softirq())
-               type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0;
-       else
-               type = out * (KM_USER1 - KM_USER0) + KM_USER0;
-
-       return type;
-}
-
-static inline void *crypto_kmap(struct page *page, int out)
-{
-       return kmap_atomic(page, crypto_kmap_type(out));
-}
-
-static inline void crypto_kunmap(void *vaddr, int out)
-{
-       kunmap_atomic(vaddr, crypto_kmap_type(out));
-}
-
-static inline void crypto_yield(u32 flags)
-{
-       if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
-               cond_resched();
-}
-
 #ifdef CONFIG_PROC_FS
 void __init crypto_init_proc(void);
 void __exit crypto_exit_proc(void);
@@ -122,6 +93,8 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm);
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
 void crypto_exit_compress_ops(struct crypto_tfm *tfm);
 
+void crypto_larval_kill(struct crypto_alg *alg);
+struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask);
 void crypto_larval_error(const char *name, u32 type, u32 mask);
 
 void crypto_shoot_alg(struct crypto_alg *alg);
diff --git a/crypto/lzo.c b/crypto/lzo.c
new file mode 100644 (file)
index 0000000..48c3288
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Cryptographic API.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/lzo.h>
+
+struct lzo_ctx {
+       void *lzo_comp_mem;
+};
+
+static int lzo_init(struct crypto_tfm *tfm)
+{
+       struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS);
+       if (!ctx->lzo_comp_mem)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void lzo_exit(struct crypto_tfm *tfm)
+{
+       struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       vfree(ctx->lzo_comp_mem);
+}
+
+static int lzo_compress(struct crypto_tfm *tfm, const u8 *src,
+                           unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+       struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+       size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
+       int err;
+
+       err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx->lzo_comp_mem);
+
+       if (err != LZO_E_OK)
+               return -EINVAL;
+
+       *dlen = tmp_len;
+       return 0;
+}
+
+static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src,
+                             unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+       int err;
+       size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
+
+       err = lzo1x_decompress_safe(src, slen, dst, &tmp_len);
+
+       if (err != LZO_E_OK)
+               return -EINVAL;
+
+       *dlen = tmp_len;
+       return 0;
+
+}
+
+static struct crypto_alg alg = {
+       .cra_name               = "lzo",
+       .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
+       .cra_ctxsize            = sizeof(struct lzo_ctx),
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(alg.cra_list),
+       .cra_init               = lzo_init,
+       .cra_exit               = lzo_exit,
+       .cra_u                  = { .compress = {
+       .coa_compress           = lzo_compress,
+       .coa_decompress         = lzo_decompress } }
+};
+
+static int __init init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LZO Compression Algorithm");
index c3ed8a1c9f4616022ad1e80525875c8f5ce776d0..fe704775f88ff0fa526a197201c1a751a8535611 100644 (file)
@@ -24,7 +24,6 @@
 
 struct crypto_pcbc_ctx {
        struct crypto_cipher *child;
-       void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
 };
 
 static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
@@ -45,9 +44,7 @@ static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
 
 static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
                                       struct blkcipher_walk *walk,
-                                      struct crypto_cipher *tfm,
-                                      void (*xor)(u8 *, const u8 *,
-                                                  unsigned int))
+                                      struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_encrypt;
@@ -58,10 +55,10 @@ static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
        u8 *iv = walk->iv;
 
        do {
-               xor(iv, src, bsize);
+               crypto_xor(iv, src, bsize);
                fn(crypto_cipher_tfm(tfm), dst, iv);
                memcpy(iv, dst, bsize);
-               xor(iv, src, bsize);
+               crypto_xor(iv, src, bsize);
 
                src += bsize;
                dst += bsize;
@@ -72,9 +69,7 @@ static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
 
 static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
                                       struct blkcipher_walk *walk,
-                                      struct crypto_cipher *tfm,
-                                      void (*xor)(u8 *, const u8 *,
-                                                  unsigned int))
+                                      struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_encrypt;
@@ -86,10 +81,10 @@ static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
 
        do {
                memcpy(tmpbuf, src, bsize);
-               xor(iv, tmpbuf, bsize);
+               crypto_xor(iv, src, bsize);
                fn(crypto_cipher_tfm(tfm), src, iv);
-               memcpy(iv, src, bsize);
-               xor(iv, tmpbuf, bsize);
+               memcpy(iv, tmpbuf, bsize);
+               crypto_xor(iv, src, bsize);
 
                src += bsize;
        } while ((nbytes -= bsize) >= bsize);
@@ -107,7 +102,6 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
        struct crypto_blkcipher *tfm = desc->tfm;
        struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
        struct crypto_cipher *child = ctx->child;
-       void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
        int err;
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -115,11 +109,11 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
 
        while ((nbytes = walk.nbytes)) {
                if (walk.src.virt.addr == walk.dst.virt.addr)
-                       nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child,
-                                                            xor);
+                       nbytes = crypto_pcbc_encrypt_inplace(desc, &walk,
+                                                            child);
                else
-                       nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child,
-                                                            xor);
+                       nbytes = crypto_pcbc_encrypt_segment(desc, &walk,
+                                                            child);
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
 
@@ -128,9 +122,7 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
 
 static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
                                       struct blkcipher_walk *walk,
-                                      struct crypto_cipher *tfm,
-                                      void (*xor)(u8 *, const u8 *,
-                                                  unsigned int))
+                                      struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_decrypt;
@@ -142,9 +134,9 @@ static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
 
        do {
                fn(crypto_cipher_tfm(tfm), dst, src);
-               xor(dst, iv, bsize);
+               crypto_xor(dst, iv, bsize);
                memcpy(iv, src, bsize);
-               xor(iv, dst, bsize);
+               crypto_xor(iv, dst, bsize);
 
                src += bsize;
                dst += bsize;
@@ -157,9 +149,7 @@ static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
 
 static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
                                       struct blkcipher_walk *walk,
-                                      struct crypto_cipher *tfm,
-                                      void (*xor)(u8 *, const u8 *,
-                                                  unsigned int))
+                                      struct crypto_cipher *tfm)
 {
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                crypto_cipher_alg(tfm)->cia_decrypt;
@@ -172,9 +162,9 @@ static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
        do {
                memcpy(tmpbuf, src, bsize);
                fn(crypto_cipher_tfm(tfm), src, src);
-               xor(src, iv, bsize);
+               crypto_xor(src, iv, bsize);
                memcpy(iv, tmpbuf, bsize);
-               xor(iv, src, bsize);
+               crypto_xor(iv, src, bsize);
 
                src += bsize;
        } while ((nbytes -= bsize) >= bsize);
@@ -192,7 +182,6 @@ static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
        struct crypto_blkcipher *tfm = desc->tfm;
        struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
        struct crypto_cipher *child = ctx->child;
-       void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
        int err;
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -200,48 +189,17 @@ static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
 
        while ((nbytes = walk.nbytes)) {
                if (walk.src.virt.addr == walk.dst.virt.addr)
-                       nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child,
-                                                            xor);
+                       nbytes = crypto_pcbc_decrypt_inplace(desc, &walk,
+                                                            child);
                else
-                       nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child,
-                                                            xor);
+                       nbytes = crypto_pcbc_decrypt_segment(desc, &walk,
+                                                            child);
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
 
        return err;
 }
 
-static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
-{
-       do {
-               *a++ ^= *b++;
-       } while (--bs);
-}
-
-static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
-{
-       u32 *a = (u32 *)dst;
-       u32 *b = (u32 *)src;
-
-       do {
-               *a++ ^= *b++;
-       } while ((bs -= 4));
-}
-
-static void xor_64(u8 *a, const u8 *b, unsigned int bs)
-{
-       ((u32 *)a)[0] ^= ((u32 *)b)[0];
-       ((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static void xor_128(u8 *a, const u8 *b, unsigned int bs)
-{
-       ((u32 *)a)[0] ^= ((u32 *)b)[0];
-       ((u32 *)a)[1] ^= ((u32 *)b)[1];
-       ((u32 *)a)[2] ^= ((u32 *)b)[2];
-       ((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
 static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_instance *inst = (void *)tfm->__crt_alg;
@@ -249,22 +207,6 @@ static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
        struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
        struct crypto_cipher *cipher;
 
-       switch (crypto_tfm_alg_blocksize(tfm)) {
-       case 8:
-               ctx->xor = xor_64;
-               break;
-
-       case 16:
-               ctx->xor = xor_128;
-               break;
-
-       default:
-               if (crypto_tfm_alg_blocksize(tfm) % 4)
-                       ctx->xor = xor_byte;
-               else
-                       ctx->xor = xor_quad;
-       }
-
        cipher = crypto_spawn_cipher(spawn);
        if (IS_ERR(cipher))
                return PTR_ERR(cipher);
@@ -304,8 +246,9 @@ static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
        inst->alg.cra_alignmask = alg->cra_alignmask;
        inst->alg.cra_type = &crypto_blkcipher_type;
 
-       if (!(alg->cra_blocksize % 4))
-               inst->alg.cra_alignmask |= 3;
+       /* We access the data as u32s when xoring. */
+       inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+
        inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
        inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
        inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c
new file mode 100644 (file)
index 0000000..1fa4e4d
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Salsa20: Salsa20 stream cipher algorithm
+ *
+ * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com>
+ *
+ * Derived from:
+ * - salsa20.c: Public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * Salsa20 is a stream cipher candidate in eSTREAM, the ECRYPT Stream
+ * Cipher Project. It is designed by Daniel J. Bernstein <djb@cr.yp.to>.
+ * More information about eSTREAM and Salsa20 can be found here:
+ *   http://www.ecrypt.eu.org/stream/
+ *   http://cr.yp.to/snuffle.html
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <asm/byteorder.h>
+
+#define SALSA20_IV_SIZE        8U
+#define SALSA20_MIN_KEY_SIZE  16U
+#define SALSA20_MAX_KEY_SIZE  32U
+
+/*
+ * Start of code taken from D. J. Bernstein's reference implementation.
+ * With some modifications and optimizations made to suit our needs.
+ */
+
+/*
+salsa20-ref.c version 20051118
+D. J. Bernstein
+Public domain.
+*/
+
+#define ROTATE(v,n) (((v) << (n)) | ((v) >> (32 - (n))))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+#define U32TO8_LITTLE(p, v) \
+       { (p)[0] = (v >>  0) & 0xff; (p)[1] = (v >>  8) & 0xff; \
+         (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; }
+#define U8TO32_LITTLE(p)   \
+       (((u32)((p)[0])      ) | ((u32)((p)[1]) <<  8) | \
+        ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24)   )
+
+struct salsa20_ctx
+{
+       u32 input[16];
+};
+
+static void salsa20_wordtobyte(u8 output[64], const u32 input[16])
+{
+       u32 x[16];
+       int i;
+
+       memcpy(x, input, sizeof(x));
+       for (i = 20; i > 0; i -= 2) {
+               x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7));
+               x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9));
+               x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13));
+               x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18));
+               x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7));
+               x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9));
+               x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13));
+               x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18));
+               x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7));
+               x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9));
+               x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13));
+               x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18));
+               x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7));
+               x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9));
+               x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13));
+               x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18));
+               x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7));
+               x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9));
+               x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13));
+               x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18));
+               x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7));
+               x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9));
+               x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13));
+               x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18));
+               x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7));
+               x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9));
+               x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13));
+               x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18));
+               x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7));
+               x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9));
+               x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13));
+               x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18));
+       }
+       for (i = 0; i < 16; ++i)
+               x[i] = PLUS(x[i],input[i]);
+       for (i = 0; i < 16; ++i)
+               U32TO8_LITTLE(output + 4 * i,x[i]);
+}
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+static void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k, u32 kbytes)
+{
+       const char *constants;
+
+       ctx->input[1] = U8TO32_LITTLE(k + 0);
+       ctx->input[2] = U8TO32_LITTLE(k + 4);
+       ctx->input[3] = U8TO32_LITTLE(k + 8);
+       ctx->input[4] = U8TO32_LITTLE(k + 12);
+       if (kbytes == 32) { /* recommended */
+               k += 16;
+               constants = sigma;
+       } else { /* kbytes == 16 */
+               constants = tau;
+       }
+       ctx->input[11] = U8TO32_LITTLE(k + 0);
+       ctx->input[12] = U8TO32_LITTLE(k + 4);
+       ctx->input[13] = U8TO32_LITTLE(k + 8);
+       ctx->input[14] = U8TO32_LITTLE(k + 12);
+       ctx->input[0] = U8TO32_LITTLE(constants + 0);
+       ctx->input[5] = U8TO32_LITTLE(constants + 4);
+       ctx->input[10] = U8TO32_LITTLE(constants + 8);
+       ctx->input[15] = U8TO32_LITTLE(constants + 12);
+}
+
+static void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv)
+{
+       ctx->input[6] = U8TO32_LITTLE(iv + 0);
+       ctx->input[7] = U8TO32_LITTLE(iv + 4);
+       ctx->input[8] = 0;
+       ctx->input[9] = 0;
+}
+
+static void salsa20_encrypt_bytes(struct salsa20_ctx *ctx, u8 *dst,
+                                 const u8 *src, unsigned int bytes)
+{
+       u8 buf[64];
+
+       if (dst != src)
+               memcpy(dst, src, bytes);
+
+       while (bytes) {
+               salsa20_wordtobyte(buf, ctx->input);
+
+               ctx->input[8] = PLUSONE(ctx->input[8]);
+               if (!ctx->input[8])
+                       ctx->input[9] = PLUSONE(ctx->input[9]);
+
+               if (bytes <= 64) {
+                       crypto_xor(dst, buf, bytes);
+                       return;
+               }
+
+               crypto_xor(dst, buf, 64);
+               bytes -= 64;
+               dst += 64;
+       }
+}
+
+/*
+ * End of code taken from D. J. Bernstein's reference implementation.
+ */
+
+static int setkey(struct crypto_tfm *tfm, const u8 *key,
+                 unsigned int keysize)
+{
+       struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm);
+       salsa20_keysetup(ctx, key, keysize);
+       return 0;
+}
+
+static int encrypt(struct blkcipher_desc *desc,
+                  struct scatterlist *dst, struct scatterlist *src,
+                  unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       struct crypto_blkcipher *tfm = desc->tfm;
+       struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm);
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, 64);
+
+       salsa20_ivsetup(ctx, walk.iv);
+
+       if (likely(walk.nbytes == nbytes))
+       {
+               salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
+                                     walk.src.virt.addr, nbytes);
+               return blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       while (walk.nbytes >= 64) {
+               salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
+                                     walk.src.virt.addr,
+                                     walk.nbytes - (walk.nbytes % 64));
+               err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64);
+       }
+
+       if (walk.nbytes) {
+               salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
+                                     walk.src.virt.addr, walk.nbytes);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+static struct crypto_alg alg = {
+       .cra_name           =   "salsa20",
+       .cra_driver_name    =   "salsa20-generic",
+       .cra_priority       =   100,
+       .cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_type           =   &crypto_blkcipher_type,
+       .cra_blocksize      =   1,
+       .cra_ctxsize        =   sizeof(struct salsa20_ctx),
+       .cra_alignmask      =   3,
+       .cra_module         =   THIS_MODULE,
+       .cra_list           =   LIST_HEAD_INIT(alg.cra_list),
+       .cra_u              =   {
+               .blkcipher = {
+                       .setkey         =   setkey,
+                       .encrypt        =   encrypt,
+                       .decrypt        =   encrypt,
+                       .min_keysize    =   SALSA20_MIN_KEY_SIZE,
+                       .max_keysize    =   SALSA20_MAX_KEY_SIZE,
+                       .ivsize         =   SALSA20_IV_SIZE,
+               }
+       }
+};
+
+static int __init init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm");
+MODULE_ALIAS("salsa20");
index b9bbda0bb9f968efc4a728dd316952b7516f617b..9aeeb52004a5399d0a9b7a3484044b5de1e3083c 100644 (file)
@@ -13,6 +13,8 @@
  * any later version.
  *
  */
+
+#include <crypto/scatterwalk.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
@@ -20,9 +22,6 @@
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
 
-#include "internal.h"
-#include "scatterwalk.h"
-
 static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
 {
        void *src = out ? buf : sgdata;
@@ -106,6 +105,9 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
        struct scatter_walk walk;
        unsigned int offset = 0;
 
+       if (!nbytes)
+               return;
+
        for (;;) {
                scatterwalk_start(&walk, sg);
 
@@ -113,7 +115,7 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
                        break;
 
                offset += sg->length;
-               sg = sg_next(sg);
+               sg = scatterwalk_sg_next(sg);
        }
 
        scatterwalk_advance(&walk, start - offset);
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h
deleted file mode 100644 (file)
index 87ed681..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com>
- * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.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.
- *
- */
-
-#ifndef _CRYPTO_SCATTERWALK_H
-#define _CRYPTO_SCATTERWALK_H
-
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-
-#include "internal.h"
-
-static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
-{
-       return (++sg)->length ? sg : (void *) sg_page(sg);
-}
-
-static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
-                                               struct scatter_walk *walk_out)
-{
-       return !(((sg_page(walk_in->sg) - sg_page(walk_out->sg)) << PAGE_SHIFT) +
-                (int)(walk_in->offset - walk_out->offset));
-}
-
-static inline unsigned int scatterwalk_pagelen(struct scatter_walk *walk)
-{
-       unsigned int len = walk->sg->offset + walk->sg->length - walk->offset;
-       unsigned int len_this_page = offset_in_page(~walk->offset) + 1;
-       return len_this_page > len ? len : len_this_page;
-}
-
-static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk,
-                                            unsigned int nbytes)
-{
-       unsigned int len_this_page = scatterwalk_pagelen(walk);
-       return nbytes > len_this_page ? len_this_page : nbytes;
-}
-
-static inline void scatterwalk_advance(struct scatter_walk *walk,
-                                      unsigned int nbytes)
-{
-       walk->offset += nbytes;
-}
-
-static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk,
-                                              unsigned int alignmask)
-{
-       return !(walk->offset & alignmask);
-}
-
-static inline struct page *scatterwalk_page(struct scatter_walk *walk)
-{
-       return sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
-}
-
-static inline void scatterwalk_unmap(void *vaddr, int out)
-{
-       crypto_kunmap(vaddr, out);
-}
-
-void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
-void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
-                           size_t nbytes, int out);
-void *scatterwalk_map(struct scatter_walk *walk, int out);
-void scatterwalk_done(struct scatter_walk *walk, int out, int more);
-
-void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
-                             unsigned int start, unsigned int nbytes, int out);
-
-#endif  /* _CRYPTO_SCATTERWALK_H */
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
new file mode 100644 (file)
index 0000000..b903aab
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * seqiv: Sequence Number IV Generator
+ *
+ * This generator generates an IV based on a sequence number by xoring it
+ * with a salt.  This algorithm is mainly useful for CTR and similar modes.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+struct seqiv_ctx {
+       spinlock_t lock;
+       u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
+};
+
+static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err)
+{
+       struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+       struct crypto_ablkcipher *geniv;
+
+       if (err == -EINPROGRESS)
+               return;
+
+       if (err)
+               goto out;
+
+       geniv = skcipher_givcrypt_reqtfm(req);
+       memcpy(req->creq.info, subreq->info, crypto_ablkcipher_ivsize(geniv));
+
+out:
+       kfree(subreq->info);
+}
+
+static void seqiv_complete(struct crypto_async_request *base, int err)
+{
+       struct skcipher_givcrypt_request *req = base->data;
+
+       seqiv_complete2(req, err);
+       skcipher_givcrypt_complete(req, err);
+}
+
+static void seqiv_aead_complete2(struct aead_givcrypt_request *req, int err)
+{
+       struct aead_request *subreq = aead_givcrypt_reqctx(req);
+       struct crypto_aead *geniv;
+
+       if (err == -EINPROGRESS)
+               return;
+
+       if (err)
+               goto out;
+
+       geniv = aead_givcrypt_reqtfm(req);
+       memcpy(req->areq.iv, subreq->iv, crypto_aead_ivsize(geniv));
+
+out:
+       kfree(subreq->iv);
+}
+
+static void seqiv_aead_complete(struct crypto_async_request *base, int err)
+{
+       struct aead_givcrypt_request *req = base->data;
+
+       seqiv_aead_complete2(req, err);
+       aead_givcrypt_complete(req, err);
+}
+
+static void seqiv_geniv(struct seqiv_ctx *ctx, u8 *info, u64 seq,
+                       unsigned int ivsize)
+{
+       unsigned int len = ivsize;
+
+       if (ivsize > sizeof(u64)) {
+               memset(info, 0, ivsize - sizeof(u64));
+               len = sizeof(u64);
+       }
+       seq = cpu_to_be64(seq);
+       memcpy(info + ivsize - len, &seq, len);
+       crypto_xor(info, ctx->salt, ivsize);
+}
+
+static int seqiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+       struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+       crypto_completion_t complete;
+       void *data;
+       u8 *info;
+       unsigned int ivsize;
+       int err;
+
+       ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+
+       complete = req->creq.base.complete;
+       data = req->creq.base.data;
+       info = req->creq.info;
+
+       ivsize = crypto_ablkcipher_ivsize(geniv);
+
+       if (unlikely(!IS_ALIGNED((unsigned long)info,
+                                crypto_ablkcipher_alignmask(geniv) + 1))) {
+               info = kmalloc(ivsize, req->creq.base.flags &
+                                      CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+                                                                 GFP_ATOMIC);
+               if (!info)
+                       return -ENOMEM;
+
+               complete = seqiv_complete;
+               data = req;
+       }
+
+       ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
+                                       data);
+       ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
+                                    req->creq.nbytes, info);
+
+       seqiv_geniv(ctx, info, req->seq, ivsize);
+       memcpy(req->giv, info, ivsize);
+
+       err = crypto_ablkcipher_encrypt(subreq);
+       if (unlikely(info != req->creq.info))
+               seqiv_complete2(req, err);
+       return err;
+}
+
+static int seqiv_aead_givencrypt(struct aead_givcrypt_request *req)
+{
+       struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
+       struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+       struct aead_request *areq = &req->areq;
+       struct aead_request *subreq = aead_givcrypt_reqctx(req);
+       crypto_completion_t complete;
+       void *data;
+       u8 *info;
+       unsigned int ivsize;
+       int err;
+
+       aead_request_set_tfm(subreq, aead_geniv_base(geniv));
+
+       complete = areq->base.complete;
+       data = areq->base.data;
+       info = areq->iv;
+
+       ivsize = crypto_aead_ivsize(geniv);
+
+       if (unlikely(!IS_ALIGNED((unsigned long)info,
+                                crypto_aead_alignmask(geniv) + 1))) {
+               info = kmalloc(ivsize, areq->base.flags &
+                                      CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+                                                                 GFP_ATOMIC);
+               if (!info)
+                       return -ENOMEM;
+
+               complete = seqiv_aead_complete;
+               data = req;
+       }
+
+       aead_request_set_callback(subreq, areq->base.flags, complete, data);
+       aead_request_set_crypt(subreq, areq->src, areq->dst, areq->cryptlen,
+                              info);
+       aead_request_set_assoc(subreq, areq->assoc, areq->assoclen);
+
+       seqiv_geniv(ctx, info, req->seq, ivsize);
+       memcpy(req->giv, info, ivsize);
+
+       err = crypto_aead_encrypt(subreq);
+       if (unlikely(info != areq->iv))
+               seqiv_aead_complete2(req, err);
+       return err;
+}
+
+static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+       struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+       struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+       spin_lock_bh(&ctx->lock);
+       if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
+               goto unlock;
+
+       crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
+       get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+       spin_unlock_bh(&ctx->lock);
+
+       return seqiv_givencrypt(req);
+}
+
+static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req)
+{
+       struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
+       struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+
+       spin_lock_bh(&ctx->lock);
+       if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
+               goto unlock;
+
+       crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
+       get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv));
+
+unlock:
+       spin_unlock_bh(&ctx->lock);
+
+       return seqiv_aead_givencrypt(req);
+}
+
+static int seqiv_init(struct crypto_tfm *tfm)
+{
+       struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
+       struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+       spin_lock_init(&ctx->lock);
+
+       tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
+
+       return skcipher_geniv_init(tfm);
+}
+
+static int seqiv_aead_init(struct crypto_tfm *tfm)
+{
+       struct crypto_aead *geniv = __crypto_aead_cast(tfm);
+       struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+
+       spin_lock_init(&ctx->lock);
+
+       tfm->crt_aead.reqsize = sizeof(struct aead_request);
+
+       return aead_geniv_init(tfm);
+}
+
+static struct crypto_template seqiv_tmpl;
+
+static struct crypto_instance *seqiv_ablkcipher_alloc(struct rtattr **tb)
+{
+       struct crypto_instance *inst;
+
+       inst = skcipher_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
+
+       if (IS_ERR(inst))
+               goto out;
+
+       inst->alg.cra_ablkcipher.givencrypt = seqiv_givencrypt_first;
+
+       inst->alg.cra_init = seqiv_init;
+       inst->alg.cra_exit = skcipher_geniv_exit;
+
+       inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+
+out:
+       return inst;
+}
+
+static struct crypto_instance *seqiv_aead_alloc(struct rtattr **tb)
+{
+       struct crypto_instance *inst;
+
+       inst = aead_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
+
+       if (IS_ERR(inst))
+               goto out;
+
+       inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first;
+
+       inst->alg.cra_init = seqiv_aead_init;
+       inst->alg.cra_exit = aead_geniv_exit;
+
+       inst->alg.cra_ctxsize = inst->alg.cra_aead.ivsize;
+
+out:
+       return inst;
+}
+
+static struct crypto_instance *seqiv_alloc(struct rtattr **tb)
+{
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
+               return ERR_PTR(err);
+
+       if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
+               inst = seqiv_ablkcipher_alloc(tb);
+       else
+               inst = seqiv_aead_alloc(tb);
+
+       if (IS_ERR(inst))
+               goto out;
+
+       inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+       inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);
+
+out:
+       return inst;
+}
+
+static void seqiv_free(struct crypto_instance *inst)
+{
+       if ((inst->alg.cra_flags ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
+               skcipher_geniv_free(inst);
+       else
+               aead_geniv_free(inst);
+}
+
+static struct crypto_template seqiv_tmpl = {
+       .name = "seqiv",
+       .alloc = seqiv_alloc,
+       .free = seqiv_free,
+       .module = THIS_MODULE,
+};
+
+static int __init seqiv_module_init(void)
+{
+       return crypto_register_template(&seqiv_tmpl);
+}
+
+static void __exit seqiv_module_exit(void)
+{
+       crypto_unregister_template(&seqiv_tmpl);
+}
+
+module_init(seqiv_module_init);
+module_exit(seqiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sequence Number IV Generator");
index fd3918be58b51be9637a854f3bab569032b9f3a0..3cc93fd61043bbb75b01ad3a8d8ae4e205e94144 100644 (file)
@@ -9,6 +9,7 @@
  * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
  * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.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
@@ -218,6 +219,22 @@ static void sha256_transform(u32 *state, const u8 *input)
        memset(W, 0, 64 * sizeof(u32));
 }
 
+
+static void sha224_init(struct crypto_tfm *tfm)
+{
+       struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+       sctx->state[0] = SHA224_H0;
+       sctx->state[1] = SHA224_H1;
+       sctx->state[2] = SHA224_H2;
+       sctx->state[3] = SHA224_H3;
+       sctx->state[4] = SHA224_H4;
+       sctx->state[5] = SHA224_H5;
+       sctx->state[6] = SHA224_H6;
+       sctx->state[7] = SHA224_H7;
+       sctx->count[0] = 0;
+       sctx->count[1] = 0;
+}
+
 static void sha256_init(struct crypto_tfm *tfm)
 {
        struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
@@ -294,8 +311,17 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out)
        memset(sctx, 0, sizeof(*sctx));
 }
 
+static void sha224_final(struct crypto_tfm *tfm, u8 *hash)
+{
+       u8 D[SHA256_DIGEST_SIZE];
+
+       sha256_final(tfm, D);
+
+       memcpy(hash, D, SHA224_DIGEST_SIZE);
+       memset(D, 0, SHA256_DIGEST_SIZE);
+}
 
-static struct crypto_alg alg = {
+static struct crypto_alg sha256 = {
        .cra_name       =       "sha256",
        .cra_driver_name=       "sha256-generic",
        .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
@@ -303,28 +329,58 @@ static struct crypto_alg alg = {
        .cra_ctxsize    =       sizeof(struct sha256_ctx),
        .cra_module     =       THIS_MODULE,
        .cra_alignmask  =       3,
-       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+       .cra_list       =       LIST_HEAD_INIT(sha256.cra_list),
        .cra_u          =       { .digest = {
        .dia_digestsize =       SHA256_DIGEST_SIZE,
-       .dia_init       =       sha256_init,
-       .dia_update     =       sha256_update,
-       .dia_final      =       sha256_final } }
+       .dia_init       =       sha256_init,
+       .dia_update     =       sha256_update,
+       .dia_final      =       sha256_final } }
+};
+
+static struct crypto_alg sha224 = {
+       .cra_name       = "sha224",
+       .cra_driver_name = "sha224-generic",
+       .cra_flags      = CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize  = SHA224_BLOCK_SIZE,
+       .cra_ctxsize    = sizeof(struct sha256_ctx),
+       .cra_module     = THIS_MODULE,
+       .cra_alignmask  = 3,
+       .cra_list       = LIST_HEAD_INIT(sha224.cra_list),
+       .cra_u          = { .digest = {
+       .dia_digestsize = SHA224_DIGEST_SIZE,
+       .dia_init       = sha224_init,
+       .dia_update     = sha256_update,
+       .dia_final      = sha224_final } }
 };
 
 static int __init init(void)
 {
-       return crypto_register_alg(&alg);
+       int ret = 0;
+
+       ret = crypto_register_alg(&sha224);
+
+       if (ret < 0)
+               return ret;
+
+       ret = crypto_register_alg(&sha256);
+
+       if (ret < 0)
+               crypto_unregister_alg(&sha224);
+
+       return ret;
 }
 
 static void __exit fini(void)
 {
-       crypto_unregister_alg(&alg);
+       crypto_unregister_alg(&sha224);
+       crypto_unregister_alg(&sha256);
 }
 
 module_init(init);
 module_exit(fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm");
+MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm");
 
+MODULE_ALIAS("sha224");
 MODULE_ALIAS("sha256");
index 24141fb6f5cba0639ae25ccca4d42a79bcd4d032..1ab8c017a0113106c5e25ee2046d36531f9a9777 100644 (file)
@@ -6,12 +6,16 @@
  *
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
+ * Copyright (c) 2007 Nokia Siemens Networks
  *
  * 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.
  *
+ * 2007-11-13 Added GCM tests
+ * 2007-11-13 Added AEAD support
+ * 2007-11-06 Added SHA-224 and SHA-224-HMAC tests
  * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
  * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
  * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt
@@ -71,22 +75,23 @@ static unsigned int sec;
 
 static int mode;
 static char *xbuf;
+static char *axbuf;
 static char *tvmem;
 
 static char *check[] = {
-       "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
-       "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
+       "des", "md5", "des3_ede", "rot13", "sha1", "sha224", "sha256",
+       "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes",
+       "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
        "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
        "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
-       "camellia", "seed", NULL
+       "camellia", "seed", "salsa20", "lzo", NULL
 };
 
 static void hexdump(unsigned char *buf, unsigned int len)
 {
-       while (len--)
-               printk("%02x", *buf++);
-
-       printk("\n");
+       print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+                       16, 1,
+                       buf, len, false);
 }
 
 static void tcrypt_complete(struct crypto_async_request *req, int err)
@@ -215,6 +220,238 @@ out:
        crypto_free_hash(tfm);
 }
 
+static void test_aead(char *algo, int enc, struct aead_testvec *template,
+                     unsigned int tcount)
+{
+       unsigned int ret, i, j, k, temp;
+       unsigned int tsize;
+       char *q;
+       struct crypto_aead *tfm;
+       char *key;
+       struct aead_testvec *aead_tv;
+       struct aead_request *req;
+       struct scatterlist sg[8];
+       struct scatterlist asg[8];
+       const char *e;
+       struct tcrypt_result result;
+       unsigned int authsize;
+
+       if (enc == ENCRYPT)
+               e = "encryption";
+       else
+               e = "decryption";
+
+       printk(KERN_INFO "\ntesting %s %s\n", algo, e);
+
+       tsize = sizeof(struct aead_testvec);
+       tsize *= tcount;
+
+       if (tsize > TVMEMSIZE) {
+               printk(KERN_INFO "template (%u) too big for tvmem (%u)\n",
+                      tsize, TVMEMSIZE);
+               return;
+       }
+
+       memcpy(tvmem, template, tsize);
+       aead_tv = (void *)tvmem;
+
+       init_completion(&result.completion);
+
+       tfm = crypto_alloc_aead(algo, 0, 0);
+
+       if (IS_ERR(tfm)) {
+               printk(KERN_INFO "failed to load transform for %s: %ld\n",
+                      algo, PTR_ERR(tfm));
+               return;
+       }
+
+       req = aead_request_alloc(tfm, GFP_KERNEL);
+       if (!req) {
+               printk(KERN_INFO "failed to allocate request for %s\n", algo);
+               goto out;
+       }
+
+       aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                 tcrypt_complete, &result);
+
+       for (i = 0, j = 0; i < tcount; i++) {
+               if (!aead_tv[i].np) {
+                       printk(KERN_INFO "test %u (%d bit key):\n",
+                              ++j, aead_tv[i].klen * 8);
+
+                       crypto_aead_clear_flags(tfm, ~0);
+                       if (aead_tv[i].wk)
+                               crypto_aead_set_flags(
+                                       tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+                       key = aead_tv[i].key;
+
+                       ret = crypto_aead_setkey(tfm, key,
+                                                aead_tv[i].klen);
+                       if (ret) {
+                               printk(KERN_INFO "setkey() failed flags=%x\n",
+                                      crypto_aead_get_flags(tfm));
+
+                               if (!aead_tv[i].fail)
+                                       goto out;
+                       }
+
+                       authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen);
+                       ret = crypto_aead_setauthsize(tfm, authsize);
+                       if (ret) {
+                               printk(KERN_INFO
+                                      "failed to set authsize = %u\n",
+                                      authsize);
+                               goto out;
+                       }
+
+                       sg_init_one(&sg[0], aead_tv[i].input,
+                                   aead_tv[i].ilen + (enc ? authsize : 0));
+
+                       sg_init_one(&asg[0], aead_tv[i].assoc,
+                                   aead_tv[i].alen);
+
+                       aead_request_set_crypt(req, sg, sg,
+                                              aead_tv[i].ilen,
+                                              aead_tv[i].iv);
+
+                       aead_request_set_assoc(req, asg, aead_tv[i].alen);
+
+                       ret = enc ?
+                               crypto_aead_encrypt(req) :
+                               crypto_aead_decrypt(req);
+
+                       switch (ret) {
+                       case 0:
+                               break;
+                       case -EINPROGRESS:
+                       case -EBUSY:
+                               ret = wait_for_completion_interruptible(
+                                       &result.completion);
+                               if (!ret && !(ret = result.err)) {
+                                       INIT_COMPLETION(result.completion);
+                                       break;
+                               }
+                               /* fall through */
+                       default:
+                               printk(KERN_INFO "%s () failed err=%d\n",
+                                      e, -ret);
+                               goto out;
+                       }
+
+                       q = kmap(sg_page(&sg[0])) + sg[0].offset;
+                       hexdump(q, aead_tv[i].rlen);
+
+                       printk(KERN_INFO "enc/dec: %s\n",
+                              memcmp(q, aead_tv[i].result,
+                                     aead_tv[i].rlen) ? "fail" : "pass");
+               }
+       }
+
+       printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
+       memset(xbuf, 0, XBUFSIZE);
+       memset(axbuf, 0, XBUFSIZE);
+
+       for (i = 0, j = 0; i < tcount; i++) {
+               if (aead_tv[i].np) {
+                       printk(KERN_INFO "test %u (%d bit key):\n",
+                              ++j, aead_tv[i].klen * 8);
+
+                       crypto_aead_clear_flags(tfm, ~0);
+                       if (aead_tv[i].wk)
+                               crypto_aead_set_flags(
+                                       tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+                       key = aead_tv[i].key;
+
+                       ret = crypto_aead_setkey(tfm, key, aead_tv[i].klen);
+                       if (ret) {
+                               printk(KERN_INFO "setkey() failed flags=%x\n",
+                                      crypto_aead_get_flags(tfm));
+
+                               if (!aead_tv[i].fail)
+                                       goto out;
+                       }
+
+                       sg_init_table(sg, aead_tv[i].np);
+                       for (k = 0, temp = 0; k < aead_tv[i].np; k++) {
+                               memcpy(&xbuf[IDX[k]],
+                                      aead_tv[i].input + temp,
+                                      aead_tv[i].tap[k]);
+                               temp += aead_tv[i].tap[k];
+                               sg_set_buf(&sg[k], &xbuf[IDX[k]],
+                                          aead_tv[i].tap[k]);
+                       }
+
+                       authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen);
+                       ret = crypto_aead_setauthsize(tfm, authsize);
+                       if (ret) {
+                               printk(KERN_INFO
+                                      "failed to set authsize = %u\n",
+                                      authsize);
+                               goto out;
+                       }
+
+                       if (enc)
+                               sg[k - 1].length += authsize;
+
+                       sg_init_table(asg, aead_tv[i].anp);
+                       for (k = 0, temp = 0; k < aead_tv[i].anp; k++) {
+                               memcpy(&axbuf[IDX[k]],
+                                      aead_tv[i].assoc + temp,
+                                      aead_tv[i].atap[k]);
+                               temp += aead_tv[i].atap[k];
+                               sg_set_buf(&asg[k], &axbuf[IDX[k]],
+                                          aead_tv[i].atap[k]);
+                       }
+
+                       aead_request_set_crypt(req, sg, sg,
+                                              aead_tv[i].ilen,
+                                              aead_tv[i].iv);
+
+                       aead_request_set_assoc(req, asg, aead_tv[i].alen);
+
+                       ret = enc ?
+                               crypto_aead_encrypt(req) :
+                               crypto_aead_decrypt(req);
+
+                       switch (ret) {
+                       case 0:
+                               break;
+                       case -EINPROGRESS:
+                       case -EBUSY:
+                               ret = wait_for_completion_interruptible(
+                                       &result.completion);
+                               if (!ret && !(ret = result.err)) {
+                                       INIT_COMPLETION(result.completion);
+                                       break;
+                               }
+                               /* fall through */
+                       default:
+                               printk(KERN_INFO "%s () failed err=%d\n",
+                                      e, -ret);
+                               goto out;
+                       }
+
+                       for (k = 0, temp = 0; k < aead_tv[i].np; k++) {
+                               printk(KERN_INFO "page %u\n", k);
+                               q = kmap(sg_page(&sg[k])) + sg[k].offset;
+                               hexdump(q, aead_tv[i].tap[k]);
+                               printk(KERN_INFO "%s\n",
+                                      memcmp(q, aead_tv[i].result + temp,
+                                             aead_tv[i].tap[k] -
+                                             (k < aead_tv[i].np - 1 || enc ?
+                                              0 : authsize)) ?
+                                      "fail" : "pass");
+
+                               temp += aead_tv[i].tap[k];
+                       }
+               }
+       }
+
+out:
+       crypto_free_aead(tfm);
+       aead_request_free(req);
+}
+
 static void test_cipher(char *algo, int enc,
                        struct cipher_testvec *template, unsigned int tcount)
 {
@@ -237,15 +474,11 @@ static void test_cipher(char *algo, int enc,
        printk("\ntesting %s %s\n", algo, e);
 
        tsize = sizeof (struct cipher_testvec);
-       tsize *= tcount;
-
        if (tsize > TVMEMSIZE) {
                printk("template (%u) too big for tvmem (%u)\n", tsize,
                       TVMEMSIZE);
                return;
        }
-
-       memcpy(tvmem, template, tsize);
        cipher_tv = (void *)tvmem;
 
        init_completion(&result.completion);
@@ -269,33 +502,34 @@ static void test_cipher(char *algo, int enc,
 
        j = 0;
        for (i = 0; i < tcount; i++) {
-               if (!(cipher_tv[i].np)) {
+               memcpy(cipher_tv, &template[i], tsize);
+               if (!(cipher_tv->np)) {
                        j++;
                        printk("test %u (%d bit key):\n",
-                       j, cipher_tv[i].klen * 8);
+                       j, cipher_tv->klen * 8);
 
                        crypto_ablkcipher_clear_flags(tfm, ~0);
-                       if (cipher_tv[i].wk)
+                       if (cipher_tv->wk)
                                crypto_ablkcipher_set_flags(
                                        tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-                       key = cipher_tv[i].key;
+                       key = cipher_tv->key;
 
                        ret = crypto_ablkcipher_setkey(tfm, key,
-                                                      cipher_tv[i].klen);
+                                                      cipher_tv->klen);
                        if (ret) {
                                printk("setkey() failed flags=%x\n",
                                       crypto_ablkcipher_get_flags(tfm));
 
-                               if (!cipher_tv[i].fail)
+                               if (!cipher_tv->fail)
                                        goto out;
                        }
 
-                       sg_init_one(&sg[0], cipher_tv[i].input,
-                                   cipher_tv[i].ilen);
+                       sg_init_one(&sg[0], cipher_tv->input,
+                                   cipher_tv->ilen);
 
                        ablkcipher_request_set_crypt(req, sg, sg,
-                                                    cipher_tv[i].ilen,
-                                                    cipher_tv[i].iv);
+                                                    cipher_tv->ilen,
+                                                    cipher_tv->iv);
 
                        ret = enc ?
                                crypto_ablkcipher_encrypt(req) :
@@ -319,11 +553,11 @@ static void test_cipher(char *algo, int enc,
                        }
 
                        q = kmap(sg_page(&sg[0])) + sg[0].offset;
-                       hexdump(q, cipher_tv[i].rlen);
+                       hexdump(q, cipher_tv->rlen);
 
                        printk("%s\n",
-                              memcmp(q, cipher_tv[i].result,
-                                     cipher_tv[i].rlen) ? "fail" : "pass");
+                              memcmp(q, cipher_tv->result,
+                                     cipher_tv->rlen) ? "fail" : "pass");
                }
        }
 
@@ -332,41 +566,42 @@ static void test_cipher(char *algo, int enc,
 
        j = 0;
        for (i = 0; i < tcount; i++) {
-               if (cipher_tv[i].np) {
+               memcpy(cipher_tv, &template[i], tsize);
+               if (cipher_tv->np) {
                        j++;
                        printk("test %u (%d bit key):\n",
-                       j, cipher_tv[i].klen * 8);
+                       j, cipher_tv->klen * 8);
 
                        crypto_ablkcipher_clear_flags(tfm, ~0);
-                       if (cipher_tv[i].wk)
+                       if (cipher_tv->wk)
                                crypto_ablkcipher_set_flags(
                                        tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-                       key = cipher_tv[i].key;
+                       key = cipher_tv->key;
 
                        ret = crypto_ablkcipher_setkey(tfm, key,
-                                                      cipher_tv[i].klen);
+                                                      cipher_tv->klen);
                        if (ret) {
                                printk("setkey() failed flags=%x\n",
                                       crypto_ablkcipher_get_flags(tfm));
 
-                               if (!cipher_tv[i].fail)
+                               if (!cipher_tv->fail)
                                        goto out;
                        }
 
                        temp = 0;
-                       sg_init_table(sg, cipher_tv[i].np);
-                       for (k = 0; k < cipher_tv[i].np; k++) {
+                       sg_init_table(sg, cipher_tv->np);
+                       for (k = 0; k < cipher_tv->np; k++) {
                                memcpy(&xbuf[IDX[k]],
-                                      cipher_tv[i].input + temp,
-                                      cipher_tv[i].tap[k]);
-                               temp += cipher_tv[i].tap[k];
+                                      cipher_tv->input + temp,
+                                      cipher_tv->tap[k]);
+                               temp += cipher_tv->tap[k];
                                sg_set_buf(&sg[k], &xbuf[IDX[k]],
-                                          cipher_tv[i].tap[k]);
+                                          cipher_tv->tap[k]);
                        }
 
                        ablkcipher_request_set_crypt(req, sg, sg,
-                                                    cipher_tv[i].ilen,
-                                                    cipher_tv[i].iv);
+                                                    cipher_tv->ilen,
+                                                    cipher_tv->iv);
 
                        ret = enc ?
                                crypto_ablkcipher_encrypt(req) :
@@ -390,15 +625,15 @@ static void test_cipher(char *algo, int enc,
                        }
 
                        temp = 0;
-                       for (k = 0; k < cipher_tv[i].np; k++) {
+                       for (k = 0; k < cipher_tv->np; k++) {
                                printk("page %u\n", k);
                                q = kmap(sg_page(&sg[k])) + sg[k].offset;
-                               hexdump(q, cipher_tv[i].tap[k]);
+                               hexdump(q, cipher_tv->tap[k]);
                                printk("%s\n",
-                                       memcmp(q, cipher_tv[i].result + temp,
-                                               cipher_tv[i].tap[k]) ? "fail" :
+                                       memcmp(q, cipher_tv->result + temp,
+                                               cipher_tv->tap[k]) ? "fail" :
                                        "pass");
-                               temp += cipher_tv[i].tap[k];
+                               temp += cipher_tv->tap[k];
                        }
                }
        }
@@ -800,7 +1035,8 @@ out:
        crypto_free_hash(tfm);
 }
 
-static void test_deflate(void)
+static void test_comp(char *algo, struct comp_testvec *ctemplate,
+                      struct comp_testvec *dtemplate, int ctcount, int dtcount)
 {
        unsigned int i;
        char result[COMP_BUF_SIZE];
@@ -808,25 +1044,26 @@ static void test_deflate(void)
        struct comp_testvec *tv;
        unsigned int tsize;
 
-       printk("\ntesting deflate compression\n");
+       printk("\ntesting %s compression\n", algo);
 
-       tsize = sizeof (deflate_comp_tv_template);
+       tsize = sizeof(struct comp_testvec);
+       tsize *= ctcount;
        if (tsize > TVMEMSIZE) {
                printk("template (%u) too big for tvmem (%u)\n", tsize,
                       TVMEMSIZE);
                return;
        }
 
-       memcpy(tvmem, deflate_comp_tv_template, tsize);
+       memcpy(tvmem, ctemplate, tsize);
        tv = (void *)tvmem;
 
-       tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC);
+       tfm = crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(tfm)) {
-               printk("failed to load transform for deflate\n");
+               printk("failed to load transform for %s\n", algo);
                return;
        }
 
-       for (i = 0; i < DEFLATE_COMP_TEST_VECTORS; i++) {
+       for (i = 0; i < ctcount; i++) {
                int ilen, ret, dlen = COMP_BUF_SIZE;
 
                printk("test %u:\n", i + 1);
@@ -845,19 +1082,20 @@ static void test_deflate(void)
                       ilen, dlen);
        }
 
-       printk("\ntesting deflate decompression\n");
+       printk("\ntesting %s decompression\n", algo);
 
-       tsize = sizeof (deflate_decomp_tv_template);
+       tsize = sizeof(struct comp_testvec);
+       tsize *= dtcount;
        if (tsize > TVMEMSIZE) {
                printk("template (%u) too big for tvmem (%u)\n", tsize,
                       TVMEMSIZE);
                goto out;
        }
 
-       memcpy(tvmem, deflate_decomp_tv_template, tsize);
+       memcpy(tvmem, dtemplate, tsize);
        tv = (void *)tvmem;
 
-       for (i = 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) {
+       for (i = 0; i < dtcount; i++) {
                int ilen, ret, dlen = COMP_BUF_SIZE;
 
                printk("test %u:\n", i + 1);
@@ -918,6 +1156,8 @@ static void do_test(void)
 
                test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
 
+               test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
+
                test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS);
 
                //BLOWFISH
@@ -969,6 +1209,18 @@ static void do_test(void)
                            AES_XTS_ENC_TEST_VECTORS);
                test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
                            AES_XTS_DEC_TEST_VECTORS);
+               test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template,
+                           AES_CTR_ENC_TEST_VECTORS);
+               test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template,
+                           AES_CTR_DEC_TEST_VECTORS);
+               test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template,
+                         AES_GCM_ENC_TEST_VECTORS);
+               test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template,
+                         AES_GCM_DEC_TEST_VECTORS);
+               test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template,
+                         AES_CCM_ENC_TEST_VECTORS);
+               test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template,
+                         AES_CCM_DEC_TEST_VECTORS);
 
                //CAST5
                test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
@@ -1057,12 +1309,18 @@ static void do_test(void)
                test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
                test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
                test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
-               test_deflate();
+               test_comp("deflate", deflate_comp_tv_template,
+                         deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS,
+                         DEFLATE_DECOMP_TEST_VECTORS);
+               test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template,
+                         LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS);
                test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
                test_hash("hmac(md5)", hmac_md5_tv_template,
                          HMAC_MD5_TEST_VECTORS);
                test_hash("hmac(sha1)", hmac_sha1_tv_template,
                          HMAC_SHA1_TEST_VECTORS);
+               test_hash("hmac(sha224)", hmac_sha224_tv_template,
+                         HMAC_SHA224_TEST_VECTORS);
                test_hash("hmac(sha256)", hmac_sha256_tv_template,
                          HMAC_SHA256_TEST_VECTORS);
                test_hash("hmac(sha384)", hmac_sha384_tv_template,
@@ -1156,6 +1414,10 @@ static void do_test(void)
                            AES_XTS_ENC_TEST_VECTORS);
                test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
                            AES_XTS_DEC_TEST_VECTORS);
+               test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template,
+                           AES_CTR_ENC_TEST_VECTORS);
+               test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template,
+                           AES_CTR_DEC_TEST_VECTORS);
                break;
 
        case 11:
@@ -1167,7 +1429,9 @@ static void do_test(void)
                break;
 
        case 13:
-               test_deflate();
+               test_comp("deflate", deflate_comp_tv_template,
+                         deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS,
+                         DEFLATE_DECOMP_TEST_VECTORS);
                break;
 
        case 14:
@@ -1291,6 +1555,34 @@ static void do_test(void)
                            camellia_cbc_dec_tv_template,
                            CAMELLIA_CBC_DEC_TEST_VECTORS);
                break;
+       case 33:
+               test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
+               break;
+
+       case 34:
+               test_cipher("salsa20", ENCRYPT,
+                           salsa20_stream_enc_tv_template,
+                           SALSA20_STREAM_ENC_TEST_VECTORS);
+               break;
+
+       case 35:
+               test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template,
+                         AES_GCM_ENC_TEST_VECTORS);
+               test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template,
+                         AES_GCM_DEC_TEST_VECTORS);
+               break;
+
+       case 36:
+               test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template,
+                         LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS);
+               break;
+
+       case 37:
+               test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template,
+                         AES_CCM_ENC_TEST_VECTORS);
+               test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template,
+                         AES_CCM_DEC_TEST_VECTORS);
+               break;
 
        case 100:
                test_hash("hmac(md5)", hmac_md5_tv_template,
@@ -1317,6 +1609,15 @@ static void do_test(void)
                          HMAC_SHA512_TEST_VECTORS);
                break;
 
+       case 105:
+               test_hash("hmac(sha224)", hmac_sha224_tv_template,
+                         HMAC_SHA224_TEST_VECTORS);
+               break;
+
+       case 106:
+               test_hash("xcbc(aes)", aes_xcbc128_tv_template,
+                         XCBC_AES_TEST_VECTORS);
+               break;
 
        case 200:
                test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
@@ -1400,6 +1701,11 @@ static void do_test(void)
                                camellia_speed_template);
                break;
 
+       case 206:
+               test_cipher_speed("salsa20", ENCRYPT, sec, NULL, 0,
+                                 salsa20_speed_template);
+               break;
+
        case 300:
                /* fall through */
 
@@ -1451,6 +1757,10 @@ static void do_test(void)
                test_hash_speed("tgr192", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
 
+       case 313:
+               test_hash_speed("sha224", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+
        case 399:
                break;
 
@@ -1467,20 +1777,21 @@ static void do_test(void)
 
 static int __init init(void)
 {
+       int err = -ENOMEM;
+
        tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL);
        if (tvmem == NULL)
-               return -ENOMEM;
+               return err;
 
        xbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
-       if (xbuf == NULL) {
-               kfree(tvmem);
-               return -ENOMEM;
-       }
+       if (xbuf == NULL)
+               goto err_free_tv;
 
-       do_test();
+       axbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
+       if (axbuf == NULL)
+               goto err_free_xbuf;
 
-       kfree(xbuf);
-       kfree(tvmem);
+       do_test();
 
        /* We intentionaly return -EAGAIN to prevent keeping
         * the module. It does all its work from init()
@@ -1488,7 +1799,15 @@ static int __init init(void)
         * => we don't need it in the memory, do we?
         *                                        -- mludvig
         */
-       return -EAGAIN;
+       err = -EAGAIN;
+
+       kfree(axbuf);
+ err_free_xbuf:
+       kfree(xbuf);
+ err_free_tv:
+       kfree(tvmem);
+
+       return err;
 }
 
 /*
index ec861388d9a0ac7a42e1bdd142a8aaeecc8fe61e..f785e5618e11f18d8dad897b484fa41c25b4bffe 100644 (file)
@@ -6,12 +6,15 @@
  *
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
+ * Copyright (c) 2007 Nokia Siemens Networks
  *
  * 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.
  *
+ * 2007-11-13 Added GCM tests
+ * 2007-11-13 Added AEAD support
  * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
  * 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net>
  * 2003-09-14 Changes by Kartikey Mahendra Bhatt
@@ -38,16 +41,34 @@ struct hash_testvec {
 };
 
 struct cipher_testvec {
+       char key[MAX_KEYLEN] __attribute__ ((__aligned__(4)));
+       char iv[MAX_IVLEN];
+       char input[4100];
+       char result[4100];
+       unsigned char tap[MAX_TAP];
+       int np;
+       unsigned char fail;
+       unsigned char wk; /* weak key flag */
+       unsigned char klen;
+       unsigned short ilen;
+       unsigned short rlen;
+};
+
+struct aead_testvec {
        char key[MAX_KEYLEN] __attribute__ ((__aligned__(4)));
        char iv[MAX_IVLEN];
        char input[512];
+       char assoc[512];
        char result[512];
        unsigned char tap[MAX_TAP];
+       unsigned char atap[MAX_TAP];
        int np;
+       int anp;
        unsigned char fail;
        unsigned char wk; /* weak key flag */
        unsigned char klen;
        unsigned short ilen;
+       unsigned short alen;
        unsigned short rlen;
 };
 
@@ -173,6 +194,33 @@ static struct hash_testvec sha1_tv_template[] = {
        }
 };
 
+
+/*
+ * SHA224 test vectors from from FIPS PUB 180-2
+ */
+#define SHA224_TEST_VECTORS     2
+
+static struct hash_testvec sha224_tv_template[] = {
+       {
+               .plaintext = "abc",
+               .psize  = 3,
+               .digest = { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
+                       0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
+                       0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
+                       0xE3, 0x6C, 0x9D, 0xA7},
+       }, {
+               .plaintext =
+               "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+               .psize  = 56,
+               .digest = { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
+                       0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
+                       0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
+                       0x52, 0x52, 0x25, 0x25 },
+               .np     = 2,
+               .tap    = { 28, 28 }
+       }
+};
+
 /*
  * SHA256 test vectors from from NIST
  */
@@ -817,6 +865,121 @@ static struct hash_testvec hmac_sha1_tv_template[] = {
        },
 };
 
+
+/*
+ * SHA224 HMAC test vectors from RFC4231
+ */
+#define HMAC_SHA224_TEST_VECTORS    4
+
+static struct hash_testvec hmac_sha224_tv_template[] = {
+       {
+               .key    = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                       0x0b, 0x0b, 0x0b, 0x0b },
+               .ksize  = 20,
+               /*  ("Hi There") */
+               .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 },
+               .psize  = 8,
+               .digest = { 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19,
+                       0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, 0xf3, 0x3f,
+                       0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f,
+                       0x53, 0x68, 0x4b, 0x22},
+       }, {
+               .key    = { 0x4a, 0x65, 0x66, 0x65 }, /* ("Jefe") */
+               .ksize  = 4,
+               /* ("what do ya want for nothing?") */
+               .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+                       0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20,
+                       0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+                       0x69, 0x6e, 0x67, 0x3f },
+               .psize  = 28,
+               .digest = { 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf,
+                       0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e, 0x6d, 0x0f,
+                       0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00,
+                       0x8f, 0xd0, 0x5e, 0x44 },
+               .np = 4,
+               .tap    = { 7, 7, 7, 7 }
+       }, {
+               .key    = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa },
+               .ksize  = 131,
+               /* ("Test Using Larger Than Block-Size Key - Hash Key First") */
+               .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+                       0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65,
+                       0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+                       0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a,
+                       0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+                       0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
+                       0x20, 0x46, 0x69, 0x72, 0x73, 0x74 },
+               .psize  = 54,
+               .digest = { 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad,
+                       0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d, 0xbc, 0xe2,
+                       0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27,
+                       0x3f, 0xa6, 0x87, 0x0e },
+       }, {
+               .key    = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                       0xaa, 0xaa, 0xaa },
+               .ksize  = 131,
+               /* ("This is a test using a larger than block-size key and a")
+               (" larger than block-size data. The key needs to be")
+                       (" hashed before being used by the HMAC algorithm.") */
+               .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+                       0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75,
+                       0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+                       0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68,
+                       0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+                       0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65,
+                       0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
+                       0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74,
+                       0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+                       0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64,
+                       0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
+                       0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65,
+                       0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
+                       0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20,
+                       0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+                       0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65,
+                       0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+                       0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c,
+                       0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e },
+               .psize  = 152,
+               .digest = { 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02,
+                       0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3, 0x9d, 0xbd,
+                       0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9,
+                       0xf6, 0xf5, 0x65, 0xd1 },
+       },
+};
+
 /*
  * HMAC-SHA256 test vectors from
  * draft-ietf-ipsec-ciph-sha-256-01.txt
@@ -2140,12 +2303,18 @@ static struct cipher_testvec cast6_dec_tv_template[] = {
  */
 #define AES_ENC_TEST_VECTORS 3
 #define AES_DEC_TEST_VECTORS 3
-#define AES_CBC_ENC_TEST_VECTORS 2
-#define AES_CBC_DEC_TEST_VECTORS 2
+#define AES_CBC_ENC_TEST_VECTORS 4
+#define AES_CBC_DEC_TEST_VECTORS 4
 #define AES_LRW_ENC_TEST_VECTORS 8
 #define AES_LRW_DEC_TEST_VECTORS 8
 #define AES_XTS_ENC_TEST_VECTORS 4
 #define AES_XTS_DEC_TEST_VECTORS 4
+#define AES_CTR_ENC_TEST_VECTORS 7
+#define AES_CTR_DEC_TEST_VECTORS 6
+#define AES_GCM_ENC_TEST_VECTORS 9
+#define AES_GCM_DEC_TEST_VECTORS 8
+#define AES_CCM_ENC_TEST_VECTORS 7
+#define AES_CCM_DEC_TEST_VECTORS 7
 
 static struct cipher_testvec aes_enc_tv_template[] = {
        { /* From FIPS-197 */
@@ -2249,6 +2418,57 @@ static struct cipher_testvec aes_cbc_enc_tv_template[] = {
                            0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
                            0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
                .rlen   = 32,
+       }, { /* From NIST SP800-38A */
+               .key    = { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+                           0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+                           0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b },
+               .klen   = 24,
+               .iv     = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+               .input  = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                           0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                           0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                           0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                           0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                           0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                           0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                           0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+               .ilen   = 64,
+               .result = { 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d,
+                           0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+                           0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4,
+                           0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+                           0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0,
+                           0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+                           0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81,
+                           0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd },
+               .rlen   = 64,
+       }, {
+               .key    = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+                           0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+                           0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+                           0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 },
+               .klen   = 32,
+               .iv     = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+               .input  = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                           0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                           0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                           0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                           0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                           0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                           0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                           0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+               .ilen   = 64,
+               .result = { 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
+                           0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+                           0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
+                           0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+                           0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
+                           0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+                           0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
+                           0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b },
+               .rlen   = 64,
        },
 };
 
@@ -2280,6 +2500,57 @@ static struct cipher_testvec aes_cbc_dec_tv_template[] = {
                            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
                .rlen   = 32,
+       }, { /* From NIST SP800-38A */
+               .key    = { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+                           0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+                           0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b },
+               .klen   = 24,
+               .iv     = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+               .input  = { 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d,
+                           0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+                           0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4,
+                           0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+                           0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0,
+                           0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+                           0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81,
+                           0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd },
+               .ilen   = 64,
+               .result = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                           0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                           0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                           0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                           0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                           0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                           0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                           0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+               .rlen   = 64,
+       }, {
+               .key    = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+                           0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+                           0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+                           0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 },
+               .klen   = 32,
+               .iv     = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+               .input  = { 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
+                           0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+                           0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
+                           0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+                           0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
+                           0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+                           0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
+                           0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b },
+               .ilen   = 64,
+               .result = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                           0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                           0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                           0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                           0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                           0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                           0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                           0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+               .rlen   = 64,
        },
 };
 
@@ -3180,6 +3451,1843 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = {
        }
 };
 
+
+static struct cipher_testvec aes_ctr_enc_tv_template[] = {
+       { /* From RFC 3686 */
+               .key    = { 0xae, 0x68, 0x52, 0xf8, 0x12, 0x10, 0x67, 0xcc,
+                           0x4b, 0xf7, 0xa5, 0x76, 0x55, 0x77, 0xf3, 0x9e,
+                           0x00, 0x00, 0x00, 0x30 },
+               .klen   = 20,
+               .iv     = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+               .input  = { "Single block msg" },
+               .ilen   = 16,
+               .result = { 0xe4, 0x09, 0x5d, 0x4f, 0xb7, 0xa7, 0xb3, 0x79,
+                           0x2d, 0x61, 0x75, 0xa3, 0x26, 0x13, 0x11, 0xb8 },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x7e, 0x24, 0x06, 0x78, 0x17, 0xfa, 0xe0, 0xd7,
+                           0x43, 0xd6, 0xce, 0x1f, 0x32, 0x53, 0x91, 0x63,
+                           0x00, 0x6c, 0xb6, 0xdb },
+               .klen   = 20,
+               .iv     = { 0xc0, 0x54, 0x3b, 0x59, 0xda, 0x48, 0xd9, 0x0b },
+               .input  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+               .ilen   = 32,
+               .result = { 0x51, 0x04, 0xa1, 0x06, 0x16, 0x8a, 0x72, 0xd9,
+                           0x79, 0x0d, 0x41, 0xee, 0x8e, 0xda, 0xd3, 0x88,
+                           0xeb, 0x2e, 0x1e, 0xfc, 0x46, 0xda, 0x57, 0xc8,
+                           0xfc, 0xe6, 0x30, 0xdf, 0x91, 0x41, 0xbe, 0x28 },
+               .rlen   = 32,
+       }, {
+               .key    = { 0x16, 0xaf, 0x5b, 0x14, 0x5f, 0xc9, 0xf5, 0x79,
+                           0xc1, 0x75, 0xf9, 0x3e, 0x3b, 0xfb, 0x0e, 0xed,
+                           0x86, 0x3d, 0x06, 0xcc, 0xfd, 0xb7, 0x85, 0x15,
+                           0x00, 0x00, 0x00, 0x48 },
+               .klen   = 28,
+               .iv     = { 0x36, 0x73, 0x3c, 0x14, 0x7d, 0x6d, 0x93, 0xcb },
+               .input  = { "Single block msg" },
+               .ilen   = 16,
+               .result = { 0x4b, 0x55, 0x38, 0x4f, 0xe2, 0x59, 0xc9, 0xc8,
+                           0x4e, 0x79, 0x35, 0xa0, 0x03, 0xcb, 0xe9, 0x28 },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x7c, 0x5c, 0xb2, 0x40, 0x1b, 0x3d, 0xc3, 0x3c,
+                           0x19, 0xe7, 0x34, 0x08, 0x19, 0xe0, 0xf6, 0x9c,
+                           0x67, 0x8c, 0x3d, 0xb8, 0xe6, 0xf6, 0xa9, 0x1a,
+                           0x00, 0x96, 0xb0, 0x3b },
+               .klen   = 28,
+               .iv     = { 0x02, 0x0c, 0x6e, 0xad, 0xc2, 0xcb, 0x50, 0x0d },
+               .input  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+               .ilen   = 32,
+               .result = { 0x45, 0x32, 0x43, 0xfc, 0x60, 0x9b, 0x23, 0x32,
+                           0x7e, 0xdf, 0xaa, 0xfa, 0x71, 0x31, 0xcd, 0x9f,
+                           0x84, 0x90, 0x70, 0x1c, 0x5a, 0xd4, 0xa7, 0x9c,
+                           0xfc, 0x1f, 0xe0, 0xff, 0x42, 0xf4, 0xfb, 0x00 },
+               .rlen   = 32,
+       }, {
+               .key    = { 0x77, 0x6b, 0xef, 0xf2, 0x85, 0x1d, 0xb0, 0x6f,
+                           0x4c, 0x8a, 0x05, 0x42, 0xc8, 0x69, 0x6f, 0x6c,
+                           0x6a, 0x81, 0xaf, 0x1e, 0xec, 0x96, 0xb4, 0xd3,
+                           0x7f, 0xc1, 0xd6, 0x89, 0xe6, 0xc1, 0xc1, 0x04,
+                           0x00, 0x00, 0x00, 0x60 },
+               .klen   = 36,
+               .iv     = { 0xdb, 0x56, 0x72, 0xc9, 0x7a, 0xa8, 0xf0, 0xb2 },
+               .input  = { "Single block msg" },
+               .ilen   = 16,
+               .result = { 0x14, 0x5a, 0xd0, 0x1d, 0xbf, 0x82, 0x4e, 0xc7,
+                           0x56, 0x08, 0x63, 0xdc, 0x71, 0xe3, 0xe0, 0xc0 },
+               .rlen   = 16,
+       }, {
+               .key    = { 0xf6, 0xd6, 0x6d, 0x6b, 0xd5, 0x2d, 0x59, 0xbb,
+                           0x07, 0x96, 0x36, 0x58, 0x79, 0xef, 0xf8, 0x86,
+                           0xc6, 0x6d, 0xd5, 0x1a, 0x5b, 0x6a, 0x99, 0x74,
+                           0x4b, 0x50, 0x59, 0x0c, 0x87, 0xa2, 0x38, 0x84,
+                           0x00, 0xfa, 0xac, 0x24 },
+               .klen   = 36,
+               .iv     = { 0xc1, 0x58, 0x5e, 0xf1, 0x5a, 0x43, 0xd8, 0x75 },
+               .input  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+               .ilen   = 32,
+               .result = { 0xf0, 0x5e, 0x23, 0x1b, 0x38, 0x94, 0x61, 0x2c,
+                           0x49, 0xee, 0x00, 0x0b, 0x80, 0x4e, 0xb2, 0xa9,
+                           0xb8, 0x30, 0x6b, 0x50, 0x8f, 0x83, 0x9d, 0x6a,
+                           0x55, 0x30, 0x83, 0x1d, 0x93, 0x44, 0xaf, 0x1c },
+               .rlen   = 32,
+       }, {
+       // generated using Crypto++
+               .key = {
+                       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                       0x00, 0x00, 0x00, 0x00,
+               },
+               .klen = 32 + 4,
+               .iv = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+               .input = {
+                       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+                       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+                       0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+                       0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+                       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+                       0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+                       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+                       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+                       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+                       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+                       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+                       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+                       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+                       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+                       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+                       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+                       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+                       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+                       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+                       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+                       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+                       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+                       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+                       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+                       0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
+                       0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d,
+                       0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45,
+                       0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d,
+                       0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75,
+                       0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d,
+                       0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5,
+                       0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
+                       0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5,
+                       0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed,
+                       0xf0, 0xf3, 0xf6, 0xf9, 0xfc, 0xff, 0x02, 0x05,
+                       0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1d,
+                       0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x35,
+                       0x38, 0x3b, 0x3e, 0x41, 0x44, 0x47, 0x4a, 0x4d,
+                       0x50, 0x53, 0x56, 0x59, 0x5c, 0x5f, 0x62, 0x65,
+                       0x68, 0x6b, 0x6e, 0x71, 0x74, 0x77, 0x7a, 0x7d,
+                       0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95,
+                       0x98, 0x9b, 0x9e, 0xa1, 0xa4, 0xa7, 0xaa, 0xad,
+                       0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc2, 0xc5,
+                       0xc8, 0xcb, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd,
+                       0xe0, 0xe3, 0xe6, 0xe9, 0xec, 0xef, 0xf2, 0xf5,
+                       0xf8, 0xfb, 0xfe, 0x01, 0x04, 0x07, 0x0a, 0x0d,
+                       0x10, 0x13, 0x16, 0x19, 0x1c, 0x1f, 0x22, 0x25,
+                       0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3d,
+                       0x40, 0x43, 0x46, 0x49, 0x4c, 0x4f, 0x52, 0x55,
+                       0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d,
+                       0x70, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85,
+                       0x88, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9d,
+                       0xa0, 0xa3, 0xa6, 0xa9, 0xac, 0xaf, 0xb2, 0xb5,
+                       0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
+                       0xd0, 0xd3, 0xd6, 0xd9, 0xdc, 0xdf, 0xe2, 0xe5,
+                       0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7, 0xfa, 0xfd,
+                       0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, 0x23,
+                       0x28, 0x2d, 0x32, 0x37, 0x3c, 0x41, 0x46, 0x4b,
+                       0x50, 0x55, 0x5a, 0x5f, 0x64, 0x69, 0x6e, 0x73,
+                       0x78, 0x7d, 0x82, 0x87, 0x8c, 0x91, 0x96, 0x9b,
+                       0xa0, 0xa5, 0xaa, 0xaf, 0xb4, 0xb9, 0xbe, 0xc3,
+                       0xc8, 0xcd, 0xd2, 0xd7, 0xdc, 0xe1, 0xe6, 0xeb,
+                       0xf0, 0xf5, 0xfa, 0xff, 0x04, 0x09, 0x0e, 0x13,
+                       0x18, 0x1d, 0x22, 0x27, 0x2c, 0x31, 0x36, 0x3b,
+                       0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59, 0x5e, 0x63,
+                       0x68, 0x6d, 0x72, 0x77, 0x7c, 0x81, 0x86, 0x8b,
+                       0x90, 0x95, 0x9a, 0x9f, 0xa4, 0xa9, 0xae, 0xb3,
+                       0xb8, 0xbd, 0xc2, 0xc7, 0xcc, 0xd1, 0xd6, 0xdb,
+                       0xe0, 0xe5, 0xea, 0xef, 0xf4, 0xf9, 0xfe, 0x03,
+                       0x08, 0x0d, 0x12, 0x17, 0x1c, 0x21, 0x26, 0x2b,
+                       0x30, 0x35, 0x3a, 0x3f, 0x44, 0x49, 0x4e, 0x53,
+                       0x58, 0x5d, 0x62, 0x67, 0x6c, 0x71, 0x76, 0x7b,
+                       0x80, 0x85, 0x8a, 0x8f, 0x94, 0x99, 0x9e, 0xa3,
+                       0xa8, 0xad, 0xb2, 0xb7, 0xbc, 0xc1, 0xc6, 0xcb,
+                       0xd0, 0xd5, 0xda, 0xdf, 0xe4, 0xe9, 0xee, 0xf3,
+                       0xf8, 0xfd, 0x02, 0x07, 0x0c, 0x11, 0x16, 0x1b,
+                       0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3e, 0x43,
+                       0x48, 0x4d, 0x52, 0x57, 0x5c, 0x61, 0x66, 0x6b,
+                       0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93,
+                       0x98, 0x9d, 0xa2, 0xa7, 0xac, 0xb1, 0xb6, 0xbb,
+                       0xc0, 0xc5, 0xca, 0xcf, 0xd4, 0xd9, 0xde, 0xe3,
+                       0xe8, 0xed, 0xf2, 0xf7, 0xfc, 0x01, 0x06, 0x0b,
+                       0x10, 0x15, 0x1a, 0x1f, 0x24, 0x29, 0x2e, 0x33,
+                       0x38, 0x3d, 0x42, 0x47, 0x4c, 0x51, 0x56, 0x5b,
+                       0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7e, 0x83,
+                       0x88, 0x8d, 0x92, 0x97, 0x9c, 0xa1, 0xa6, 0xab,
+                       0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xce, 0xd3,
+                       0xd8, 0xdd, 0xe2, 0xe7, 0xec, 0xf1, 0xf6, 0xfb,
+                       0x00, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31,
+                       0x38, 0x3f, 0x46, 0x4d, 0x54, 0x5b, 0x62, 0x69,
+                       0x70, 0x77, 0x7e, 0x85, 0x8c, 0x93, 0x9a, 0xa1,
+                       0xa8, 0xaf, 0xb6, 0xbd, 0xc4, 0xcb, 0xd2, 0xd9,
+                       0xe0, 0xe7, 0xee, 0xf5, 0xfc, 0x03, 0x0a, 0x11,
+                       0x18, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x42, 0x49,
+                       0x50, 0x57, 0x5e, 0x65, 0x6c, 0x73, 0x7a, 0x81,
+                       0x88, 0x8f, 0x96, 0x9d, 0xa4, 0xab, 0xb2, 0xb9,
+                       0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1,
+                       0xf8, 0xff, 0x06, 0x0d, 0x14, 0x1b, 0x22, 0x29,
+                       0x30, 0x37, 0x3e, 0x45, 0x4c, 0x53, 0x5a, 0x61,
+                       0x68, 0x6f, 0x76, 0x7d, 0x84, 0x8b, 0x92, 0x99,
+                       0xa0, 0xa7, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd1,
+                       0xd8, 0xdf, 0xe6, 0xed, 0xf4, 0xfb, 0x02, 0x09,
+                       0x10, 0x17, 0x1e, 0x25, 0x2c, 0x33, 0x3a, 0x41,
+                       0x48, 0x4f, 0x56, 0x5d, 0x64, 0x6b, 0x72, 0x79,
+                       0x80, 0x87, 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1,
+                       0xb8, 0xbf, 0xc6, 0xcd, 0xd4, 0xdb, 0xe2, 0xe9,
+                       0xf0, 0xf7, 0xfe, 0x05, 0x0c, 0x13, 0x1a, 0x21,
+                       0x28, 0x2f, 0x36, 0x3d, 0x44, 0x4b, 0x52, 0x59,
+                       0x60, 0x67, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x91,
+                       0x98, 0x9f, 0xa6, 0xad, 0xb4, 0xbb, 0xc2, 0xc9,
+                       0xd0, 0xd7, 0xde, 0xe5, 0xec, 0xf3, 0xfa, 0x01,
+                       0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2b, 0x32, 0x39,
+                       0x40, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71,
+                       0x78, 0x7f, 0x86, 0x8d, 0x94, 0x9b, 0xa2, 0xa9,
+                       0xb0, 0xb7, 0xbe, 0xc5, 0xcc, 0xd3, 0xda, 0xe1,
+                       0xe8, 0xef, 0xf6, 0xfd, 0x04, 0x0b, 0x12, 0x19,
+                       0x20, 0x27, 0x2e, 0x35, 0x3c, 0x43, 0x4a, 0x51,
+                       0x58, 0x5f, 0x66, 0x6d, 0x74, 0x7b, 0x82, 0x89,
+                       0x90, 0x97, 0x9e, 0xa5, 0xac, 0xb3, 0xba, 0xc1,
+                       0xc8, 0xcf, 0xd6, 0xdd, 0xe4, 0xeb, 0xf2, 0xf9,
+                       0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+                       0x48, 0x51, 0x5a, 0x63, 0x6c, 0x75, 0x7e, 0x87,
+                       0x90, 0x99, 0xa2, 0xab, 0xb4, 0xbd, 0xc6, 0xcf,
+                       0xd8, 0xe1, 0xea, 0xf3, 0xfc, 0x05, 0x0e, 0x17,
+                       0x20, 0x29, 0x32, 0x3b, 0x44, 0x4d, 0x56, 0x5f,
+                       0x68, 0x71, 0x7a, 0x83, 0x8c, 0x95, 0x9e, 0xa7,
+                       0xb0, 0xb9, 0xc2, 0xcb, 0xd4, 0xdd, 0xe6, 0xef,
+                       0xf8, 0x01, 0x0a, 0x13, 0x1c, 0x25, 0x2e, 0x37,
+                       0x40, 0x49, 0x52, 0x5b, 0x64, 0x6d, 0x76, 0x7f,
+                       0x88, 0x91, 0x9a, 0xa3, 0xac, 0xb5, 0xbe, 0xc7,
+                       0xd0, 0xd9, 0xe2, 0xeb, 0xf4, 0xfd, 0x06, 0x0f,
+                       0x18, 0x21, 0x2a, 0x33, 0x3c, 0x45, 0x4e, 0x57,
+                       0x60, 0x69, 0x72, 0x7b, 0x84, 0x8d, 0x96, 0x9f,
+                       0xa8, 0xb1, 0xba, 0xc3, 0xcc, 0xd5, 0xde, 0xe7,
+                       0xf0, 0xf9, 0x02, 0x0b, 0x14, 0x1d, 0x26, 0x2f,
+                       0x38, 0x41, 0x4a, 0x53, 0x5c, 0x65, 0x6e, 0x77,
+                       0x80, 0x89, 0x92, 0x9b, 0xa4, 0xad, 0xb6, 0xbf,
+                       0xc8, 0xd1, 0xda, 0xe3, 0xec, 0xf5, 0xfe, 0x07,
+                       0x10, 0x19, 0x22, 0x2b, 0x34, 0x3d, 0x46, 0x4f,
+                       0x58, 0x61, 0x6a, 0x73, 0x7c, 0x85, 0x8e, 0x97,
+                       0xa0, 0xa9, 0xb2, 0xbb, 0xc4, 0xcd, 0xd6, 0xdf,
+                       0xe8, 0xf1, 0xfa, 0x03, 0x0c, 0x15, 0x1e, 0x27,
+                       0x30, 0x39, 0x42, 0x4b, 0x54, 0x5d, 0x66, 0x6f,
+                       0x78, 0x81, 0x8a, 0x93, 0x9c, 0xa5, 0xae, 0xb7,
+                       0xc0, 0xc9, 0xd2, 0xdb, 0xe4, 0xed, 0xf6, 0xff,
+                       0x08, 0x11, 0x1a, 0x23, 0x2c, 0x35, 0x3e, 0x47,
+                       0x50, 0x59, 0x62, 0x6b, 0x74, 0x7d, 0x86, 0x8f,
+                       0x98, 0xa1, 0xaa, 0xb3, 0xbc, 0xc5, 0xce, 0xd7,
+                       0xe0, 0xe9, 0xf2, 0xfb, 0x04, 0x0d, 0x16, 0x1f,
+                       0x28, 0x31, 0x3a, 0x43, 0x4c, 0x55, 0x5e, 0x67,
+                       0x70, 0x79, 0x82, 0x8b, 0x94, 0x9d, 0xa6, 0xaf,
+                       0xb8, 0xc1, 0xca, 0xd3, 0xdc, 0xe5, 0xee, 0xf7,
+                       0x00, 0x0b, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d,
+                       0x58, 0x63, 0x6e, 0x79, 0x84, 0x8f, 0x9a, 0xa5,
+                       0xb0, 0xbb, 0xc6, 0xd1, 0xdc, 0xe7, 0xf2, 0xfd,
+                       0x08, 0x13, 0x1e, 0x29, 0x34, 0x3f, 0x4a, 0x55,
+                       0x60, 0x6b, 0x76, 0x81, 0x8c, 0x97, 0xa2, 0xad,
+                       0xb8, 0xc3, 0xce, 0xd9, 0xe4, 0xef, 0xfa, 0x05,
+                       0x10, 0x1b, 0x26, 0x31, 0x3c, 0x47, 0x52, 0x5d,
+                       0x68, 0x73, 0x7e, 0x89, 0x94, 0x9f, 0xaa, 0xb5,
+                       0xc0, 0xcb, 0xd6, 0xe1, 0xec, 0xf7, 0x02, 0x0d,
+                       0x18, 0x23, 0x2e, 0x39, 0x44, 0x4f, 0x5a, 0x65,
+                       0x70, 0x7b, 0x86, 0x91, 0x9c, 0xa7, 0xb2, 0xbd,
+                       0xc8, 0xd3, 0xde, 0xe9, 0xf4, 0xff, 0x0a, 0x15,
+                       0x20, 0x2b, 0x36, 0x41, 0x4c, 0x57, 0x62, 0x6d,
+                       0x78, 0x83, 0x8e, 0x99, 0xa4, 0xaf, 0xba, 0xc5,
+                       0xd0, 0xdb, 0xe6, 0xf1, 0xfc, 0x07, 0x12, 0x1d,
+                       0x28, 0x33, 0x3e, 0x49, 0x54, 0x5f, 0x6a, 0x75,
+                       0x80, 0x8b, 0x96, 0xa1, 0xac, 0xb7, 0xc2, 0xcd,
+                       0xd8, 0xe3, 0xee, 0xf9, 0x04, 0x0f, 0x1a, 0x25,
+                       0x30, 0x3b, 0x46, 0x51, 0x5c, 0x67, 0x72, 0x7d,
+                       0x88, 0x93, 0x9e, 0xa9, 0xb4, 0xbf, 0xca, 0xd5,
+                       0xe0, 0xeb, 0xf6, 0x01, 0x0c, 0x17, 0x22, 0x2d,
+                       0x38, 0x43, 0x4e, 0x59, 0x64, 0x6f, 0x7a, 0x85,
+                       0x90, 0x9b, 0xa6, 0xb1, 0xbc, 0xc7, 0xd2, 0xdd,
+                       0xe8, 0xf3, 0xfe, 0x09, 0x14, 0x1f, 0x2a, 0x35,
+                       0x40, 0x4b, 0x56, 0x61, 0x6c, 0x77, 0x82, 0x8d,
+                       0x98, 0xa3, 0xae, 0xb9, 0xc4, 0xcf, 0xda, 0xe5,
+                       0xf0, 0xfb, 0x06, 0x11, 0x1c, 0x27, 0x32, 0x3d,
+                       0x48, 0x53, 0x5e, 0x69, 0x74, 0x7f, 0x8a, 0x95,
+                       0xa0, 0xab, 0xb6, 0xc1, 0xcc, 0xd7, 0xe2, 0xed,
+                       0xf8, 0x03, 0x0e, 0x19, 0x24, 0x2f, 0x3a, 0x45,
+                       0x50, 0x5b, 0x66, 0x71, 0x7c, 0x87, 0x92, 0x9d,
+                       0xa8, 0xb3, 0xbe, 0xc9, 0xd4, 0xdf, 0xea, 0xf5,
+                       0x00, 0x0d, 0x1a, 0x27, 0x34, 0x41, 0x4e, 0x5b,
+                       0x68, 0x75, 0x82, 0x8f, 0x9c, 0xa9, 0xb6, 0xc3,
+                       0xd0, 0xdd, 0xea, 0xf7, 0x04, 0x11, 0x1e, 0x2b,
+                       0x38, 0x45, 0x52, 0x5f, 0x6c, 0x79, 0x86, 0x93,
+                       0xa0, 0xad, 0xba, 0xc7, 0xd4, 0xe1, 0xee, 0xfb,
+                       0x08, 0x15, 0x22, 0x2f, 0x3c, 0x49, 0x56, 0x63,
+                       0x70, 0x7d, 0x8a, 0x97, 0xa4, 0xb1, 0xbe, 0xcb,
+                       0xd8, 0xe5, 0xf2, 0xff, 0x0c, 0x19, 0x26, 0x33,
+                       0x40, 0x4d, 0x5a, 0x67, 0x74, 0x81, 0x8e, 0x9b,
+                       0xa8, 0xb5, 0xc2, 0xcf, 0xdc, 0xe9, 0xf6, 0x03,
+                       0x10, 0x1d, 0x2a, 0x37, 0x44, 0x51, 0x5e, 0x6b,
+                       0x78, 0x85, 0x92, 0x9f, 0xac, 0xb9, 0xc6, 0xd3,
+                       0xe0, 0xed, 0xfa, 0x07, 0x14, 0x21, 0x2e, 0x3b,
+                       0x48, 0x55, 0x62, 0x6f, 0x7c, 0x89, 0x96, 0xa3,
+                       0xb0, 0xbd, 0xca, 0xd7, 0xe4, 0xf1, 0xfe, 0x0b,
+                       0x18, 0x25, 0x32, 0x3f, 0x4c, 0x59, 0x66, 0x73,
+                       0x80, 0x8d, 0x9a, 0xa7, 0xb4, 0xc1, 0xce, 0xdb,
+                       0xe8, 0xf5, 0x02, 0x0f, 0x1c, 0x29, 0x36, 0x43,
+                       0x50, 0x5d, 0x6a, 0x77, 0x84, 0x91, 0x9e, 0xab,
+                       0xb8, 0xc5, 0xd2, 0xdf, 0xec, 0xf9, 0x06, 0x13,
+                       0x20, 0x2d, 0x3a, 0x47, 0x54, 0x61, 0x6e, 0x7b,
+                       0x88, 0x95, 0xa2, 0xaf, 0xbc, 0xc9, 0xd6, 0xe3,
+                       0xf0, 0xfd, 0x0a, 0x17, 0x24, 0x31, 0x3e, 0x4b,
+                       0x58, 0x65, 0x72, 0x7f, 0x8c, 0x99, 0xa6, 0xb3,
+                       0xc0, 0xcd, 0xda, 0xe7, 0xf4, 0x01, 0x0e, 0x1b,
+                       0x28, 0x35, 0x42, 0x4f, 0x5c, 0x69, 0x76, 0x83,
+                       0x90, 0x9d, 0xaa, 0xb7, 0xc4, 0xd1, 0xde, 0xeb,
+                       0xf8, 0x05, 0x12, 0x1f, 0x2c, 0x39, 0x46, 0x53,
+                       0x60, 0x6d, 0x7a, 0x87, 0x94, 0xa1, 0xae, 0xbb,
+                       0xc8, 0xd5, 0xe2, 0xef, 0xfc, 0x09, 0x16, 0x23,
+                       0x30, 0x3d, 0x4a, 0x57, 0x64, 0x71, 0x7e, 0x8b,
+                       0x98, 0xa5, 0xb2, 0xbf, 0xcc, 0xd9, 0xe6, 0xf3,
+                       0x00, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69,
+                       0x78, 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1,
+                       0xf0, 0xff, 0x0e, 0x1d, 0x2c, 0x3b, 0x4a, 0x59,
+                       0x68, 0x77, 0x86, 0x95, 0xa4, 0xb3, 0xc2, 0xd1,
+                       0xe0, 0xef, 0xfe, 0x0d, 0x1c, 0x2b, 0x3a, 0x49,
+                       0x58, 0x67, 0x76, 0x85, 0x94, 0xa3, 0xb2, 0xc1,
+                       0xd0, 0xdf, 0xee, 0xfd, 0x0c, 0x1b, 0x2a, 0x39,
+                       0x48, 0x57, 0x66, 0x75, 0x84, 0x93, 0xa2, 0xb1,
+                       0xc0, 0xcf, 0xde, 0xed, 0xfc, 0x0b, 0x1a, 0x29,
+                       0x38, 0x47, 0x56, 0x65, 0x74, 0x83, 0x92, 0xa1,
+                       0xb0, 0xbf, 0xce, 0xdd, 0xec, 0xfb, 0x0a, 0x19,
+                       0x28, 0x37, 0x46, 0x55, 0x64, 0x73, 0x82, 0x91,
+                       0xa0, 0xaf, 0xbe, 0xcd, 0xdc, 0xeb, 0xfa, 0x09,
+                       0x18, 0x27, 0x36, 0x45, 0x54, 0x63, 0x72, 0x81,
+                       0x90, 0x9f, 0xae, 0xbd, 0xcc, 0xdb, 0xea, 0xf9,
+                       0x08, 0x17, 0x26, 0x35, 0x44, 0x53, 0x62, 0x71,
+                       0x80, 0x8f, 0x9e, 0xad, 0xbc, 0xcb, 0xda, 0xe9,
+                       0xf8, 0x07, 0x16, 0x25, 0x34, 0x43, 0x52, 0x61,
+                       0x70, 0x7f, 0x8e, 0x9d, 0xac, 0xbb, 0xca, 0xd9,
+                       0xe8, 0xf7, 0x06, 0x15, 0x24, 0x33, 0x42, 0x51,
+                       0x60, 0x6f, 0x7e, 0x8d, 0x9c, 0xab, 0xba, 0xc9,
+                       0xd8, 0xe7, 0xf6, 0x05, 0x14, 0x23, 0x32, 0x41,
+                       0x50, 0x5f, 0x6e, 0x7d, 0x8c, 0x9b, 0xaa, 0xb9,
+                       0xc8, 0xd7, 0xe6, 0xf5, 0x04, 0x13, 0x22, 0x31,
+                       0x40, 0x4f, 0x5e, 0x6d, 0x7c, 0x8b, 0x9a, 0xa9,
+                       0xb8, 0xc7, 0xd6, 0xe5, 0xf4, 0x03, 0x12, 0x21,
+                       0x30, 0x3f, 0x4e, 0x5d, 0x6c, 0x7b, 0x8a, 0x99,
+                       0xa8, 0xb7, 0xc6, 0xd5, 0xe4, 0xf3, 0x02, 0x11,
+                       0x20, 0x2f, 0x3e, 0x4d, 0x5c, 0x6b, 0x7a, 0x89,
+                       0x98, 0xa7, 0xb6, 0xc5, 0xd4, 0xe3, 0xf2, 0x01,
+                       0x10, 0x1f, 0x2e, 0x3d, 0x4c, 0x5b, 0x6a, 0x79,
+                       0x88, 0x97, 0xa6, 0xb5, 0xc4, 0xd3, 0xe2, 0xf1,
+                       0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                       0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+                       0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87,
+                       0x98, 0xa9, 0xba, 0xcb, 0xdc, 0xed, 0xfe, 0x0f,
+                       0x20, 0x31, 0x42, 0x53, 0x64, 0x75, 0x86, 0x97,
+                       0xa8, 0xb9, 0xca, 0xdb, 0xec, 0xfd, 0x0e, 0x1f,
+                       0x30, 0x41, 0x52, 0x63, 0x74, 0x85, 0x96, 0xa7,
+                       0xb8, 0xc9, 0xda, 0xeb, 0xfc, 0x0d, 0x1e, 0x2f,
+                       0x40, 0x51, 0x62, 0x73, 0x84, 0x95, 0xa6, 0xb7,
+                       0xc8, 0xd9, 0xea, 0xfb, 0x0c, 0x1d, 0x2e, 0x3f,
+                       0x50, 0x61, 0x72, 0x83, 0x94, 0xa5, 0xb6, 0xc7,
+                       0xd8, 0xe9, 0xfa, 0x0b, 0x1c, 0x2d, 0x3e, 0x4f,
+                       0x60, 0x71, 0x82, 0x93, 0xa4, 0xb5, 0xc6, 0xd7,
+                       0xe8, 0xf9, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f,
+                       0x70, 0x81, 0x92, 0xa3, 0xb4, 0xc5, 0xd6, 0xe7,
+                       0xf8, 0x09, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f,
+                       0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7,
+                       0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f,
+                       0x90, 0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6, 0x07,
+                       0x18, 0x29, 0x3a, 0x4b, 0x5c, 0x6d, 0x7e, 0x8f,
+                       0xa0, 0xb1, 0xc2, 0xd3, 0xe4, 0xf5, 0x06, 0x17,
+                       0x28, 0x39, 0x4a, 0x5b, 0x6c, 0x7d, 0x8e, 0x9f,
+                       0xb0, 0xc1, 0xd2, 0xe3, 0xf4, 0x05, 0x16, 0x27,
+                       0x38, 0x49, 0x5a, 0x6b, 0x7c, 0x8d, 0x9e, 0xaf,
+                       0xc0, 0xd1, 0xe2, 0xf3, 0x04, 0x15, 0x26, 0x37,
+                       0x48, 0x59, 0x6a, 0x7b, 0x8c, 0x9d, 0xae, 0xbf,
+                       0xd0, 0xe1, 0xf2, 0x03, 0x14, 0x25, 0x36, 0x47,
+                       0x58, 0x69, 0x7a, 0x8b, 0x9c, 0xad, 0xbe, 0xcf,
+                       0xe0, 0xf1, 0x02, 0x13, 0x24, 0x35, 0x46, 0x57,
+                       0x68, 0x79, 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf,
+                       0xf0, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
+                       0x78, 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef,
+                       0x00, 0x13, 0x26, 0x39, 0x4c, 0x5f, 0x72, 0x85,
+                       0x98, 0xab, 0xbe, 0xd1, 0xe4, 0xf7, 0x0a, 0x1d,
+                       0x30, 0x43, 0x56, 0x69, 0x7c, 0x8f, 0xa2, 0xb5,
+                       0xc8, 0xdb, 0xee, 0x01, 0x14, 0x27, 0x3a, 0x4d,
+                       0x60, 0x73, 0x86, 0x99, 0xac, 0xbf, 0xd2, 0xe5,
+                       0xf8, 0x0b, 0x1e, 0x31, 0x44, 0x57, 0x6a, 0x7d,
+                       0x90, 0xa3, 0xb6, 0xc9, 0xdc, 0xef, 0x02, 0x15,
+                       0x28, 0x3b, 0x4e, 0x61, 0x74, 0x87, 0x9a, 0xad,
+                       0xc0, 0xd3, 0xe6, 0xf9, 0x0c, 0x1f, 0x32, 0x45,
+                       0x58, 0x6b, 0x7e, 0x91, 0xa4, 0xb7, 0xca, 0xdd,
+                       0xf0, 0x03, 0x16, 0x29, 0x3c, 0x4f, 0x62, 0x75,
+                       0x88, 0x9b, 0xae, 0xc1, 0xd4, 0xe7, 0xfa, 0x0d,
+                       0x20, 0x33, 0x46, 0x59, 0x6c, 0x7f, 0x92, 0xa5,
+                       0xb8, 0xcb, 0xde, 0xf1, 0x04, 0x17, 0x2a, 0x3d,
+                       0x50, 0x63, 0x76, 0x89, 0x9c, 0xaf, 0xc2, 0xd5,
+                       0xe8, 0xfb, 0x0e, 0x21, 0x34, 0x47, 0x5a, 0x6d,
+                       0x80, 0x93, 0xa6, 0xb9, 0xcc, 0xdf, 0xf2, 0x05,
+                       0x18, 0x2b, 0x3e, 0x51, 0x64, 0x77, 0x8a, 0x9d,
+                       0xb0, 0xc3, 0xd6, 0xe9, 0xfc, 0x0f, 0x22, 0x35,
+                       0x48, 0x5b, 0x6e, 0x81, 0x94, 0xa7, 0xba, 0xcd,
+                       0xe0, 0xf3, 0x06, 0x19, 0x2c, 0x3f, 0x52, 0x65,
+                       0x78, 0x8b, 0x9e, 0xb1, 0xc4, 0xd7, 0xea, 0xfd,
+                       0x10, 0x23, 0x36, 0x49, 0x5c, 0x6f, 0x82, 0x95,
+                       0xa8, 0xbb, 0xce, 0xe1, 0xf4, 0x07, 0x1a, 0x2d,
+                       0x40, 0x53, 0x66, 0x79, 0x8c, 0x9f, 0xb2, 0xc5,
+                       0xd8, 0xeb, 0xfe, 0x11, 0x24, 0x37, 0x4a, 0x5d,
+                       0x70, 0x83, 0x96, 0xa9, 0xbc, 0xcf, 0xe2, 0xf5,
+                       0x08, 0x1b, 0x2e, 0x41, 0x54, 0x67, 0x7a, 0x8d,
+                       0xa0, 0xb3, 0xc6, 0xd9, 0xec, 0xff, 0x12, 0x25,
+                       0x38, 0x4b, 0x5e, 0x71, 0x84, 0x97, 0xaa, 0xbd,
+                       0xd0, 0xe3, 0xf6, 0x09, 0x1c, 0x2f, 0x42, 0x55,
+                       0x68, 0x7b, 0x8e, 0xa1, 0xb4, 0xc7, 0xda, 0xed,
+                       0x00, 0x15, 0x2a, 0x3f, 0x54, 0x69, 0x7e, 0x93,
+                       0xa8, 0xbd, 0xd2, 0xe7, 0xfc, 0x11, 0x26, 0x3b,
+                       0x50, 0x65, 0x7a, 0x8f, 0xa4, 0xb9, 0xce, 0xe3,
+                       0xf8, 0x0d, 0x22, 0x37, 0x4c, 0x61, 0x76, 0x8b,
+                       0xa0, 0xb5, 0xca, 0xdf, 0xf4, 0x09, 0x1e, 0x33,
+                       0x48, 0x5d, 0x72, 0x87, 0x9c, 0xb1, 0xc6, 0xdb,
+                       0xf0, 0x05, 0x1a, 0x2f, 0x44, 0x59, 0x6e, 0x83,
+                       0x98, 0xad, 0xc2, 0xd7, 0xec, 0x01, 0x16, 0x2b,
+                       0x40, 0x55, 0x6a, 0x7f, 0x94, 0xa9, 0xbe, 0xd3,
+                       0xe8, 0xfd, 0x12, 0x27, 0x3c, 0x51, 0x66, 0x7b,
+                       0x90, 0xa5, 0xba, 0xcf, 0xe4, 0xf9, 0x0e, 0x23,
+                       0x38, 0x4d, 0x62, 0x77, 0x8c, 0xa1, 0xb6, 0xcb,
+                       0xe0, 0xf5, 0x0a, 0x1f, 0x34, 0x49, 0x5e, 0x73,
+                       0x88, 0x9d, 0xb2, 0xc7, 0xdc, 0xf1, 0x06, 0x1b,
+                       0x30, 0x45, 0x5a, 0x6f, 0x84, 0x99, 0xae, 0xc3,
+                       0xd8, 0xed, 0x02, 0x17, 0x2c, 0x41, 0x56, 0x6b,
+                       0x80, 0x95, 0xaa, 0xbf, 0xd4, 0xe9, 0xfe, 0x13,
+                       0x28, 0x3d, 0x52, 0x67, 0x7c, 0x91, 0xa6, 0xbb,
+                       0xd0, 0xe5, 0xfa, 0x0f, 0x24, 0x39, 0x4e, 0x63,
+                       0x78, 0x8d, 0xa2, 0xb7, 0xcc, 0xe1, 0xf6, 0x0b,
+                       0x20, 0x35, 0x4a, 0x5f, 0x74, 0x89, 0x9e, 0xb3,
+                       0xc8, 0xdd, 0xf2, 0x07, 0x1c, 0x31, 0x46, 0x5b,
+                       0x70, 0x85, 0x9a, 0xaf, 0xc4, 0xd9, 0xee, 0x03,
+                       0x18, 0x2d, 0x42, 0x57, 0x6c, 0x81, 0x96, 0xab,
+                       0xc0, 0xd5, 0xea, 0xff, 0x14, 0x29, 0x3e, 0x53,
+                       0x68, 0x7d, 0x92, 0xa7, 0xbc, 0xd1, 0xe6, 0xfb,
+                       0x10, 0x25, 0x3a, 0x4f, 0x64, 0x79, 0x8e, 0xa3,
+                       0xb8, 0xcd, 0xe2, 0xf7, 0x0c, 0x21, 0x36, 0x4b,
+                       0x60, 0x75, 0x8a, 0x9f, 0xb4, 0xc9, 0xde, 0xf3,
+                       0x08, 0x1d, 0x32, 0x47, 0x5c, 0x71, 0x86, 0x9b,
+                       0xb0, 0xc5, 0xda, 0xef, 0x04, 0x19, 0x2e, 0x43,
+                       0x58, 0x6d, 0x82, 0x97, 0xac, 0xc1, 0xd6, 0xeb,
+                       0x00, 0x17, 0x2e, 0x45, 0x5c, 0x73, 0x8a, 0xa1,
+                       0xb8, 0xcf, 0xe6, 0xfd, 0x14, 0x2b, 0x42, 0x59,
+                       0x70, 0x87, 0x9e, 0xb5, 0xcc, 0xe3, 0xfa, 0x11,
+                       0x28, 0x3f, 0x56, 0x6d, 0x84, 0x9b, 0xb2, 0xc9,
+                       0xe0, 0xf7, 0x0e, 0x25, 0x3c, 0x53, 0x6a, 0x81,
+                       0x98, 0xaf, 0xc6, 0xdd, 0xf4, 0x0b, 0x22, 0x39,
+                       0x50, 0x67, 0x7e, 0x95, 0xac, 0xc3, 0xda, 0xf1,
+                       0x08, 0x1f, 0x36, 0x4d, 0x64, 0x7b, 0x92, 0xa9,
+                       0xc0, 0xd7, 0xee, 0x05, 0x1c, 0x33, 0x4a, 0x61,
+                       0x78, 0x8f, 0xa6, 0xbd, 0xd4, 0xeb, 0x02, 0x19,
+                       0x30, 0x47, 0x5e, 0x75, 0x8c, 0xa3, 0xba, 0xd1,
+                       0xe8, 0xff, 0x16, 0x2d, 0x44, 0x5b, 0x72, 0x89,
+                       0xa0, 0xb7, 0xce, 0xe5, 0xfc, 0x13, 0x2a, 0x41,
+                       0x58, 0x6f, 0x86, 0x9d, 0xb4, 0xcb, 0xe2, 0xf9,
+                       0x10, 0x27, 0x3e, 0x55, 0x6c, 0x83, 0x9a, 0xb1,
+                       0xc8, 0xdf, 0xf6, 0x0d, 0x24, 0x3b, 0x52, 0x69,
+                       0x80, 0x97, 0xae, 0xc5, 0xdc, 0xf3, 0x0a, 0x21,
+                       0x38, 0x4f, 0x66, 0x7d, 0x94, 0xab, 0xc2, 0xd9,
+                       0xf0, 0x07, 0x1e, 0x35, 0x4c, 0x63, 0x7a, 0x91,
+                       0xa8, 0xbf, 0xd6, 0xed, 0x04, 0x1b, 0x32, 0x49,
+                       0x60, 0x77, 0x8e, 0xa5, 0xbc, 0xd3, 0xea, 0x01,
+                       0x18, 0x2f, 0x46, 0x5d, 0x74, 0x8b, 0xa2, 0xb9,
+                       0xd0, 0xe7, 0xfe, 0x15, 0x2c, 0x43, 0x5a, 0x71,
+                       0x88, 0x9f, 0xb6, 0xcd, 0xe4, 0xfb, 0x12, 0x29,
+                       0x40, 0x57, 0x6e, 0x85, 0x9c, 0xb3, 0xca, 0xe1,
+                       0xf8, 0x0f, 0x26, 0x3d, 0x54, 0x6b, 0x82, 0x99,
+                       0xb0, 0xc7, 0xde, 0xf5, 0x0c, 0x23, 0x3a, 0x51,
+                       0x68, 0x7f, 0x96, 0xad, 0xc4, 0xdb, 0xf2, 0x09,
+                       0x20, 0x37, 0x4e, 0x65, 0x7c, 0x93, 0xaa, 0xc1,
+                       0xd8, 0xef, 0x06, 0x1d, 0x34, 0x4b, 0x62, 0x79,
+                       0x90, 0xa7, 0xbe, 0xd5, 0xec, 0x03, 0x1a, 0x31,
+                       0x48, 0x5f, 0x76, 0x8d, 0xa4, 0xbb, 0xd2, 0xe9,
+                       0x00, 0x19, 0x32, 0x4b, 0x64, 0x7d, 0x96, 0xaf,
+                       0xc8, 0xe1, 0xfa, 0x13, 0x2c, 0x45, 0x5e, 0x77,
+                       0x90, 0xa9, 0xc2, 0xdb, 0xf4, 0x0d, 0x26, 0x3f,
+                       0x58, 0x71, 0x8a, 0xa3, 0xbc, 0xd5, 0xee, 0x07,
+                       0x20, 0x39, 0x52, 0x6b, 0x84, 0x9d, 0xb6, 0xcf,
+                       0xe8, 0x01, 0x1a, 0x33, 0x4c, 0x65, 0x7e, 0x97,
+                       0xb0, 0xc9, 0xe2, 0xfb, 0x14, 0x2d, 0x46, 0x5f,
+                       0x78, 0x91, 0xaa, 0xc3, 0xdc, 0xf5, 0x0e, 0x27,
+                       0x40, 0x59, 0x72, 0x8b, 0xa4, 0xbd, 0xd6, 0xef,
+                       0x08, 0x21, 0x3a, 0x53, 0x6c, 0x85, 0x9e, 0xb7,
+                       0xd0, 0xe9, 0x02, 0x1b, 0x34, 0x4d, 0x66, 0x7f,
+                       0x98, 0xb1, 0xca, 0xe3, 0xfc, 0x15, 0x2e, 0x47,
+                       0x60, 0x79, 0x92, 0xab, 0xc4, 0xdd, 0xf6, 0x0f,
+                       0x28, 0x41, 0x5a, 0x73, 0x8c, 0xa5, 0xbe, 0xd7,
+                       0xf0, 0x09, 0x22, 0x3b, 0x54, 0x6d, 0x86, 0x9f,
+                       0xb8, 0xd1, 0xea, 0x03, 0x1c, 0x35, 0x4e, 0x67,
+                       0x80, 0x99, 0xb2, 0xcb, 0xe4, 0xfd, 0x16, 0x2f,
+                       0x48, 0x61, 0x7a, 0x93, 0xac, 0xc5, 0xde, 0xf7,
+                       0x10, 0x29, 0x42, 0x5b, 0x74, 0x8d, 0xa6, 0xbf,
+                       0xd8, 0xf1, 0x0a, 0x23, 0x3c, 0x55, 0x6e, 0x87,
+                       0xa0, 0xb9, 0xd2, 0xeb, 0x04, 0x1d, 0x36, 0x4f,
+                       0x68, 0x81, 0x9a, 0xb3, 0xcc, 0xe5, 0xfe, 0x17,
+                       0x30, 0x49, 0x62, 0x7b, 0x94, 0xad, 0xc6, 0xdf,
+                       0xf8, 0x11, 0x2a, 0x43, 0x5c, 0x75, 0x8e, 0xa7,
+                       0xc0, 0xd9, 0xf2, 0x0b, 0x24, 0x3d, 0x56, 0x6f,
+                       0x88, 0xa1, 0xba, 0xd3, 0xec, 0x05, 0x1e, 0x37,
+                       0x50, 0x69, 0x82, 0x9b, 0xb4, 0xcd, 0xe6, 0xff,
+                       0x18, 0x31, 0x4a, 0x63, 0x7c, 0x95, 0xae, 0xc7,
+                       0xe0, 0xf9, 0x12, 0x2b, 0x44, 0x5d, 0x76, 0x8f,
+                       0xa8, 0xc1, 0xda, 0xf3, 0x0c, 0x25, 0x3e, 0x57,
+                       0x70, 0x89, 0xa2, 0xbb, 0xd4, 0xed, 0x06, 0x1f,
+                       0x38, 0x51, 0x6a, 0x83, 0x9c, 0xb5, 0xce, 0xe7,
+                       0x00, 0x1b, 0x36, 0x51, 0x6c, 0x87, 0xa2, 0xbd,
+                       0xd8, 0xf3, 0x0e, 0x29, 0x44, 0x5f, 0x7a, 0x95,
+                       0xb0, 0xcb, 0xe6, 0x01, 0x1c, 0x37, 0x52, 0x6d,
+                       0x88, 0xa3, 0xbe, 0xd9, 0xf4, 0x0f, 0x2a, 0x45,
+                       0x60, 0x7b, 0x96, 0xb1, 0xcc, 0xe7, 0x02, 0x1d,
+                       0x38, 0x53, 0x6e, 0x89, 0xa4, 0xbf, 0xda, 0xf5,
+                       0x10, 0x2b, 0x46, 0x61, 0x7c, 0x97, 0xb2, 0xcd,
+                       0xe8, 0x03, 0x1e, 0x39, 0x54, 0x6f, 0x8a, 0xa5,
+                       0xc0, 0xdb, 0xf6, 0x11, 0x2c, 0x47, 0x62, 0x7d,
+                       0x98, 0xb3, 0xce, 0xe9, 0x04, 0x1f, 0x3a, 0x55,
+                       0x70, 0x8b, 0xa6, 0xc1, 0xdc, 0xf7, 0x12, 0x2d,
+                       0x48, 0x63, 0x7e, 0x99, 0xb4, 0xcf, 0xea, 0x05,
+                       0x20, 0x3b, 0x56, 0x71, 0x8c, 0xa7, 0xc2, 0xdd,
+                       0xf8, 0x13, 0x2e, 0x49, 0x64, 0x7f, 0x9a, 0xb5,
+                       0xd0, 0xeb, 0x06, 0x21, 0x3c, 0x57, 0x72, 0x8d,
+                       0xa8, 0xc3, 0xde, 0xf9, 0x14, 0x2f, 0x4a, 0x65,
+                       0x80, 0x9b, 0xb6, 0xd1, 0xec, 0x07, 0x22, 0x3d,
+                       0x58, 0x73, 0x8e, 0xa9, 0xc4, 0xdf, 0xfa, 0x15,
+                       0x30, 0x4b, 0x66, 0x81, 0x9c, 0xb7, 0xd2, 0xed,
+                       0x08, 0x23, 0x3e, 0x59, 0x74, 0x8f, 0xaa, 0xc5,
+                       0xe0, 0xfb, 0x16, 0x31, 0x4c, 0x67, 0x82, 0x9d,
+                       0xb8, 0xd3, 0xee, 0x09, 0x24, 0x3f, 0x5a, 0x75,
+                       0x90, 0xab, 0xc6, 0xe1, 0xfc, 0x17, 0x32, 0x4d,
+                       0x68, 0x83, 0x9e, 0xb9, 0xd4, 0xef, 0x0a, 0x25,
+                       0x40, 0x5b, 0x76, 0x91, 0xac, 0xc7, 0xe2, 0xfd,
+                       0x18, 0x33, 0x4e, 0x69, 0x84, 0x9f, 0xba, 0xd5,
+                       0xf0, 0x0b, 0x26, 0x41, 0x5c, 0x77, 0x92, 0xad,
+                       0xc8, 0xe3, 0xfe, 0x19, 0x34, 0x4f, 0x6a, 0x85,
+                       0xa0, 0xbb, 0xd6, 0xf1, 0x0c, 0x27, 0x42, 0x5d,
+                       0x78, 0x93, 0xae, 0xc9, 0xe4, 0xff, 0x1a, 0x35,
+                       0x50, 0x6b, 0x86, 0xa1, 0xbc, 0xd7, 0xf2, 0x0d,
+                       0x28, 0x43, 0x5e, 0x79, 0x94, 0xaf, 0xca, 0xe5,
+                       0x00, 0x1d, 0x3a, 0x57, 0x74, 0x91, 0xae, 0xcb,
+                       0xe8, 0x05, 0x22, 0x3f, 0x5c, 0x79, 0x96, 0xb3,
+                       0xd0, 0xed, 0x0a, 0x27, 0x44, 0x61, 0x7e, 0x9b,
+                       0xb8, 0xd5, 0xf2, 0x0f, 0x2c, 0x49, 0x66, 0x83,
+                       0xa0, 0xbd, 0xda, 0xf7, 0x14, 0x31, 0x4e, 0x6b,
+                       0x88, 0xa5, 0xc2, 0xdf, 0xfc, 0x19, 0x36, 0x53,
+                       0x70, 0x8d, 0xaa, 0xc7, 0xe4, 0x01, 0x1e, 0x3b,
+                       0x58, 0x75, 0x92, 0xaf, 0xcc, 0xe9, 0x06, 0x23,
+                       0x40, 0x5d, 0x7a, 0x97, 0xb4, 0xd1, 0xee, 0x0b,
+                       0x28, 0x45, 0x62, 0x7f, 0x9c, 0xb9, 0xd6, 0xf3,
+                       0x10, 0x2d, 0x4a, 0x67, 0x84, 0xa1, 0xbe, 0xdb,
+                       0xf8, 0x15, 0x32, 0x4f, 0x6c, 0x89, 0xa6, 0xc3,
+                       0xe0, 0xfd, 0x1a, 0x37, 0x54, 0x71, 0x8e, 0xab,
+                       0xc8, 0xe5, 0x02, 0x1f, 0x3c, 0x59, 0x76, 0x93,
+                       0xb0, 0xcd, 0xea, 0x07, 0x24, 0x41, 0x5e, 0x7b,
+                       0x98, 0xb5, 0xd2, 0xef, 0x0c, 0x29, 0x46, 0x63,
+                       0x80, 0x9d, 0xba, 0xd7, 0xf4, 0x11, 0x2e, 0x4b,
+                       0x68, 0x85, 0xa2, 0xbf, 0xdc, 0xf9, 0x16, 0x33,
+                       0x50, 0x6d, 0x8a, 0xa7, 0xc4, 0xe1, 0xfe, 0x1b,
+                       0x38, 0x55, 0x72, 0x8f, 0xac, 0xc9, 0xe6, 0x03,
+                       0x20, 0x3d, 0x5a, 0x77, 0x94, 0xb1, 0xce, 0xeb,
+                       0x08, 0x25, 0x42, 0x5f, 0x7c, 0x99, 0xb6, 0xd3,
+                       0xf0, 0x0d, 0x2a, 0x47, 0x64, 0x81, 0x9e, 0xbb,
+                       0xd8, 0xf5, 0x12, 0x2f, 0x4c, 0x69, 0x86, 0xa3,
+                       0xc0, 0xdd, 0xfa, 0x17, 0x34, 0x51, 0x6e, 0x8b,
+                       0xa8, 0xc5, 0xe2, 0xff, 0x1c, 0x39, 0x56, 0x73,
+                       0x90, 0xad, 0xca, 0xe7, 0x04, 0x21, 0x3e, 0x5b,
+                       0x78, 0x95, 0xb2, 0xcf, 0xec, 0x09, 0x26, 0x43,
+                       0x60, 0x7d, 0x9a, 0xb7, 0xd4, 0xf1, 0x0e, 0x2b,
+                       0x48, 0x65, 0x82, 0x9f, 0xbc, 0xd9, 0xf6, 0x13,
+                       0x30, 0x4d, 0x6a, 0x87, 0xa4, 0xc1, 0xde, 0xfb,
+                       0x18, 0x35, 0x52, 0x6f, 0x8c, 0xa9, 0xc6, 0xe3,
+                       0x00, 0x1f, 0x3e, 0x5d, 0x7c, 0x9b, 0xba, 0xd9,
+                       0xf8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xb2, 0xd1,
+                       0xf0, 0x0f, 0x2e, 0x4d, 0x6c, 0x8b, 0xaa, 0xc9,
+                       0xe8, 0x07, 0x26, 0x45, 0x64, 0x83, 0xa2, 0xc1,
+                       0xe0, 0xff, 0x1e, 0x3d, 0x5c, 0x7b, 0x9a, 0xb9,
+                       0xd8, 0xf7, 0x16, 0x35, 0x54, 0x73, 0x92, 0xb1,
+                       0xd0, 0xef, 0x0e, 0x2d, 0x4c, 0x6b, 0x8a, 0xa9,
+                       0xc8, 0xe7, 0x06, 0x25, 0x44, 0x63, 0x82, 0xa1,
+                       0xc0, 0xdf, 0xfe, 0x1d, 0x3c, 0x5b, 0x7a, 0x99,
+                       0xb8, 0xd7, 0xf6, 0x15, 0x34, 0x53, 0x72, 0x91,
+                       0xb0, 0xcf, 0xee, 0x0d, 0x2c, 0x4b, 0x6a, 0x89,
+                       0xa8, 0xc7, 0xe6, 0x05, 0x24, 0x43, 0x62, 0x81,
+                       0xa0, 0xbf, 0xde, 0xfd, 0x1c, 0x3b, 0x5a, 0x79,
+                       0x98, 0xb7, 0xd6, 0xf5, 0x14, 0x33, 0x52, 0x71,
+                       0x90, 0xaf, 0xce, 0xed, 0x0c, 0x2b, 0x4a, 0x69,
+                       0x88, 0xa7, 0xc6, 0xe5, 0x04, 0x23, 0x42, 0x61,
+                       0x80, 0x9f, 0xbe, 0xdd, 0xfc, 0x1b, 0x3a, 0x59,
+                       0x78, 0x97, 0xb6, 0xd5, 0xf4, 0x13, 0x32, 0x51,
+                       0x70, 0x8f, 0xae, 0xcd, 0xec, 0x0b, 0x2a, 0x49,
+                       0x68, 0x87, 0xa6, 0xc5, 0xe4, 0x03, 0x22, 0x41,
+                       0x60, 0x7f, 0x9e, 0xbd, 0xdc, 0xfb, 0x1a, 0x39,
+                       0x58, 0x77, 0x96, 0xb5, 0xd4, 0xf3, 0x12, 0x31,
+                       0x50, 0x6f, 0x8e, 0xad, 0xcc, 0xeb, 0x0a, 0x29,
+                       0x48, 0x67, 0x86, 0xa5, 0xc4, 0xe3, 0x02, 0x21,
+                       0x40, 0x5f, 0x7e, 0x9d, 0xbc, 0xdb, 0xfa, 0x19,
+                       0x38, 0x57, 0x76, 0x95, 0xb4, 0xd3, 0xf2, 0x11,
+                       0x30, 0x4f, 0x6e, 0x8d, 0xac, 0xcb, 0xea, 0x09,
+                       0x28, 0x47, 0x66, 0x85, 0xa4, 0xc3, 0xe2, 0x01,
+                       0x20, 0x3f, 0x5e, 0x7d, 0x9c, 0xbb, 0xda, 0xf9,
+                       0x18, 0x37, 0x56, 0x75, 0x94, 0xb3, 0xd2, 0xf1,
+                       0x10, 0x2f, 0x4e, 0x6d, 0x8c, 0xab, 0xca, 0xe9,
+                       0x08, 0x27, 0x46, 0x65, 0x84, 0xa3, 0xc2, 0xe1,
+                       0x00, 0x21, 0x42, 0x63,
+               },
+               .ilen = 4100,
+               .result = {
+                       0xf0, 0x5c, 0x74, 0xad, 0x4e, 0xbc, 0x99, 0xe2,
+                       0xae, 0xff, 0x91, 0x3a, 0x44, 0xcf, 0x38, 0x32,
+                       0x1e, 0xad, 0xa7, 0xcd, 0xa1, 0x39, 0x95, 0xaa,
+                       0x10, 0xb1, 0xb3, 0x2e, 0x04, 0x31, 0x8f, 0x86,
+                       0xf2, 0x62, 0x74, 0x70, 0x0c, 0xa4, 0x46, 0x08,
+                       0xa8, 0xb7, 0x99, 0xa8, 0xe9, 0xd2, 0x73, 0x79,
+                       0x7e, 0x6e, 0xd4, 0x8f, 0x1e, 0xc7, 0x8e, 0x31,
+                       0x0b, 0xfa, 0x4b, 0xce, 0xfd, 0xf3, 0x57, 0x71,
+                       0xe9, 0x46, 0x03, 0xa5, 0x3d, 0x34, 0x00, 0xe2,
+                       0x18, 0xff, 0x75, 0x6d, 0x06, 0x2d, 0x00, 0xab,
+                       0xb9, 0x3e, 0x6c, 0x59, 0xc5, 0x84, 0x06, 0xb5,
+                       0x8b, 0xd0, 0x89, 0x9c, 0x4a, 0x79, 0x16, 0xc6,
+                       0x3d, 0x74, 0x54, 0xfa, 0x44, 0xcd, 0x23, 0x26,
+                       0x5c, 0xcf, 0x7e, 0x28, 0x92, 0x32, 0xbf, 0xdf,
+                       0xa7, 0x20, 0x3c, 0x74, 0x58, 0x2a, 0x9a, 0xde,
+                       0x61, 0x00, 0x1c, 0x4f, 0xff, 0x59, 0xc4, 0x22,
+                       0xac, 0x3c, 0xd0, 0xe8, 0x6c, 0xf9, 0x97, 0x1b,
+                       0x58, 0x9b, 0xad, 0x71, 0xe8, 0xa9, 0xb5, 0x0d,
+                       0xee, 0x2f, 0x04, 0x1f, 0x7f, 0xbc, 0x99, 0xee,
+                       0x84, 0xff, 0x42, 0x60, 0xdc, 0x3a, 0x18, 0xa5,
+                       0x81, 0xf9, 0xef, 0xdc, 0x7a, 0x0f, 0x65, 0x41,
+                       0x2f, 0xa3, 0xd3, 0xf9, 0xc2, 0xcb, 0xc0, 0x4d,
+                       0x8f, 0xd3, 0x76, 0x96, 0xad, 0x49, 0x6d, 0x38,
+                       0x3d, 0x39, 0x0b, 0x6c, 0x80, 0xb7, 0x54, 0x69,
+                       0xf0, 0x2c, 0x90, 0x02, 0x29, 0x0d, 0x1c, 0x12,
+                       0xad, 0x55, 0xc3, 0x8b, 0x68, 0xd9, 0xcc, 0xb3,
+                       0xb2, 0x64, 0x33, 0x90, 0x5e, 0xca, 0x4b, 0xe2,
+                       0xfb, 0x75, 0xdc, 0x63, 0xf7, 0x9f, 0x82, 0x74,
+                       0xf0, 0xc9, 0xaa, 0x7f, 0xe9, 0x2a, 0x9b, 0x33,
+                       0xbc, 0x88, 0x00, 0x7f, 0xca, 0xb2, 0x1f, 0x14,
+                       0xdb, 0xc5, 0x8e, 0x7b, 0x11, 0x3c, 0x3e, 0x08,
+                       0xf3, 0x83, 0xe8, 0xe0, 0x94, 0x86, 0x2e, 0x92,
+                       0x78, 0x6b, 0x01, 0xc9, 0xc7, 0x83, 0xba, 0x21,
+                       0x6a, 0x25, 0x15, 0x33, 0x4e, 0x45, 0x08, 0xec,
+                       0x35, 0xdb, 0xe0, 0x6e, 0x31, 0x51, 0x79, 0xa9,
+                       0x42, 0x44, 0x65, 0xc1, 0xa0, 0xf1, 0xf9, 0x2a,
+                       0x70, 0xd5, 0xb6, 0xc6, 0xc1, 0x8c, 0x39, 0xfc,
+                       0x25, 0xa6, 0x55, 0xd9, 0xdd, 0x2d, 0x4c, 0xec,
+                       0x49, 0xc6, 0xeb, 0x0e, 0xa8, 0x25, 0x2a, 0x16,
+                       0x1b, 0x66, 0x84, 0xda, 0xe2, 0x92, 0xe5, 0xc0,
+                       0xc8, 0x53, 0x07, 0xaf, 0x80, 0x84, 0xec, 0xfd,
+                       0xcd, 0xd1, 0x6e, 0xcd, 0x6f, 0x6a, 0xf5, 0x36,
+                       0xc5, 0x15, 0xe5, 0x25, 0x7d, 0x77, 0xd1, 0x1a,
+                       0x93, 0x36, 0xa9, 0xcf, 0x7c, 0xa4, 0x54, 0x4a,
+                       0x06, 0x51, 0x48, 0x4e, 0xf6, 0x59, 0x87, 0xd2,
+                       0x04, 0x02, 0xef, 0xd3, 0x44, 0xde, 0x76, 0x31,
+                       0xb3, 0x34, 0x17, 0x1b, 0x9d, 0x66, 0x11, 0x9f,
+                       0x1e, 0xcc, 0x17, 0xe9, 0xc7, 0x3c, 0x1b, 0xe7,
+                       0xcb, 0x50, 0x08, 0xfc, 0xdc, 0x2b, 0x24, 0xdb,
+                       0x65, 0x83, 0xd0, 0x3b, 0xe3, 0x30, 0xea, 0x94,
+                       0x6c, 0xe7, 0xe8, 0x35, 0x32, 0xc7, 0xdb, 0x64,
+                       0xb4, 0x01, 0xab, 0x36, 0x2c, 0x77, 0x13, 0xaf,
+                       0xf8, 0x2b, 0x88, 0x3f, 0x54, 0x39, 0xc4, 0x44,
+                       0xfe, 0xef, 0x6f, 0x68, 0x34, 0xbe, 0x0f, 0x05,
+                       0x16, 0x6d, 0xf6, 0x0a, 0x30, 0xe7, 0xe3, 0xed,
+                       0xc4, 0xde, 0x3c, 0x1b, 0x13, 0xd8, 0xdb, 0xfe,
+                       0x41, 0x62, 0xe5, 0x28, 0xd4, 0x8d, 0xa3, 0xc7,
+                       0x93, 0x97, 0xc6, 0x48, 0x45, 0x1d, 0x9f, 0x83,
+                       0xdf, 0x4b, 0x40, 0x3e, 0x42, 0x25, 0x87, 0x80,
+                       0x4c, 0x7d, 0xa8, 0xd4, 0x98, 0x23, 0x95, 0x75,
+                       0x41, 0x8c, 0xda, 0x41, 0x9b, 0xd4, 0xa7, 0x06,
+                       0xb5, 0xf1, 0x71, 0x09, 0x53, 0xbe, 0xca, 0xbf,
+                       0x32, 0x03, 0xed, 0xf0, 0x50, 0x1c, 0x56, 0x39,
+                       0x5b, 0xa4, 0x75, 0x18, 0xf7, 0x9b, 0x58, 0xef,
+                       0x53, 0xfc, 0x2a, 0x38, 0x23, 0x15, 0x75, 0xcd,
+                       0x45, 0xe5, 0x5a, 0x82, 0x55, 0xba, 0x21, 0xfa,
+                       0xd4, 0xbd, 0xc6, 0x94, 0x7c, 0xc5, 0x80, 0x12,
+                       0xf7, 0x4b, 0x32, 0xc4, 0x9a, 0x82, 0xd8, 0x28,
+                       0x8f, 0xd9, 0xc2, 0x0f, 0x60, 0x03, 0xbe, 0x5e,
+                       0x21, 0xd6, 0x5f, 0x58, 0xbf, 0x5c, 0xb1, 0x32,
+                       0x82, 0x8d, 0xa9, 0xe5, 0xf2, 0x66, 0x1a, 0xc0,
+                       0xa0, 0xbc, 0x58, 0x2f, 0x71, 0xf5, 0x2f, 0xed,
+                       0xd1, 0x26, 0xb9, 0xd8, 0x49, 0x5a, 0x07, 0x19,
+                       0x01, 0x7c, 0x59, 0xb0, 0xf8, 0xa4, 0xb7, 0xd3,
+                       0x7b, 0x1a, 0x8c, 0x38, 0xf4, 0x50, 0xa4, 0x59,
+                       0xb0, 0xcc, 0x41, 0x0b, 0x88, 0x7f, 0xe5, 0x31,
+                       0xb3, 0x42, 0xba, 0xa2, 0x7e, 0xd4, 0x32, 0x71,
+                       0x45, 0x87, 0x48, 0xa9, 0xc2, 0xf2, 0x89, 0xb3,
+                       0xe4, 0xa7, 0x7e, 0x52, 0x15, 0x61, 0xfa, 0xfe,
+                       0xc9, 0xdd, 0x81, 0xeb, 0x13, 0xab, 0xab, 0xc3,
+                       0x98, 0x59, 0xd8, 0x16, 0x3d, 0x14, 0x7a, 0x1c,
+                       0x3c, 0x41, 0x9a, 0x16, 0x16, 0x9b, 0xd2, 0xd2,
+                       0x69, 0x3a, 0x29, 0x23, 0xac, 0x86, 0x32, 0xa5,
+                       0x48, 0x9c, 0x9e, 0xf3, 0x47, 0x77, 0x81, 0x70,
+                       0x24, 0xe8, 0x85, 0xd2, 0xf5, 0xb5, 0xfa, 0xff,
+                       0x59, 0x6a, 0xd3, 0x50, 0x59, 0x43, 0x59, 0xde,
+                       0xd9, 0xf1, 0x55, 0xa5, 0x0c, 0xc3, 0x1a, 0x1a,
+                       0x18, 0x34, 0x0d, 0x1a, 0x63, 0x33, 0xed, 0x10,
+                       0xe0, 0x1d, 0x2a, 0x18, 0xd2, 0xc0, 0x54, 0xa8,
+                       0xca, 0xb5, 0x9a, 0xd3, 0xdd, 0xca, 0x45, 0x84,
+                       0x50, 0xe7, 0x0f, 0xfe, 0xa4, 0x99, 0x5a, 0xbe,
+                       0x43, 0x2d, 0x9a, 0xcb, 0x92, 0x3f, 0x5a, 0x1d,
+                       0x85, 0xd8, 0xc9, 0xdf, 0x68, 0xc9, 0x12, 0x80,
+                       0x56, 0x0c, 0xdc, 0x00, 0xdc, 0x3a, 0x7d, 0x9d,
+                       0xa3, 0xa2, 0xe8, 0x4d, 0xbf, 0xf9, 0x70, 0xa0,
+                       0xa4, 0x13, 0x4f, 0x6b, 0xaf, 0x0a, 0x89, 0x7f,
+                       0xda, 0xf0, 0xbf, 0x9b, 0xc8, 0x1d, 0xe5, 0xf8,
+                       0x2e, 0x8b, 0x07, 0xb5, 0x73, 0x1b, 0xcc, 0xa2,
+                       0xa6, 0xad, 0x30, 0xbc, 0x78, 0x3c, 0x5b, 0x10,
+                       0xfa, 0x5e, 0x62, 0x2d, 0x9e, 0x64, 0xb3, 0x33,
+                       0xce, 0xf9, 0x1f, 0x86, 0xe7, 0x8b, 0xa2, 0xb8,
+                       0xe8, 0x99, 0x57, 0x8c, 0x11, 0xed, 0x66, 0xd9,
+                       0x3c, 0x72, 0xb9, 0xc3, 0xe6, 0x4e, 0x17, 0x3a,
+                       0x6a, 0xcb, 0x42, 0x24, 0x06, 0xed, 0x3e, 0x4e,
+                       0xa3, 0xe8, 0x6a, 0x94, 0xda, 0x0d, 0x4e, 0xd5,
+                       0x14, 0x19, 0xcf, 0xb6, 0x26, 0xd8, 0x2e, 0xcc,
+                       0x64, 0x76, 0x38, 0x49, 0x4d, 0xfe, 0x30, 0x6d,
+                       0xe4, 0xc8, 0x8c, 0x7b, 0xc4, 0xe0, 0x35, 0xba,
+                       0x22, 0x6e, 0x76, 0xe1, 0x1a, 0xf2, 0x53, 0xc3,
+                       0x28, 0xa2, 0x82, 0x1f, 0x61, 0x69, 0xad, 0xc1,
+                       0x7b, 0x28, 0x4b, 0x1e, 0x6c, 0x85, 0x95, 0x9b,
+                       0x51, 0xb5, 0x17, 0x7f, 0x12, 0x69, 0x8c, 0x24,
+                       0xd5, 0xc7, 0x5a, 0x5a, 0x11, 0x54, 0xff, 0x5a,
+                       0xf7, 0x16, 0xc3, 0x91, 0xa6, 0xf0, 0xdc, 0x0a,
+                       0xb6, 0xa7, 0x4a, 0x0d, 0x7a, 0x58, 0xfe, 0xa5,
+                       0xf5, 0xcb, 0x8f, 0x7b, 0x0e, 0xea, 0x57, 0xe7,
+                       0xbd, 0x79, 0xd6, 0x1c, 0x88, 0x23, 0x6c, 0xf2,
+                       0x4d, 0x29, 0x77, 0x53, 0x35, 0x6a, 0x00, 0x8d,
+                       0xcd, 0xa3, 0x58, 0xbe, 0x77, 0x99, 0x18, 0xf8,
+                       0xe6, 0xe1, 0x8f, 0xe9, 0x37, 0x8f, 0xe3, 0xe2,
+                       0x5a, 0x8a, 0x93, 0x25, 0xaf, 0xf3, 0x78, 0x80,
+                       0xbe, 0xa6, 0x1b, 0xc6, 0xac, 0x8b, 0x1c, 0x91,
+                       0x58, 0xe1, 0x9f, 0x89, 0x35, 0x9d, 0x1d, 0x21,
+                       0x29, 0x9f, 0xf4, 0x99, 0x02, 0x27, 0x0f, 0xa8,
+                       0x4f, 0x79, 0x94, 0x2b, 0x33, 0x2c, 0xda, 0xa2,
+                       0x26, 0x39, 0x83, 0x94, 0xef, 0x27, 0xd8, 0x53,
+                       0x8f, 0x66, 0x0d, 0xe4, 0x41, 0x7d, 0x34, 0xcd,
+                       0x43, 0x7c, 0x95, 0x0a, 0x53, 0xef, 0x66, 0xda,
+                       0x7e, 0x9b, 0xf3, 0x93, 0xaf, 0xd0, 0x73, 0x71,
+                       0xba, 0x40, 0x9b, 0x74, 0xf8, 0xd7, 0xd7, 0x41,
+                       0x6d, 0xaf, 0x72, 0x9c, 0x8d, 0x21, 0x87, 0x3c,
+                       0xfd, 0x0a, 0x90, 0xa9, 0x47, 0x96, 0x9e, 0xd3,
+                       0x88, 0xee, 0x73, 0xcf, 0x66, 0x2f, 0x52, 0x56,
+                       0x6d, 0xa9, 0x80, 0x4c, 0xe2, 0x6f, 0x62, 0x88,
+                       0x3f, 0x0e, 0x54, 0x17, 0x48, 0x80, 0x5d, 0xd3,
+                       0xc3, 0xda, 0x25, 0x3d, 0xa1, 0xc8, 0xcb, 0x9f,
+                       0x9b, 0x70, 0xb3, 0xa1, 0xeb, 0x04, 0x52, 0xa1,
+                       0xf2, 0x22, 0x0f, 0xfc, 0xc8, 0x18, 0xfa, 0xf9,
+                       0x85, 0x9c, 0xf1, 0xac, 0xeb, 0x0c, 0x02, 0x46,
+                       0x75, 0xd2, 0xf5, 0x2c, 0xe3, 0xd2, 0x59, 0x94,
+                       0x12, 0xf3, 0x3c, 0xfc, 0xd7, 0x92, 0xfa, 0x36,
+                       0xba, 0x61, 0x34, 0x38, 0x7c, 0xda, 0x48, 0x3e,
+                       0x08, 0xc9, 0x39, 0x23, 0x5e, 0x02, 0x2c, 0x1a,
+                       0x18, 0x7e, 0xb4, 0xd9, 0xfd, 0x9e, 0x40, 0x02,
+                       0xb1, 0x33, 0x37, 0x32, 0xe7, 0xde, 0xd6, 0xd0,
+                       0x7c, 0x58, 0x65, 0x4b, 0xf8, 0x34, 0x27, 0x9c,
+                       0x44, 0xb4, 0xbd, 0xe9, 0xe9, 0x4c, 0x78, 0x7d,
+                       0x4b, 0x9f, 0xce, 0xb1, 0xcd, 0x47, 0xa5, 0x37,
+                       0xe5, 0x6d, 0xbd, 0xb9, 0x43, 0x94, 0x0a, 0xd4,
+                       0xd6, 0xf9, 0x04, 0x5f, 0xb5, 0x66, 0x6c, 0x1a,
+                       0x35, 0x12, 0xe3, 0x36, 0x28, 0x27, 0x36, 0x58,
+                       0x01, 0x2b, 0x79, 0xe4, 0xba, 0x6d, 0x10, 0x7d,
+                       0x65, 0xdf, 0x84, 0x95, 0xf4, 0xd5, 0xb6, 0x8f,
+                       0x2b, 0x9f, 0x96, 0x00, 0x86, 0x60, 0xf0, 0x21,
+                       0x76, 0xa8, 0x6a, 0x8c, 0x28, 0x1c, 0xb3, 0x6b,
+                       0x97, 0xd7, 0xb6, 0x53, 0x2a, 0xcc, 0xab, 0x40,
+                       0x9d, 0x62, 0x79, 0x58, 0x52, 0xe6, 0x65, 0xb7,
+                       0xab, 0x55, 0x67, 0x9c, 0x89, 0x7c, 0x03, 0xb0,
+                       0x73, 0x59, 0xc5, 0x81, 0xf5, 0x18, 0x17, 0x5c,
+                       0x89, 0xf3, 0x78, 0x35, 0x44, 0x62, 0x78, 0x72,
+                       0xd0, 0x96, 0xeb, 0x31, 0xe7, 0x87, 0x77, 0x14,
+                       0x99, 0x51, 0xf2, 0x59, 0x26, 0x9e, 0xb5, 0xa6,
+                       0x45, 0xfe, 0x6e, 0xbd, 0x07, 0x4c, 0x94, 0x5a,
+                       0xa5, 0x7d, 0xfc, 0xf1, 0x2b, 0x77, 0xe2, 0xfe,
+                       0x17, 0xd4, 0x84, 0xa0, 0xac, 0xb5, 0xc7, 0xda,
+                       0xa9, 0x1a, 0xb6, 0xf3, 0x74, 0x11, 0xb4, 0x9d,
+                       0xfb, 0x79, 0x2e, 0x04, 0x2d, 0x50, 0x28, 0x83,
+                       0xbf, 0xc6, 0x52, 0xd3, 0x34, 0xd6, 0xe8, 0x7a,
+                       0xb6, 0xea, 0xe7, 0xa8, 0x6c, 0x15, 0x1e, 0x2c,
+                       0x57, 0xbc, 0x48, 0x4e, 0x5f, 0x5c, 0xb6, 0x92,
+                       0xd2, 0x49, 0x77, 0x81, 0x6d, 0x90, 0x70, 0xae,
+                       0x98, 0xa1, 0x03, 0x0d, 0x6b, 0xb9, 0x77, 0x14,
+                       0xf1, 0x4e, 0x23, 0xd3, 0xf8, 0x68, 0xbd, 0xc2,
+                       0xfe, 0x04, 0xb7, 0x5c, 0xc5, 0x17, 0x60, 0x8f,
+                       0x65, 0x54, 0xa4, 0x7a, 0x42, 0xdc, 0x18, 0x0d,
+                       0xb5, 0xcf, 0x0f, 0xd3, 0xc7, 0x91, 0x66, 0x1b,
+                       0x45, 0x42, 0x27, 0x75, 0x50, 0xe5, 0xee, 0xb8,
+                       0x7f, 0x33, 0x2c, 0xba, 0x4a, 0x92, 0x4d, 0x2c,
+                       0x3c, 0xe3, 0x0d, 0x80, 0x01, 0xba, 0x0d, 0x29,
+                       0xd8, 0x3c, 0xe9, 0x13, 0x16, 0x57, 0xe6, 0xea,
+                       0x94, 0x52, 0xe7, 0x00, 0x4d, 0x30, 0xb0, 0x0f,
+                       0x35, 0xb8, 0xb8, 0xa7, 0xb1, 0xb5, 0x3b, 0x44,
+                       0xe1, 0x2f, 0xfd, 0x88, 0xed, 0x43, 0xe7, 0x52,
+                       0x10, 0x93, 0xb3, 0x8a, 0x30, 0x6b, 0x0a, 0xf7,
+                       0x23, 0xc6, 0x50, 0x9d, 0x4a, 0xb0, 0xde, 0xc3,
+                       0xdc, 0x9b, 0x2f, 0x01, 0x56, 0x36, 0x09, 0xc5,
+                       0x2f, 0x6b, 0xfe, 0xf1, 0xd8, 0x27, 0x45, 0x03,
+                       0x30, 0x5e, 0x5c, 0x5b, 0xb4, 0x62, 0x0e, 0x1a,
+                       0xa9, 0x21, 0x2b, 0x92, 0x94, 0x87, 0x62, 0x57,
+                       0x4c, 0x10, 0x74, 0x1a, 0xf1, 0x0a, 0xc5, 0x84,
+                       0x3b, 0x9e, 0x72, 0x02, 0xd7, 0xcc, 0x09, 0x56,
+                       0xbd, 0x54, 0xc1, 0xf0, 0xc3, 0xe3, 0xb3, 0xf8,
+                       0xd2, 0x0d, 0x61, 0xcb, 0xef, 0xce, 0x0d, 0x05,
+                       0xb0, 0x98, 0xd9, 0x8e, 0x4f, 0xf9, 0xbc, 0x93,
+                       0xa6, 0xea, 0xc8, 0xcf, 0x10, 0x53, 0x4b, 0xf1,
+                       0xec, 0xfc, 0x89, 0xf9, 0x64, 0xb0, 0x22, 0xbf,
+                       0x9e, 0x55, 0x46, 0x9f, 0x7c, 0x50, 0x8e, 0x84,
+                       0x54, 0x20, 0x98, 0xd7, 0x6c, 0x40, 0x1e, 0xdb,
+                       0x69, 0x34, 0x78, 0x61, 0x24, 0x21, 0x9c, 0x8a,
+                       0xb3, 0x62, 0x31, 0x8b, 0x6e, 0xf5, 0x2a, 0x35,
+                       0x86, 0x13, 0xb1, 0x6c, 0x64, 0x2e, 0x41, 0xa5,
+                       0x05, 0xf2, 0x42, 0xba, 0xd2, 0x3a, 0x0d, 0x8e,
+                       0x8a, 0x59, 0x94, 0x3c, 0xcf, 0x36, 0x27, 0x82,
+                       0xc2, 0x45, 0xee, 0x58, 0xcd, 0x88, 0xb4, 0xec,
+                       0xde, 0xb2, 0x96, 0x0a, 0xaf, 0x38, 0x6f, 0x88,
+                       0xd7, 0xd8, 0xe1, 0xdf, 0xb9, 0x96, 0xa9, 0x0a,
+                       0xb1, 0x95, 0x28, 0x86, 0x20, 0xe9, 0x17, 0x49,
+                       0xa2, 0x29, 0x38, 0xaa, 0xa5, 0xe9, 0x6e, 0xf1,
+                       0x19, 0x27, 0xc0, 0xd5, 0x2a, 0x22, 0xc3, 0x0b,
+                       0xdb, 0x7c, 0x73, 0x10, 0xb9, 0xba, 0x89, 0x76,
+                       0x54, 0xae, 0x7d, 0x71, 0xb3, 0x93, 0xf6, 0x32,
+                       0xe6, 0x47, 0x43, 0x55, 0xac, 0xa0, 0x0d, 0xc2,
+                       0x93, 0x27, 0x4a, 0x8e, 0x0e, 0x74, 0x15, 0xc7,
+                       0x0b, 0x85, 0xd9, 0x0c, 0xa9, 0x30, 0x7a, 0x3e,
+                       0xea, 0x8f, 0x85, 0x6d, 0x3a, 0x12, 0x4f, 0x72,
+                       0x69, 0x58, 0x7a, 0x80, 0xbb, 0xb5, 0x97, 0xf3,
+                       0xcf, 0x70, 0xd2, 0x5d, 0xdd, 0x4d, 0x21, 0x79,
+                       0x54, 0x4d, 0xe4, 0x05, 0xe8, 0xbd, 0xc2, 0x62,
+                       0xb1, 0x3b, 0x77, 0x1c, 0xd6, 0x5c, 0xf3, 0xa0,
+                       0x79, 0x00, 0xa8, 0x6c, 0x29, 0xd9, 0x18, 0x24,
+                       0x36, 0xa2, 0x46, 0xc0, 0x96, 0x65, 0x7f, 0xbd,
+                       0x2a, 0xed, 0x36, 0x16, 0x0c, 0xaa, 0x9f, 0xf4,
+                       0xc5, 0xb4, 0xe2, 0x12, 0xed, 0x69, 0xed, 0x4f,
+                       0x26, 0x2c, 0x39, 0x52, 0x89, 0x98, 0xe7, 0x2c,
+                       0x99, 0xa4, 0x9e, 0xa3, 0x9b, 0x99, 0x46, 0x7a,
+                       0x3a, 0xdc, 0xa8, 0x59, 0xa3, 0xdb, 0xc3, 0x3b,
+                       0x95, 0x0d, 0x3b, 0x09, 0x6e, 0xee, 0x83, 0x5d,
+                       0x32, 0x4d, 0xed, 0xab, 0xfa, 0x98, 0x14, 0x4e,
+                       0xc3, 0x15, 0x45, 0x53, 0x61, 0xc4, 0x93, 0xbd,
+                       0x90, 0xf4, 0x99, 0x95, 0x4c, 0xe6, 0x76, 0x92,
+                       0x29, 0x90, 0x46, 0x30, 0x92, 0x69, 0x7d, 0x13,
+                       0xf2, 0xa5, 0xcd, 0x69, 0x49, 0x44, 0xb2, 0x0f,
+                       0x63, 0x40, 0x36, 0x5f, 0x09, 0xe2, 0x78, 0xf8,
+                       0x91, 0xe3, 0xe2, 0xfa, 0x10, 0xf7, 0xc8, 0x24,
+                       0xa8, 0x89, 0x32, 0x5c, 0x37, 0x25, 0x1d, 0xb2,
+                       0xea, 0x17, 0x8a, 0x0a, 0xa9, 0x64, 0xc3, 0x7c,
+                       0x3c, 0x7c, 0xbd, 0xc6, 0x79, 0x34, 0xe7, 0xe2,
+                       0x85, 0x8e, 0xbf, 0xf8, 0xde, 0x92, 0xa0, 0xae,
+                       0x20, 0xc4, 0xf6, 0xbb, 0x1f, 0x38, 0x19, 0x0e,
+                       0xe8, 0x79, 0x9c, 0xa1, 0x23, 0xe9, 0x54, 0x7e,
+                       0x37, 0x2f, 0xe2, 0x94, 0x32, 0xaf, 0xa0, 0x23,
+                       0x49, 0xe4, 0xc0, 0xb3, 0xac, 0x00, 0x8f, 0x36,
+                       0x05, 0xc4, 0xa6, 0x96, 0xec, 0x05, 0x98, 0x4f,
+                       0x96, 0x67, 0x57, 0x1f, 0x20, 0x86, 0x1b, 0x2d,
+                       0x69, 0xe4, 0x29, 0x93, 0x66, 0x5f, 0xaf, 0x6b,
+                       0x88, 0x26, 0x2c, 0x67, 0x02, 0x4b, 0x52, 0xd0,
+                       0x83, 0x7a, 0x43, 0x1f, 0xc0, 0x71, 0x15, 0x25,
+                       0x77, 0x65, 0x08, 0x60, 0x11, 0x76, 0x4c, 0x8d,
+                       0xed, 0xa9, 0x27, 0xc6, 0xb1, 0x2a, 0x2c, 0x6a,
+                       0x4a, 0x97, 0xf5, 0xc6, 0xb7, 0x70, 0x42, 0xd3,
+                       0x03, 0xd1, 0x24, 0x95, 0xec, 0x6d, 0xab, 0x38,
+                       0x72, 0xce, 0xe2, 0x8b, 0x33, 0xd7, 0x51, 0x09,
+                       0xdc, 0x45, 0xe0, 0x09, 0x96, 0x32, 0xf3, 0xc4,
+                       0x84, 0xdc, 0x73, 0x73, 0x2d, 0x1b, 0x11, 0x98,
+                       0xc5, 0x0e, 0x69, 0x28, 0x94, 0xc7, 0xb5, 0x4d,
+                       0xc8, 0x8a, 0xd0, 0xaa, 0x13, 0x2e, 0x18, 0x74,
+                       0xdd, 0xd1, 0x1e, 0xf3, 0x90, 0xe8, 0xfc, 0x9a,
+                       0x72, 0x4a, 0x0e, 0xd1, 0xe4, 0xfb, 0x0d, 0x96,
+                       0xd1, 0x0c, 0x79, 0x85, 0x1b, 0x1c, 0xfe, 0xe1,
+                       0x62, 0x8f, 0x7a, 0x73, 0x32, 0xab, 0xc8, 0x18,
+                       0x69, 0xe3, 0x34, 0x30, 0xdf, 0x13, 0xa6, 0xe5,
+                       0xe8, 0x0e, 0x67, 0x7f, 0x81, 0x11, 0xb4, 0x60,
+                       0xc7, 0xbd, 0x79, 0x65, 0x50, 0xdc, 0xc4, 0x5b,
+                       0xde, 0x39, 0xa4, 0x01, 0x72, 0x63, 0xf3, 0xd1,
+                       0x64, 0x4e, 0xdf, 0xfc, 0x27, 0x92, 0x37, 0x0d,
+                       0x57, 0xcd, 0x11, 0x4f, 0x11, 0x04, 0x8e, 0x1d,
+                       0x16, 0xf7, 0xcd, 0x92, 0x9a, 0x99, 0x30, 0x14,
+                       0xf1, 0x7c, 0x67, 0x1b, 0x1f, 0x41, 0x0b, 0xe8,
+                       0x32, 0xe8, 0xb8, 0xc1, 0x4f, 0x54, 0x86, 0x4f,
+                       0xe5, 0x79, 0x81, 0x73, 0xcd, 0x43, 0x59, 0x68,
+                       0x73, 0x02, 0x3b, 0x78, 0x21, 0x72, 0x43, 0x00,
+                       0x49, 0x17, 0xf7, 0x00, 0xaf, 0x68, 0x24, 0x53,
+                       0x05, 0x0a, 0xc3, 0x33, 0xe0, 0x33, 0x3f, 0x69,
+                       0xd2, 0x84, 0x2f, 0x0b, 0xed, 0xde, 0x04, 0xf4,
+                       0x11, 0x94, 0x13, 0x69, 0x51, 0x09, 0x28, 0xde,
+                       0x57, 0x5c, 0xef, 0xdc, 0x9a, 0x49, 0x1c, 0x17,
+                       0x97, 0xf3, 0x96, 0xc1, 0x7f, 0x5d, 0x2e, 0x7d,
+                       0x55, 0xb8, 0xb3, 0x02, 0x09, 0xb3, 0x1f, 0xe7,
+                       0xc9, 0x8d, 0xa3, 0x36, 0x34, 0x8a, 0x77, 0x13,
+                       0x30, 0x63, 0x4c, 0xa5, 0xcd, 0xc3, 0xe0, 0x7e,
+                       0x05, 0xa1, 0x7b, 0x0c, 0xcb, 0x74, 0x47, 0x31,
+                       0x62, 0x03, 0x43, 0xf1, 0x87, 0xb4, 0xb0, 0x85,
+                       0x87, 0x8e, 0x4b, 0x25, 0xc7, 0xcf, 0xae, 0x4b,
+                       0x36, 0x46, 0x3e, 0x62, 0xbc, 0x6f, 0xeb, 0x5f,
+                       0x73, 0xac, 0xe6, 0x07, 0xee, 0xc1, 0xa1, 0xd6,
+                       0xc4, 0xab, 0xc9, 0xd6, 0x89, 0x45, 0xe1, 0xf1,
+                       0x04, 0x4e, 0x1a, 0x6f, 0xbb, 0x4f, 0x3a, 0xa3,
+                       0xa0, 0xcb, 0xa3, 0x0a, 0xd8, 0x71, 0x35, 0x55,
+                       0xe4, 0xbc, 0x2e, 0x04, 0x06, 0xe6, 0xff, 0x5b,
+                       0x1c, 0xc0, 0x11, 0x7c, 0xc5, 0x17, 0xf3, 0x38,
+                       0xcf, 0xe9, 0xba, 0x0f, 0x0e, 0xef, 0x02, 0xc2,
+                       0x8d, 0xc6, 0xbc, 0x4b, 0x67, 0x20, 0x95, 0xd7,
+                       0x2c, 0x45, 0x5b, 0x86, 0x44, 0x8c, 0x6f, 0x2e,
+                       0x7e, 0x9f, 0x1c, 0x77, 0xba, 0x6b, 0x0e, 0xa3,
+                       0x69, 0xdc, 0xab, 0x24, 0x57, 0x60, 0x47, 0xc1,
+                       0xd1, 0xa5, 0x9d, 0x23, 0xe6, 0xb1, 0x37, 0xfe,
+                       0x93, 0xd2, 0x4c, 0x46, 0xf9, 0x0c, 0xc6, 0xfb,
+                       0xd6, 0x9d, 0x99, 0x69, 0xab, 0x7a, 0x07, 0x0c,
+                       0x65, 0xe7, 0xc4, 0x08, 0x96, 0xe2, 0xa5, 0x01,
+                       0x3f, 0x46, 0x07, 0x05, 0x7e, 0xe8, 0x9a, 0x90,
+                       0x50, 0xdc, 0xe9, 0x7a, 0xea, 0xa1, 0x39, 0x6e,
+                       0x66, 0xe4, 0x6f, 0xa5, 0x5f, 0xb2, 0xd9, 0x5b,
+                       0xf5, 0xdb, 0x2a, 0x32, 0xf0, 0x11, 0x6f, 0x7c,
+                       0x26, 0x10, 0x8f, 0x3d, 0x80, 0xe9, 0x58, 0xf7,
+                       0xe0, 0xa8, 0x57, 0xf8, 0xdb, 0x0e, 0xce, 0x99,
+                       0x63, 0x19, 0x3d, 0xd5, 0xec, 0x1b, 0x77, 0x69,
+                       0x98, 0xf6, 0xe4, 0x5f, 0x67, 0x17, 0x4b, 0x09,
+                       0x85, 0x62, 0x82, 0x70, 0x18, 0xe2, 0x9a, 0x78,
+                       0xe2, 0x62, 0xbd, 0xb4, 0xf1, 0x42, 0xc6, 0xfb,
+                       0x08, 0xd0, 0xbd, 0xeb, 0x4e, 0x09, 0xf2, 0xc8,
+                       0x1e, 0xdc, 0x3d, 0x32, 0x21, 0x56, 0x9c, 0x4f,
+                       0x35, 0xf3, 0x61, 0x06, 0x72, 0x84, 0xc4, 0x32,
+                       0xf2, 0xf1, 0xfa, 0x0b, 0x2f, 0xc3, 0xdb, 0x02,
+                       0x04, 0xc2, 0xde, 0x57, 0x64, 0x60, 0x8d, 0xcf,
+                       0xcb, 0x86, 0x5d, 0x97, 0x3e, 0xb1, 0x9c, 0x01,
+                       0xd6, 0x28, 0x8f, 0x99, 0xbc, 0x46, 0xeb, 0x05,
+                       0xaf, 0x7e, 0xb8, 0x21, 0x2a, 0x56, 0x85, 0x1c,
+                       0xb3, 0x71, 0xa0, 0xde, 0xca, 0x96, 0xf1, 0x78,
+                       0x49, 0xa2, 0x99, 0x81, 0x80, 0x5c, 0x01, 0xf5,
+                       0xa0, 0xa2, 0x56, 0x63, 0xe2, 0x70, 0x07, 0xa5,
+                       0x95, 0xd6, 0x85, 0xeb, 0x36, 0x9e, 0xa9, 0x51,
+                       0x66, 0x56, 0x5f, 0x1d, 0x02, 0x19, 0xe2, 0xf6,
+                       0x4f, 0x73, 0x38, 0x09, 0x75, 0x64, 0x48, 0xe0,
+                       0xf1, 0x7e, 0x0e, 0xe8, 0x9d, 0xf9, 0xed, 0x94,
+                       0xfe, 0x16, 0x26, 0x62, 0x49, 0x74, 0xf4, 0xb0,
+                       0xd4, 0xa9, 0x6c, 0xb0, 0xfd, 0x53, 0xe9, 0x81,
+                       0xe0, 0x7a, 0xbf, 0xcf, 0xb5, 0xc4, 0x01, 0x81,
+                       0x79, 0x99, 0x77, 0x01, 0x3b, 0xe9, 0xa2, 0xb6,
+                       0xe6, 0x6a, 0x8a, 0x9e, 0x56, 0x1c, 0x8d, 0x1e,
+                       0x8f, 0x06, 0x55, 0x2c, 0x6c, 0xdc, 0x92, 0x87,
+                       0x64, 0x3b, 0x4b, 0x19, 0xa1, 0x13, 0x64, 0x1d,
+                       0x4a, 0xe9, 0xc0, 0x00, 0xb8, 0x95, 0xef, 0x6b,
+                       0x1a, 0x86, 0x6d, 0x37, 0x52, 0x02, 0xc2, 0xe0,
+                       0xc8, 0xbb, 0x42, 0x0c, 0x02, 0x21, 0x4a, 0xc9,
+                       0xef, 0xa0, 0x54, 0xe4, 0x5e, 0x16, 0x53, 0x81,
+                       0x70, 0x62, 0x10, 0xaf, 0xde, 0xb8, 0xb5, 0xd3,
+                       0xe8, 0x5e, 0x6c, 0xc3, 0x8a, 0x3e, 0x18, 0x07,
+                       0xf2, 0x2f, 0x7d, 0xa7, 0xe1, 0x3d, 0x4e, 0xb4,
+                       0x26, 0xa7, 0xa3, 0x93, 0x86, 0xb2, 0x04, 0x1e,
+                       0x53, 0x5d, 0x86, 0xd6, 0xde, 0x65, 0xca, 0xe3,
+                       0x4e, 0xc1, 0xcf, 0xef, 0xc8, 0x70, 0x1b, 0x83,
+                       0x13, 0xdd, 0x18, 0x8b, 0x0d, 0x76, 0xd2, 0xf6,
+                       0x37, 0x7a, 0x93, 0x7a, 0x50, 0x11, 0x9f, 0x96,
+                       0x86, 0x25, 0xfd, 0xac, 0xdc, 0xbe, 0x18, 0x93,
+                       0x19, 0x6b, 0xec, 0x58, 0x4f, 0xb9, 0x75, 0xa7,
+                       0xdd, 0x3f, 0x2f, 0xec, 0xc8, 0x5a, 0x84, 0xab,
+                       0xd5, 0xe4, 0x8a, 0x07, 0xf6, 0x4d, 0x23, 0xd6,
+                       0x03, 0xfb, 0x03, 0x6a, 0xea, 0x66, 0xbf, 0xd4,
+                       0xb1, 0x34, 0xfb, 0x78, 0xe9, 0x55, 0xdc, 0x7c,
+                       0x3d, 0x9c, 0xe5, 0x9a, 0xac, 0xc3, 0x7a, 0x80,
+                       0x24, 0x6d, 0xa0, 0xef, 0x25, 0x7c, 0xb7, 0xea,
+                       0xce, 0x4d, 0x5f, 0x18, 0x60, 0xce, 0x87, 0x22,
+                       0x66, 0x2f, 0xd5, 0xdd, 0xdd, 0x02, 0x21, 0x75,
+                       0x82, 0xa0, 0x1f, 0x58, 0xc6, 0xd3, 0x62, 0xf7,
+                       0x32, 0xd8, 0xaf, 0x1e, 0x07, 0x77, 0x51, 0x96,
+                       0xd5, 0x6b, 0x1e, 0x7e, 0x80, 0x02, 0xe8, 0x67,
+                       0xea, 0x17, 0x0b, 0x10, 0xd2, 0x3f, 0x28, 0x25,
+                       0x4f, 0x05, 0x77, 0x02, 0x14, 0x69, 0xf0, 0x2c,
+                       0xbe, 0x0c, 0xf1, 0x74, 0x30, 0xd1, 0xb9, 0x9b,
+                       0xfc, 0x8c, 0xbb, 0x04, 0x16, 0xd9, 0xba, 0xc3,
+                       0xbc, 0x91, 0x8a, 0xc4, 0x30, 0xa4, 0xb0, 0x12,
+                       0x4c, 0x21, 0x87, 0xcb, 0xc9, 0x1d, 0x16, 0x96,
+                       0x07, 0x6f, 0x23, 0x54, 0xb9, 0x6f, 0x79, 0xe5,
+                       0x64, 0xc0, 0x64, 0xda, 0xb1, 0xae, 0xdd, 0x60,
+                       0x6c, 0x1a, 0x9d, 0xd3, 0x04, 0x8e, 0x45, 0xb0,
+                       0x92, 0x61, 0xd0, 0x48, 0x81, 0xed, 0x5e, 0x1d,
+                       0xa0, 0xc9, 0xa4, 0x33, 0xc7, 0x13, 0x51, 0x5d,
+                       0x7f, 0x83, 0x73, 0xb6, 0x70, 0x18, 0x65, 0x3e,
+                       0x2f, 0x0e, 0x7a, 0x12, 0x39, 0x98, 0xab, 0xd8,
+                       0x7e, 0x6f, 0xa3, 0xd1, 0xba, 0x56, 0xad, 0xbd,
+                       0xf0, 0x03, 0x01, 0x1c, 0x85, 0x35, 0x9f, 0xeb,
+                       0x19, 0x63, 0xa1, 0xaf, 0xfe, 0x2d, 0x35, 0x50,
+                       0x39, 0xa0, 0x65, 0x7c, 0x95, 0x7e, 0x6b, 0xfe,
+                       0xc1, 0xac, 0x07, 0x7c, 0x98, 0x4f, 0xbe, 0x57,
+                       0xa7, 0x22, 0xec, 0xe2, 0x7e, 0x29, 0x09, 0x53,
+                       0xe8, 0xbf, 0xb4, 0x7e, 0x3f, 0x8f, 0xfc, 0x14,
+                       0xce, 0x54, 0xf9, 0x18, 0x58, 0xb5, 0xff, 0x44,
+                       0x05, 0x9d, 0xce, 0x1b, 0xb6, 0x82, 0x23, 0xc8,
+                       0x2e, 0xbc, 0x69, 0xbb, 0x4a, 0x29, 0x0f, 0x65,
+                       0x94, 0xf0, 0x63, 0x06, 0x0e, 0xef, 0x8c, 0xbd,
+                       0xff, 0xfd, 0xb0, 0x21, 0x6e, 0x57, 0x05, 0x75,
+                       0xda, 0xd5, 0xc4, 0xeb, 0x8d, 0x32, 0xf7, 0x50,
+                       0xd3, 0x6f, 0x22, 0xed, 0x5f, 0x8e, 0xa2, 0x5b,
+                       0x80, 0x8c, 0xc8, 0x78, 0x40, 0x24, 0x4b, 0x89,
+                       0x30, 0xce, 0x7a, 0x97, 0x0e, 0xc4, 0xaf, 0xef,
+                       0x9b, 0xb4, 0xcd, 0x66, 0x74, 0x14, 0x04, 0x2b,
+                       0xf7, 0xce, 0x0b, 0x1c, 0x6e, 0xc2, 0x78, 0x8c,
+                       0xca, 0xc5, 0xd0, 0x1c, 0x95, 0x4a, 0x91, 0x2d,
+                       0xa7, 0x20, 0xeb, 0x86, 0x52, 0xb7, 0x67, 0xd8,
+                       0x0c, 0xd6, 0x04, 0x14, 0xde, 0x51, 0x74, 0x75,
+                       0xe7, 0x11, 0xb4, 0x87, 0xa3, 0x3d, 0x2d, 0xad,
+                       0x4f, 0xef, 0xa0, 0x0f, 0x70, 0x00, 0x6d, 0x13,
+                       0x19, 0x1d, 0x41, 0x50, 0xe9, 0xd8, 0xf0, 0x32,
+                       0x71, 0xbc, 0xd3, 0x11, 0xf2, 0xac, 0xbe, 0xaf,
+                       0x75, 0x46, 0x65, 0x4e, 0x07, 0x34, 0x37, 0xa3,
+                       0x89, 0xfe, 0x75, 0xd4, 0x70, 0x4c, 0xc6, 0x3f,
+                       0x69, 0x24, 0x0e, 0x38, 0x67, 0x43, 0x8c, 0xde,
+                       0x06, 0xb5, 0xb8, 0xe7, 0xc4, 0xf0, 0x41, 0x8f,
+                       0xf0, 0xbd, 0x2f, 0x0b, 0xb9, 0x18, 0xf8, 0xde,
+                       0x64, 0xb1, 0xdb, 0xee, 0x00, 0x50, 0x77, 0xe1,
+                       0xc7, 0xff, 0xa6, 0xfa, 0xdd, 0x70, 0xf4, 0xe3,
+                       0x93, 0xe9, 0x77, 0x35, 0x3d, 0x4b, 0x2f, 0x2b,
+                       0x6d, 0x55, 0xf0, 0xfc, 0x88, 0x54, 0x4e, 0x89,
+                       0xc1, 0x8a, 0x23, 0x31, 0x2d, 0x14, 0x2a, 0xb8,
+                       0x1b, 0x15, 0xdd, 0x9e, 0x6e, 0x7b, 0xda, 0x05,
+                       0x91, 0x7d, 0x62, 0x64, 0x96, 0x72, 0xde, 0xfc,
+                       0xc1, 0xec, 0xf0, 0x23, 0x51, 0x6f, 0xdb, 0x5b,
+                       0x1d, 0x08, 0x57, 0xce, 0x09, 0xb8, 0xf6, 0xcd,
+                       0x8d, 0x95, 0xf2, 0x20, 0xbf, 0x0f, 0x20, 0x57,
+                       0x98, 0x81, 0x84, 0x4f, 0x15, 0x5c, 0x76, 0xe7,
+                       0x3e, 0x0a, 0x3a, 0x6c, 0xc4, 0x8a, 0xbe, 0x78,
+                       0x74, 0x77, 0xc3, 0x09, 0x4b, 0x5d, 0x48, 0xe4,
+                       0xc8, 0xcb, 0x0b, 0xea, 0x17, 0x28, 0xcf, 0xcf,
+                       0x31, 0x32, 0x44, 0xa4, 0xe5, 0x0e, 0x1a, 0x98,
+                       0x94, 0xc4, 0xf0, 0xff, 0xae, 0x3e, 0x44, 0xe8,
+                       0xa5, 0xb3, 0xb5, 0x37, 0x2f, 0xe8, 0xaf, 0x6f,
+                       0x28, 0xc1, 0x37, 0x5f, 0x31, 0xd2, 0xb9, 0x33,
+                       0xb1, 0xb2, 0x52, 0x94, 0x75, 0x2c, 0x29, 0x59,
+                       0x06, 0xc2, 0x25, 0xe8, 0x71, 0x65, 0x4e, 0xed,
+                       0xc0, 0x9c, 0xb1, 0xbb, 0x25, 0xdc, 0x6c, 0xe7,
+                       0x4b, 0xa5, 0x7a, 0x54, 0x7a, 0x60, 0xff, 0x7a,
+                       0xe0, 0x50, 0x40, 0x96, 0x35, 0x63, 0xe4, 0x0b,
+                       0x76, 0xbd, 0xa4, 0x65, 0x00, 0x1b, 0x57, 0x88,
+                       0xae, 0xed, 0x39, 0x88, 0x42, 0x11, 0x3c, 0xed,
+                       0x85, 0x67, 0x7d, 0xb9, 0x68, 0x82, 0xe9, 0x43,
+                       0x3c, 0x47, 0x53, 0xfa, 0xe8, 0xf8, 0x9f, 0x1f,
+                       0x9f, 0xef, 0x0f, 0xf7, 0x30, 0xd9, 0x30, 0x0e,
+                       0xb9, 0x9f, 0x69, 0x18, 0x2f, 0x7e, 0xf8, 0xf8,
+                       0xf8, 0x8c, 0x0f, 0xd4, 0x02, 0x4d, 0xea, 0xcd,
+                       0x0a, 0x9c, 0x6f, 0x71, 0x6d, 0x5a, 0x4c, 0x60,
+                       0xce, 0x20, 0x56, 0x32, 0xc6, 0xc5, 0x99, 0x1f,
+                       0x09, 0xe6, 0x4e, 0x18, 0x1a, 0x15, 0x13, 0xa8,
+                       0x7d, 0xb1, 0x6b, 0xc0, 0xb2, 0x6d, 0xf8, 0x26,
+                       0x66, 0xf8, 0x3d, 0x18, 0x74, 0x70, 0x66, 0x7a,
+                       0x34, 0x17, 0xde, 0xba, 0x47, 0xf1, 0x06, 0x18,
+                       0xcb, 0xaf, 0xeb, 0x4a, 0x1e, 0x8f, 0xa7, 0x77,
+                       0xe0, 0x3b, 0x78, 0x62, 0x66, 0xc9, 0x10, 0xea,
+                       0x1f, 0xb7, 0x29, 0x0a, 0x45, 0xa1, 0x1d, 0x1e,
+                       0x1d, 0xe2, 0x65, 0x61, 0x50, 0x9c, 0xd7, 0x05,
+                       0xf2, 0x0b, 0x5b, 0x12, 0x61, 0x02, 0xc8, 0xe5,
+                       0x63, 0x4f, 0x20, 0x0c, 0x07, 0x17, 0x33, 0x5e,
+                       0x03, 0x9a, 0x53, 0x0f, 0x2e, 0x55, 0xfe, 0x50,
+                       0x43, 0x7d, 0xd0, 0xb6, 0x7e, 0x5a, 0xda, 0xae,
+                       0x58, 0xef, 0x15, 0xa9, 0x83, 0xd9, 0x46, 0xb1,
+                       0x42, 0xaa, 0xf5, 0x02, 0x6c, 0xce, 0x92, 0x06,
+                       0x1b, 0xdb, 0x66, 0x45, 0x91, 0x79, 0xc2, 0x2d,
+                       0xe6, 0x53, 0xd3, 0x14, 0xfd, 0xbb, 0x44, 0x63,
+                       0xc6, 0xd7, 0x3d, 0x7a, 0x0c, 0x75, 0x78, 0x9d,
+                       0x5c, 0xa6, 0x39, 0xb3, 0xe5, 0x63, 0xca, 0x8b,
+                       0xfe, 0xd3, 0xef, 0x60, 0x83, 0xf6, 0x8e, 0x70,
+                       0xb6, 0x67, 0xc7, 0x77, 0xed, 0x23, 0xef, 0x4c,
+                       0xf0, 0xed, 0x2d, 0x07, 0x59, 0x6f, 0xc1, 0x01,
+                       0x34, 0x37, 0x08, 0xab, 0xd9, 0x1f, 0x09, 0xb1,
+                       0xce, 0x5b, 0x17, 0xff, 0x74, 0xf8, 0x9c, 0xd5,
+                       0x2c, 0x56, 0x39, 0x79, 0x0f, 0x69, 0x44, 0x75,
+                       0x58, 0x27, 0x01, 0xc4, 0xbf, 0xa7, 0xa1, 0x1d,
+                       0x90, 0x17, 0x77, 0x86, 0x5a, 0x3f, 0xd9, 0xd1,
+                       0x0e, 0xa0, 0x10, 0xf8, 0xec, 0x1e, 0xa5, 0x7f,
+                       0x5e, 0x36, 0xd1, 0xe3, 0x04, 0x2c, 0x70, 0xf7,
+                       0x8e, 0xc0, 0x98, 0x2f, 0x6c, 0x94, 0x2b, 0x41,
+                       0xb7, 0x60, 0x00, 0xb7, 0x2e, 0xb8, 0x02, 0x8d,
+                       0xb8, 0xb0, 0xd3, 0x86, 0xba, 0x1d, 0xd7, 0x90,
+                       0xd6, 0xb6, 0xe1, 0xfc, 0xd7, 0xd8, 0x28, 0x06,
+                       0x63, 0x9b, 0xce, 0x61, 0x24, 0x79, 0xc0, 0x70,
+                       0x52, 0xd0, 0xb6, 0xd4, 0x28, 0x95, 0x24, 0x87,
+                       0x03, 0x1f, 0xb7, 0x9a, 0xda, 0xa3, 0xfb, 0x52,
+                       0x5b, 0x68, 0xe7, 0x4c, 0x8c, 0x24, 0xe1, 0x42,
+                       0xf7, 0xd5, 0xfd, 0xad, 0x06, 0x32, 0x9f, 0xba,
+                       0xc1, 0xfc, 0xdd, 0xc6, 0xfc, 0xfc, 0xb3, 0x38,
+                       0x74, 0x56, 0x58, 0x40, 0x02, 0x37, 0x52, 0x2c,
+                       0x55, 0xcc, 0xb3, 0x9e, 0x7a, 0xe9, 0xd4, 0x38,
+                       0x41, 0x5e, 0x0c, 0x35, 0xe2, 0x11, 0xd1, 0x13,
+                       0xf8, 0xb7, 0x8d, 0x72, 0x6b, 0x22, 0x2a, 0xb0,
+                       0xdb, 0x08, 0xba, 0x35, 0xb9, 0x3f, 0xc8, 0xd3,
+                       0x24, 0x90, 0xec, 0x58, 0xd2, 0x09, 0xc7, 0x2d,
+                       0xed, 0x38, 0x80, 0x36, 0x72, 0x43, 0x27, 0x49,
+                       0x4a, 0x80, 0x8a, 0xa2, 0xe8, 0xd3, 0xda, 0x30,
+                       0x7d, 0xb6, 0x82, 0x37, 0x86, 0x92, 0x86, 0x3e,
+                       0x08, 0xb2, 0x28, 0x5a, 0x55, 0x44, 0x24, 0x7d,
+                       0x40, 0x48, 0x8a, 0xb6, 0x89, 0x58, 0x08, 0xa0,
+                       0xd6, 0x6d, 0x3a, 0x17, 0xbf, 0xf6, 0x54, 0xa2,
+                       0xf5, 0xd3, 0x8c, 0x0f, 0x78, 0x12, 0x57, 0x8b,
+                       0xd5, 0xc2, 0xfd, 0x58, 0x5b, 0x7f, 0x38, 0xe3,
+                       0xcc, 0xb7, 0x7c, 0x48, 0xb3, 0x20, 0xe8, 0x81,
+                       0x14, 0x32, 0x45, 0x05, 0xe0, 0xdb, 0x9f, 0x75,
+                       0x85, 0xb4, 0x6a, 0xfc, 0x95, 0xe3, 0x54, 0x22,
+                       0x12, 0xee, 0x30, 0xfe, 0xd8, 0x30, 0xef, 0x34,
+                       0x50, 0xab, 0x46, 0x30, 0x98, 0x2f, 0xb7, 0xc0,
+                       0x15, 0xa2, 0x83, 0xb6, 0xf2, 0x06, 0x21, 0xa2,
+                       0xc3, 0x26, 0x37, 0x14, 0xd1, 0x4d, 0xb5, 0x10,
+                       0x52, 0x76, 0x4d, 0x6a, 0xee, 0xb5, 0x2b, 0x15,
+                       0xb7, 0xf9, 0x51, 0xe8, 0x2a, 0xaf, 0xc7, 0xfa,
+                       0x77, 0xaf, 0xb0, 0x05, 0x4d, 0xd1, 0x68, 0x8e,
+                       0x74, 0x05, 0x9f, 0x9d, 0x93, 0xa5, 0x3e, 0x7f,
+                       0x4e, 0x5f, 0x9d, 0xcb, 0x09, 0xc7, 0x83, 0xe3,
+                       0x02, 0x9d, 0x27, 0x1f, 0xef, 0x85, 0x05, 0x8d,
+                       0xec, 0x55, 0x88, 0x0f, 0x0d, 0x7c, 0x4c, 0xe8,
+                       0xa1, 0x75, 0xa0, 0xd8, 0x06, 0x47, 0x14, 0xef,
+                       0xaa, 0x61, 0xcf, 0x26, 0x15, 0xad, 0xd8, 0xa3,
+                       0xaa, 0x75, 0xf2, 0x78, 0x4a, 0x5a, 0x61, 0xdf,
+                       0x8b, 0xc7, 0x04, 0xbc, 0xb2, 0x32, 0xd2, 0x7e,
+                       0x42, 0xee, 0xb4, 0x2f, 0x51, 0xff, 0x7b, 0x2e,
+                       0xd3, 0x02, 0xe8, 0xdc, 0x5d, 0x0d, 0x50, 0xdc,
+                       0xae, 0xb7, 0x46, 0xf9, 0xa8, 0xe6, 0xd0, 0x16,
+                       0xcc, 0xe6, 0x2c, 0x81, 0xc7, 0xad, 0xe9, 0xf0,
+                       0x05, 0x72, 0x6d, 0x3d, 0x0a, 0x7a, 0xa9, 0x02,
+                       0xac, 0x82, 0x93, 0x6e, 0xb6, 0x1c, 0x28, 0xfc,
+                       0x44, 0x12, 0xfb, 0x73, 0x77, 0xd4, 0x13, 0x39,
+                       0x29, 0x88, 0x8a, 0xf3, 0x5c, 0xa6, 0x36, 0xa0,
+                       0x2a, 0xed, 0x7e, 0xb1, 0x1d, 0xd6, 0x4c, 0x6b,
+                       0x41, 0x01, 0x18, 0x5d, 0x5d, 0x07, 0x97, 0xa6,
+                       0x4b, 0xef, 0x31, 0x18, 0xea, 0xac, 0xb1, 0x84,
+                       0x21, 0xed, 0xda, 0x86,
+               },
+               .rlen = 4100,
+       },
+};
+
+static struct cipher_testvec aes_ctr_dec_tv_template[] = {
+       { /* From RFC 3686 */
+               .key    = { 0xae, 0x68, 0x52, 0xf8, 0x12, 0x10, 0x67, 0xcc,
+                           0x4b, 0xf7, 0xa5, 0x76, 0x55, 0x77, 0xf3, 0x9e,
+                           0x00, 0x00, 0x00, 0x30 },
+               .klen   = 20,
+               .iv     = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+               .input  = { 0xe4, 0x09, 0x5d, 0x4f, 0xb7, 0xa7, 0xb3, 0x79,
+                           0x2d, 0x61, 0x75, 0xa3, 0x26, 0x13, 0x11, 0xb8 },
+               .ilen   = 16,
+               .result = { "Single block msg" },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x7e, 0x24, 0x06, 0x78, 0x17, 0xfa, 0xe0, 0xd7,
+                           0x43, 0xd6, 0xce, 0x1f, 0x32, 0x53, 0x91, 0x63,
+                           0x00, 0x6c, 0xb6, 0xdb },
+               .klen   = 20,
+               .iv     = { 0xc0, 0x54, 0x3b, 0x59, 0xda, 0x48, 0xd9, 0x0b },
+               .input  = { 0x51, 0x04, 0xa1, 0x06, 0x16, 0x8a, 0x72, 0xd9,
+                           0x79, 0x0d, 0x41, 0xee, 0x8e, 0xda, 0xd3, 0x88,
+                           0xeb, 0x2e, 0x1e, 0xfc, 0x46, 0xda, 0x57, 0xc8,
+                           0xfc, 0xe6, 0x30, 0xdf, 0x91, 0x41, 0xbe, 0x28 },
+               .ilen   = 32,
+               .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+               .rlen   = 32,
+       }, {
+               .key    = { 0x16, 0xaf, 0x5b, 0x14, 0x5f, 0xc9, 0xf5, 0x79,
+                           0xc1, 0x75, 0xf9, 0x3e, 0x3b, 0xfb, 0x0e, 0xed,
+                           0x86, 0x3d, 0x06, 0xcc, 0xfd, 0xb7, 0x85, 0x15,
+                           0x00, 0x00, 0x00, 0x48 },
+               .klen   = 28,
+               .iv     = { 0x36, 0x73, 0x3c, 0x14, 0x7d, 0x6d, 0x93, 0xcb },
+               .input  = { 0x4b, 0x55, 0x38, 0x4f, 0xe2, 0x59, 0xc9, 0xc8,
+                           0x4e, 0x79, 0x35, 0xa0, 0x03, 0xcb, 0xe9, 0x28 },
+               .ilen   = 16,
+               .result = { "Single block msg" },
+               .rlen   = 16,
+       }, {
+               .key    = { 0x7c, 0x5c, 0xb2, 0x40, 0x1b, 0x3d, 0xc3, 0x3c,
+                           0x19, 0xe7, 0x34, 0x08, 0x19, 0xe0, 0xf6, 0x9c,
+                           0x67, 0x8c, 0x3d, 0xb8, 0xe6, 0xf6, 0xa9, 0x1a,
+                           0x00, 0x96, 0xb0, 0x3b },
+               .klen   = 28,
+               .iv     = { 0x02, 0x0c, 0x6e, 0xad, 0xc2, 0xcb, 0x50, 0x0d },
+               .input  = { 0x45, 0x32, 0x43, 0xfc, 0x60, 0x9b, 0x23, 0x32,
+                           0x7e, 0xdf, 0xaa, 0xfa, 0x71, 0x31, 0xcd, 0x9f,
+                           0x84, 0x90, 0x70, 0x1c, 0x5a, 0xd4, 0xa7, 0x9c,
+                           0xfc, 0x1f, 0xe0, 0xff, 0x42, 0xf4, 0xfb, 0x00 },
+               .ilen   = 32,
+               .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+               .rlen   = 32,
+       }, { 
+               .key    = { 0x77, 0x6b, 0xef, 0xf2, 0x85, 0x1d, 0xb0, 0x6f,
+                           0x4c, 0x8a, 0x05, 0x42, 0xc8, 0x69, 0x6f, 0x6c,
+                           0x6a, 0x81, 0xaf, 0x1e, 0xec, 0x96, 0xb4, 0xd3,
+                           0x7f, 0xc1, 0xd6, 0x89, 0xe6, 0xc1, 0xc1, 0x04,
+                           0x00, 0x00, 0x00, 0x60 },
+               .klen   = 36,
+               .iv     = { 0xdb, 0x56, 0x72, 0xc9, 0x7a, 0xa8, 0xf0, 0xb2 },
+               .input  = { 0x14, 0x5a, 0xd0, 0x1d, 0xbf, 0x82, 0x4e, 0xc7,
+                           0x56, 0x08, 0x63, 0xdc, 0x71, 0xe3, 0xe0, 0xc0 },
+               .ilen   = 16,
+               .result = { "Single block msg" },
+               .rlen   = 16,
+       }, {
+               .key    = { 0xf6, 0xd6, 0x6d, 0x6b, 0xd5, 0x2d, 0x59, 0xbb,
+                           0x07, 0x96, 0x36, 0x58, 0x79, 0xef, 0xf8, 0x86,
+                           0xc6, 0x6d, 0xd5, 0x1a, 0x5b, 0x6a, 0x99, 0x74,
+                           0x4b, 0x50, 0x59, 0x0c, 0x87, 0xa2, 0x38, 0x84,
+                           0x00, 0xfa, 0xac, 0x24 },
+               .klen   = 36,
+               .iv     = { 0xc1, 0x58, 0x5e, 0xf1, 0x5a, 0x43, 0xd8, 0x75 },
+               .input  = { 0xf0, 0x5e, 0x23, 0x1b, 0x38, 0x94, 0x61, 0x2c,
+                           0x49, 0xee, 0x00, 0x0b, 0x80, 0x4e, 0xb2, 0xa9,
+                           0xb8, 0x30, 0x6b, 0x50, 0x8f, 0x83, 0x9d, 0x6a,
+                           0x55, 0x30, 0x83, 0x1d, 0x93, 0x44, 0xaf, 0x1c },
+               .ilen   = 32,
+               .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+               .rlen   = 32,
+       },
+};
+
+static struct aead_testvec aes_gcm_enc_tv_template[] = {
+       { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
+               .klen   = 16,
+               .result = { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
+                           0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a },
+               .rlen   = 16,
+       }, {
+               .klen   = 16,
+               .ilen   = 16,
+               .result = { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
+                           0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78,
+                           0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
+                           0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf },
+               .rlen   = 32,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+               .klen   = 16,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
+               .ilen   = 64,
+               .result = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+                           0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+                           0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+                           0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+                           0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+                           0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+                           0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+                           0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85,
+                           0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+                           0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 },
+               .rlen   = 80,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+               .klen   = 16,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39 },
+               .ilen   = 60,
+               .assoc  = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xab, 0xad, 0xda, 0xd2 },
+               .alen   = 20,
+               .result = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+                           0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+                           0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+                           0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+                           0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+                           0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+                           0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+                           0x3d, 0x58, 0xe0, 0x91,
+                           0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
+                           0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 },
+               .rlen   = 76,
+       }, {
+               .klen   = 24,
+               .result = { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b,
+                           0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 },
+               .rlen   = 16,
+       }, {
+               .klen   = 24,
+               .ilen   = 16,
+               .result = { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
+                           0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00,
+                           0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
+                           0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb },
+               .rlen   = 32,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+                           0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c },
+               .klen   = 24,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
+               .ilen   = 64,
+               .result = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+                           0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+                           0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+                           0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+                           0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+                           0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+                           0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+                           0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56,
+                           0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
+                           0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 },
+               .rlen   = 80,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+                           0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c },
+               .klen   = 24,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39 },
+               .ilen   = 60,
+               .assoc  = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xab, 0xad, 0xda, 0xd2 },
+               .alen   = 20,
+               .result = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+                           0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+                           0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+                           0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+                           0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+                           0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+                           0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+                           0xcc, 0xda, 0x27, 0x10,
+                           0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
+                           0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c },
+               .rlen   = 76,
+               .np     = 2,
+               .tap    = { 32, 28 },
+               .anp    = 2,
+               .atap   = { 8, 12 }
+       }, {
+               .klen   = 32,
+               .result = { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
+                           0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b },
+               .rlen   = 16,
+       }
+};
+
+static struct aead_testvec aes_gcm_dec_tv_template[] = {
+       { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
+               .klen   = 32,
+               .input  = { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
+                           0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18,
+                           0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0,
+                           0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 },
+               .ilen   = 32,
+               .rlen   = 16,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+                           0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+               .klen   = 32,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+                           0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+                           0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+                           0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+                           0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+                           0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+                           0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+                           0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad,
+                           0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
+                           0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c },
+               .ilen   = 80,
+               .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
+               .rlen   = 64,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+                           0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+               .klen   = 32,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+                           0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+                           0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+                           0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+                           0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+                           0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+                           0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+                           0xbc, 0xc9, 0xf6, 0x62,
+                           0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
+                           0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b },
+               .ilen   = 76,
+               .assoc  = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xab, 0xad, 0xda, 0xd2 },
+               .alen   = 20,
+               .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39 },
+               .rlen   = 60,
+               .np     = 2,
+               .tap    = { 48, 28 },
+               .anp    = 3,
+               .atap   = { 8, 8, 4 }
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+               .klen   = 16,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+                           0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+                           0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+                           0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+                           0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+                           0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+                           0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+                           0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85,
+                           0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+                           0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 },
+               .ilen   = 80,
+               .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
+               .rlen   = 64,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+               .klen   = 16,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+                           0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+                           0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+                           0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+                           0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+                           0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+                           0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+                           0x3d, 0x58, 0xe0, 0x91,
+                           0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
+                           0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 },
+               .ilen   = 76,
+               .assoc  = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xab, 0xad, 0xda, 0xd2 },
+               .alen   = 20,
+               .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39 },
+               .rlen   = 60,
+       }, {
+               .klen   = 24,
+               .input  = { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
+                           0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00,
+                           0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
+                           0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb },
+               .ilen   = 32,
+               .rlen   = 16,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+                           0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c },
+               .klen   = 24,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+                           0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+                           0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+                           0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+                           0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+                           0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+                           0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+                           0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56,
+                           0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
+                           0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 },
+               .ilen   = 80,
+               .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
+               .rlen   = 64,
+       }, {
+               .key    = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                           0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+                           0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c },
+               .klen   = 24,
+               .iv     = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+                           0xde, 0xca, 0xf8, 0x88 },
+               .input  = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+                           0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+                           0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+                           0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+                           0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+                           0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+                           0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+                           0xcc, 0xda, 0x27, 0x10,
+                           0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
+                           0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c },
+               .ilen   = 76,
+               .assoc  = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+                           0xab, 0xad, 0xda, 0xd2 },
+               .alen   = 20,
+               .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+                           0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+                           0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+                           0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+                           0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+                           0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+                           0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+                           0xba, 0x63, 0x7b, 0x39 },
+               .rlen   = 60,
+       }
+};
+
+static struct aead_testvec aes_ccm_enc_tv_template[] = {
+       { /* From RFC 3610 */
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+               .alen   = 8,
+               .input  = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e },
+               .ilen   = 23,
+               .result = { 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2,
+                           0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80,
+                           0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17,
+                           0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 },
+               .rlen   = 31,
+       }, {
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x07, 0x06, 0x05, 0x04,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b },
+               .alen   = 12,
+               .input  = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+                           0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+                           0x1c, 0x1d, 0x1e, 0x1f },
+               .ilen   = 20,
+               .result = { 0xdc, 0xf1, 0xfb, 0x7b, 0x5d, 0x9e, 0x23, 0xfb,
+                           0x9d, 0x4e, 0x13, 0x12, 0x53, 0x65, 0x8a, 0xd8,
+                           0x6e, 0xbd, 0xca, 0x3e, 0x51, 0xe8, 0x3f, 0x07,
+                           0x7d, 0x9c, 0x2d, 0x93 },
+               .rlen   = 28,
+       }, {
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x09, 0x08,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+               .alen   = 8,
+               .input  = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                           0x20 },
+               .ilen   = 25,
+               .result = { 0x82, 0x53, 0x1a, 0x60, 0xcc, 0x24, 0x94, 0x5a,
+                           0x4b, 0x82, 0x79, 0x18, 0x1a, 0xb5, 0xc8, 0x4d,
+                           0xf2, 0x1c, 0xe7, 0xf9, 0xb7, 0x3f, 0x42, 0xe1,
+                           0x97, 0xea, 0x9c, 0x07, 0xe5, 0x6b, 0x5e, 0xb1,
+                           0x7e, 0x5f, 0x4e },
+               .rlen   = 35,
+       }, {
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x0c, 0x0b, 0x0a, 0x09,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b },
+               .alen   = 12,
+               .input  = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+                           0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+                           0x1c, 0x1d, 0x1e },
+               .ilen   = 19,
+               .result = { 0x07, 0x34, 0x25, 0x94, 0x15, 0x77, 0x85, 0x15,
+                           0x2b, 0x07, 0x40, 0x98, 0x33, 0x0a, 0xbb, 0x14,
+                           0x1b, 0x94, 0x7b, 0x56, 0x6a, 0xa9, 0x40, 0x6b,
+                           0x4d, 0x99, 0x99, 0x88, 0xdd },
+               .rlen   = 29,
+       }, {
+               .key    = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3,
+                           0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x33, 0x56, 0x8e, 0xf7, 0xb2, 0x63,
+                           0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 },
+               .assoc  = { 0x63, 0x01, 0x8f, 0x76, 0xdc, 0x8a, 0x1b, 0xcb },
+               .alen   = 8,
+               .input  = { 0x90, 0x20, 0xea, 0x6f, 0x91, 0xbd, 0xd8, 0x5a,
+                           0xfa, 0x00, 0x39, 0xba, 0x4b, 0xaf, 0xf9, 0xbf,
+                           0xb7, 0x9c, 0x70, 0x28, 0x94, 0x9c, 0xd0, 0xec },
+               .ilen   = 24,
+               .result = { 0x4c, 0xcb, 0x1e, 0x7c, 0xa9, 0x81, 0xbe, 0xfa,
+                           0xa0, 0x72, 0x6c, 0x55, 0xd3, 0x78, 0x06, 0x12,
+                           0x98, 0xc8, 0x5c, 0x92, 0x81, 0x4a, 0xbc, 0x33,
+                           0xc5, 0x2e, 0xe8, 0x1d, 0x7d, 0x77, 0xc0, 0x8a },
+               .rlen   = 32,
+       }, {
+               .key    = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3,
+                           0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0xd5, 0x60, 0x91, 0x2d, 0x3f, 0x70,
+                           0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 },
+               .assoc  = { 0xcd, 0x90, 0x44, 0xd2, 0xb7, 0x1f, 0xdb, 0x81,
+                           0x20, 0xea, 0x60, 0xc0 },
+               .alen   = 12,
+               .input  = { 0x64, 0x35, 0xac, 0xba, 0xfb, 0x11, 0xa8, 0x2e,
+                           0x2f, 0x07, 0x1d, 0x7c, 0xa4, 0xa5, 0xeb, 0xd9,
+                           0x3a, 0x80, 0x3b, 0xa8, 0x7f },
+               .ilen   = 21,
+               .result = { 0x00, 0x97, 0x69, 0xec, 0xab, 0xdf, 0x48, 0x62,
+                           0x55, 0x94, 0xc5, 0x92, 0x51, 0xe6, 0x03, 0x57,
+                           0x22, 0x67, 0x5e, 0x04, 0xc8, 0x47, 0x09, 0x9e,
+                           0x5a, 0xe0, 0x70, 0x45, 0x51 },
+               .rlen   = 29,
+       }, {
+               .key    = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3,
+                           0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x42, 0xff, 0xf8, 0xf1, 0x95, 0x1c,
+                           0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 },
+               .assoc  = { 0xd8, 0x5b, 0xc7, 0xe6, 0x9f, 0x94, 0x4f, 0xb8 },
+               .alen   = 8,
+               .input  = { 0x8a, 0x19, 0xb9, 0x50, 0xbc, 0xf7, 0x1a, 0x01,
+                           0x8e, 0x5e, 0x67, 0x01, 0xc9, 0x17, 0x87, 0x65,
+                           0x98, 0x09, 0xd6, 0x7d, 0xbe, 0xdd, 0x18 },
+               .ilen   = 23,
+               .result = { 0xbc, 0x21, 0x8d, 0xaa, 0x94, 0x74, 0x27, 0xb6,
+                           0xdb, 0x38, 0x6a, 0x99, 0xac, 0x1a, 0xef, 0x23,
+                           0xad, 0xe0, 0xb5, 0x29, 0x39, 0xcb, 0x6a, 0x63,
+                           0x7c, 0xf9, 0xbe, 0xc2, 0x40, 0x88, 0x97, 0xc6,
+                           0xba },
+               .rlen   = 33,
+       },
+};
+
+static struct aead_testvec aes_ccm_dec_tv_template[] = {
+       { /* From RFC 3610 */
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+               .alen   = 8,
+               .input  = { 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2,
+                           0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80,
+                           0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17,
+                           0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 },
+               .ilen   = 31,
+               .result = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e },
+               .rlen   = 23,
+       }, {
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x07, 0x06, 0x05, 0x04,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b },
+               .alen   = 12,
+               .input  = { 0xdc, 0xf1, 0xfb, 0x7b, 0x5d, 0x9e, 0x23, 0xfb,
+                           0x9d, 0x4e, 0x13, 0x12, 0x53, 0x65, 0x8a, 0xd8,
+                           0x6e, 0xbd, 0xca, 0x3e, 0x51, 0xe8, 0x3f, 0x07,
+                           0x7d, 0x9c, 0x2d, 0x93 },
+               .ilen   = 28,
+               .result = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+                           0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+                           0x1c, 0x1d, 0x1e, 0x1f },
+               .rlen   = 20,
+       }, {
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x09, 0x08,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+               .alen   = 8,
+               .input  = { 0x82, 0x53, 0x1a, 0x60, 0xcc, 0x24, 0x94, 0x5a,
+                           0x4b, 0x82, 0x79, 0x18, 0x1a, 0xb5, 0xc8, 0x4d,
+                           0xf2, 0x1c, 0xe7, 0xf9, 0xb7, 0x3f, 0x42, 0xe1,
+                           0x97, 0xea, 0x9c, 0x07, 0xe5, 0x6b, 0x5e, 0xb1,
+                           0x7e, 0x5f, 0x4e },
+               .ilen   = 35,
+               .result = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                           0x20 },
+               .rlen   = 25,
+       }, {
+               .key    = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                           0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x00, 0x00, 0x0c, 0x0b, 0x0a, 0x09,
+                           0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 },
+               .assoc  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0a, 0x0b },
+               .alen   = 12,
+               .input  = { 0x07, 0x34, 0x25, 0x94, 0x15, 0x77, 0x85, 0x15,
+                           0x2b, 0x07, 0x40, 0x98, 0x33, 0x0a, 0xbb, 0x14,
+                           0x1b, 0x94, 0x7b, 0x56, 0x6a, 0xa9, 0x40, 0x6b,
+                           0x4d, 0x99, 0x99, 0x88, 0xdd },
+               .ilen   = 29,
+               .result = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+                           0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+                           0x1c, 0x1d, 0x1e },
+               .rlen   = 19,
+       }, {
+               .key    = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3,
+                           0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x33, 0x56, 0x8e, 0xf7, 0xb2, 0x63,
+                           0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 },
+               .assoc  = { 0x63, 0x01, 0x8f, 0x76, 0xdc, 0x8a, 0x1b, 0xcb },
+               .alen   = 8,
+               .input  = { 0x4c, 0xcb, 0x1e, 0x7c, 0xa9, 0x81, 0xbe, 0xfa,
+                           0xa0, 0x72, 0x6c, 0x55, 0xd3, 0x78, 0x06, 0x12,
+                           0x98, 0xc8, 0x5c, 0x92, 0x81, 0x4a, 0xbc, 0x33,
+                           0xc5, 0x2e, 0xe8, 0x1d, 0x7d, 0x77, 0xc0, 0x8a },
+               .ilen   = 32,
+               .result = { 0x90, 0x20, 0xea, 0x6f, 0x91, 0xbd, 0xd8, 0x5a,
+                           0xfa, 0x00, 0x39, 0xba, 0x4b, 0xaf, 0xf9, 0xbf,
+                           0xb7, 0x9c, 0x70, 0x28, 0x94, 0x9c, 0xd0, 0xec },
+               .rlen   = 24,
+       }, {
+               .key    = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3,
+                           0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0xd5, 0x60, 0x91, 0x2d, 0x3f, 0x70,
+                           0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 },
+               .assoc  = { 0xcd, 0x90, 0x44, 0xd2, 0xb7, 0x1f, 0xdb, 0x81,
+                           0x20, 0xea, 0x60, 0xc0 },
+               .alen   = 12,
+               .input  = { 0x00, 0x97, 0x69, 0xec, 0xab, 0xdf, 0x48, 0x62,
+                           0x55, 0x94, 0xc5, 0x92, 0x51, 0xe6, 0x03, 0x57,
+                           0x22, 0x67, 0x5e, 0x04, 0xc8, 0x47, 0x09, 0x9e,
+                           0x5a, 0xe0, 0x70, 0x45, 0x51 },
+               .ilen   = 29,
+               .result = { 0x64, 0x35, 0xac, 0xba, 0xfb, 0x11, 0xa8, 0x2e,
+                           0x2f, 0x07, 0x1d, 0x7c, 0xa4, 0xa5, 0xeb, 0xd9,
+                           0x3a, 0x80, 0x3b, 0xa8, 0x7f },
+               .rlen   = 21,
+       }, {
+               .key    = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3,
+                           0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b },
+               .klen   = 16,
+               .iv     = { 0x01, 0x00, 0x42, 0xff, 0xf8, 0xf1, 0x95, 0x1c,
+                           0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 },
+               .assoc  = { 0xd8, 0x5b, 0xc7, 0xe6, 0x9f, 0x94, 0x4f, 0xb8 },
+               .alen   = 8,
+               .input  = { 0xbc, 0x21, 0x8d, 0xaa, 0x94, 0x74, 0x27, 0xb6,
+                           0xdb, 0x38, 0x6a, 0x99, 0xac, 0x1a, 0xef, 0x23,
+                           0xad, 0xe0, 0xb5, 0x29, 0x39, 0xcb, 0x6a, 0x63,
+                           0x7c, 0xf9, 0xbe, 0xc2, 0x40, 0x88, 0x97, 0xc6,
+                           0xba },
+               .ilen   = 33,
+               .result = { 0x8a, 0x19, 0xb9, 0x50, 0xbc, 0xf7, 0x1a, 0x01,
+                           0x8e, 0x5e, 0x67, 0x01, 0xc9, 0x17, 0x87, 0x65,
+                           0x98, 0x09, 0xd6, 0x7d, 0xbe, 0xdd, 0x18 },
+               .rlen   = 23,
+       },
+};
+
 /* Cast5 test vectors from RFC 2144 */
 #define CAST5_ENC_TEST_VECTORS 3
 #define CAST5_DEC_TEST_VECTORS 3
@@ -4317,6 +6425,1211 @@ static struct cipher_testvec seed_dec_tv_template[] = {
        }
 };
 
+#define SALSA20_STREAM_ENC_TEST_VECTORS 5
+static struct cipher_testvec salsa20_stream_enc_tv_template[] = {
+       /*
+       * Testvectors from verified.test-vectors submitted to ECRYPT.
+       * They are truncated to size 39, 64, 111, 129 to test a variety
+       * of input length.
+       */
+       { /* Set 3, vector 0 */
+               .key    = {
+                           0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                           0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+                         },
+               .klen   = 16,
+               .iv     = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+               .input  = {
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         },
+               .ilen   = 39,
+               .result = {
+                           0x2D, 0xD5, 0xC3, 0xF7, 0xBA, 0x2B, 0x20, 0xF7,
+                            0x68, 0x02, 0x41, 0x0C, 0x68, 0x86, 0x88, 0x89,
+                            0x5A, 0xD8, 0xC1, 0xBD, 0x4E, 0xA6, 0xC9, 0xB1,
+                            0x40, 0xFB, 0x9B, 0x90, 0xE2, 0x10, 0x49, 0xBF,
+                            0x58, 0x3F, 0x52, 0x79, 0x70, 0xEB, 0xC1,
+                       },
+               .rlen   = 39,
+       }, { /* Set 5, vector 0 */
+               .key    = {
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+                         },
+               .klen   = 16,
+               .iv     = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+               .input  = {
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         },
+               .ilen   = 64,
+               .result = {
+                           0xB6, 0x6C, 0x1E, 0x44, 0x46, 0xDD, 0x95, 0x57,
+                            0xE5, 0x78, 0xE2, 0x23, 0xB0, 0xB7, 0x68, 0x01,
+                            0x7B, 0x23, 0xB2, 0x67, 0xBB, 0x02, 0x34, 0xAE,
+                            0x46, 0x26, 0xBF, 0x44, 0x3F, 0x21, 0x97, 0x76,
+                            0x43, 0x6F, 0xB1, 0x9F, 0xD0, 0xE8, 0x86, 0x6F,
+                            0xCD, 0x0D, 0xE9, 0xA9, 0x53, 0x8F, 0x4A, 0x09,
+                            0xCA, 0x9A, 0xC0, 0x73, 0x2E, 0x30, 0xBC, 0xF9,
+                            0x8E, 0x4F, 0x13, 0xE4, 0xB9, 0xE2, 0x01, 0xD9,
+                         },
+               .rlen   = 64,
+       }, { /* Set 3, vector 27 */
+               .key    = {
+                           0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+                           0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
+                            0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
+                           0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A
+                         },
+               .klen   = 32,
+               .iv     = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+               .input  = {
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         },
+               .ilen   = 111,
+               .result = {
+                           0xAE, 0x39, 0x50, 0x8E, 0xAC, 0x9A, 0xEC, 0xE7,
+                            0xBF, 0x97, 0xBB, 0x20, 0xB9, 0xDE, 0xE4, 0x1F,
+                            0x87, 0xD9, 0x47, 0xF8, 0x28, 0x91, 0x35, 0x98,
+                            0xDB, 0x72, 0xCC, 0x23, 0x29, 0x48, 0x56, 0x5E,
+                            0x83, 0x7E, 0x0B, 0xF3, 0x7D, 0x5D, 0x38, 0x7B,
+                            0x2D, 0x71, 0x02, 0xB4, 0x3B, 0xB5, 0xD8, 0x23,
+                            0xB0, 0x4A, 0xDF, 0x3C, 0xEC, 0xB6, 0xD9, 0x3B,
+                            0x9B, 0xA7, 0x52, 0xBE, 0xC5, 0xD4, 0x50, 0x59,
+
+                            0x15, 0x14, 0xB4, 0x0E, 0x40, 0xE6, 0x53, 0xD1,
+                            0x83, 0x9C, 0x5B, 0xA0, 0x92, 0x29, 0x6B, 0x5E,
+                            0x96, 0x5B, 0x1E, 0x2F, 0xD3, 0xAC, 0xC1, 0x92,
+                            0xB1, 0x41, 0x3F, 0x19, 0x2F, 0xC4, 0x3B, 0xC6,
+                            0x95, 0x46, 0x45, 0x54, 0xE9, 0x75, 0x03, 0x08,
+                            0x44, 0xAF, 0xE5, 0x8A, 0x81, 0x12, 0x09,
+                         },
+               .rlen   = 111,
+
+       }, { /* Set 5, vector 27 */
+               .key    = {
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+                         },
+               .klen   = 32,
+               .iv     = { 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 },
+               .input  = {
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+                           0x00,
+                         },
+               .ilen   = 129,
+               .result = {
+                           0xD2, 0xDB, 0x1A, 0x5C, 0xF1, 0xC1, 0xAC, 0xDB,
+                            0xE8, 0x1A, 0x7A, 0x43, 0x40, 0xEF, 0x53, 0x43,
+                            0x5E, 0x7F, 0x4B, 0x1A, 0x50, 0x52, 0x3F, 0x8D,
+                            0x28, 0x3D, 0xCF, 0x85, 0x1D, 0x69, 0x6E, 0x60,
+                            0xF2, 0xDE, 0x74, 0x56, 0x18, 0x1B, 0x84, 0x10,
+                            0xD4, 0x62, 0xBA, 0x60, 0x50, 0xF0, 0x61, 0xF2,
+                            0x1C, 0x78, 0x7F, 0xC1, 0x24, 0x34, 0xAF, 0x58,
+                            0xBF, 0x2C, 0x59, 0xCA, 0x90, 0x77, 0xF3, 0xB0,
+
+                            0x5B, 0x4A, 0xDF, 0x89, 0xCE, 0x2C, 0x2F, 0xFC,
+                            0x67, 0xF0, 0xE3, 0x45, 0xE8, 0xB3, 0xB3, 0x75,
+                            0xA0, 0x95, 0x71, 0xA1, 0x29, 0x39, 0x94, 0xCA,
+                            0x45, 0x2F, 0xBD, 0xCB, 0x10, 0xB6, 0xBE, 0x9F,
+                            0x8E, 0xF9, 0xB2, 0x01, 0x0A, 0x5A, 0x0A, 0xB7,
+                            0x6B, 0x9D, 0x70, 0x8E, 0x4B, 0xD6, 0x2F, 0xCD,
+                            0x2E, 0x40, 0x48, 0x75, 0xE9, 0xE2, 0x21, 0x45,
+                            0x0B, 0xC9, 0xB6, 0xB5, 0x66, 0xBC, 0x9A, 0x59,
+
+                            0x5A,
+                         },
+               .rlen   = 129,
+       }, { /* large test vector generated using Crypto++ */
+               .key = {
+                       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+               },
+               .klen = 32,
+               .iv = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+               .input = {
+                       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+                       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+                       0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+                       0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+                       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+                       0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+                       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+                       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+                       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+                       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+                       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+                       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+                       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+                       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+                       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+                       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+                       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+                       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+                       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+                       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+                       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+                       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+                       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+                       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+                       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+                       0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
+                       0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d,
+                       0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45,
+                       0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d,
+                       0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75,
+                       0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d,
+                       0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5,
+                       0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
+                       0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5,
+                       0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed,
+                       0xf0, 0xf3, 0xf6, 0xf9, 0xfc, 0xff, 0x02, 0x05,
+                       0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1d,
+                       0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x35,
+                       0x38, 0x3b, 0x3e, 0x41, 0x44, 0x47, 0x4a, 0x4d,
+                       0x50, 0x53, 0x56, 0x59, 0x5c, 0x5f, 0x62, 0x65,
+                       0x68, 0x6b, 0x6e, 0x71, 0x74, 0x77, 0x7a, 0x7d,
+                       0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95,
+                       0x98, 0x9b, 0x9e, 0xa1, 0xa4, 0xa7, 0xaa, 0xad,
+                       0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc2, 0xc5,
+                       0xc8, 0xcb, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd,
+                       0xe0, 0xe3, 0xe6, 0xe9, 0xec, 0xef, 0xf2, 0xf5,
+                       0xf8, 0xfb, 0xfe, 0x01, 0x04, 0x07, 0x0a, 0x0d,
+                       0x10, 0x13, 0x16, 0x19, 0x1c, 0x1f, 0x22, 0x25,
+                       0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3d,
+                       0x40, 0x43, 0x46, 0x49, 0x4c, 0x4f, 0x52, 0x55,
+                       0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d,
+                       0x70, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85,
+                       0x88, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9d,
+                       0xa0, 0xa3, 0xa6, 0xa9, 0xac, 0xaf, 0xb2, 0xb5,
+                       0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
+                       0xd0, 0xd3, 0xd6, 0xd9, 0xdc, 0xdf, 0xe2, 0xe5,
+                       0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7, 0xfa, 0xfd,
+                       0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, 0x23,
+                       0x28, 0x2d, 0x32, 0x37, 0x3c, 0x41, 0x46, 0x4b,
+                       0x50, 0x55, 0x5a, 0x5f, 0x64, 0x69, 0x6e, 0x73,
+                       0x78, 0x7d, 0x82, 0x87, 0x8c, 0x91, 0x96, 0x9b,
+                       0xa0, 0xa5, 0xaa, 0xaf, 0xb4, 0xb9, 0xbe, 0xc3,
+                       0xc8, 0xcd, 0xd2, 0xd7, 0xdc, 0xe1, 0xe6, 0xeb,
+                       0xf0, 0xf5, 0xfa, 0xff, 0x04, 0x09, 0x0e, 0x13,
+                       0x18, 0x1d, 0x22, 0x27, 0x2c, 0x31, 0x36, 0x3b,
+                       0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59, 0x5e, 0x63,
+                       0x68, 0x6d, 0x72, 0x77, 0x7c, 0x81, 0x86, 0x8b,
+                       0x90, 0x95, 0x9a, 0x9f, 0xa4, 0xa9, 0xae, 0xb3,
+                       0xb8, 0xbd, 0xc2, 0xc7, 0xcc, 0xd1, 0xd6, 0xdb,
+                       0xe0, 0xe5, 0xea, 0xef, 0xf4, 0xf9, 0xfe, 0x03,
+                       0x08, 0x0d, 0x12, 0x17, 0x1c, 0x21, 0x26, 0x2b,
+                       0x30, 0x35, 0x3a, 0x3f, 0x44, 0x49, 0x4e, 0x53,
+                       0x58, 0x5d, 0x62, 0x67, 0x6c, 0x71, 0x76, 0x7b,
+                       0x80, 0x85, 0x8a, 0x8f, 0x94, 0x99, 0x9e, 0xa3,
+                       0xa8, 0xad, 0xb2, 0xb7, 0xbc, 0xc1, 0xc6, 0xcb,
+                       0xd0, 0xd5, 0xda, 0xdf, 0xe4, 0xe9, 0xee, 0xf3,
+                       0xf8, 0xfd, 0x02, 0x07, 0x0c, 0x11, 0x16, 0x1b,
+                       0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3e, 0x43,
+                       0x48, 0x4d, 0x52, 0x57, 0x5c, 0x61, 0x66, 0x6b,
+                       0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93,
+                       0x98, 0x9d, 0xa2, 0xa7, 0xac, 0xb1, 0xb6, 0xbb,
+                       0xc0, 0xc5, 0xca, 0xcf, 0xd4, 0xd9, 0xde, 0xe3,
+                       0xe8, 0xed, 0xf2, 0xf7, 0xfc, 0x01, 0x06, 0x0b,
+                       0x10, 0x15, 0x1a, 0x1f, 0x24, 0x29, 0x2e, 0x33,
+                       0x38, 0x3d, 0x42, 0x47, 0x4c, 0x51, 0x56, 0x5b,
+                       0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7e, 0x83,
+                       0x88, 0x8d, 0x92, 0x97, 0x9c, 0xa1, 0xa6, 0xab,
+                       0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xce, 0xd3,
+                       0xd8, 0xdd, 0xe2, 0xe7, 0xec, 0xf1, 0xf6, 0xfb,
+                       0x00, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31,
+                       0x38, 0x3f, 0x46, 0x4d, 0x54, 0x5b, 0x62, 0x69,
+                       0x70, 0x77, 0x7e, 0x85, 0x8c, 0x93, 0x9a, 0xa1,
+                       0xa8, 0xaf, 0xb6, 0xbd, 0xc4, 0xcb, 0xd2, 0xd9,
+                       0xe0, 0xe7, 0xee, 0xf5, 0xfc, 0x03, 0x0a, 0x11,
+                       0x18, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x42, 0x49,
+                       0x50, 0x57, 0x5e, 0x65, 0x6c, 0x73, 0x7a, 0x81,
+                       0x88, 0x8f, 0x96, 0x9d, 0xa4, 0xab, 0xb2, 0xb9,
+                       0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1,
+                       0xf8, 0xff, 0x06, 0x0d, 0x14, 0x1b, 0x22, 0x29,
+                       0x30, 0x37, 0x3e, 0x45, 0x4c, 0x53, 0x5a, 0x61,
+                       0x68, 0x6f, 0x76, 0x7d, 0x84, 0x8b, 0x92, 0x99,
+                       0xa0, 0xa7, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd1,
+                       0xd8, 0xdf, 0xe6, 0xed, 0xf4, 0xfb, 0x02, 0x09,
+                       0x10, 0x17, 0x1e, 0x25, 0x2c, 0x33, 0x3a, 0x41,
+                       0x48, 0x4f, 0x56, 0x5d, 0x64, 0x6b, 0x72, 0x79,
+                       0x80, 0x87, 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1,
+                       0xb8, 0xbf, 0xc6, 0xcd, 0xd4, 0xdb, 0xe2, 0xe9,
+                       0xf0, 0xf7, 0xfe, 0x05, 0x0c, 0x13, 0x1a, 0x21,
+                       0x28, 0x2f, 0x36, 0x3d, 0x44, 0x4b, 0x52, 0x59,
+                       0x60, 0x67, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x91,
+                       0x98, 0x9f, 0xa6, 0xad, 0xb4, 0xbb, 0xc2, 0xc9,
+                       0xd0, 0xd7, 0xde, 0xe5, 0xec, 0xf3, 0xfa, 0x01,
+                       0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2b, 0x32, 0x39,
+                       0x40, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71,
+                       0x78, 0x7f, 0x86, 0x8d, 0x94, 0x9b, 0xa2, 0xa9,
+                       0xb0, 0xb7, 0xbe, 0xc5, 0xcc, 0xd3, 0xda, 0xe1,
+                       0xe8, 0xef, 0xf6, 0xfd, 0x04, 0x0b, 0x12, 0x19,
+                       0x20, 0x27, 0x2e, 0x35, 0x3c, 0x43, 0x4a, 0x51,
+                       0x58, 0x5f, 0x66, 0x6d, 0x74, 0x7b, 0x82, 0x89,
+                       0x90, 0x97, 0x9e, 0xa5, 0xac, 0xb3, 0xba, 0xc1,
+                       0xc8, 0xcf, 0xd6, 0xdd, 0xe4, 0xeb, 0xf2, 0xf9,
+                       0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+                       0x48, 0x51, 0x5a, 0x63, 0x6c, 0x75, 0x7e, 0x87,
+                       0x90, 0x99, 0xa2, 0xab, 0xb4, 0xbd, 0xc6, 0xcf,
+                       0xd8, 0xe1, 0xea, 0xf3, 0xfc, 0x05, 0x0e, 0x17,
+                       0x20, 0x29, 0x32, 0x3b, 0x44, 0x4d, 0x56, 0x5f,
+                       0x68, 0x71, 0x7a, 0x83, 0x8c, 0x95, 0x9e, 0xa7,
+                       0xb0, 0xb9, 0xc2, 0xcb, 0xd4, 0xdd, 0xe6, 0xef,
+                       0xf8, 0x01, 0x0a, 0x13, 0x1c, 0x25, 0x2e, 0x37,
+                       0x40, 0x49, 0x52, 0x5b, 0x64, 0x6d, 0x76, 0x7f,
+                       0x88, 0x91, 0x9a, 0xa3, 0xac, 0xb5, 0xbe, 0xc7,
+                       0xd0, 0xd9, 0xe2, 0xeb, 0xf4, 0xfd, 0x06, 0x0f,
+                       0x18, 0x21, 0x2a, 0x33, 0x3c, 0x45, 0x4e, 0x57,
+                       0x60, 0x69, 0x72, 0x7b, 0x84, 0x8d, 0x96, 0x9f,
+                       0xa8, 0xb1, 0xba, 0xc3, 0xcc, 0xd5, 0xde, 0xe7,
+                       0xf0, 0xf9, 0x02, 0x0b, 0x14, 0x1d, 0x26, 0x2f,
+                       0x38, 0x41, 0x4a, 0x53, 0x5c, 0x65, 0x6e, 0x77,
+                       0x80, 0x89, 0x92, 0x9b, 0xa4, 0xad, 0xb6, 0xbf,
+                       0xc8, 0xd1, 0xda, 0xe3, 0xec, 0xf5, 0xfe, 0x07,
+                       0x10, 0x19, 0x22, 0x2b, 0x34, 0x3d, 0x46, 0x4f,
+                       0x58, 0x61, 0x6a, 0x73, 0x7c, 0x85, 0x8e, 0x97,
+                       0xa0, 0xa9, 0xb2, 0xbb, 0xc4, 0xcd, 0xd6, 0xdf,
+                       0xe8, 0xf1, 0xfa, 0x03, 0x0c, 0x15, 0x1e, 0x27,
+                       0x30, 0x39, 0x42, 0x4b, 0x54, 0x5d, 0x66, 0x6f,
+                       0x78, 0x81, 0x8a, 0x93, 0x9c, 0xa5, 0xae, 0xb7,
+                       0xc0, 0xc9, 0xd2, 0xdb, 0xe4, 0xed, 0xf6, 0xff,
+                       0x08, 0x11, 0x1a, 0x23, 0x2c, 0x35, 0x3e, 0x47,
+                       0x50, 0x59, 0x62, 0x6b, 0x74, 0x7d, 0x86, 0x8f,
+                       0x98, 0xa1, 0xaa, 0xb3, 0xbc, 0xc5, 0xce, 0xd7,
+                       0xe0, 0xe9, 0xf2, 0xfb, 0x04, 0x0d, 0x16, 0x1f,
+                       0x28, 0x31, 0x3a, 0x43, 0x4c, 0x55, 0x5e, 0x67,
+                       0x70, 0x79, 0x82, 0x8b, 0x94, 0x9d, 0xa6, 0xaf,
+                       0xb8, 0xc1, 0xca, 0xd3, 0xdc, 0xe5, 0xee, 0xf7,
+                       0x00, 0x0b, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d,
+                       0x58, 0x63, 0x6e, 0x79, 0x84, 0x8f, 0x9a, 0xa5,
+                       0xb0, 0xbb, 0xc6, 0xd1, 0xdc, 0xe7, 0xf2, 0xfd,
+                       0x08, 0x13, 0x1e, 0x29, 0x34, 0x3f, 0x4a, 0x55,
+                       0x60, 0x6b, 0x76, 0x81, 0x8c, 0x97, 0xa2, 0xad,
+                       0xb8, 0xc3, 0xce, 0xd9, 0xe4, 0xef, 0xfa, 0x05,
+                       0x10, 0x1b, 0x26, 0x31, 0x3c, 0x47, 0x52, 0x5d,
+                       0x68, 0x73, 0x7e, 0x89, 0x94, 0x9f, 0xaa, 0xb5,
+                       0xc0, 0xcb, 0xd6, 0xe1, 0xec, 0xf7, 0x02, 0x0d,
+                       0x18, 0x23, 0x2e, 0x39, 0x44, 0x4f, 0x5a, 0x65,
+                       0x70, 0x7b, 0x86, 0x91, 0x9c, 0xa7, 0xb2, 0xbd,
+                       0xc8, 0xd3, 0xde, 0xe9, 0xf4, 0xff, 0x0a, 0x15,
+                       0x20, 0x2b, 0x36, 0x41, 0x4c, 0x57, 0x62, 0x6d,
+                       0x78, 0x83, 0x8e, 0x99, 0xa4, 0xaf, 0xba, 0xc5,
+                       0xd0, 0xdb, 0xe6, 0xf1, 0xfc, 0x07, 0x12, 0x1d,
+                       0x28, 0x33, 0x3e, 0x49, 0x54, 0x5f, 0x6a, 0x75,
+                       0x80, 0x8b, 0x96, 0xa1, 0xac, 0xb7, 0xc2, 0xcd,
+                       0xd8, 0xe3, 0xee, 0xf9, 0x04, 0x0f, 0x1a, 0x25,
+                       0x30, 0x3b, 0x46, 0x51, 0x5c, 0x67, 0x72, 0x7d,
+                       0x88, 0x93, 0x9e, 0xa9, 0xb4, 0xbf, 0xca, 0xd5,
+                       0xe0, 0xeb, 0xf6, 0x01, 0x0c, 0x17, 0x22, 0x2d,
+                       0x38, 0x43, 0x4e, 0x59, 0x64, 0x6f, 0x7a, 0x85,
+                       0x90, 0x9b, 0xa6, 0xb1, 0xbc, 0xc7, 0xd2, 0xdd,
+                       0xe8, 0xf3, 0xfe, 0x09, 0x14, 0x1f, 0x2a, 0x35,
+                       0x40, 0x4b, 0x56, 0x61, 0x6c, 0x77, 0x82, 0x8d,
+                       0x98, 0xa3, 0xae, 0xb9, 0xc4, 0xcf, 0xda, 0xe5,
+                       0xf0, 0xfb, 0x06, 0x11, 0x1c, 0x27, 0x32, 0x3d,
+                       0x48, 0x53, 0x5e, 0x69, 0x74, 0x7f, 0x8a, 0x95,
+                       0xa0, 0xab, 0xb6, 0xc1, 0xcc, 0xd7, 0xe2, 0xed,
+                       0xf8, 0x03, 0x0e, 0x19, 0x24, 0x2f, 0x3a, 0x45,
+                       0x50, 0x5b, 0x66, 0x71, 0x7c, 0x87, 0x92, 0x9d,
+                       0xa8, 0xb3, 0xbe, 0xc9, 0xd4, 0xdf, 0xea, 0xf5,
+                       0x00, 0x0d, 0x1a, 0x27, 0x34, 0x41, 0x4e, 0x5b,
+                       0x68, 0x75, 0x82, 0x8f, 0x9c, 0xa9, 0xb6, 0xc3,
+                       0xd0, 0xdd, 0xea, 0xf7, 0x04, 0x11, 0x1e, 0x2b,
+                       0x38, 0x45, 0x52, 0x5f, 0x6c, 0x79, 0x86, 0x93,
+                       0xa0, 0xad, 0xba, 0xc7, 0xd4, 0xe1, 0xee, 0xfb,
+                       0x08, 0x15, 0x22, 0x2f, 0x3c, 0x49, 0x56, 0x63,
+                       0x70, 0x7d, 0x8a, 0x97, 0xa4, 0xb1, 0xbe, 0xcb,
+                       0xd8, 0xe5, 0xf2, 0xff, 0x0c, 0x19, 0x26, 0x33,
+                       0x40, 0x4d, 0x5a, 0x67, 0x74, 0x81, 0x8e, 0x9b,
+                       0xa8, 0xb5, 0xc2, 0xcf, 0xdc, 0xe9, 0xf6, 0x03,
+                       0x10, 0x1d, 0x2a, 0x37, 0x44, 0x51, 0x5e, 0x6b,
+                       0x78, 0x85, 0x92, 0x9f, 0xac, 0xb9, 0xc6, 0xd3,
+                       0xe0, 0xed, 0xfa, 0x07, 0x14, 0x21, 0x2e, 0x3b,
+                       0x48, 0x55, 0x62, 0x6f, 0x7c, 0x89, 0x96, 0xa3,
+                       0xb0, 0xbd, 0xca, 0xd7, 0xe4, 0xf1, 0xfe, 0x0b,
+                       0x18, 0x25, 0x32, 0x3f, 0x4c, 0x59, 0x66, 0x73,
+                       0x80, 0x8d, 0x9a, 0xa7, 0xb4, 0xc1, 0xce, 0xdb,
+                       0xe8, 0xf5, 0x02, 0x0f, 0x1c, 0x29, 0x36, 0x43,
+                       0x50, 0x5d, 0x6a, 0x77, 0x84, 0x91, 0x9e, 0xab,
+                       0xb8, 0xc5, 0xd2, 0xdf, 0xec, 0xf9, 0x06, 0x13,
+                       0x20, 0x2d, 0x3a, 0x47, 0x54, 0x61, 0x6e, 0x7b,
+                       0x88, 0x95, 0xa2, 0xaf, 0xbc, 0xc9, 0xd6, 0xe3,
+                       0xf0, 0xfd, 0x0a, 0x17, 0x24, 0x31, 0x3e, 0x4b,
+                       0x58, 0x65, 0x72, 0x7f, 0x8c, 0x99, 0xa6, 0xb3,
+                       0xc0, 0xcd, 0xda, 0xe7, 0xf4, 0x01, 0x0e, 0x1b,
+                       0x28, 0x35, 0x42, 0x4f, 0x5c, 0x69, 0x76, 0x83,
+                       0x90, 0x9d, 0xaa, 0xb7, 0xc4, 0xd1, 0xde, 0xeb,
+                       0xf8, 0x05, 0x12, 0x1f, 0x2c, 0x39, 0x46, 0x53,
+                       0x60, 0x6d, 0x7a, 0x87, 0x94, 0xa1, 0xae, 0xbb,
+                       0xc8, 0xd5, 0xe2, 0xef, 0xfc, 0x09, 0x16, 0x23,
+                       0x30, 0x3d, 0x4a, 0x57, 0x64, 0x71, 0x7e, 0x8b,
+                       0x98, 0xa5, 0xb2, 0xbf, 0xcc, 0xd9, 0xe6, 0xf3,
+                       0x00, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69,
+                       0x78, 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1,
+                       0xf0, 0xff, 0x0e, 0x1d, 0x2c, 0x3b, 0x4a, 0x59,
+                       0x68, 0x77, 0x86, 0x95, 0xa4, 0xb3, 0xc2, 0xd1,
+                       0xe0, 0xef, 0xfe, 0x0d, 0x1c, 0x2b, 0x3a, 0x49,
+                       0x58, 0x67, 0x76, 0x85, 0x94, 0xa3, 0xb2, 0xc1,
+                       0xd0, 0xdf, 0xee, 0xfd, 0x0c, 0x1b, 0x2a, 0x39,
+                       0x48, 0x57, 0x66, 0x75, 0x84, 0x93, 0xa2, 0xb1,
+                       0xc0, 0xcf, 0xde, 0xed, 0xfc, 0x0b, 0x1a, 0x29,
+                       0x38, 0x47, 0x56, 0x65, 0x74, 0x83, 0x92, 0xa1,
+                       0xb0, 0xbf, 0xce, 0xdd, 0xec, 0xfb, 0x0a, 0x19,
+                       0x28, 0x37, 0x46, 0x55, 0x64, 0x73, 0x82, 0x91,
+                       0xa0, 0xaf, 0xbe, 0xcd, 0xdc, 0xeb, 0xfa, 0x09,
+                       0x18, 0x27, 0x36, 0x45, 0x54, 0x63, 0x72, 0x81,
+                       0x90, 0x9f, 0xae, 0xbd, 0xcc, 0xdb, 0xea, 0xf9,
+                       0x08, 0x17, 0x26, 0x35, 0x44, 0x53, 0x62, 0x71,
+                       0x80, 0x8f, 0x9e, 0xad, 0xbc, 0xcb, 0xda, 0xe9,
+                       0xf8, 0x07, 0x16, 0x25, 0x34, 0x43, 0x52, 0x61,
+                       0x70, 0x7f, 0x8e, 0x9d, 0xac, 0xbb, 0xca, 0xd9,
+                       0xe8, 0xf7, 0x06, 0x15, 0x24, 0x33, 0x42, 0x51,
+                       0x60, 0x6f, 0x7e, 0x8d, 0x9c, 0xab, 0xba, 0xc9,
+                       0xd8, 0xe7, 0xf6, 0x05, 0x14, 0x23, 0x32, 0x41,
+                       0x50, 0x5f, 0x6e, 0x7d, 0x8c, 0x9b, 0xaa, 0xb9,
+                       0xc8, 0xd7, 0xe6, 0xf5, 0x04, 0x13, 0x22, 0x31,
+                       0x40, 0x4f, 0x5e, 0x6d, 0x7c, 0x8b, 0x9a, 0xa9,
+                       0xb8, 0xc7, 0xd6, 0xe5, 0xf4, 0x03, 0x12, 0x21,
+                       0x30, 0x3f, 0x4e, 0x5d, 0x6c, 0x7b, 0x8a, 0x99,
+                       0xa8, 0xb7, 0xc6, 0xd5, 0xe4, 0xf3, 0x02, 0x11,
+                       0x20, 0x2f, 0x3e, 0x4d, 0x5c, 0x6b, 0x7a, 0x89,
+                       0x98, 0xa7, 0xb6, 0xc5, 0xd4, 0xe3, 0xf2, 0x01,
+                       0x10, 0x1f, 0x2e, 0x3d, 0x4c, 0x5b, 0x6a, 0x79,
+                       0x88, 0x97, 0xa6, 0xb5, 0xc4, 0xd3, 0xe2, 0xf1,
+                       0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                       0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+                       0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87,
+                       0x98, 0xa9, 0xba, 0xcb, 0xdc, 0xed, 0xfe, 0x0f,
+                       0x20, 0x31, 0x42, 0x53, 0x64, 0x75, 0x86, 0x97,
+                       0xa8, 0xb9, 0xca, 0xdb, 0xec, 0xfd, 0x0e, 0x1f,
+                       0x30, 0x41, 0x52, 0x63, 0x74, 0x85, 0x96, 0xa7,
+                       0xb8, 0xc9, 0xda, 0xeb, 0xfc, 0x0d, 0x1e, 0x2f,
+                       0x40, 0x51, 0x62, 0x73, 0x84, 0x95, 0xa6, 0xb7,
+                       0xc8, 0xd9, 0xea, 0xfb, 0x0c, 0x1d, 0x2e, 0x3f,
+                       0x50, 0x61, 0x72, 0x83, 0x94, 0xa5, 0xb6, 0xc7,
+                       0xd8, 0xe9, 0xfa, 0x0b, 0x1c, 0x2d, 0x3e, 0x4f,
+                       0x60, 0x71, 0x82, 0x93, 0xa4, 0xb5, 0xc6, 0xd7,
+                       0xe8, 0xf9, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f,
+                       0x70, 0x81, 0x92, 0xa3, 0xb4, 0xc5, 0xd6, 0xe7,
+                       0xf8, 0x09, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f,
+                       0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7,
+                       0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f,
+                       0x90, 0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6, 0x07,
+                       0x18, 0x29, 0x3a, 0x4b, 0x5c, 0x6d, 0x7e, 0x8f,
+                       0xa0, 0xb1, 0xc2, 0xd3, 0xe4, 0xf5, 0x06, 0x17,
+                       0x28, 0x39, 0x4a, 0x5b, 0x6c, 0x7d, 0x8e, 0x9f,
+                       0xb0, 0xc1, 0xd2, 0xe3, 0xf4, 0x05, 0x16, 0x27,
+                       0x38, 0x49, 0x5a, 0x6b, 0x7c, 0x8d, 0x9e, 0xaf,
+                       0xc0, 0xd1, 0xe2, 0xf3, 0x04, 0x15, 0x26, 0x37,
+                       0x48, 0x59, 0x6a, 0x7b, 0x8c, 0x9d, 0xae, 0xbf,
+                       0xd0, 0xe1, 0xf2, 0x03, 0x14, 0x25, 0x36, 0x47,
+                       0x58, 0x69, 0x7a, 0x8b, 0x9c, 0xad, 0xbe, 0xcf,
+                       0xe0, 0xf1, 0x02, 0x13, 0x24, 0x35, 0x46, 0x57,
+                       0x68, 0x79, 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf,
+                       0xf0, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
+                       0x78, 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef,
+                       0x00, 0x13, 0x26, 0x39, 0x4c, 0x5f, 0x72, 0x85,
+                       0x98, 0xab, 0xbe, 0xd1, 0xe4, 0xf7, 0x0a, 0x1d,
+                       0x30, 0x43, 0x56, 0x69, 0x7c, 0x8f, 0xa2, 0xb5,
+                       0xc8, 0xdb, 0xee, 0x01, 0x14, 0x27, 0x3a, 0x4d,
+                       0x60, 0x73, 0x86, 0x99, 0xac, 0xbf, 0xd2, 0xe5,
+                       0xf8, 0x0b, 0x1e, 0x31, 0x44, 0x57, 0x6a, 0x7d,
+                       0x90, 0xa3, 0xb6, 0xc9, 0xdc, 0xef, 0x02, 0x15,
+                       0x28, 0x3b, 0x4e, 0x61, 0x74, 0x87, 0x9a, 0xad,
+                       0xc0, 0xd3, 0xe6, 0xf9, 0x0c, 0x1f, 0x32, 0x45,
+                       0x58, 0x6b, 0x7e, 0x91, 0xa4, 0xb7, 0xca, 0xdd,
+                       0xf0, 0x03, 0x16, 0x29, 0x3c, 0x4f, 0x62, 0x75,
+                       0x88, 0x9b, 0xae, 0xc1, 0xd4, 0xe7, 0xfa, 0x0d,
+                       0x20, 0x33, 0x46, 0x59, 0x6c, 0x7f, 0x92, 0xa5,
+                       0xb8, 0xcb, 0xde, 0xf1, 0x04, 0x17, 0x2a, 0x3d,
+                       0x50, 0x63, 0x76, 0x89, 0x9c, 0xaf, 0xc2, 0xd5,
+                       0xe8, 0xfb, 0x0e, 0x21, 0x34, 0x47, 0x5a, 0x6d,
+                       0x80, 0x93, 0xa6, 0xb9, 0xcc, 0xdf, 0xf2, 0x05,
+                       0x18, 0x2b, 0x3e, 0x51, 0x64, 0x77, 0x8a, 0x9d,
+                       0xb0, 0xc3, 0xd6, 0xe9, 0xfc, 0x0f, 0x22, 0x35,
+                       0x48, 0x5b, 0x6e, 0x81, 0x94, 0xa7, 0xba, 0xcd,
+                       0xe0, 0xf3, 0x06, 0x19, 0x2c, 0x3f, 0x52, 0x65,
+                       0x78, 0x8b, 0x9e, 0xb1, 0xc4, 0xd7, 0xea, 0xfd,
+                       0x10, 0x23, 0x36, 0x49, 0x5c, 0x6f, 0x82, 0x95,
+                       0xa8, 0xbb, 0xce, 0xe1, 0xf4, 0x07, 0x1a, 0x2d,
+                       0x40, 0x53, 0x66, 0x79, 0x8c, 0x9f, 0xb2, 0xc5,
+                       0xd8, 0xeb, 0xfe, 0x11, 0x24, 0x37, 0x4a, 0x5d,
+                       0x70, 0x83, 0x96, 0xa9, 0xbc, 0xcf, 0xe2, 0xf5,
+                       0x08, 0x1b, 0x2e, 0x41, 0x54, 0x67, 0x7a, 0x8d,
+                       0xa0, 0xb3, 0xc6, 0xd9, 0xec, 0xff, 0x12, 0x25,
+                       0x38, 0x4b, 0x5e, 0x71, 0x84, 0x97, 0xaa, 0xbd,
+                       0xd0, 0xe3, 0xf6, 0x09, 0x1c, 0x2f, 0x42, 0x55,
+                       0x68, 0x7b, 0x8e, 0xa1, 0xb4, 0xc7, 0xda, 0xed,
+                       0x00, 0x15, 0x2a, 0x3f, 0x54, 0x69, 0x7e, 0x93,
+                       0xa8, 0xbd, 0xd2, 0xe7, 0xfc, 0x11, 0x26, 0x3b,
+                       0x50, 0x65, 0x7a, 0x8f, 0xa4, 0xb9, 0xce, 0xe3,
+                       0xf8, 0x0d, 0x22, 0x37, 0x4c, 0x61, 0x76, 0x8b,
+                       0xa0, 0xb5, 0xca, 0xdf, 0xf4, 0x09, 0x1e, 0x33,
+                       0x48, 0x5d, 0x72, 0x87, 0x9c, 0xb1, 0xc6, 0xdb,
+                       0xf0, 0x05, 0x1a, 0x2f, 0x44, 0x59, 0x6e, 0x83,
+                       0x98, 0xad, 0xc2, 0xd7, 0xec, 0x01, 0x16, 0x2b,
+                       0x40, 0x55, 0x6a, 0x7f, 0x94, 0xa9, 0xbe, 0xd3,
+                       0xe8, 0xfd, 0x12, 0x27, 0x3c, 0x51, 0x66, 0x7b,
+                       0x90, 0xa5, 0xba, 0xcf, 0xe4, 0xf9, 0x0e, 0x23,
+                       0x38, 0x4d, 0x62, 0x77, 0x8c, 0xa1, 0xb6, 0xcb,
+                       0xe0, 0xf5, 0x0a, 0x1f, 0x34, 0x49, 0x5e, 0x73,
+                       0x88, 0x9d, 0xb2, 0xc7, 0xdc, 0xf1, 0x06, 0x1b,
+                       0x30, 0x45, 0x5a, 0x6f, 0x84, 0x99, 0xae, 0xc3,
+                       0xd8, 0xed, 0x02, 0x17, 0x2c, 0x41, 0x56, 0x6b,
+                       0x80, 0x95, 0xaa, 0xbf, 0xd4, 0xe9, 0xfe, 0x13,
+                       0x28, 0x3d, 0x52, 0x67, 0x7c, 0x91, 0xa6, 0xbb,
+                       0xd0, 0xe5, 0xfa, 0x0f, 0x24, 0x39, 0x4e, 0x63,
+                       0x78, 0x8d, 0xa2, 0xb7, 0xcc, 0xe1, 0xf6, 0x0b,
+                       0x20, 0x35, 0x4a, 0x5f, 0x74, 0x89, 0x9e, 0xb3,
+                       0xc8, 0xdd, 0xf2, 0x07, 0x1c, 0x31, 0x46, 0x5b,
+                       0x70, 0x85, 0x9a, 0xaf, 0xc4, 0xd9, 0xee, 0x03,
+                       0x18, 0x2d, 0x42, 0x57, 0x6c, 0x81, 0x96, 0xab,
+                       0xc0, 0xd5, 0xea, 0xff, 0x14, 0x29, 0x3e, 0x53,
+                       0x68, 0x7d, 0x92, 0xa7, 0xbc, 0xd1, 0xe6, 0xfb,
+                       0x10, 0x25, 0x3a, 0x4f, 0x64, 0x79, 0x8e, 0xa3,
+                       0xb8, 0xcd, 0xe2, 0xf7, 0x0c, 0x21, 0x36, 0x4b,
+                       0x60, 0x75, 0x8a, 0x9f, 0xb4, 0xc9, 0xde, 0xf3,
+                       0x08, 0x1d, 0x32, 0x47, 0x5c, 0x71, 0x86, 0x9b,
+                       0xb0, 0xc5, 0xda, 0xef, 0x04, 0x19, 0x2e, 0x43,
+                       0x58, 0x6d, 0x82, 0x97, 0xac, 0xc1, 0xd6, 0xeb,
+                       0x00, 0x17, 0x2e, 0x45, 0x5c, 0x73, 0x8a, 0xa1,
+                       0xb8, 0xcf, 0xe6, 0xfd, 0x14, 0x2b, 0x42, 0x59,
+                       0x70, 0x87, 0x9e, 0xb5, 0xcc, 0xe3, 0xfa, 0x11,
+                       0x28, 0x3f, 0x56, 0x6d, 0x84, 0x9b, 0xb2, 0xc9,
+                       0xe0, 0xf7, 0x0e, 0x25, 0x3c, 0x53, 0x6a, 0x81,
+                       0x98, 0xaf, 0xc6, 0xdd, 0xf4, 0x0b, 0x22, 0x39,
+                       0x50, 0x67, 0x7e, 0x95, 0xac, 0xc3, 0xda, 0xf1,
+                       0x08, 0x1f, 0x36, 0x4d, 0x64, 0x7b, 0x92, 0xa9,
+                       0xc0, 0xd7, 0xee, 0x05, 0x1c, 0x33, 0x4a, 0x61,
+                       0x78, 0x8f, 0xa6, 0xbd, 0xd4, 0xeb, 0x02, 0x19,
+                       0x30, 0x47, 0x5e, 0x75, 0x8c, 0xa3, 0xba, 0xd1,
+                       0xe8, 0xff, 0x16, 0x2d, 0x44, 0x5b, 0x72, 0x89,
+                       0xa0, 0xb7, 0xce, 0xe5, 0xfc, 0x13, 0x2a, 0x41,
+                       0x58, 0x6f, 0x86, 0x9d, 0xb4, 0xcb, 0xe2, 0xf9,
+                       0x10, 0x27, 0x3e, 0x55, 0x6c, 0x83, 0x9a, 0xb1,
+                       0xc8, 0xdf, 0xf6, 0x0d, 0x24, 0x3b, 0x52, 0x69,
+                       0x80, 0x97, 0xae, 0xc5, 0xdc, 0xf3, 0x0a, 0x21,
+                       0x38, 0x4f, 0x66, 0x7d, 0x94, 0xab, 0xc2, 0xd9,
+                       0xf0, 0x07, 0x1e, 0x35, 0x4c, 0x63, 0x7a, 0x91,
+                       0xa8, 0xbf, 0xd6, 0xed, 0x04, 0x1b, 0x32, 0x49,
+                       0x60, 0x77, 0x8e, 0xa5, 0xbc, 0xd3, 0xea, 0x01,
+                       0x18, 0x2f, 0x46, 0x5d, 0x74, 0x8b, 0xa2, 0xb9,
+                       0xd0, 0xe7, 0xfe, 0x15, 0x2c, 0x43, 0x5a, 0x71,
+                       0x88, 0x9f, 0xb6, 0xcd, 0xe4, 0xfb, 0x12, 0x29,
+                       0x40, 0x57, 0x6e, 0x85, 0x9c, 0xb3, 0xca, 0xe1,
+                       0xf8, 0x0f, 0x26, 0x3d, 0x54, 0x6b, 0x82, 0x99,
+                       0xb0, 0xc7, 0xde, 0xf5, 0x0c, 0x23, 0x3a, 0x51,
+                       0x68, 0x7f, 0x96, 0xad, 0xc4, 0xdb, 0xf2, 0x09,
+                       0x20, 0x37, 0x4e, 0x65, 0x7c, 0x93, 0xaa, 0xc1,
+                       0xd8, 0xef, 0x06, 0x1d, 0x34, 0x4b, 0x62, 0x79,
+                       0x90, 0xa7, 0xbe, 0xd5, 0xec, 0x03, 0x1a, 0x31,
+                       0x48, 0x5f, 0x76, 0x8d, 0xa4, 0xbb, 0xd2, 0xe9,
+                       0x00, 0x19, 0x32, 0x4b, 0x64, 0x7d, 0x96, 0xaf,
+                       0xc8, 0xe1, 0xfa, 0x13, 0x2c, 0x45, 0x5e, 0x77,
+                       0x90, 0xa9, 0xc2, 0xdb, 0xf4, 0x0d, 0x26, 0x3f,
+                       0x58, 0x71, 0x8a, 0xa3, 0xbc, 0xd5, 0xee, 0x07,
+                       0x20, 0x39, 0x52, 0x6b, 0x84, 0x9d, 0xb6, 0xcf,
+                       0xe8, 0x01, 0x1a, 0x33, 0x4c, 0x65, 0x7e, 0x97,
+                       0xb0, 0xc9, 0xe2, 0xfb, 0x14, 0x2d, 0x46, 0x5f,
+                       0x78, 0x91, 0xaa, 0xc3, 0xdc, 0xf5, 0x0e, 0x27,
+                       0x40, 0x59, 0x72, 0x8b, 0xa4, 0xbd, 0xd6, 0xef,
+                       0x08, 0x21, 0x3a, 0x53, 0x6c, 0x85, 0x9e, 0xb7,
+                       0xd0, 0xe9, 0x02, 0x1b, 0x34, 0x4d, 0x66, 0x7f,
+                       0x98, 0xb1, 0xca, 0xe3, 0xfc, 0x15, 0x2e, 0x47,
+                       0x60, 0x79, 0x92, 0xab, 0xc4, 0xdd, 0xf6, 0x0f,
+                       0x28, 0x41, 0x5a, 0x73, 0x8c, 0xa5, 0xbe, 0xd7,
+                       0xf0, 0x09, 0x22, 0x3b, 0x54, 0x6d, 0x86, 0x9f,
+                       0xb8, 0xd1, 0xea, 0x03, 0x1c, 0x35, 0x4e, 0x67,
+                       0x80, 0x99, 0xb2, 0xcb, 0xe4, 0xfd, 0x16, 0x2f,
+                       0x48, 0x61, 0x7a, 0x93, 0xac, 0xc5, 0xde, 0xf7,
+                       0x10, 0x29, 0x42, 0x5b, 0x74, 0x8d, 0xa6, 0xbf,
+                       0xd8, 0xf1, 0x0a, 0x23, 0x3c, 0x55, 0x6e, 0x87,
+                       0xa0, 0xb9, 0xd2, 0xeb, 0x04, 0x1d, 0x36, 0x4f,
+                       0x68, 0x81, 0x9a, 0xb3, 0xcc, 0xe5, 0xfe, 0x17,
+                       0x30, 0x49, 0x62, 0x7b, 0x94, 0xad, 0xc6, 0xdf,
+                       0xf8, 0x11, 0x2a, 0x43, 0x5c, 0x75, 0x8e, 0xa7,
+                       0xc0, 0xd9, 0xf2, 0x0b, 0x24, 0x3d, 0x56, 0x6f,
+                       0x88, 0xa1, 0xba, 0xd3, 0xec, 0x05, 0x1e, 0x37,
+                       0x50, 0x69, 0x82, 0x9b, 0xb4, 0xcd, 0xe6, 0xff,
+                       0x18, 0x31, 0x4a, 0x63, 0x7c, 0x95, 0xae, 0xc7,
+                       0xe0, 0xf9, 0x12, 0x2b, 0x44, 0x5d, 0x76, 0x8f,
+                       0xa8, 0xc1, 0xda, 0xf3, 0x0c, 0x25, 0x3e, 0x57,
+                       0x70, 0x89, 0xa2, 0xbb, 0xd4, 0xed, 0x06, 0x1f,
+                       0x38, 0x51, 0x6a, 0x83, 0x9c, 0xb5, 0xce, 0xe7,
+                       0x00, 0x1b, 0x36, 0x51, 0x6c, 0x87, 0xa2, 0xbd,
+                       0xd8, 0xf3, 0x0e, 0x29, 0x44, 0x5f, 0x7a, 0x95,
+                       0xb0, 0xcb, 0xe6, 0x01, 0x1c, 0x37, 0x52, 0x6d,
+                       0x88, 0xa3, 0xbe, 0xd9, 0xf4, 0x0f, 0x2a, 0x45,
+                       0x60, 0x7b, 0x96, 0xb1, 0xcc, 0xe7, 0x02, 0x1d,
+                       0x38, 0x53, 0x6e, 0x89, 0xa4, 0xbf, 0xda, 0xf5,
+                       0x10, 0x2b, 0x46, 0x61, 0x7c, 0x97, 0xb2, 0xcd,
+                       0xe8, 0x03, 0x1e, 0x39, 0x54, 0x6f, 0x8a, 0xa5,
+                       0xc0, 0xdb, 0xf6, 0x11, 0x2c, 0x47, 0x62, 0x7d,
+                       0x98, 0xb3, 0xce, 0xe9, 0x04, 0x1f, 0x3a, 0x55,
+                       0x70, 0x8b, 0xa6, 0xc1, 0xdc, 0xf7, 0x12, 0x2d,
+                       0x48, 0x63, 0x7e, 0x99, 0xb4, 0xcf, 0xea, 0x05,
+                       0x20, 0x3b, 0x56, 0x71, 0x8c, 0xa7, 0xc2, 0xdd,
+                       0xf8, 0x13, 0x2e, 0x49, 0x64, 0x7f, 0x9a, 0xb5,
+                       0xd0, 0xeb, 0x06, 0x21, 0x3c, 0x57, 0x72, 0x8d,
+                       0xa8, 0xc3, 0xde, 0xf9, 0x14, 0x2f, 0x4a, 0x65,
+                       0x80, 0x9b, 0xb6, 0xd1, 0xec, 0x07, 0x22, 0x3d,
+                       0x58, 0x73, 0x8e, 0xa9, 0xc4, 0xdf, 0xfa, 0x15,
+                       0x30, 0x4b, 0x66, 0x81, 0x9c, 0xb7, 0xd2, 0xed,
+                       0x08, 0x23, 0x3e, 0x59, 0x74, 0x8f, 0xaa, 0xc5,
+                       0xe0, 0xfb, 0x16, 0x31, 0x4c, 0x67, 0x82, 0x9d,
+                       0xb8, 0xd3, 0xee, 0x09, 0x24, 0x3f, 0x5a, 0x75,
+                       0x90, 0xab, 0xc6, 0xe1, 0xfc, 0x17, 0x32, 0x4d,
+                       0x68, 0x83, 0x9e, 0xb9, 0xd4, 0xef, 0x0a, 0x25,
+                       0x40, 0x5b, 0x76, 0x91, 0xac, 0xc7, 0xe2, 0xfd,
+                       0x18, 0x33, 0x4e, 0x69, 0x84, 0x9f, 0xba, 0xd5,
+                       0xf0, 0x0b, 0x26, 0x41, 0x5c, 0x77, 0x92, 0xad,
+                       0xc8, 0xe3, 0xfe, 0x19, 0x34, 0x4f, 0x6a, 0x85,
+                       0xa0, 0xbb, 0xd6, 0xf1, 0x0c, 0x27, 0x42, 0x5d,
+                       0x78, 0x93, 0xae, 0xc9, 0xe4, 0xff, 0x1a, 0x35,
+                       0x50, 0x6b, 0x86, 0xa1, 0xbc, 0xd7, 0xf2, 0x0d,
+                       0x28, 0x43, 0x5e, 0x79, 0x94, 0xaf, 0xca, 0xe5,
+                       0x00, 0x1d, 0x3a, 0x57, 0x74, 0x91, 0xae, 0xcb,
+                       0xe8, 0x05, 0x22, 0x3f, 0x5c, 0x79, 0x96, 0xb3,
+                       0xd0, 0xed, 0x0a, 0x27, 0x44, 0x61, 0x7e, 0x9b,
+                       0xb8, 0xd5, 0xf2, 0x0f, 0x2c, 0x49, 0x66, 0x83,
+                       0xa0, 0xbd, 0xda, 0xf7, 0x14, 0x31, 0x4e, 0x6b,
+                       0x88, 0xa5, 0xc2, 0xdf, 0xfc, 0x19, 0x36, 0x53,
+                       0x70, 0x8d, 0xaa, 0xc7, 0xe4, 0x01, 0x1e, 0x3b,
+                       0x58, 0x75, 0x92, 0xaf, 0xcc, 0xe9, 0x06, 0x23,
+                       0x40, 0x5d, 0x7a, 0x97, 0xb4, 0xd1, 0xee, 0x0b,
+                       0x28, 0x45, 0x62, 0x7f, 0x9c, 0xb9, 0xd6, 0xf3,
+                       0x10, 0x2d, 0x4a, 0x67, 0x84, 0xa1, 0xbe, 0xdb,
+                       0xf8, 0x15, 0x32, 0x4f, 0x6c, 0x89, 0xa6, 0xc3,
+                       0xe0, 0xfd, 0x1a, 0x37, 0x54, 0x71, 0x8e, 0xab,
+                       0xc8, 0xe5, 0x02, 0x1f, 0x3c, 0x59, 0x76, 0x93,
+                       0xb0, 0xcd, 0xea, 0x07, 0x24, 0x41, 0x5e, 0x7b,
+                       0x98, 0xb5, 0xd2, 0xef, 0x0c, 0x29, 0x46, 0x63,
+                       0x80, 0x9d, 0xba, 0xd7, 0xf4, 0x11, 0x2e, 0x4b,
+                       0x68, 0x85, 0xa2, 0xbf, 0xdc, 0xf9, 0x16, 0x33,
+                       0x50, 0x6d, 0x8a, 0xa7, 0xc4, 0xe1, 0xfe, 0x1b,
+                       0x38, 0x55, 0x72, 0x8f, 0xac, 0xc9, 0xe6, 0x03,
+                       0x20, 0x3d, 0x5a, 0x77, 0x94, 0xb1, 0xce, 0xeb,
+                       0x08, 0x25, 0x42, 0x5f, 0x7c, 0x99, 0xb6, 0xd3,
+                       0xf0, 0x0d, 0x2a, 0x47, 0x64, 0x81, 0x9e, 0xbb,
+                       0xd8, 0xf5, 0x12, 0x2f, 0x4c, 0x69, 0x86, 0xa3,
+                       0xc0, 0xdd, 0xfa, 0x17, 0x34, 0x51, 0x6e, 0x8b,
+                       0xa8, 0xc5, 0xe2, 0xff, 0x1c, 0x39, 0x56, 0x73,
+                       0x90, 0xad, 0xca, 0xe7, 0x04, 0x21, 0x3e, 0x5b,
+                       0x78, 0x95, 0xb2, 0xcf, 0xec, 0x09, 0x26, 0x43,
+                       0x60, 0x7d, 0x9a, 0xb7, 0xd4, 0xf1, 0x0e, 0x2b,
+                       0x48, 0x65, 0x82, 0x9f, 0xbc, 0xd9, 0xf6, 0x13,
+                       0x30, 0x4d, 0x6a, 0x87, 0xa4, 0xc1, 0xde, 0xfb,
+                       0x18, 0x35, 0x52, 0x6f, 0x8c, 0xa9, 0xc6, 0xe3,
+                       0x00, 0x1f, 0x3e, 0x5d, 0x7c, 0x9b, 0xba, 0xd9,
+                       0xf8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xb2, 0xd1,
+                       0xf0, 0x0f, 0x2e, 0x4d, 0x6c, 0x8b, 0xaa, 0xc9,
+                       0xe8, 0x07, 0x26, 0x45, 0x64, 0x83, 0xa2, 0xc1,
+                       0xe0, 0xff, 0x1e, 0x3d, 0x5c, 0x7b, 0x9a, 0xb9,
+                       0xd8, 0xf7, 0x16, 0x35, 0x54, 0x73, 0x92, 0xb1,
+                       0xd0, 0xef, 0x0e, 0x2d, 0x4c, 0x6b, 0x8a, 0xa9,
+                       0xc8, 0xe7, 0x06, 0x25, 0x44, 0x63, 0x82, 0xa1,
+                       0xc0, 0xdf, 0xfe, 0x1d, 0x3c, 0x5b, 0x7a, 0x99,
+                       0xb8, 0xd7, 0xf6, 0x15, 0x34, 0x53, 0x72, 0x91,
+                       0xb0, 0xcf, 0xee, 0x0d, 0x2c, 0x4b, 0x6a, 0x89,
+                       0xa8, 0xc7, 0xe6, 0x05, 0x24, 0x43, 0x62, 0x81,
+                       0xa0, 0xbf, 0xde, 0xfd, 0x1c, 0x3b, 0x5a, 0x79,
+                       0x98, 0xb7, 0xd6, 0xf5, 0x14, 0x33, 0x52, 0x71,
+                       0x90, 0xaf, 0xce, 0xed, 0x0c, 0x2b, 0x4a, 0x69,
+                       0x88, 0xa7, 0xc6, 0xe5, 0x04, 0x23, 0x42, 0x61,
+                       0x80, 0x9f, 0xbe, 0xdd, 0xfc, 0x1b, 0x3a, 0x59,
+                       0x78, 0x97, 0xb6, 0xd5, 0xf4, 0x13, 0x32, 0x51,
+                       0x70, 0x8f, 0xae, 0xcd, 0xec, 0x0b, 0x2a, 0x49,
+                       0x68, 0x87, 0xa6, 0xc5, 0xe4, 0x03, 0x22, 0x41,
+                       0x60, 0x7f, 0x9e, 0xbd, 0xdc, 0xfb, 0x1a, 0x39,
+                       0x58, 0x77, 0x96, 0xb5, 0xd4, 0xf3, 0x12, 0x31,
+                       0x50, 0x6f, 0x8e, 0xad, 0xcc, 0xeb, 0x0a, 0x29,
+                       0x48, 0x67, 0x86, 0xa5, 0xc4, 0xe3, 0x02, 0x21,
+                       0x40, 0x5f, 0x7e, 0x9d, 0xbc, 0xdb, 0xfa, 0x19,
+                       0x38, 0x57, 0x76, 0x95, 0xb4, 0xd3, 0xf2, 0x11,
+                       0x30, 0x4f, 0x6e, 0x8d, 0xac, 0xcb, 0xea, 0x09,
+                       0x28, 0x47, 0x66, 0x85, 0xa4, 0xc3, 0xe2, 0x01,
+                       0x20, 0x3f, 0x5e, 0x7d, 0x9c, 0xbb, 0xda, 0xf9,
+                       0x18, 0x37, 0x56, 0x75, 0x94, 0xb3, 0xd2, 0xf1,
+                       0x10, 0x2f, 0x4e, 0x6d, 0x8c, 0xab, 0xca, 0xe9,
+                       0x08, 0x27, 0x46, 0x65, 0x84, 0xa3, 0xc2, 0xe1,
+                       0x00, 0x21, 0x42, 0x63,
+               },
+               .ilen = 4100,
+               .result = {
+                       0xb5, 0x81, 0xf5, 0x64, 0x18, 0x73, 0xe3, 0xf0,
+                       0x4c, 0x13, 0xf2, 0x77, 0x18, 0x60, 0x65, 0x5e,
+                       0x29, 0x01, 0xce, 0x98, 0x55, 0x53, 0xf9, 0x0c,
+                       0x2a, 0x08, 0xd5, 0x09, 0xb3, 0x57, 0x55, 0x56,
+                       0xc5, 0xe9, 0x56, 0x90, 0xcb, 0x6a, 0xa3, 0xc0,
+                       0xff, 0xc4, 0x79, 0xb4, 0xd2, 0x97, 0x5d, 0xc4,
+                       0x43, 0xd1, 0xfe, 0x94, 0x7b, 0x88, 0x06, 0x5a,
+                       0xb2, 0x9e, 0x2c, 0xfc, 0x44, 0x03, 0xb7, 0x90,
+                       0xa0, 0xc1, 0xba, 0x6a, 0x33, 0xb8, 0xc7, 0xb2,
+                       0x9d, 0xe1, 0x12, 0x4f, 0xc0, 0x64, 0xd4, 0x01,
+                       0xfe, 0x8c, 0x7a, 0x66, 0xf7, 0xe6, 0x5a, 0x91,
+                       0xbb, 0xde, 0x56, 0x86, 0xab, 0x65, 0x21, 0x30,
+                       0x00, 0x84, 0x65, 0x24, 0xa5, 0x7d, 0x85, 0xb4,
+                       0xe3, 0x17, 0xed, 0x3a, 0xb7, 0x6f, 0xb4, 0x0b,
+                       0x0b, 0xaf, 0x15, 0xae, 0x5a, 0x8f, 0xf2, 0x0c,
+                       0x2f, 0x27, 0xf4, 0x09, 0xd8, 0xd2, 0x96, 0xb7,
+                       0x71, 0xf2, 0xc5, 0x99, 0x4d, 0x7e, 0x7f, 0x75,
+                       0x77, 0x89, 0x30, 0x8b, 0x59, 0xdb, 0xa2, 0xb2,
+                       0xa0, 0xf3, 0x19, 0x39, 0x2b, 0xc5, 0x7e, 0x3f,
+                       0x4f, 0xd9, 0xd3, 0x56, 0x28, 0x97, 0x44, 0xdc,
+                       0xc0, 0x8b, 0x77, 0x24, 0xd9, 0x52, 0xe7, 0xc5,
+                       0xaf, 0xf6, 0x7d, 0x59, 0xb2, 0x44, 0x05, 0x1d,
+                       0xb1, 0xb0, 0x11, 0xa5, 0x0f, 0xec, 0x33, 0xe1,
+                       0x6d, 0x1b, 0x4e, 0x1f, 0xff, 0x57, 0x91, 0xb4,
+                       0x5b, 0x9a, 0x96, 0xc5, 0x53, 0xbc, 0xae, 0x20,
+                       0x3c, 0xbb, 0x14, 0xe2, 0xe8, 0x22, 0x33, 0xc1,
+                       0x5e, 0x76, 0x9e, 0x46, 0x99, 0xf6, 0x2a, 0x15,
+                       0xc6, 0x97, 0x02, 0xa0, 0x66, 0x43, 0xd1, 0xa6,
+                       0x31, 0xa6, 0x9f, 0xfb, 0xf4, 0xd3, 0x69, 0xe5,
+                       0xcd, 0x76, 0x95, 0xb8, 0x7a, 0x82, 0x7f, 0x21,
+                       0x45, 0xff, 0x3f, 0xce, 0x55, 0xf6, 0x95, 0x10,
+                       0x08, 0x77, 0x10, 0x43, 0xc6, 0xf3, 0x09, 0xe5,
+                       0x68, 0xe7, 0x3c, 0xad, 0x00, 0x52, 0x45, 0x0d,
+                       0xfe, 0x2d, 0xc6, 0xc2, 0x94, 0x8c, 0x12, 0x1d,
+                       0xe6, 0x25, 0xae, 0x98, 0x12, 0x8e, 0x19, 0x9c,
+                       0x81, 0x68, 0xb1, 0x11, 0xf6, 0x69, 0xda, 0xe3,
+                       0x62, 0x08, 0x18, 0x7a, 0x25, 0x49, 0x28, 0xac,
+                       0xba, 0x71, 0x12, 0x0b, 0xe4, 0xa2, 0xe5, 0xc7,
+                       0x5d, 0x8e, 0xec, 0x49, 0x40, 0x21, 0xbf, 0x5a,
+                       0x98, 0xf3, 0x02, 0x68, 0x55, 0x03, 0x7f, 0x8a,
+                       0xe5, 0x94, 0x0c, 0x32, 0x5c, 0x07, 0x82, 0x63,
+                       0xaf, 0x6f, 0x91, 0x40, 0x84, 0x8e, 0x52, 0x25,
+                       0xd0, 0xb0, 0x29, 0x53, 0x05, 0xe2, 0x50, 0x7a,
+                       0x34, 0xeb, 0xc9, 0x46, 0x20, 0xa8, 0x3d, 0xde,
+                       0x7f, 0x16, 0x5f, 0x36, 0xc5, 0x2e, 0xdc, 0xd1,
+                       0x15, 0x47, 0xc7, 0x50, 0x40, 0x6d, 0x91, 0xc5,
+                       0xe7, 0x93, 0x95, 0x1a, 0xd3, 0x57, 0xbc, 0x52,
+                       0x33, 0xee, 0x14, 0x19, 0x22, 0x52, 0x89, 0xa7,
+                       0x4a, 0x25, 0x56, 0x77, 0x4b, 0xca, 0xcf, 0x0a,
+                       0xe1, 0xf5, 0x35, 0x85, 0x30, 0x7e, 0x59, 0x4a,
+                       0xbd, 0x14, 0x5b, 0xdf, 0xe3, 0x46, 0xcb, 0xac,
+                       0x1f, 0x6c, 0x96, 0x0e, 0xf4, 0x81, 0xd1, 0x99,
+                       0xca, 0x88, 0x63, 0x3d, 0x02, 0x58, 0x6b, 0xa9,
+                       0xe5, 0x9f, 0xb3, 0x00, 0xb2, 0x54, 0xc6, 0x74,
+                       0x1c, 0xbf, 0x46, 0xab, 0x97, 0xcc, 0xf8, 0x54,
+                       0x04, 0x07, 0x08, 0x52, 0xe6, 0xc0, 0xda, 0x93,
+                       0x74, 0x7d, 0x93, 0x99, 0x5d, 0x78, 0x68, 0xa6,
+                       0x2e, 0x6b, 0xd3, 0x6a, 0x69, 0xcc, 0x12, 0x6b,
+                       0xd4, 0xc7, 0xa5, 0xc6, 0xe7, 0xf6, 0x03, 0x04,
+                       0x5d, 0xcd, 0x61, 0x5e, 0x17, 0x40, 0xdc, 0xd1,
+                       0x5c, 0xf5, 0x08, 0xdf, 0x5c, 0x90, 0x85, 0xa4,
+                       0xaf, 0xf6, 0x78, 0xbb, 0x0d, 0xf1, 0xf4, 0xa4,
+                       0x54, 0x26, 0x72, 0x9e, 0x61, 0xfa, 0x86, 0xcf,
+                       0xe8, 0x9e, 0xa1, 0xe0, 0xc7, 0x48, 0x23, 0xae,
+                       0x5a, 0x90, 0xae, 0x75, 0x0a, 0x74, 0x18, 0x89,
+                       0x05, 0xb1, 0x92, 0xb2, 0x7f, 0xd0, 0x1b, 0xa6,
+                       0x62, 0x07, 0x25, 0x01, 0xc7, 0xc2, 0x4f, 0xf9,
+                       0xe8, 0xfe, 0x63, 0x95, 0x80, 0x07, 0xb4, 0x26,
+                       0xcc, 0xd1, 0x26, 0xb6, 0xc4, 0x3f, 0x9e, 0xcb,
+                       0x8e, 0x3b, 0x2e, 0x44, 0x16, 0xd3, 0x10, 0x9a,
+                       0x95, 0x08, 0xeb, 0xc8, 0xcb, 0xeb, 0xbf, 0x6f,
+                       0x0b, 0xcd, 0x1f, 0xc8, 0xca, 0x86, 0xaa, 0xec,
+                       0x33, 0xe6, 0x69, 0xf4, 0x45, 0x25, 0x86, 0x3a,
+                       0x22, 0x94, 0x4f, 0x00, 0x23, 0x6a, 0x44, 0xc2,
+                       0x49, 0x97, 0x33, 0xab, 0x36, 0x14, 0x0a, 0x70,
+                       0x24, 0xc3, 0xbe, 0x04, 0x3b, 0x79, 0xa0, 0xf9,
+                       0xb8, 0xe7, 0x76, 0x29, 0x22, 0x83, 0xd7, 0xf2,
+                       0x94, 0xf4, 0x41, 0x49, 0xba, 0x5f, 0x7b, 0x07,
+                       0xb5, 0xfb, 0xdb, 0x03, 0x1a, 0x9f, 0xb6, 0x4c,
+                       0xc2, 0x2e, 0x37, 0x40, 0x49, 0xc3, 0x38, 0x16,
+                       0xe2, 0x4f, 0x77, 0x82, 0xb0, 0x68, 0x4c, 0x71,
+                       0x1d, 0x57, 0x61, 0x9c, 0xd9, 0x4e, 0x54, 0x99,
+                       0x47, 0x13, 0x28, 0x73, 0x3c, 0xbb, 0x00, 0x90,
+                       0xf3, 0x4d, 0xc9, 0x0e, 0xfd, 0xe7, 0xb1, 0x71,
+                       0xd3, 0x15, 0x79, 0xbf, 0xcc, 0x26, 0x2f, 0xbd,
+                       0xad, 0x6c, 0x50, 0x69, 0x6c, 0x3e, 0x6d, 0x80,
+                       0x9a, 0xea, 0x78, 0xaf, 0x19, 0xb2, 0x0d, 0x4d,
+                       0xad, 0x04, 0x07, 0xae, 0x22, 0x90, 0x4a, 0x93,
+                       0x32, 0x0e, 0x36, 0x9b, 0x1b, 0x46, 0xba, 0x3b,
+                       0xb4, 0xac, 0xc6, 0xd1, 0xa2, 0x31, 0x53, 0x3b,
+                       0x2a, 0x3d, 0x45, 0xfe, 0x03, 0x61, 0x10, 0x85,
+                       0x17, 0x69, 0xa6, 0x78, 0xcc, 0x6c, 0x87, 0x49,
+                       0x53, 0xf9, 0x80, 0x10, 0xde, 0x80, 0xa2, 0x41,
+                       0x6a, 0xc3, 0x32, 0x02, 0xad, 0x6d, 0x3c, 0x56,
+                       0x00, 0x71, 0x51, 0x06, 0xa7, 0xbd, 0xfb, 0xef,
+                       0x3c, 0xb5, 0x9f, 0xfc, 0x48, 0x7d, 0x53, 0x7c,
+                       0x66, 0xb0, 0x49, 0x23, 0xc4, 0x47, 0x10, 0x0e,
+                       0xe5, 0x6c, 0x74, 0x13, 0xe6, 0xc5, 0x3f, 0xaa,
+                       0xde, 0xff, 0x07, 0x44, 0xdd, 0x56, 0x1b, 0xad,
+                       0x09, 0x77, 0xfb, 0x5b, 0x12, 0xb8, 0x0d, 0x38,
+                       0x17, 0x37, 0x35, 0x7b, 0x9b, 0xbc, 0xfe, 0xd4,
+                       0x7e, 0x8b, 0xda, 0x7e, 0x5b, 0x04, 0xa7, 0x22,
+                       0xa7, 0x31, 0xa1, 0x20, 0x86, 0xc7, 0x1b, 0x99,
+                       0xdb, 0xd1, 0x89, 0xf4, 0x94, 0xa3, 0x53, 0x69,
+                       0x8d, 0xe7, 0xe8, 0x74, 0x11, 0x8d, 0x74, 0xd6,
+                       0x07, 0x37, 0x91, 0x9f, 0xfd, 0x67, 0x50, 0x3a,
+                       0xc9, 0xe1, 0xf4, 0x36, 0xd5, 0xa0, 0x47, 0xd1,
+                       0xf9, 0xe5, 0x39, 0xa3, 0x31, 0xac, 0x07, 0x36,
+                       0x23, 0xf8, 0x66, 0x18, 0x14, 0x28, 0x34, 0x0f,
+                       0xb8, 0xd0, 0xe7, 0x29, 0xb3, 0x04, 0x4b, 0x55,
+                       0x01, 0x41, 0xb2, 0x75, 0x8d, 0xcb, 0x96, 0x85,
+                       0x3a, 0xfb, 0xab, 0x2b, 0x9e, 0xfa, 0x58, 0x20,
+                       0x44, 0x1f, 0xc0, 0x14, 0x22, 0x75, 0x61, 0xe8,
+                       0xaa, 0x19, 0xcf, 0xf1, 0x82, 0x56, 0xf4, 0xd7,
+                       0x78, 0x7b, 0x3d, 0x5f, 0xb3, 0x9e, 0x0b, 0x8a,
+                       0x57, 0x50, 0xdb, 0x17, 0x41, 0x65, 0x4d, 0xa3,
+                       0x02, 0xc9, 0x9c, 0x9c, 0x53, 0xfb, 0x39, 0x39,
+                       0x9b, 0x1d, 0x72, 0x24, 0xda, 0xb7, 0x39, 0xbe,
+                       0x13, 0x3b, 0xfa, 0x29, 0xda, 0x9e, 0x54, 0x64,
+                       0x6e, 0xba, 0xd8, 0xa1, 0xcb, 0xb3, 0x36, 0xfa,
+                       0xcb, 0x47, 0x85, 0xe9, 0x61, 0x38, 0xbc, 0xbe,
+                       0xc5, 0x00, 0x38, 0x2a, 0x54, 0xf7, 0xc4, 0xb9,
+                       0xb3, 0xd3, 0x7b, 0xa0, 0xa0, 0xf8, 0x72, 0x7f,
+                       0x8c, 0x8e, 0x82, 0x0e, 0xc6, 0x1c, 0x75, 0x9d,
+                       0xca, 0x8e, 0x61, 0x87, 0xde, 0xad, 0x80, 0xd2,
+                       0xf5, 0xf9, 0x80, 0xef, 0x15, 0x75, 0xaf, 0xf5,
+                       0x80, 0xfb, 0xff, 0x6d, 0x1e, 0x25, 0xb7, 0x40,
+                       0x61, 0x6a, 0x39, 0x5a, 0x6a, 0xb5, 0x31, 0xab,
+                       0x97, 0x8a, 0x19, 0x89, 0x44, 0x40, 0xc0, 0xa6,
+                       0xb4, 0x4e, 0x30, 0x32, 0x7b, 0x13, 0xe7, 0x67,
+                       0xa9, 0x8b, 0x57, 0x04, 0xc2, 0x01, 0xa6, 0xf4,
+                       0x28, 0x99, 0xad, 0x2c, 0x76, 0xa3, 0x78, 0xc2,
+                       0x4a, 0xe6, 0xca, 0x5c, 0x50, 0x6a, 0xc1, 0xb0,
+                       0x62, 0x4b, 0x10, 0x8e, 0x7c, 0x17, 0x43, 0xb3,
+                       0x17, 0x66, 0x1c, 0x3e, 0x8d, 0x69, 0xf0, 0x5a,
+                       0x71, 0xf5, 0x97, 0xdc, 0xd1, 0x45, 0xdd, 0x28,
+                       0xf3, 0x5d, 0xdf, 0x53, 0x7b, 0x11, 0xe5, 0xbc,
+                       0x4c, 0xdb, 0x1b, 0x51, 0x6b, 0xe9, 0xfb, 0x3d,
+                       0xc1, 0xc3, 0x2c, 0xb9, 0x71, 0xf5, 0xb6, 0xb2,
+                       0x13, 0x36, 0x79, 0x80, 0x53, 0xe8, 0xd3, 0xa6,
+                       0x0a, 0xaf, 0xfd, 0x56, 0x97, 0xf7, 0x40, 0x8e,
+                       0x45, 0xce, 0xf8, 0xb0, 0x9e, 0x5c, 0x33, 0x82,
+                       0xb0, 0x44, 0x56, 0xfc, 0x05, 0x09, 0xe9, 0x2a,
+                       0xac, 0x26, 0x80, 0x14, 0x1d, 0xc8, 0x3a, 0x35,
+                       0x4c, 0x82, 0x97, 0xfd, 0x76, 0xb7, 0xa9, 0x0a,
+                       0x35, 0x58, 0x79, 0x8e, 0x0f, 0x66, 0xea, 0xaf,
+                       0x51, 0x6c, 0x09, 0xa9, 0x6e, 0x9b, 0xcb, 0x9a,
+                       0x31, 0x47, 0xa0, 0x2f, 0x7c, 0x71, 0xb4, 0x4a,
+                       0x11, 0xaa, 0x8c, 0x66, 0xc5, 0x64, 0xe6, 0x3a,
+                       0x54, 0xda, 0x24, 0x6a, 0xc4, 0x41, 0x65, 0x46,
+                       0x82, 0xa0, 0x0a, 0x0f, 0x5f, 0xfb, 0x25, 0xd0,
+                       0x2c, 0x91, 0xa7, 0xee, 0xc4, 0x81, 0x07, 0x86,
+                       0x75, 0x5e, 0x33, 0x69, 0x97, 0xe4, 0x2c, 0xa8,
+                       0x9d, 0x9f, 0x0b, 0x6a, 0xbe, 0xad, 0x98, 0xda,
+                       0x6d, 0x94, 0x41, 0xda, 0x2c, 0x1e, 0x89, 0xc4,
+                       0xc2, 0xaf, 0x1e, 0x00, 0x05, 0x0b, 0x83, 0x60,
+                       0xbd, 0x43, 0xea, 0x15, 0x23, 0x7f, 0xb9, 0xac,
+                       0xee, 0x4f, 0x2c, 0xaf, 0x2a, 0xf3, 0xdf, 0xd0,
+                       0xf3, 0x19, 0x31, 0xbb, 0x4a, 0x74, 0x84, 0x17,
+                       0x52, 0x32, 0x2c, 0x7d, 0x61, 0xe4, 0xcb, 0xeb,
+                       0x80, 0x38, 0x15, 0x52, 0xcb, 0x6f, 0xea, 0xe5,
+                       0x73, 0x9c, 0xd9, 0x24, 0x69, 0xc6, 0x95, 0x32,
+                       0x21, 0xc8, 0x11, 0xe4, 0xdc, 0x36, 0xd7, 0x93,
+                       0x38, 0x66, 0xfb, 0xb2, 0x7f, 0x3a, 0xb9, 0xaf,
+                       0x31, 0xdd, 0x93, 0x75, 0x78, 0x8a, 0x2c, 0x94,
+                       0x87, 0x1a, 0x58, 0xec, 0x9e, 0x7d, 0x4d, 0xba,
+                       0xe1, 0xe5, 0x4d, 0xfc, 0xbc, 0xa4, 0x2a, 0x14,
+                       0xef, 0xcc, 0xa7, 0xec, 0xab, 0x43, 0x09, 0x18,
+                       0xd3, 0xab, 0x68, 0xd1, 0x07, 0x99, 0x44, 0x47,
+                       0xd6, 0x83, 0x85, 0x3b, 0x30, 0xea, 0xa9, 0x6b,
+                       0x63, 0xea, 0xc4, 0x07, 0xfb, 0x43, 0x2f, 0xa4,
+                       0xaa, 0xb0, 0xab, 0x03, 0x89, 0xce, 0x3f, 0x8c,
+                       0x02, 0x7c, 0x86, 0x54, 0xbc, 0x88, 0xaf, 0x75,
+                       0xd2, 0xdc, 0x63, 0x17, 0xd3, 0x26, 0xf6, 0x96,
+                       0xa9, 0x3c, 0xf1, 0x61, 0x8c, 0x11, 0x18, 0xcc,
+                       0xd6, 0xea, 0x5b, 0xe2, 0xcd, 0xf0, 0xf1, 0xb2,
+                       0xe5, 0x35, 0x90, 0x1f, 0x85, 0x4c, 0x76, 0x5b,
+                       0x66, 0xce, 0x44, 0xa4, 0x32, 0x9f, 0xe6, 0x7b,
+                       0x71, 0x6e, 0x9f, 0x58, 0x15, 0x67, 0x72, 0x87,
+                       0x64, 0x8e, 0x3a, 0x44, 0x45, 0xd4, 0x76, 0xfa,
+                       0xc2, 0xf6, 0xef, 0x85, 0x05, 0x18, 0x7a, 0x9b,
+                       0xba, 0x41, 0x54, 0xac, 0xf0, 0xfc, 0x59, 0x12,
+                       0x3f, 0xdf, 0xa0, 0xe5, 0x8a, 0x65, 0xfd, 0x3a,
+                       0x62, 0x8d, 0x83, 0x2c, 0x03, 0xbe, 0x05, 0x76,
+                       0x2e, 0x53, 0x49, 0x97, 0x94, 0x33, 0xae, 0x40,
+                       0x81, 0x15, 0xdb, 0x6e, 0xad, 0xaa, 0xf5, 0x4b,
+                       0xe3, 0x98, 0x70, 0xdf, 0xe0, 0x7c, 0xcd, 0xdb,
+                       0x02, 0xd4, 0x7d, 0x2f, 0xc1, 0xe6, 0xb4, 0xf3,
+                       0xd7, 0x0d, 0x7a, 0xd9, 0x23, 0x9e, 0x87, 0x2d,
+                       0xce, 0x87, 0xad, 0xcc, 0x72, 0x05, 0x00, 0x29,
+                       0xdc, 0x73, 0x7f, 0x64, 0xc1, 0x15, 0x0e, 0xc2,
+                       0xdf, 0xa7, 0x5f, 0xeb, 0x41, 0xa1, 0xcd, 0xef,
+                       0x5c, 0x50, 0x79, 0x2a, 0x56, 0x56, 0x71, 0x8c,
+                       0xac, 0xc0, 0x79, 0x50, 0x69, 0xca, 0x59, 0x32,
+                       0x65, 0xf2, 0x54, 0xe4, 0x52, 0x38, 0x76, 0xd1,
+                       0x5e, 0xde, 0x26, 0x9e, 0xfb, 0x75, 0x2e, 0x11,
+                       0xb5, 0x10, 0xf4, 0x17, 0x73, 0xf5, 0x89, 0xc7,
+                       0x4f, 0x43, 0x5c, 0x8e, 0x7c, 0xb9, 0x05, 0x52,
+                       0x24, 0x40, 0x99, 0xfe, 0x9b, 0x85, 0x0b, 0x6c,
+                       0x22, 0x3e, 0x8b, 0xae, 0x86, 0xa1, 0xd2, 0x79,
+                       0x05, 0x68, 0x6b, 0xab, 0xe3, 0x41, 0x49, 0xed,
+                       0x15, 0xa1, 0x8d, 0x40, 0x2d, 0x61, 0xdf, 0x1a,
+                       0x59, 0xc9, 0x26, 0x8b, 0xef, 0x30, 0x4c, 0x88,
+                       0x4b, 0x10, 0xf8, 0x8d, 0xa6, 0x92, 0x9f, 0x4b,
+                       0xf3, 0xc4, 0x53, 0x0b, 0x89, 0x5d, 0x28, 0x92,
+                       0xcf, 0x78, 0xb2, 0xc0, 0x5d, 0xed, 0x7e, 0xfc,
+                       0xc0, 0x12, 0x23, 0x5f, 0x5a, 0x78, 0x86, 0x43,
+                       0x6e, 0x27, 0xf7, 0x5a, 0xa7, 0x6a, 0xed, 0x19,
+                       0x04, 0xf0, 0xb3, 0x12, 0xd1, 0xbd, 0x0e, 0x89,
+                       0x6e, 0xbc, 0x96, 0xa8, 0xd8, 0x49, 0x39, 0x9f,
+                       0x7e, 0x67, 0xf0, 0x2e, 0x3e, 0x01, 0xa9, 0xba,
+                       0xec, 0x8b, 0x62, 0x8e, 0xcb, 0x4a, 0x70, 0x43,
+                       0xc7, 0xc2, 0xc4, 0xca, 0x82, 0x03, 0x73, 0xe9,
+                       0x11, 0xdf, 0xcf, 0x54, 0xea, 0xc9, 0xb0, 0x95,
+                       0x51, 0xc0, 0x13, 0x3d, 0x92, 0x05, 0xfa, 0xf4,
+                       0xa9, 0x34, 0xc8, 0xce, 0x6c, 0x3d, 0x54, 0xcc,
+                       0xc4, 0xaf, 0xf1, 0xdc, 0x11, 0x44, 0x26, 0xa2,
+                       0xaf, 0xf1, 0x85, 0x75, 0x7d, 0x03, 0x61, 0x68,
+                       0x4e, 0x78, 0xc6, 0x92, 0x7d, 0x86, 0x7d, 0x77,
+                       0xdc, 0x71, 0x72, 0xdb, 0xc6, 0xae, 0xa1, 0xcb,
+                       0x70, 0x9a, 0x0b, 0x19, 0xbe, 0x4a, 0x6c, 0x2a,
+                       0xe2, 0xba, 0x6c, 0x64, 0x9a, 0x13, 0x28, 0xdf,
+                       0x85, 0x75, 0xe6, 0x43, 0xf6, 0x87, 0x08, 0x68,
+                       0x6e, 0xba, 0x6e, 0x79, 0x9f, 0x04, 0xbc, 0x23,
+                       0x50, 0xf6, 0x33, 0x5c, 0x1f, 0x24, 0x25, 0xbe,
+                       0x33, 0x47, 0x80, 0x45, 0x56, 0xa3, 0xa7, 0xd7,
+                       0x7a, 0xb1, 0x34, 0x0b, 0x90, 0x3c, 0x9c, 0xad,
+                       0x44, 0x5f, 0x9e, 0x0e, 0x9d, 0xd4, 0xbd, 0x93,
+                       0x5e, 0xfa, 0x3c, 0xe0, 0xb0, 0xd9, 0xed, 0xf3,
+                       0xd6, 0x2e, 0xff, 0x24, 0xd8, 0x71, 0x6c, 0xed,
+                       0xaf, 0x55, 0xeb, 0x22, 0xac, 0x93, 0x68, 0x32,
+                       0x05, 0x5b, 0x47, 0xdd, 0xc6, 0x4a, 0xcb, 0xc7,
+                       0x10, 0xe1, 0x3c, 0x92, 0x1a, 0xf3, 0x23, 0x78,
+                       0x2b, 0xa1, 0xd2, 0x80, 0xf4, 0x12, 0xb1, 0x20,
+                       0x8f, 0xff, 0x26, 0x35, 0xdd, 0xfb, 0xc7, 0x4e,
+                       0x78, 0xf1, 0x2d, 0x50, 0x12, 0x77, 0xa8, 0x60,
+                       0x7c, 0x0f, 0xf5, 0x16, 0x2f, 0x63, 0x70, 0x2a,
+                       0xc0, 0x96, 0x80, 0x4e, 0x0a, 0xb4, 0x93, 0x35,
+                       0x5d, 0x1d, 0x3f, 0x56, 0xf7, 0x2f, 0xbb, 0x90,
+                       0x11, 0x16, 0x8f, 0xa2, 0xec, 0x47, 0xbe, 0xac,
+                       0x56, 0x01, 0x26, 0x56, 0xb1, 0x8c, 0xb2, 0x10,
+                       0xf9, 0x1a, 0xca, 0xf5, 0xd1, 0xb7, 0x39, 0x20,
+                       0x63, 0xf1, 0x69, 0x20, 0x4f, 0x13, 0x12, 0x1f,
+                       0x5b, 0x65, 0xfc, 0x98, 0xf7, 0xc4, 0x7a, 0xbe,
+                       0xf7, 0x26, 0x4d, 0x2b, 0x84, 0x7b, 0x42, 0xad,
+                       0xd8, 0x7a, 0x0a, 0xb4, 0xd8, 0x74, 0xbf, 0xc1,
+                       0xf0, 0x6e, 0xb4, 0x29, 0xa3, 0xbb, 0xca, 0x46,
+                       0x67, 0x70, 0x6a, 0x2d, 0xce, 0x0e, 0xa2, 0x8a,
+                       0xa9, 0x87, 0xbf, 0x05, 0xc4, 0xc1, 0x04, 0xa3,
+                       0xab, 0xd4, 0x45, 0x43, 0x8c, 0xb6, 0x02, 0xb0,
+                       0x41, 0xc8, 0xfc, 0x44, 0x3d, 0x59, 0xaa, 0x2e,
+                       0x44, 0x21, 0x2a, 0x8d, 0x88, 0x9d, 0x57, 0xf4,
+                       0xa0, 0x02, 0x77, 0xb8, 0xa6, 0xa0, 0xe6, 0x75,
+                       0x5c, 0x82, 0x65, 0x3e, 0x03, 0x5c, 0x29, 0x8f,
+                       0x38, 0x55, 0xab, 0x33, 0x26, 0xef, 0x9f, 0x43,
+                       0x52, 0xfd, 0x68, 0xaf, 0x36, 0xb4, 0xbb, 0x9a,
+                       0x58, 0x09, 0x09, 0x1b, 0xc3, 0x65, 0x46, 0x46,
+                       0x1d, 0xa7, 0x94, 0x18, 0x23, 0x50, 0x2c, 0xca,
+                       0x2c, 0x55, 0x19, 0x97, 0x01, 0x9d, 0x93, 0x3b,
+                       0x63, 0x86, 0xf2, 0x03, 0x67, 0x45, 0xd2, 0x72,
+                       0x28, 0x52, 0x6c, 0xf4, 0xe3, 0x1c, 0xb5, 0x11,
+                       0x13, 0xf1, 0xeb, 0x21, 0xc7, 0xd9, 0x56, 0x82,
+                       0x2b, 0x82, 0x39, 0xbd, 0x69, 0x54, 0xed, 0x62,
+                       0xc3, 0xe2, 0xde, 0x73, 0xd4, 0x6a, 0x12, 0xae,
+                       0x13, 0x21, 0x7f, 0x4b, 0x5b, 0xfc, 0xbf, 0xe8,
+                       0x2b, 0xbe, 0x56, 0xba, 0x68, 0x8b, 0x9a, 0xb1,
+                       0x6e, 0xfa, 0xbf, 0x7e, 0x5a, 0x4b, 0xf1, 0xac,
+                       0x98, 0x65, 0x85, 0xd1, 0x93, 0x53, 0xd3, 0x7b,
+                       0x09, 0xdd, 0x4b, 0x10, 0x6d, 0x84, 0xb0, 0x13,
+                       0x65, 0xbd, 0xcf, 0x52, 0x09, 0xc4, 0x85, 0xe2,
+                       0x84, 0x74, 0x15, 0x65, 0xb7, 0xf7, 0x51, 0xaf,
+                       0x55, 0xad, 0xa4, 0xd1, 0x22, 0x54, 0x70, 0x94,
+                       0xa0, 0x1c, 0x90, 0x41, 0xfd, 0x99, 0xd7, 0x5a,
+                       0x31, 0xef, 0xaa, 0x25, 0xd0, 0x7f, 0x4f, 0xea,
+                       0x1d, 0x55, 0x42, 0xe5, 0x49, 0xb0, 0xd0, 0x46,
+                       0x62, 0x36, 0x43, 0xb2, 0x82, 0x15, 0x75, 0x50,
+                       0xa4, 0x72, 0xeb, 0x54, 0x27, 0x1f, 0x8a, 0xe4,
+                       0x7d, 0xe9, 0x66, 0xc5, 0xf1, 0x53, 0xa4, 0xd1,
+                       0x0c, 0xeb, 0xb8, 0xf8, 0xbc, 0xd4, 0xe2, 0xe7,
+                       0xe1, 0xf8, 0x4b, 0xcb, 0xa9, 0xa1, 0xaf, 0x15,
+                       0x83, 0xcb, 0x72, 0xd0, 0x33, 0x79, 0x00, 0x2d,
+                       0x9f, 0xd7, 0xf1, 0x2e, 0x1e, 0x10, 0xe4, 0x45,
+                       0xc0, 0x75, 0x3a, 0x39, 0xea, 0x68, 0xf7, 0x5d,
+                       0x1b, 0x73, 0x8f, 0xe9, 0x8e, 0x0f, 0x72, 0x47,
+                       0xae, 0x35, 0x0a, 0x31, 0x7a, 0x14, 0x4d, 0x4a,
+                       0x6f, 0x47, 0xf7, 0x7e, 0x91, 0x6e, 0x74, 0x8b,
+                       0x26, 0x47, 0xf9, 0xc3, 0xf9, 0xde, 0x70, 0xf5,
+                       0x61, 0xab, 0xa9, 0x27, 0x9f, 0x82, 0xe4, 0x9c,
+                       0x89, 0x91, 0x3f, 0x2e, 0x6a, 0xfd, 0xb5, 0x49,
+                       0xe9, 0xfd, 0x59, 0x14, 0x36, 0x49, 0x40, 0x6d,
+                       0x32, 0xd8, 0x85, 0x42, 0xf3, 0xa5, 0xdf, 0x0c,
+                       0xa8, 0x27, 0xd7, 0x54, 0xe2, 0x63, 0x2f, 0xf2,
+                       0x7e, 0x8b, 0x8b, 0xe7, 0xf1, 0x9a, 0x95, 0x35,
+                       0x43, 0xdc, 0x3a, 0xe4, 0xb6, 0xf4, 0xd0, 0xdf,
+                       0x9c, 0xcb, 0x94, 0xf3, 0x21, 0xa0, 0x77, 0x50,
+                       0xe2, 0xc6, 0xc4, 0xc6, 0x5f, 0x09, 0x64, 0x5b,
+                       0x92, 0x90, 0xd8, 0xe1, 0xd1, 0xed, 0x4b, 0x42,
+                       0xd7, 0x37, 0xaf, 0x65, 0x3d, 0x11, 0x39, 0xb6,
+                       0x24, 0x8a, 0x60, 0xae, 0xd6, 0x1e, 0xbf, 0x0e,
+                       0x0d, 0xd7, 0xdc, 0x96, 0x0e, 0x65, 0x75, 0x4e,
+                       0x29, 0x06, 0x9d, 0xa4, 0x51, 0x3a, 0x10, 0x63,
+                       0x8f, 0x17, 0x07, 0xd5, 0x8e, 0x3c, 0xf4, 0x28,
+                       0x00, 0x5a, 0x5b, 0x05, 0x19, 0xd8, 0xc0, 0x6c,
+                       0xe5, 0x15, 0xe4, 0x9c, 0x9d, 0x71, 0x9d, 0x5e,
+                       0x94, 0x29, 0x1a, 0xa7, 0x80, 0xfa, 0x0e, 0x33,
+                       0x03, 0xdd, 0xb7, 0x3e, 0x9a, 0xa9, 0x26, 0x18,
+                       0x37, 0xa9, 0x64, 0x08, 0x4d, 0x94, 0x5a, 0x88,
+                       0xca, 0x35, 0xce, 0x81, 0x02, 0xe3, 0x1f, 0x1b,
+                       0x89, 0x1a, 0x77, 0x85, 0xe3, 0x41, 0x6d, 0x32,
+                       0x42, 0x19, 0x23, 0x7d, 0xc8, 0x73, 0xee, 0x25,
+                       0x85, 0x0d, 0xf8, 0x31, 0x25, 0x79, 0x1b, 0x6f,
+                       0x79, 0x25, 0xd2, 0xd8, 0xd4, 0x23, 0xfd, 0xf7,
+                       0x82, 0x36, 0x6a, 0x0c, 0x46, 0x22, 0x15, 0xe9,
+                       0xff, 0x72, 0x41, 0x91, 0x91, 0x7d, 0x3a, 0xb7,
+                       0xdd, 0x65, 0x99, 0x70, 0xf6, 0x8d, 0x84, 0xf8,
+                       0x67, 0x15, 0x20, 0x11, 0xd6, 0xb2, 0x55, 0x7b,
+                       0xdb, 0x87, 0xee, 0xef, 0x55, 0x89, 0x2a, 0x59,
+                       0x2b, 0x07, 0x8f, 0x43, 0x8a, 0x59, 0x3c, 0x01,
+                       0x8b, 0x65, 0x54, 0xa1, 0x66, 0xd5, 0x38, 0xbd,
+                       0xc6, 0x30, 0xa9, 0xcc, 0x49, 0xb6, 0xa8, 0x1b,
+                       0xb8, 0xc0, 0x0e, 0xe3, 0x45, 0x28, 0xe2, 0xff,
+                       0x41, 0x9f, 0x7e, 0x7c, 0xd1, 0xae, 0x9e, 0x25,
+                       0x3f, 0x4c, 0x7c, 0x7c, 0xf4, 0xa8, 0x26, 0x4d,
+                       0x5c, 0xfd, 0x4b, 0x27, 0x18, 0xf9, 0x61, 0x76,
+                       0x48, 0xba, 0x0c, 0x6b, 0xa9, 0x4d, 0xfc, 0xf5,
+                       0x3b, 0x35, 0x7e, 0x2f, 0x4a, 0xa9, 0xc2, 0x9a,
+                       0xae, 0xab, 0x86, 0x09, 0x89, 0xc9, 0xc2, 0x40,
+                       0x39, 0x2c, 0x81, 0xb3, 0xb8, 0x17, 0x67, 0xc2,
+                       0x0d, 0x32, 0x4a, 0x3a, 0x67, 0x81, 0xd7, 0x1a,
+                       0x34, 0x52, 0xc5, 0xdb, 0x0a, 0xf5, 0x63, 0x39,
+                       0xea, 0x1f, 0xe1, 0x7c, 0xa1, 0x9e, 0xc1, 0x35,
+                       0xe3, 0xb1, 0x18, 0x45, 0x67, 0xf9, 0x22, 0x38,
+                       0x95, 0xd9, 0x34, 0x34, 0x86, 0xc6, 0x41, 0x94,
+                       0x15, 0xf9, 0x5b, 0x41, 0xa6, 0x87, 0x8b, 0xf8,
+                       0xd5, 0xe1, 0x1b, 0xe2, 0x5b, 0xf3, 0x86, 0x10,
+                       0xff, 0xe6, 0xae, 0x69, 0x76, 0xbc, 0x0d, 0xb4,
+                       0x09, 0x90, 0x0c, 0xa2, 0x65, 0x0c, 0xad, 0x74,
+                       0xf5, 0xd7, 0xff, 0xda, 0xc1, 0xce, 0x85, 0xbe,
+                       0x00, 0xa7, 0xff, 0x4d, 0x2f, 0x65, 0xd3, 0x8c,
+                       0x86, 0x2d, 0x05, 0xe8, 0xed, 0x3e, 0x6b, 0x8b,
+                       0x0f, 0x3d, 0x83, 0x8c, 0xf1, 0x1d, 0x5b, 0x96,
+                       0x2e, 0xb1, 0x9c, 0xc2, 0x98, 0xe1, 0x70, 0xb9,
+                       0xba, 0x5c, 0x8a, 0x43, 0xd6, 0x34, 0xa7, 0x2d,
+                       0xc9, 0x92, 0xae, 0xf2, 0xa5, 0x7b, 0x05, 0x49,
+                       0xa7, 0x33, 0x34, 0x86, 0xca, 0xe4, 0x96, 0x23,
+                       0x76, 0x5b, 0xf2, 0xc6, 0xf1, 0x51, 0x28, 0x42,
+                       0x7b, 0xcc, 0x76, 0x8f, 0xfa, 0xa2, 0xad, 0x31,
+                       0xd4, 0xd6, 0x7a, 0x6d, 0x25, 0x25, 0x54, 0xe4,
+                       0x3f, 0x50, 0x59, 0xe1, 0x5c, 0x05, 0xb7, 0x27,
+                       0x48, 0xbf, 0x07, 0xec, 0x1b, 0x13, 0xbe, 0x2b,
+                       0xa1, 0x57, 0x2b, 0xd5, 0xab, 0xd7, 0xd0, 0x4c,
+                       0x1e, 0xcb, 0x71, 0x9b, 0xc5, 0x90, 0x85, 0xd3,
+                       0xde, 0x59, 0xec, 0x71, 0xeb, 0x89, 0xbb, 0xd0,
+                       0x09, 0x50, 0xe1, 0x16, 0x3f, 0xfd, 0x1c, 0x34,
+                       0xc3, 0x1c, 0xa1, 0x10, 0x77, 0x53, 0x98, 0xef,
+                       0xf2, 0xfd, 0xa5, 0x01, 0x59, 0xc2, 0x9b, 0x26,
+                       0xc7, 0x42, 0xd9, 0x49, 0xda, 0x58, 0x2b, 0x6e,
+                       0x9f, 0x53, 0x19, 0x76, 0x7e, 0xd9, 0xc9, 0x0e,
+                       0x68, 0xc8, 0x7f, 0x51, 0x22, 0x42, 0xef, 0x49,
+                       0xa4, 0x55, 0xb6, 0x36, 0xac, 0x09, 0xc7, 0x31,
+                       0x88, 0x15, 0x4b, 0x2e, 0x8f, 0x3a, 0x08, 0xf7,
+                       0xd8, 0xf7, 0xa8, 0xc5, 0xa9, 0x33, 0xa6, 0x45,
+                       0xe4, 0xc4, 0x94, 0x76, 0xf3, 0x0d, 0x8f, 0x7e,
+                       0xc8, 0xf6, 0xbc, 0x23, 0x0a, 0xb6, 0x4c, 0xd3,
+                       0x6a, 0xcd, 0x36, 0xc2, 0x90, 0x5c, 0x5c, 0x3c,
+                       0x65, 0x7b, 0xc2, 0xd6, 0xcc, 0xe6, 0x0d, 0x87,
+                       0x73, 0x2e, 0x71, 0x79, 0x16, 0x06, 0x63, 0x28,
+                       0x09, 0x15, 0xd8, 0x89, 0x38, 0x38, 0x3d, 0xb5,
+                       0x42, 0x1c, 0x08, 0x24, 0xf7, 0x2a, 0xd2, 0x9d,
+                       0xc8, 0xca, 0xef, 0xf9, 0x27, 0xd8, 0x07, 0x86,
+                       0xf7, 0x43, 0x0b, 0x55, 0x15, 0x3f, 0x9f, 0x83,
+                       0xef, 0xdc, 0x49, 0x9d, 0x2a, 0xc1, 0x54, 0x62,
+                       0xbd, 0x9b, 0x66, 0x55, 0x9f, 0xb7, 0x12, 0xf3,
+                       0x1b, 0x4d, 0x9d, 0x2a, 0x5c, 0xed, 0x87, 0x75,
+                       0x87, 0x26, 0xec, 0x61, 0x2c, 0xb4, 0x0f, 0x89,
+                       0xb0, 0xfb, 0x2e, 0x68, 0x5d, 0x15, 0xc7, 0x8d,
+                       0x2e, 0xc0, 0xd9, 0xec, 0xaf, 0x4f, 0xd2, 0x25,
+                       0x29, 0xe8, 0xd2, 0x26, 0x2b, 0x67, 0xe9, 0xfc,
+                       0x2b, 0xa8, 0x67, 0x96, 0x12, 0x1f, 0x5b, 0x96,
+                       0xc6, 0x14, 0x53, 0xaf, 0x44, 0xea, 0xd6, 0xe2,
+                       0x94, 0x98, 0xe4, 0x12, 0x93, 0x4c, 0x92, 0xe0,
+                       0x18, 0xa5, 0x8d, 0x2d, 0xe4, 0x71, 0x3c, 0x47,
+                       0x4c, 0xf7, 0xe6, 0x47, 0x9e, 0xc0, 0x68, 0xdf,
+                       0xd4, 0xf5, 0x5a, 0x74, 0xb1, 0x2b, 0x29, 0x03,
+                       0x19, 0x07, 0xaf, 0x90, 0x62, 0x5c, 0x68, 0x98,
+                       0x48, 0x16, 0x11, 0x02, 0x9d, 0xee, 0xb4, 0x9b,
+                       0xe5, 0x42, 0x7f, 0x08, 0xfd, 0x16, 0x32, 0x0b,
+                       0xd0, 0xb3, 0xfa, 0x2b, 0xb7, 0x99, 0xf9, 0x29,
+                       0xcd, 0x20, 0x45, 0x9f, 0xb3, 0x1a, 0x5d, 0xa2,
+                       0xaf, 0x4d, 0xe0, 0xbd, 0x42, 0x0d, 0xbc, 0x74,
+                       0x99, 0x9c, 0x8e, 0x53, 0x1a, 0xb4, 0x3e, 0xbd,
+                       0xa2, 0x9a, 0x2d, 0xf7, 0xf8, 0x39, 0x0f, 0x67,
+                       0x63, 0xfc, 0x6b, 0xc0, 0xaf, 0xb3, 0x4b, 0x4f,
+                       0x55, 0xc4, 0xcf, 0xa7, 0xc8, 0x04, 0x11, 0x3e,
+                       0x14, 0x32, 0xbb, 0x1b, 0x38, 0x77, 0xd6, 0x7f,
+                       0x54, 0x4c, 0xdf, 0x75, 0xf3, 0x07, 0x2d, 0x33,
+                       0x9b, 0xa8, 0x20, 0xe1, 0x7b, 0x12, 0xb5, 0xf3,
+                       0xef, 0x2f, 0xce, 0x72, 0xe5, 0x24, 0x60, 0xc1,
+                       0x30, 0xe2, 0xab, 0xa1, 0x8e, 0x11, 0x09, 0xa8,
+                       0x21, 0x33, 0x44, 0xfe, 0x7f, 0x35, 0x32, 0x93,
+                       0x39, 0xa7, 0xad, 0x8b, 0x79, 0x06, 0xb2, 0xcb,
+                       0x4e, 0xa9, 0x5f, 0xc7, 0xba, 0x74, 0x29, 0xec,
+                       0x93, 0xa0, 0x4e, 0x54, 0x93, 0xc0, 0xbc, 0x55,
+                       0x64, 0xf0, 0x48, 0xe5, 0x57, 0x99, 0xee, 0x75,
+                       0xd6, 0x79, 0x0f, 0x66, 0xb7, 0xc6, 0x57, 0x76,
+                       0xf7, 0xb7, 0xf3, 0x9c, 0xc5, 0x60, 0xe8, 0x7f,
+                       0x83, 0x76, 0xd6, 0x0e, 0xaa, 0xe6, 0x90, 0x39,
+                       0x1d, 0xa6, 0x32, 0x6a, 0x34, 0xe3, 0x55, 0xf8,
+                       0x58, 0xa0, 0x58, 0x7d, 0x33, 0xe0, 0x22, 0x39,
+                       0x44, 0x64, 0x87, 0x86, 0x5a, 0x2f, 0xa7, 0x7e,
+                       0x0f, 0x38, 0xea, 0xb0, 0x30, 0xcc, 0x61, 0xa5,
+                       0x6a, 0x32, 0xae, 0x1e, 0xf7, 0xe9, 0xd0, 0xa9,
+                       0x0c, 0x32, 0x4b, 0xb5, 0x49, 0x28, 0xab, 0x85,
+                       0x2f, 0x8e, 0x01, 0x36, 0x38, 0x52, 0xd0, 0xba,
+                       0xd6, 0x02, 0x78, 0xf8, 0x0e, 0x3e, 0x9c, 0x8b,
+                       0x6b, 0x45, 0x99, 0x3f, 0x5c, 0xfe, 0x58, 0xf1,
+                       0x5c, 0x94, 0x04, 0xe1, 0xf5, 0x18, 0x6d, 0x51,
+                       0xb2, 0x5d, 0x18, 0x20, 0xb6, 0xc2, 0x9a, 0x42,
+                       0x1d, 0xb3, 0xab, 0x3c, 0xb6, 0x3a, 0x13, 0x03,
+                       0xb2, 0x46, 0x82, 0x4f, 0xfc, 0x64, 0xbc, 0x4f,
+                       0xca, 0xfa, 0x9c, 0xc0, 0xd5, 0xa7, 0xbd, 0x11,
+                       0xb7, 0xe4, 0x5a, 0xf6, 0x6f, 0x4d, 0x4d, 0x54,
+                       0xea, 0xa4, 0x98, 0x66, 0xd4, 0x22, 0x3b, 0xd3,
+                       0x8f, 0x34, 0x47, 0xd9, 0x7c, 0xf4, 0x72, 0x3b,
+                       0x4d, 0x02, 0x77, 0xf6, 0xd6, 0xdd, 0x08, 0x0a,
+                       0x81, 0xe1, 0x86, 0x89, 0x3e, 0x56, 0x10, 0x3c,
+                       0xba, 0xd7, 0x81, 0x8c, 0x08, 0xbc, 0x8b, 0xe2,
+                       0x53, 0xec, 0xa7, 0x89, 0xee, 0xc8, 0x56, 0xb5,
+                       0x36, 0x2c, 0xb2, 0x03, 0xba, 0x99, 0xdd, 0x7c,
+                       0x48, 0xa0, 0xb0, 0xbc, 0x91, 0x33, 0xe9, 0xa8,
+                       0xcb, 0xcd, 0xcf, 0x59, 0x5f, 0x1f, 0x15, 0xe2,
+                       0x56, 0xf5, 0x4e, 0x01, 0x35, 0x27, 0x45, 0x77,
+                       0x47, 0xc8, 0xbc, 0xcb, 0x7e, 0x39, 0xc1, 0x97,
+                       0x28, 0xd3, 0x84, 0xfc, 0x2c, 0x3e, 0xc8, 0xad,
+                       0x9c, 0xf8, 0x8a, 0x61, 0x9c, 0x28, 0xaa, 0xc5,
+                       0x99, 0x20, 0x43, 0x85, 0x9d, 0xa5, 0xe2, 0x8b,
+                       0xb8, 0xae, 0xeb, 0xd0, 0x32, 0x0d, 0x52, 0x78,
+                       0x09, 0x56, 0x3f, 0xc7, 0xd8, 0x7e, 0x26, 0xfc,
+                       0x37, 0xfb, 0x6f, 0x04, 0xfc, 0xfa, 0x92, 0x10,
+                       0xac, 0xf8, 0x3e, 0x21, 0xdc, 0x8c, 0x21, 0x16,
+                       0x7d, 0x67, 0x6e, 0xf6, 0xcd, 0xda, 0xb6, 0x98,
+                       0x23, 0xab, 0x23, 0x3c, 0xb2, 0x10, 0xa0, 0x53,
+                       0x5a, 0x56, 0x9f, 0xc5, 0xd0, 0xff, 0xbb, 0xe4,
+                       0x98, 0x3c, 0x69, 0x1e, 0xdb, 0x38, 0x8f, 0x7e,
+                       0x0f, 0xd2, 0x98, 0x88, 0x81, 0x8b, 0x45, 0x67,
+                       0xea, 0x33, 0xf1, 0xeb, 0xe9, 0x97, 0x55, 0x2e,
+                       0xd9, 0xaa, 0xeb, 0x5a, 0xec, 0xda, 0xe1, 0x68,
+                       0xa8, 0x9d, 0x3c, 0x84, 0x7c, 0x05, 0x3d, 0x62,
+                       0x87, 0x8f, 0x03, 0x21, 0x28, 0x95, 0x0c, 0x89,
+                       0x25, 0x22, 0x4a, 0xb0, 0x93, 0xa9, 0x50, 0xa2,
+                       0x2f, 0x57, 0x6e, 0x18, 0x42, 0x19, 0x54, 0x0c,
+                       0x55, 0x67, 0xc6, 0x11, 0x49, 0xf4, 0x5c, 0xd2,
+                       0xe9, 0x3d, 0xdd, 0x8b, 0x48, 0x71, 0x21, 0x00,
+                       0xc3, 0x9a, 0x6c, 0x85, 0x74, 0x28, 0x83, 0x4a,
+                       0x1b, 0x31, 0x05, 0xe1, 0x06, 0x92, 0xe7, 0xda,
+                       0x85, 0x73, 0x78, 0x45, 0x20, 0x7f, 0xae, 0x13,
+                       0x7c, 0x33, 0x06, 0x22, 0xf4, 0x83, 0xf9, 0x35,
+                       0x3f, 0x6c, 0x71, 0xa8, 0x4e, 0x48, 0xbe, 0x9b,
+                       0xce, 0x8a, 0xba, 0xda, 0xbe, 0x28, 0x08, 0xf7,
+                       0xe2, 0x14, 0x8c, 0x71, 0xea, 0x72, 0xf9, 0x33,
+                       0xf2, 0x88, 0x3f, 0xd7, 0xbb, 0x69, 0x6c, 0x29,
+                       0x19, 0xdc, 0x84, 0xce, 0x1f, 0x12, 0x4f, 0xc8,
+                       0xaf, 0xa5, 0x04, 0xba, 0x5a, 0xab, 0xb0, 0xd9,
+                       0x14, 0x1f, 0x6c, 0x68, 0x98, 0x39, 0x89, 0x7a,
+                       0xd9, 0xd8, 0x2f, 0xdf, 0xa8, 0x47, 0x4a, 0x25,
+                       0xe2, 0xfb, 0x33, 0xf4, 0x59, 0x78, 0xe1, 0x68,
+                       0x85, 0xcf, 0xfe, 0x59, 0x20, 0xd4, 0x05, 0x1d,
+                       0x80, 0x99, 0xae, 0xbc, 0xca, 0xae, 0x0f, 0x2f,
+                       0x65, 0x43, 0x34, 0x8e, 0x7e, 0xac, 0xd3, 0x93,
+                       0x2f, 0xac, 0x6d, 0x14, 0x3d, 0x02, 0x07, 0x70,
+                       0x9d, 0xa4, 0xf3, 0x1b, 0x5c, 0x36, 0xfc, 0x01,
+                       0x73, 0x34, 0x85, 0x0c, 0x6c, 0xd6, 0xf1, 0xbd,
+                       0x3f, 0xdf, 0xee, 0xf5, 0xd9, 0xba, 0x56, 0xef,
+                       0xf4, 0x9b, 0x6b, 0xee, 0x9f, 0x5a, 0x78, 0x6d,
+                       0x32, 0x19, 0xf4, 0xf7, 0xf8, 0x4c, 0x69, 0x0b,
+                       0x4b, 0xbc, 0xbb, 0xb7, 0xf2, 0x85, 0xaf, 0x70,
+                       0x75, 0x24, 0x6c, 0x54, 0xa7, 0x0e, 0x4d, 0x1d,
+                       0x01, 0xbf, 0x08, 0xac, 0xcf, 0x7f, 0x2c, 0xe3,
+                       0x14, 0x89, 0x5e, 0x70, 0x5a, 0x99, 0x92, 0xcd,
+                       0x01, 0x84, 0xc8, 0xd2, 0xab, 0xe5, 0x4f, 0x58,
+                       0xe7, 0x0f, 0x2f, 0x0e, 0xff, 0x68, 0xea, 0xfd,
+                       0x15, 0xb3, 0x17, 0xe6, 0xb0, 0xe7, 0x85, 0xd8,
+                       0x23, 0x2e, 0x05, 0xc7, 0xc9, 0xc4, 0x46, 0x1f,
+                       0xe1, 0x9e, 0x49, 0x20, 0x23, 0x24, 0x4d, 0x7e,
+                       0x29, 0x65, 0xff, 0xf4, 0xb6, 0xfd, 0x1a, 0x85,
+                       0xc4, 0x16, 0xec, 0xfc, 0xea, 0x7b, 0xd6, 0x2c,
+                       0x43, 0xf8, 0xb7, 0xbf, 0x79, 0xc0, 0x85, 0xcd,
+                       0xef, 0xe1, 0x98, 0xd3, 0xa5, 0xf7, 0x90, 0x8c,
+                       0xe9, 0x7f, 0x80, 0x6b, 0xd2, 0xac, 0x4c, 0x30,
+                       0xa7, 0xc6, 0x61, 0x6c, 0xd2, 0xf9, 0x2c, 0xff,
+                       0x30, 0xbc, 0x22, 0x81, 0x7d, 0x93, 0x12, 0xe4,
+                       0x0a, 0xcd, 0xaf, 0xdd, 0xe8, 0xab, 0x0a, 0x1e,
+                       0x13, 0xa4, 0x27, 0xc3, 0x5f, 0xf7, 0x4b, 0xbb,
+                       0x37, 0x09, 0x4b, 0x91, 0x6f, 0x92, 0x4f, 0xaf,
+                       0x52, 0xee, 0xdf, 0xef, 0x09, 0x6f, 0xf7, 0x5c,
+                       0x6e, 0x12, 0x17, 0x72, 0x63, 0x57, 0xc7, 0xba,
+                       0x3b, 0x6b, 0x38, 0x32, 0x73, 0x1b, 0x9c, 0x80,
+                       0xc1, 0x7a, 0xc6, 0xcf, 0xcd, 0x35, 0xc0, 0x6b,
+                       0x31, 0x1a, 0x6b, 0xe9, 0xd8, 0x2c, 0x29, 0x3f,
+                       0x96, 0xfb, 0xb6, 0xcd, 0x13, 0x91, 0x3b, 0xc2,
+                       0xd2, 0xa3, 0x31, 0x8d, 0xa4, 0xcd, 0x57, 0xcd,
+                       0x13, 0x3d, 0x64, 0xfd, 0x06, 0xce, 0xe6, 0xdc,
+                       0x0c, 0x24, 0x43, 0x31, 0x40, 0x57, 0xf1, 0x72,
+                       0x17, 0xe3, 0x3a, 0x63, 0x6d, 0x35, 0xcf, 0x5d,
+                       0x97, 0x40, 0x59, 0xdd, 0xf7, 0x3c, 0x02, 0xf7,
+                       0x1c, 0x7e, 0x05, 0xbb, 0xa9, 0x0d, 0x01, 0xb1,
+                       0x8e, 0xc0, 0x30, 0xa9, 0x53, 0x24, 0xc9, 0x89,
+                       0x84, 0x6d, 0xaa, 0xd0, 0xcd, 0x91, 0xc2, 0x4d,
+                       0x91, 0xb0, 0x89, 0xe2, 0xbf, 0x83, 0x44, 0xaa,
+                       0x28, 0x72, 0x23, 0xa0, 0xc2, 0xad, 0xad, 0x1c,
+                       0xfc, 0x3f, 0x09, 0x7a, 0x0b, 0xdc, 0xc5, 0x1b,
+                       0x87, 0x13, 0xc6, 0x5b, 0x59, 0x8d, 0xf2, 0xc8,
+                       0xaf, 0xdf, 0x11, 0x95,
+               },
+               .rlen = 4100,
+       },
+};
+
 /*
  * Compression stuff.
  */
@@ -4407,6 +7720,88 @@ static struct comp_testvec deflate_decomp_tv_template[] = {
        },
 };
 
+/*
+ * LZO test vectors (null-terminated strings).
+ */
+#define LZO_COMP_TEST_VECTORS 2
+#define LZO_DECOMP_TEST_VECTORS 2
+
+static struct comp_testvec lzo_comp_tv_template[] = {
+       {
+               .inlen  = 70,
+               .outlen = 46,
+               .input  = "Join us now and share the software "
+                         "Join us now and share the software ",
+               .output = {  0x00, 0x0d, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75,
+                            0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e,
+                            0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20,
+                            0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74,
+                            0x77, 0x70, 0x01, 0x01, 0x4a, 0x6f, 0x69, 0x6e,
+                            0x3d, 0x88, 0x00, 0x11, 0x00, 0x00 },
+       }, {
+               .inlen  = 159,
+               .outlen = 133,
+               .input  = "This document describes a compression method based on the LZO "
+                         "compression algorithm.  This document defines the application of "
+                         "the LZO algorithm used in UBIFS.",
+               .output = { 0x00, 0x2b, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64,
+                           0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20,
+                           0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+                           0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70,
+                           0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+                           0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x62,
+                           0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20,
+                           0x74, 0x68, 0x65, 0x20, 0x4c, 0x5a, 0x4f, 0x2b,
+                           0x8c, 0x00, 0x0d, 0x61, 0x6c, 0x67, 0x6f, 0x72,
+                           0x69, 0x74, 0x68, 0x6d, 0x2e, 0x20, 0x20, 0x54,
+                           0x68, 0x69, 0x73, 0x2a, 0x54, 0x01, 0x02, 0x66,
+                           0x69, 0x6e, 0x65, 0x73, 0x94, 0x06, 0x05, 0x61,
+                           0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x76,
+                           0x0a, 0x6f, 0x66, 0x88, 0x02, 0x60, 0x09, 0x27,
+                           0xf0, 0x00, 0x0c, 0x20, 0x75, 0x73, 0x65, 0x64,
+                           0x20, 0x69, 0x6e, 0x20, 0x55, 0x42, 0x49, 0x46,
+                           0x53, 0x2e, 0x11, 0x00, 0x00 },
+       },
+};
+
+static struct comp_testvec lzo_decomp_tv_template[] = {
+       {
+               .inlen  = 133,
+               .outlen = 159,
+               .input  = { 0x00, 0x2b, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64,
+                           0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20,
+                           0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+                           0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70,
+                           0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+                           0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x62,
+                           0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20,
+                           0x74, 0x68, 0x65, 0x20, 0x4c, 0x5a, 0x4f, 0x2b,
+                           0x8c, 0x00, 0x0d, 0x61, 0x6c, 0x67, 0x6f, 0x72,
+                           0x69, 0x74, 0x68, 0x6d, 0x2e, 0x20, 0x20, 0x54,
+                           0x68, 0x69, 0x73, 0x2a, 0x54, 0x01, 0x02, 0x66,
+                           0x69, 0x6e, 0x65, 0x73, 0x94, 0x06, 0x05, 0x61,
+                           0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x76,
+                           0x0a, 0x6f, 0x66, 0x88, 0x02, 0x60, 0x09, 0x27,
+                           0xf0, 0x00, 0x0c, 0x20, 0x75, 0x73, 0x65, 0x64,
+                           0x20, 0x69, 0x6e, 0x20, 0x55, 0x42, 0x49, 0x46,
+                           0x53, 0x2e, 0x11, 0x00, 0x00 },
+               .output = "This document describes a compression method based on the LZO "
+                         "compression algorithm.  This document defines the application of "
+                         "the LZO algorithm used in UBIFS.",
+       }, {
+               .inlen  = 46,
+               .outlen = 70,
+               .input  = { 0x00, 0x0d, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75,
+                           0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e,
+                           0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20,
+                           0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74,
+                           0x77, 0x70, 0x01, 0x01, 0x4a, 0x6f, 0x69, 0x6e,
+                           0x3d, 0x88, 0x00, 0x11, 0x00, 0x00 },
+               .output = "Join us now and share the software "
+                         "Join us now and share the software ",
+       },
+};
+
 /*
  * Michael MIC test vectors from IEEE 802.11i
  */
@@ -4812,4 +8207,20 @@ static struct cipher_speed camellia_speed_template[] = {
       {  .klen = 0, .blen = 0, }
 };
 
+static struct cipher_speed salsa20_speed_template[] = {
+      { .klen = 16, .blen = 16, },
+      { .klen = 16, .blen = 64, },
+      { .klen = 16, .blen = 256, },
+      { .klen = 16, .blen = 1024, },
+      { .klen = 16, .blen = 8192, },
+      { .klen = 32, .blen = 16, },
+      { .klen = 32, .blen = 64, },
+      { .klen = 32, .blen = 256, },
+      { .klen = 32, .blen = 1024, },
+      { .klen = 32, .blen = 8192, },
+
+      /* End marker */
+      {  .klen = 0, .blen = 0, }
+};
+
 #endif /* _CRYPTO_TCRYPT_H */
index b4b9c0c3f4ae74852a3a0fa1c71d59a17c6fbc90..0af216c75d7ea8f41666be90c201f757e029ef1b 100644 (file)
@@ -655,84 +655,48 @@ int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
                        CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
                }
 
-               /* Calculate whitening and round subkeys.  The constants are
-                * indices of subkeys, preprocessed through q0 and q1. */
-               CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
-               CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
-               CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
-               CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
-               CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
-               CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
-               CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
-               CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
-               CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
-               CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
-               CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
-               CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
-               CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
-               CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
-               CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
-               CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
-               CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
-               CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
-               CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
-               CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+               /* CALC_K256/CALC_K192/CALC_K loops were unrolled.
+                * Unrolling produced x2.5 more code (+18k on i386),
+                * and speeded up key setup by 7%:
+                * unrolled: twofish_setkey/sec: 41128
+                *     loop: twofish_setkey/sec: 38148
+                * CALC_K256: ~100 insns each
+                * CALC_K192: ~90 insns
+                *    CALC_K: ~70 insns
+                */
+               /* Calculate whitening and round subkeys */
+               for ( i = 0; i < 8; i += 2 ) {
+                       CALC_K256 (w, i, q0[i], q1[i], q0[i+1], q1[i+1]);
+               }
+               for ( i = 0; i < 32; i += 2 ) {
+                       CALC_K256 (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]);
+               }
        } else if (key_len == 24) { /* 192-bit key */
                /* Compute the S-boxes. */
                for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
                        CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
                }
 
-               /* Calculate whitening and round subkeys.  The constants are
-                * indices of subkeys, preprocessed through q0 and q1. */
-               CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
-               CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
-               CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
-               CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
-               CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
-               CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
-               CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
-               CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
-               CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
-               CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
-               CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71);
-               CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
-               CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F);
-               CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
-               CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
-               CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F);
-               CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
-               CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
-               CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00);
-               CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+               /* Calculate whitening and round subkeys */
+               for ( i = 0; i < 8; i += 2 ) {
+                       CALC_K192 (w, i, q0[i], q1[i], q0[i+1], q1[i+1]);
+               }
+               for ( i = 0; i < 32; i += 2 ) {
+                       CALC_K192 (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]);
+               }
        } else { /* 128-bit key */
                /* Compute the S-boxes. */
                for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
                        CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
                }
 
-               /* Calculate whitening and round subkeys.  The constants are
-                * indices of subkeys, preprocessed through q0 and q1. */
-               CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
-               CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
-               CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
-               CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
-               CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
-               CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
-               CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
-               CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
-               CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
-               CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
-               CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
-               CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
-               CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
-               CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
-               CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
-               CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
-               CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
-               CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
-               CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
-               CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+               /* Calculate whitening and round subkeys */
+               for ( i = 0; i < 8; i += 2 ) {
+                       CALC_K (w, i, q0[i], q1[i], q0[i+1], q1[i+1]);
+               }
+               for ( i = 0; i < 32; i += 2 ) {
+                       CALC_K (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]);
+               }
        }
 
        return 0;
index ac68f3b62fde7c533cd1d1faf8c169c313864773..a82959df678c3741f17b9a6bb30bbaf63a540524 100644 (file)
@@ -19,6 +19,7 @@
  *     Kazunori Miyazawa <miyazawa@linux-ipv6.org>
  */
 
+#include <crypto/scatterwalk.h>
 #include <linux/crypto.h>
 #include <linux/err.h>
 #include <linux/hardirq.h>
@@ -27,7 +28,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
-#include "internal.h"
 
 static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
                           0x02020202, 0x02020202, 0x02020202, 0x02020202,
@@ -307,7 +307,8 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
        case 16:
                break;
        default:
-               return ERR_PTR(PTR_ERR(alg));
+               inst = ERR_PTR(-EINVAL);
+               goto out_put_alg;
        }
 
        inst = crypto_alloc_instance("xcbc", alg);
@@ -320,10 +321,7 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
        inst->alg.cra_alignmask = alg->cra_alignmask;
        inst->alg.cra_type = &crypto_hash_type;
 
-       inst->alg.cra_hash.digestsize =
-               (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
-               CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
-                                      alg->cra_blocksize;
+       inst->alg.cra_hash.digestsize = alg->cra_blocksize;
        inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) +
                                ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *));
        inst->alg.cra_init = xcbc_init_tfm;
index b9f923ef173d8fc283e2122bc600e59039f0f396..ccf6ea95f68c76dc27d5eb9f06b15e3cd384d9d6 100644 (file)
@@ -82,6 +82,12 @@ config ACPI_PROCFS_POWER
          and functions, which do not yet exist in /sys
 
          Say N to delete power /proc/acpi/ folders that have moved to /sys/
+config ACPI_SYSFS_POWER
+       bool "Future power /sys interface"
+       select POWER_SUPPLY
+       default y
+       ---help---
+         Say N to disable power /sys interface
 config ACPI_PROC_EVENT
        bool "Deprecated /proc/acpi/event support"
        depends on PROC_FS
@@ -103,7 +109,6 @@ config ACPI_PROC_EVENT
 config ACPI_AC
        tristate "AC Adapter"
        depends on X86
-       select POWER_SUPPLY
        default y
        help
          This driver adds support for the AC Adapter object, which indicates
@@ -113,7 +118,6 @@ config ACPI_AC
 config ACPI_BATTERY
        tristate "Battery"
        depends on X86
-       select POWER_SUPPLY
        default y
        help
          This driver adds support for battery information through
@@ -368,7 +372,6 @@ config ACPI_HOTPLUG_MEMORY
 config ACPI_SBS
        tristate "Smart Battery System"
        depends on X86
-       select POWER_SUPPLY
        help
          This driver adds support for the Smart Battery System, another
          type of access to battery information, found on some laptops.
index 76ed4f52bebd6df84be95abc388fa45a8d5e35d0..76b9bea98b6d95729b6750072b7c40de2a9ec922 100644 (file)
@@ -31,7 +31,9 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #endif
+#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
+#endif
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -79,7 +81,9 @@ static struct acpi_driver acpi_ac_driver = {
 };
 
 struct acpi_ac {
+#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply charger;
+#endif
        struct acpi_device * device;
        unsigned long state;
 };
@@ -94,7 +98,7 @@ static const struct file_operations acpi_ac_fops = {
        .release = single_release,
 };
 #endif
-
+#ifdef CONFIG_ACPI_SYSFS_POWER
 static int get_ac_property(struct power_supply *psy,
                           enum power_supply_property psp,
                           union power_supply_propval *val)
@@ -113,7 +117,7 @@ static int get_ac_property(struct power_supply *psy,
 static enum power_supply_property ac_props[] = {
        POWER_SUPPLY_PROP_ONLINE,
 };
-
+#endif
 /* --------------------------------------------------------------------------
                                AC Adapter Management
    -------------------------------------------------------------------------- */
@@ -241,7 +245,9 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  device->dev.bus_id, event,
                                                  (u32) ac->state);
+#ifdef CONFIG_ACPI_SYSFS_POWER
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
+#endif
                break;
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -280,12 +286,14 @@ static int acpi_ac_add(struct acpi_device *device)
 #endif
        if (result)
                goto end;
+#ifdef CONFIG_ACPI_SYSFS_POWER
        ac->charger.name = acpi_device_bid(device);
        ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
        ac->charger.properties = ac_props;
        ac->charger.num_properties = ARRAY_SIZE(ac_props);
        ac->charger.get_property = get_ac_property;
        power_supply_register(&ac->device->dev, &ac->charger);
+#endif
        status = acpi_install_notify_handler(device->handle,
                                             ACPI_ALL_NOTIFY, acpi_ac_notify,
                                             ac);
@@ -319,8 +327,10 @@ static int acpi_ac_resume(struct acpi_device *device)
        old_state = ac->state;
        if (acpi_ac_get_state(ac))
                return 0;
+#ifdef CONFIG_ACPI_SYSFS_POWER
        if (old_state != ac->state)
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
+#endif
        return 0;
 }
 
@@ -337,8 +347,10 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
 
        status = acpi_remove_notify_handler(device->handle,
                                            ACPI_ALL_NOTIFY, acpi_ac_notify);
+#ifdef CONFIG_ACPI_SYSFS_POWER
        if (ac->charger.dev)
                power_supply_unregister(&ac->charger);
+#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_ac_remove_fs(device);
 #endif
index 8f7505d304b58790c077e4bc257380eccf523117..c4a769d1ba8542bf0210f71eb6930641c9062a2f 100644 (file)
@@ -40,7 +40,9 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
+#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
+#endif
 
 #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
 
@@ -86,7 +88,9 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids);
 
 struct acpi_battery {
        struct mutex lock;
+#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply bat;
+#endif
        struct acpi_device *device;
        unsigned long update_time;
        int current_now;
@@ -117,6 +121,7 @@ inline int acpi_battery_present(struct acpi_battery *battery)
        return battery->device->status.battery_present;
 }
 
+#ifdef CONFIG_ACPI_SYSFS_POWER
 static int acpi_battery_technology(struct acpi_battery *battery)
 {
        if (!strcasecmp("NiCd", battery->type))
@@ -222,6 +227,7 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
+#endif
 
 #ifdef CONFIG_ACPI_PROCFS_POWER
 inline char *acpi_battery_units(struct acpi_battery *battery)
@@ -398,6 +404,7 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
        return acpi_battery_set_alarm(battery);
 }
 
+#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -429,11 +436,6 @@ static int sysfs_add_battery(struct acpi_battery *battery)
 {
        int result;
 
-       battery->update_time = 0;
-       result = acpi_battery_get_info(battery);
-       acpi_battery_init_alarm(battery);
-       if (result)
-               return result;
        if (battery->power_unit) {
                battery->bat.properties = charge_battery_props;
                battery->bat.num_properties =
@@ -462,18 +464,31 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
        power_supply_unregister(&battery->bat);
        battery->bat.dev = NULL;
 }
+#endif
 
 static int acpi_battery_update(struct acpi_battery *battery)
 {
-       int result = acpi_battery_get_status(battery);
+       int result;
+       result = acpi_battery_get_status(battery);
        if (result)
                return result;
+#ifdef CONFIG_ACPI_SYSFS_POWER
        if (!acpi_battery_present(battery)) {
                sysfs_remove_battery(battery);
+               battery->update_time = 0;
                return 0;
        }
+#endif
+       if (!battery->update_time) {
+               result = acpi_battery_get_info(battery);
+               if (result)
+                       return result;
+               acpi_battery_init_alarm(battery);
+       }
+#ifdef CONFIG_ACPI_SYSFS_POWER
        if (!battery->bat.dev)
                sysfs_add_battery(battery);
+#endif
        return acpi_battery_get_state(battery);
 }
 
@@ -767,9 +782,11 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        device->dev.bus_id, event,
                                        acpi_battery_present(battery));
+#ifdef CONFIG_ACPI_SYSFS_POWER
        /* acpi_batter_update could remove power_supply object */
        if (battery->bat.dev)
                kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
+#endif
 }
 
 static int acpi_battery_add(struct acpi_device *device)
@@ -828,7 +845,9 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_remove_fs(device);
 #endif
+#ifdef CONFIG_ACPI_SYSFS_POWER
        sysfs_remove_battery(battery);
+#endif
        mutex_destroy(&battery->lock);
        kfree(battery);
        return 0;
index 3ec110ce00c8c3096b6f0ed7c379777b05e4822d..8809654d6cc965e292b2424f5f85cdecca15c1a2 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Check to see if the given machine has a known bad ACPI BIOS
  *  or if the BIOS is too old.
+ *  Check given machine against acpi_osi_dmi_table[].
  *
  *  Copyright (C) 2004 Len Brown <len.brown@intel.com>
  *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
@@ -50,6 +51,8 @@ struct acpi_blacklist_item {
        u32 is_critical_error;
 };
 
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata;
+
 /*
  * POLICY: If *anything* doesn't work, put it on the blacklist.
  *        If they are critical errors, mark it critical, and abort driver load.
@@ -165,5 +168,383 @@ int __init acpi_blacklisted(void)
 
        blacklisted += blacklist_by_year();
 
+       dmi_check_system(acpi_osi_dmi_table);
+
        return blacklisted;
 }
+#ifdef CONFIG_DMI
+static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
+{
+       acpi_dmi_osi_linux(1, d);       /* enable */
+       return 0;
+}
+static int __init dmi_disable_osi_linux(const struct dmi_system_id *d)
+{
+       acpi_dmi_osi_linux(0, d);       /* disable */
+       return 0;
+}
+static int __init dmi_unknown_osi_linux(const struct dmi_system_id *d)
+{
+       acpi_dmi_osi_linux(-1, d);      /* unknown */
+       return 0;
+}
+
+/*
+ * Most BIOS that invoke OSI(Linux) do nothing with it.
+ * But some cause Linux to break.
+ * Only a couple use it to make Linux run better.
+ *
+ * Thus, Linux should continue to disable OSI(Linux) by default,
+ * should continue to discourage BIOS writers from using it, and
+ * should whitelist the few existing systems that require it.
+ *
+ * If it appears clear a vendor isn't using OSI(Linux)
+ * for anything constructive, blacklist them by name to disable
+ * unnecessary dmesg warnings on all of their products.
+ */
+
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
+       /*
+        * Disable OSI(Linux) warnings on all "Acer, inc."
+        *
+        * _OSI(Linux) disables the latest Windows BIOS code:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
+        * _OSI(Linux) effect unknown:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Acer, inc.",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "Acer"
+        *
+        * _OSI(Linux) effect unknown:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
+        */
+       {
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Acer",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
+        *
+        * _OSI(Linux) confirmed to be a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+        * _OSI(Linux) effect unknown:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Apple",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "BenQ"
+        *
+        * _OSI(Linux) confirmed to be a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Joybook S31"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "BenQ",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "BenQ"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "Clevo Co."
+        *
+        * _OSI(Linux) confirmed to be a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "M570RU"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Clevo",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "COMPAL"
+        *
+        * _OSI(Linux) confirmed to be a NOP:
+        * DMI_MATCH(DMI_BOARD_NAME, "HEL8X"),
+        * _OSI(Linux) unknown effect:
+        * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
+        */
+       {
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Compal",
+       .matches = {
+                    DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
+               },
+       },
+       { /* OSI(Linux) touches USB, breaks suspend to disk */
+       .callback = dmi_disable_osi_linux,
+       .ident = "Dell Dimension 5150",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM051"),
+               },
+       },
+       { /* OSI(Linux) is a NOP */
+       .callback = dmi_disable_osi_linux,
+       .ident = "Dell",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
+               },
+       },
+       { /* OSI(Linux) effect unknown */
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Dell",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
+               },
+       },
+       { /* OSI(Linux) effect unknown */
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Dell",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
+               },
+       },
+       { /* OSI(Linux) effect unknown */
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Dell",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
+               },
+       },
+       { /* OSI(Linux) touches USB */
+       .callback = dmi_disable_osi_linux,
+       .ident = "Dell",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
+               },
+       },
+       { /* OSI(Linux) is a NOP */
+       .callback = dmi_disable_osi_linux,
+       .ident = "Dell Vostro 1000",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Vostro   1000"),
+               },
+       },
+       { /* OSI(Linux) effect unknown */
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Dell",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
+               },
+       },
+       { /* OSI(Linux) effect unknown */
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Dialogue Flybook V5",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Dialogue Technology Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Flybook V5"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "FUJITSU SIEMENS"
+        *
+        * _OSI(Linux) disables latest Windows BIOS code:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2510"),
+        * _OSI(Linux) confirmed to be a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1536"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1556"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 1546"),
+        * _OSI(Linux) unknown effect:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo M1425"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo Si 1520"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Fujitsu Siemens",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "Hewlett-Packard"
+        *
+        * _OSI(Linux) confirmed to be a NOP:
+        * .ident = "HP Pavilion tx 1000"
+        * DMI_MATCH(DMI_BOARD_NAME, "30BF"),
+        * .ident = "HP Pavilion dv2000"
+        * DMI_MATCH(DMI_BOARD_NAME, "30B5"),
+        * .ident = "HP Pavilion dv5000",
+        * DMI_MATCH(DMI_BOARD_NAME, "30A7"),
+        * .ident = "HP Pavilion dv6300 30BC",
+        * DMI_MATCH(DMI_BOARD_NAME, "30BC"),
+        * .ident = "HP Pavilion dv6000",
+        * DMI_MATCH(DMI_BOARD_NAME, "30B7"),
+        * DMI_MATCH(DMI_BOARD_NAME, "30B8"),
+        * .ident = "HP Pavilion dv9000",
+        * DMI_MATCH(DMI_BOARD_NAME, "30B9"),
+        * .ident = "HP Pavilion dv9500",
+        * DMI_MATCH(DMI_BOARD_NAME, "30CB"),
+        * .ident = "HP/Compaq Presario C500",
+        * DMI_MATCH(DMI_BOARD_NAME, "30C6"),
+        * .ident = "HP/Compaq Presario F500",
+        * DMI_MATCH(DMI_BOARD_NAME, "30D3"),
+        * _OSI(Linux) unknown effect:
+        * .ident = "HP Pavilion dv6500",
+        * DMI_MATCH(DMI_BOARD_NAME, "30D0"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Hewlett-Packard",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               },
+       },
+       /*
+        * Lenovo has a mix of systems OSI(Linux) situations
+        * and thus we can not wildcard the vendor.
+        *
+        * _OSI(Linux) helps sound
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+        * _OSI(Linux) is a NOP:
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+        */
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad R61",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
+               },
+       },
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad T61",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+               },
+       },
+       {
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Lenovo 3000 V100",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Lenovo 3000 N100",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "LG Electronics"
+        *
+        * _OSI(Linux) confirmed to be a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "LG",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
+               },
+       },
+       /* NEC - OSI(Linux) effect unknown */
+       {
+       .callback = dmi_unknown_osi_linux,
+       .ident = "NEC VERSA M360",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "NEC Computers SAS"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "NEC VERSA M360"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "Samsung Electronics"
+        *
+        * OSI(Linux) disables PNP0C32 and other BIOS code for Windows:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "R40P/R41P"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "R59P/R60P/R61P"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Samsung",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "Sony Corporation"
+        *
+        * _OSI(Linux) is a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ38GP_C"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TZ21MN_N"),
+        * _OSI(Linux) unknown effect:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
+        */
+       {
+       .callback = dmi_unknown_osi_linux,
+       .ident = "Sony",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               },
+       },
+       /*
+        * Disable OSI(Linux) warnings on all "TOSHIBA"
+        *
+        * _OSI(Linux) breaks sound (bugzilla 7787):
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P100"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P105"),
+        * _OSI(Linux) is a NOP:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A100"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A210"),
+        * _OSI(Linux) unknown effect:
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A135"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A200"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P205"),
+        * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U305"),
+        */
+       {
+       .callback = dmi_disable_osi_linux,
+       .ident = "Toshiba",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               },
+       },
+       {}
+};
+
+#endif /* CONFIG_DMI */
index 49d432d0a12c6d7682b5325015f6612124058d19..1b4cf984b081d0f0a697d139d1df0c1d281fe31e 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
-#include <linux/pm_legacy.h>
 #include <linux/device.h>
 #include <linux/proc_fs.h>
 #ifdef CONFIG_X86
@@ -201,7 +200,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
         * Get device's current power state
         */
        acpi_bus_get_power(device->handle, &device->power.state);
-       if (state == device->power.state) {
+       if ((state == device->power.state) && !device->flags.force_power_state) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
                                  state));
                return 0;
@@ -744,7 +743,7 @@ static int __init acpi_bus_init(void)
        return -ENODEV;
 }
 
-decl_subsys(acpi, NULL, NULL);
+struct kobject *acpi_kobj;
 
 static int __init acpi_init(void)
 {
@@ -756,24 +755,23 @@ static int __init acpi_init(void)
                return -ENODEV;
        }
 
-       result = firmware_register(&acpi_subsys);
-       if (result < 0)
-               printk(KERN_WARNING "%s: firmware_register error: %d\n",
-                       __FUNCTION__, result);
+       acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
+       if (!acpi_kobj) {
+               printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__);
+               acpi_kobj = NULL;
+       }
 
        result = acpi_bus_init();
 
        if (!result) {
-#ifdef CONFIG_PM_LEGACY
-               if (!PM_IS_ACTIVE())
-                       pm_active = 1;
+               if (!(pm_flags & PM_APM))
+                       pm_flags |= PM_ACPI;
                else {
                        printk(KERN_INFO PREFIX
                               "APM is already active, exiting\n");
                        disable_acpi();
                        result = -ENODEV;
                }
-#endif
        } else
                disable_acpi();
 
index d411017f8c066994cc0c06065a0776b9105397d6..987b967c74670728831af322571e4a182fb84d7e 100644 (file)
@@ -26,6 +26,9 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+/* Uncomment next line to get verbose print outs*/
+/* #define DEBUG */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -47,9 +50,6 @@
 #undef PREFIX
 #define PREFIX                         "ACPI: EC: "
 
-/* Uncomment next line to get verbose print outs*/
-/* #define DEBUG */
-
 /* EC status register */
 #define ACPI_EC_FLAG_OBF       0x01    /* Output buffer full */
 #define ACPI_EC_FLAG_IBF       0x02    /* Input buffer full */
@@ -82,6 +82,7 @@ enum {
        EC_FLAGS_ADDRESS,               /* Address is being written */
        EC_FLAGS_NO_WDATA_GPE,          /* Don't expect WDATA GPE event */
        EC_FLAGS_WDATA,                 /* Data is being written */
+       EC_FLAGS_NO_OBF1_GPE,           /* Don't expect GPE before read */
 };
 
 static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -138,26 +139,26 @@ static struct acpi_ec {
 static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
 {
        u8 x = inb(ec->command_addr);
-       pr_debug(PREFIX "---> status = 0x%2x\n", x);
+       pr_debug(PREFIX "---> status = 0x%2.2x\n", x);
        return x;
 }
 
 static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
 {
        u8 x = inb(ec->data_addr);
-       pr_debug(PREFIX "---> data = 0x%2x\n", x);
+       pr_debug(PREFIX "---> data = 0x%2.2x\n", x);
        return inb(ec->data_addr);
 }
 
 static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
-       pr_debug(PREFIX "<--- command = 0x%2x\n", command);
+       pr_debug(PREFIX "<--- command = 0x%2.2x\n", command);
        outb(command, ec->command_addr);
 }
 
 static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 {
-       pr_debug(PREFIX "<--- data = 0x%2x\n", data);
+       pr_debug(PREFIX "<--- data = 0x%2.2x\n", data);
        outb(data, ec->data_addr);
 }
 
@@ -179,6 +180,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
 static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 {
        int ret = 0;
+
+       if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
+                    test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
+               force_poll = 1;
        if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
                     test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
                force_poll = 1;
@@ -192,7 +197,12 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
                        goto end;
                clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
                if (acpi_ec_check_status(ec, event)) {
-                       if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
+                       if (event == ACPI_EC_EVENT_OBF_1) {
+                               /* miss OBF_1 GPE, don't expect it */
+                               pr_info(PREFIX "missing OBF confirmation, "
+                                       "don't expect it any longer.\n");
+                               set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
+                       } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
                                /* miss address GPE, don't expect it anymore */
                                pr_info(PREFIX "missing address confirmation, "
                                        "don't expect it any longer.\n");
@@ -892,6 +902,17 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
        return 0;
 }
 
+int __init acpi_boot_ec_enable(void)
+{
+       if (!boot_ec || boot_ec->handlers_installed)
+               return 0;
+       if (!ec_install_handlers(boot_ec)) {
+               first_ec = boot_ec;
+               return 0;
+       }
+       return -EFAULT;
+}
+
 int __init acpi_ec_ecdt_probe(void)
 {
        int ret;
@@ -924,9 +945,10 @@ int __init acpi_ec_ecdt_probe(void)
                        goto error;
                /* We really need to limit this workaround, the only ASUS,
                 * which needs it, has fake EC._INI method, so use it as flag.
+                * Keep boot_ec struct as it will be needed soon.
                 */
                if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
-                       goto error;
+                       return -ENODEV;
        }
 
        ret = ec_install_handlers(boot_ec);
index e99f0c435a4724006c9d204c69349733b91d763f..58ad09725dd2a69dcac8f1f45fa3226041981bf3 100644 (file)
@@ -344,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * setup will potentially execute control methods
                 * (e.g., _REG method for this region)
                 */
-               acpi_ex_relinquish_interpreter();
+               acpi_ex_exit_interpreter();
 
                status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
                                      handler_desc->address_space.context,
@@ -352,7 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
 
                /* Re-enter the interpreter */
 
-               acpi_ex_reacquire_interpreter();
+               acpi_ex_enter_interpreter();
 
                /* Check for failure of the Region Setup */
 
@@ -405,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * exit the interpreter because the handler *might* block -- we don't
                 * know what it will do, so we can't hold the lock on the intepreter.
                 */
-               acpi_ex_relinquish_interpreter();
+               acpi_ex_exit_interpreter();
        }
 
        /* Call the handler */
@@ -426,7 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * We just returned from a non-default handler, we must re-enter the
                 * interpreter
                 */
-               acpi_ex_reacquire_interpreter();
+               acpi_ex_enter_interpreter();
        }
 
        return_ACPI_STATUS(status);
index a5a5532db268084307ae31d655a04af6b9913925..a6e149d692cbd332aaf947d689815392474cda34 100644 (file)
@@ -47,6 +47,8 @@ MODULE_LICENSE("GPL");
 
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
 
 static const struct acpi_device_id fan_device_ids[] = {
        {"PNP0C0B", 0},
@@ -61,6 +63,8 @@ static struct acpi_driver acpi_fan_driver = {
        .ops = {
                .add = acpi_fan_add,
                .remove = acpi_fan_remove,
+               .suspend = acpi_fan_suspend,
+               .resume = acpi_fan_resume,
                },
 };
 
@@ -191,6 +195,10 @@ static int acpi_fan_add(struct acpi_device *device)
                goto end;
        }
 
+       device->flags.force_power_state = 1;
+       acpi_bus_set_power(device->handle, state);
+       device->flags.force_power_state = 0;
+
        result = acpi_fan_add_fs(device);
        if (result)
                goto end;
@@ -216,6 +224,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
+{
+       if (!device)
+               return -EINVAL;
+
+       acpi_bus_set_power(device->handle, ACPI_STATE_D0);
+
+       return AE_OK;
+}
+
+static int acpi_fan_resume(struct acpi_device *device)
+{
+       int result = 0;
+       int power_state = 0;
+
+       if (!device)
+               return -EINVAL;
+
+       result = acpi_bus_get_power(device->handle, &power_state);
+       if (result) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                                 "Error reading fan power state\n"));
+               return result;
+       }
+
+       device->flags.force_power_state = 1;
+       acpi_bus_set_power(device->handle, power_state);
+       device->flags.force_power_state = 0;
+
+       return result;
+}
+
 static int __init acpi_fan_init(void)
 {
        int result = 0;
index e3a673a008453dfda694aab503dad0c89b19cb1e..e53fb516f9d45538dbfdedc002ad3dcb753e200e 100644 (file)
@@ -77,11 +77,55 @@ static struct workqueue_struct *kacpi_notify_wq;
 #define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
-static int osi_linux;          /* disable _OSI(Linux) by default */
+/*
+ * "Ode to _OSI(Linux)"
+ *
+ * osi_linux -- Control response to BIOS _OSI(Linux) query.
+ *
+ * As Linux evolves, the features that it supports change.
+ * So an OSI string such as "Linux" is not specific enough
+ * to be useful across multiple versions of Linux.  It
+ * doesn't identify any particular feature, interface,
+ * or even any particular version of Linux...
+ *
+ * Unfortunately, Linux-2.6.22 and earlier responded "yes"
+ * to a BIOS _OSI(Linux) query.  When
+ * a reference mobile BIOS started using it, its use
+ * started to spread to many vendor platforms.
+ * As it is not supportable, we need to halt that spread.
+ *
+ * Today, most BIOS references to _OSI(Linux) are noise --
+ * they have no functional effect and are just dead code
+ * carried over from the reference BIOS.
+ *
+ * The next most common case is that _OSI(Linux) harms Linux,
+ * usually by causing the BIOS to follow paths that are
+ * not tested during Windows validation.
+ *
+ * Finally, there is a short list of platforms
+ * where OSI(Linux) benefits Linux.
+ *
+ * In Linux-2.6.23, OSI(Linux) is first disabled by default.
+ * DMI is used to disable the dmesg warning about OSI(Linux)
+ * on platforms where it is known to have no effect.
+ * But a dmesg warning remains for systems where
+ * we do not know if OSI(Linux) is good or bad for the system.
+ * DMI is also used to enable OSI(Linux) for the machines
+ * that are known to need it.
+ *
+ * BIOS writers should NOT query _OSI(Linux) on future systems.
+ * It will be ignored by default, and to get Linux to
+ * not ignore it will require a kernel source update to
+ * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation.
+ */
+#define OSI_LINUX_ENABLE 0
 
-#ifdef CONFIG_DMI
-static struct __initdata dmi_system_id acpi_osl_dmi_table[];
-#endif
+struct osi_linux {
+       unsigned int    enable:1;
+       unsigned int    dmi:1;
+       unsigned int    cmdline:1;
+       unsigned int    known:1;
+} osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0};
 
 static void __init acpi_request_region (struct acpi_generic_address *addr,
        unsigned int length, char *desc)
@@ -133,7 +177,6 @@ device_initcall(acpi_reserve_resources);
 
 acpi_status __init acpi_os_initialize(void)
 {
-       dmi_check_system(acpi_osl_dmi_table);
        return AE_OK;
 }
 
@@ -964,13 +1007,37 @@ static int __init acpi_os_name_setup(char *str)
 
 __setup("acpi_os_name=", acpi_os_name_setup);
 
-static void enable_osi_linux(int enable) {
+static void __init set_osi_linux(unsigned int enable)
+{
+       if (osi_linux.enable != enable) {
+               osi_linux.enable = enable;
+               printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
+                       enable ? "Add": "Delet");
+       }
+       return;
+}
 
-       if (osi_linux != enable)
-               printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
-                       enable ? "En": "Dis");
+static void __init acpi_cmdline_osi_linux(unsigned int enable)
+{
+       osi_linux.cmdline = 1;  /* cmdline set the default */
+       set_osi_linux(enable);
+
+       return;
+}
+
+void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
+{
+       osi_linux.dmi = 1;      /* DMI knows that this box asks OSI(Linux) */
+
+       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+
+       if (enable == -1)
+               return;
+
+       osi_linux.known = 1;    /* DMI knows which OSI(Linux) default needed */
+
+       set_osi_linux(enable);
 
-       osi_linux = enable;
        return;
 }
 
@@ -987,12 +1054,12 @@ static int __init acpi_osi_setup(char *str)
                printk(KERN_INFO PREFIX "_OSI method disabled\n");
                acpi_gbl_create_osi_method = FALSE;
        } else if (!strcmp("!Linux", str)) {
-               enable_osi_linux(0);
+               acpi_cmdline_osi_linux(0);      /* !enable */
        } else if (*str == '!') {
                if (acpi_osi_invalidate(++str) == AE_OK)
                        printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
        } else if (!strcmp("Linux", str)) {
-               enable_osi_linux(1);
+               acpi_cmdline_osi_linux(1);      /* enable */
        } else if (*osi_additional_string == '\0') {
                strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
                printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
@@ -1141,6 +1208,34 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
        return (AE_OK);
 }
 
+/**
+ *     acpi_dmi_dump - dump DMI slots needed for blacklist entry
+ *
+ *     Returns 0 on success
+ */
+int acpi_dmi_dump(void)
+{
+
+       if (!dmi_available)
+               return -1;
+
+       printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
+               dmi_get_slot(DMI_SYS_VENDOR));
+       printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
+               dmi_get_slot(DMI_PRODUCT_NAME));
+       printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
+               dmi_get_slot(DMI_PRODUCT_VERSION));
+       printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
+               dmi_get_slot(DMI_BOARD_NAME));
+       printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
+               dmi_get_slot(DMI_BIOS_VENDOR));
+       printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
+               dmi_get_slot(DMI_BIOS_DATE));
+
+       return 0;
+}
+
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_os_validate_interface
@@ -1160,13 +1255,29 @@ acpi_os_validate_interface (char *interface)
        if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
                return AE_OK;
        if (!strcmp("Linux", interface)) {
-               printk(KERN_WARNING PREFIX
-                       "System BIOS is requesting _OSI(Linux)\n");
-               printk(KERN_WARNING PREFIX
-                       "If \"acpi_osi=Linux\" works better,\n"
-                       "Please send dmidecode "
-                       "to linux-acpi@vger.kernel.org\n");
-               if(osi_linux)
+
+               printk(KERN_NOTICE PREFIX
+                       "BIOS _OSI(Linux) query %s%s\n",
+                       osi_linux.enable ? "honored" : "ignored",
+                       osi_linux.cmdline ? " via cmdline" :
+                       osi_linux.dmi ? " via DMI" : "");
+
+               if (!osi_linux.dmi) {
+                       if (acpi_dmi_dump())
+                               printk(KERN_NOTICE PREFIX
+                                       "[please extract dmidecode output]\n");
+                       printk(KERN_NOTICE PREFIX
+                               "Please send DMI info above to "
+                               "linux-acpi@vger.kernel.org\n");
+               }
+               if (!osi_linux.known && !osi_linux.cmdline) {
+                       printk(KERN_NOTICE PREFIX
+                               "If \"acpi_osi=%sLinux\" works better, "
+                               "please notify linux-acpi@vger.kernel.org\n",
+                               osi_linux.enable ? "!" : "");
+               }
+
+               if (osi_linux.enable)
                        return AE_OK;
        }
        return AE_SUPPORT;
@@ -1198,28 +1309,4 @@ acpi_os_validate_address (
     return AE_OK;
 }
 
-#ifdef CONFIG_DMI
-static int dmi_osi_linux(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
-       enable_osi_linux(1);
-       return 0;
-}
-
-static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-       /*
-        * Boxes that need _OSI(Linux)
-        */
-       {
-        .callback = dmi_osi_linux,
-        .ident = "Intel Napa CRB",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-                    DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
-                    },
-        },
-       {}
-};
-#endif /* CONFIG_DMI */
-
 #endif
index dd3186abe07a9c464df616aae6fb05454fb53085..62010c2481b3614b9b9ddd3e1cbbae2118f40fd7 100644 (file)
@@ -429,6 +429,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                                          &polarity, &link,
                                          acpi_pci_allocate_irq);
 
+       if (irq < 0) {
+               /*
+                * IDE legacy mode controller IRQs are magic. Why do compat
+                * extensions always make such a nasty mess.
+                */
+               if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE &&
+                               (dev->class & 0x05) == 0)
+                       return 0;
+       }
        /*
         * No IRQ known to the ACPI subsystem - maybe the BIOS / 
         * driver reported one, then use it. Exit in any case.
index c9f526e55392b1260fb6896772b0ba77ef2ace8a..5400ea173f6fdf0fe309658e2c4de0b13bdbd462 100644 (file)
@@ -911,7 +911,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set);
 
 /* FIXME: we will remove this interface after all drivers call pci_disable_device */
 static struct sysdev_class irqrouter_sysdev_class = {
-       set_kset_name("irqrouter"),
+       .name = "irqrouter",
        .resume = irqrouter_resume,
 };
 
index 2fe34cc73c1327a191a48aee32b70ee14c922c9e..2235f4e02d26f46267b512a0d3c4c14badc34526 100644 (file)
@@ -76,7 +76,11 @@ static void (*pm_idle_save) (void) __read_mostly;
 #define PM_TIMER_TICKS_TO_US(p)                (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
 
 static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
+#ifdef CONFIG_CPU_IDLE
 module_param(max_cstate, uint, 0000);
+#else
+module_param(max_cstate, uint, 0644);
+#endif
 static unsigned int nocst __read_mostly;
 module_param(nocst, uint, 0000);
 
index 6742d7bc4777d8343d10aa34aa5d40a920f5f41a..1685b40abda7c2dba944939917a4993f8a4a5f3d 100644 (file)
@@ -775,12 +775,12 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
                acpi_processor_get_throttling_states(pr) ||
                acpi_processor_get_platform_limit(pr))
        {
-               if (acpi_processor_get_fadt_info(pr))
-                       return 0;
                pr->throttling.acpi_processor_get_throttling =
                    &acpi_processor_get_throttling_fadt;
                pr->throttling.acpi_processor_set_throttling =
                    &acpi_processor_set_throttling_fadt;
+               if (acpi_processor_get_fadt_info(pr))
+                       return 0;
        } else {
                pr->throttling.acpi_processor_get_throttling =
                    &acpi_processor_get_throttling_ptc;
index 22cb95b349e49835be4b28599b23864634b13221..f136c7d3b3c234c0d5a5b4fabf19aa95df3733d1 100644 (file)
@@ -40,7 +40,9 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 
+#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
+#endif
 
 #include "sbshc.h"
 
@@ -80,7 +82,9 @@ static const struct acpi_device_id sbs_device_ids[] = {
 MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
 
 struct acpi_battery {
+#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply bat;
+#endif
        struct acpi_sbs *sbs;
 #ifdef CONFIG_ACPI_PROCFS_POWER
        struct proc_dir_entry *proc_entry;
@@ -113,7 +117,9 @@ struct acpi_battery {
 #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
 
 struct acpi_sbs {
+#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply charger;
+#endif
        struct acpi_device *device;
        struct acpi_smb_hc *hc;
        struct mutex lock;
@@ -157,6 +163,7 @@ static inline int acpi_battery_scale(struct acpi_battery *battery)
            acpi_battery_ipscale(battery);
 }
 
+#ifdef CONFIG_ACPI_SYSFS_POWER
 static int sbs_get_ac_property(struct power_supply *psy,
                               enum power_supply_property psp,
                               union power_supply_propval *val)
@@ -294,6 +301,7 @@ static enum power_supply_property sbs_energy_battery_props[] = {
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
+#endif
 
 /* --------------------------------------------------------------------------
                             Smart Battery System Management
@@ -429,6 +437,7 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs)
        return result;
 }
 
+#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -458,6 +467,7 @@ static struct device_attribute alarm_attr = {
        .show = acpi_battery_alarm_show,
        .store = acpi_battery_alarm_store,
 };
+#endif
 
 /* --------------------------------------------------------------------------
                               FS Interface (/proc/acpi)
@@ -793,6 +803,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
                        &acpi_battery_state_fops, &acpi_battery_alarm_fops,
                        battery);
 #endif
+#ifdef CONFIG_ACPI_SYSFS_POWER
        battery->bat.name = battery->name;
        battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
        if (!acpi_battery_mode(battery)) {
@@ -813,6 +824,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
                goto end;
        battery->have_sysfs_alarm = 1;
       end:
+#endif
        printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
               ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
               battery->name, sbs->battery->present ? "present" : "absent");
@@ -822,12 +834,13 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
 static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
 {
        struct acpi_battery *battery = &sbs->battery[id];
-
+#ifdef CONFIG_ACPI_SYSFS_POWER
        if (battery->bat.dev) {
                if (battery->have_sysfs_alarm)
                        device_remove_file(battery->bat.dev, &alarm_attr);
                power_supply_unregister(&battery->bat);
        }
+#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
        if (battery->proc_entry)
                acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
@@ -848,12 +861,14 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
        if (result)
                goto end;
 #endif
+#ifdef CONFIG_ACPI_SYSFS_POWER
        sbs->charger.name = "sbs-charger";
        sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
        sbs->charger.properties = sbs_ac_props;
        sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
        sbs->charger.get_property = sbs_get_ac_property;
        power_supply_register(&sbs->device->dev, &sbs->charger);
+#endif
        printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
               ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
               ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
@@ -863,8 +878,10 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
 
 static void acpi_charger_remove(struct acpi_sbs *sbs)
 {
+#ifdef CONFIG_ACPI_SYSFS_POWER
        if (sbs->charger.dev)
                power_supply_unregister(&sbs->charger);
+#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
        if (sbs->charger_entry)
                acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
@@ -885,7 +902,9 @@ void acpi_sbs_callback(void *context)
                                              ACPI_SBS_NOTIFY_STATUS,
                                              sbs->charger_present);
 #endif
+#ifdef CONFIG_ACPI_SYSFS_POWER
                kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
+#endif
        }
        if (sbs->manager_present) {
                for (id = 0; id < MAX_SBS_BAT; ++id) {
@@ -902,7 +921,9 @@ void acpi_sbs_callback(void *context)
                                                      ACPI_SBS_NOTIFY_STATUS,
                                                      bat->present);
 #endif
+#ifdef CONFIG_ACPI_SYSFS_POWER
                        kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
+#endif
                }
        }
 }
index 5b4d462117cf915c6e1f2a89d7604ec9ddaa712b..cbfe9ae7a9e55226d82c86e6e6947121ee6e7adc 100644 (file)
@@ -1449,6 +1449,8 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
        return result;
 }
 
+int __init acpi_boot_ec_enable(void);
+
 static int __init acpi_scan_init(void)
 {
        int result;
@@ -1480,6 +1482,10 @@ static int __init acpi_scan_init(void)
         * Enumerate devices in the ACPI namespace.
         */
        result = acpi_bus_scan_fixed(acpi_root);
+
+       /* EC region might be needed at bus_scan, so enable it now */
+       acpi_boot_ec_enable();
+
        if (!result)
                result = acpi_bus_scan(acpi_root, &ops);
 
index edee2806e37bcec904e6640a90fb2423b981260c..5ffe0ea18967a82cf8a8ecb4fd64dd7362f125b6 100644 (file)
@@ -58,7 +58,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
                               FS Interface (/sys)
    -------------------------------------------------------------------------- */
 static LIST_HEAD(acpi_table_attr_list);
-static struct kobject tables_kobj;
+static struct kobject *tables_kobj;
 
 struct acpi_table_attr {
        struct bin_attribute attr;
@@ -135,11 +135,9 @@ static int acpi_system_sysfs_init(void)
        int table_index = 0;
        int result;
 
-       tables_kobj.parent = &acpi_subsys.kobj;
-       kobject_set_name(&tables_kobj, "tables");
-       result = kobject_register(&tables_kobj);
-       if (result)
-               return result;
+       tables_kobj = kobject_create_and_add("tables", acpi_kobj);
+       if (!tables_kobj)
+               return -ENOMEM;
 
        do {
                result = acpi_get_table_by_index(table_index, &table_header);
@@ -153,7 +151,7 @@ static int acpi_system_sysfs_init(void)
 
                        acpi_table_attr_init(table_attr, table_header);
                        result =
-                           sysfs_create_bin_file(&tables_kobj,
+                           sysfs_create_bin_file(tables_kobj,
                                                  &table_attr->attr);
                        if (result) {
                                kfree(table_attr);
@@ -163,6 +161,7 @@ static int acpi_system_sysfs_init(void)
                                              &acpi_table_attr_list);
                }
        } while (!result);
+       kobject_uevent(tables_kobj, KOBJ_ADD);
 
        return 0;
 }
index ba63619ae5df20623ec530cc6eb7188da0b0c1df..2478cca653de8cabf4d5cc8cf0a77633750e164c 100644 (file)
@@ -459,6 +459,15 @@ config PATA_NETCELL
 
          If unsure, say N.
 
+config PATA_NINJA32
+       tristate "Ninja32/Delkin Cardbus ATA support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the Ninja32, Delkin and
+         possibly other brands of Cardbus ATA adapter
+
+         If unsure, say N.
+
 config PATA_NS87410
        tristate "Nat Semi NS87410 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
index b13feb2c5dae02cf934e1447b743a396749113fe..82550c16818c7977a6a64b41e2a49b74557b7abe 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_PATA_IT821X)     += pata_it821x.o
 obj-$(CONFIG_PATA_IT8213)      += pata_it8213.o
 obj-$(CONFIG_PATA_JMICRON)     += pata_jmicron.o
 obj-$(CONFIG_PATA_NETCELL)     += pata_netcell.o
+obj-$(CONFIG_PATA_NINJA32)     += pata_ninja32.o
 obj-$(CONFIG_PATA_NS87410)     += pata_ns87410.o
 obj-$(CONFIG_PATA_NS87415)     += pata_ns87415.o
 obj-$(CONFIG_PATA_OPTI)                += pata_opti.o
index 54f38c21dd9585e90f6a931fb6bb516eaf7af3c1..6f089b899a1a7e9587bbba731f9b9047e7c15eae 100644 (file)
@@ -198,18 +198,18 @@ enum {
 };
 
 struct ahci_cmd_hdr {
-       u32                     opts;
-       u32                     status;
-       u32                     tbl_addr;
-       u32                     tbl_addr_hi;
-       u32                     reserved[4];
+       __le32                  opts;
+       __le32                  status;
+       __le32                  tbl_addr;
+       __le32                  tbl_addr_hi;
+       __le32                  reserved[4];
 };
 
 struct ahci_sg {
-       u32                     addr;
-       u32                     addr_hi;
-       u32                     reserved;
-       u32                     flags_size;
+       __le32                  addr;
+       __le32                  addr_hi;
+       __le32                  reserved;
+       __le32                  flags_size;
 };
 
 struct ahci_host_priv {
@@ -597,6 +597,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
        return __ahci_port_base(ap->host, ap->port_no);
 }
 
+static void ahci_enable_ahci(void __iomem *mmio)
+{
+       u32 tmp;
+
+       /* turn on AHCI_EN */
+       tmp = readl(mmio + HOST_CTL);
+       if (!(tmp & HOST_AHCI_EN)) {
+               tmp |= HOST_AHCI_EN;
+               writel(tmp, mmio + HOST_CTL);
+               tmp = readl(mmio + HOST_CTL);   /* flush && sanity check */
+               WARN_ON(!(tmp & HOST_AHCI_EN));
+       }
+}
+
 /**
  *     ahci_save_initial_config - Save and fixup initial config values
  *     @pdev: target PCI device
@@ -619,6 +633,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
        u32 cap, port_map;
        int i;
 
+       /* make sure AHCI mode is enabled before accessing CAP */
+       ahci_enable_ahci(mmio);
+
        /* Values prefixed with saved_ are written back to host after
         * reset.  Values without are used for driver operation.
         */
@@ -1036,19 +1053,17 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 static int ahci_reset_controller(struct ata_host *host)
 {
        struct pci_dev *pdev = to_pci_dev(host->dev);
+       struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 tmp;
 
        /* we must be in AHCI mode, before using anything
         * AHCI-specific, such as HOST_RESET.
         */
-       tmp = readl(mmio + HOST_CTL);
-       if (!(tmp & HOST_AHCI_EN)) {
-               tmp |= HOST_AHCI_EN;
-               writel(tmp, mmio + HOST_CTL);
-       }
+       ahci_enable_ahci(mmio);
 
        /* global controller reset */
+       tmp = readl(mmio + HOST_CTL);
        if ((tmp & HOST_RESET) == 0) {
                writel(tmp | HOST_RESET, mmio + HOST_CTL);
                readl(mmio + HOST_CTL); /* flush */
@@ -1067,8 +1082,7 @@ static int ahci_reset_controller(struct ata_host *host)
        }
 
        /* turn on AHCI mode */
-       writel(HOST_AHCI_EN, mmio + HOST_CTL);
-       (void) readl(mmio + HOST_CTL);  /* flush */
+       ahci_enable_ahci(mmio);
 
        /* some registers might be cleared on reset.  restore initial values */
        ahci_restore_initial_config(host);
@@ -1078,8 +1092,10 @@ static int ahci_reset_controller(struct ata_host *host)
 
                /* configure PCS */
                pci_read_config_word(pdev, 0x92, &tmp16);
-               tmp16 |= 0xf;
-               pci_write_config_word(pdev, 0x92, tmp16);
+               if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
+                       tmp16 |= hpriv->port_map;
+                       pci_write_config_word(pdev, 0x92, tmp16);
+               }
        }
 
        return 0;
@@ -1480,35 +1496,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
 {
        struct scatterlist *sg;
-       struct ahci_sg *ahci_sg;
-       unsigned int n_sg = 0;
+       struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+       unsigned int si;
 
        VPRINTK("ENTER\n");
 
        /*
         * Next, the S/G list.
         */
-       ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                dma_addr_t addr = sg_dma_address(sg);
                u32 sg_len = sg_dma_len(sg);
 
-               ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
-               ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
-               ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
-
-               ahci_sg++;
-               n_sg++;
+               ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+               ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+               ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
        }
 
-       return n_sg;
+       return si;
 }
 
 static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct ahci_port_priv *pp = ap->private_data;
-       int is_atapi = is_atapi_taskfile(&qc->tf);
+       int is_atapi = ata_is_atapi(qc->tf.protocol);
        void *cmd_tbl;
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
index 90329982bef760fe6a4cadead1f1d526943f4958..20534202fc79b28c5e93f944fe3224a460016318 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "ata_generic"
-#define DRV_VERSION "0.2.13"
+#define DRV_VERSION "0.2.15"
 
 /*
  *     A generic parallel ATA driver using libata
@@ -48,27 +48,47 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
        struct ata_port *ap = link->ap;
        int dma_enabled = 0;
        struct ata_device *dev;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        /* Bits 5 and 6 indicate if DMA is active on master/slave */
        if (ap->ioaddr.bmdma_addr)
                dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
 
+       if (pdev->vendor == PCI_VENDOR_ID_CENATEK)
+               dma_enabled = 0xFF;
+
        ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
-                       /* We don't really care */
-                       dev->pio_mode = XFER_PIO_0;
-                       dev->dma_mode = XFER_MW_DMA_0;
-                       /* We do need the right mode information for DMA or PIO
-                          and this comes from the current configuration flags */
-                       if (dma_enabled & (1 << (5 + dev->devno))) {
-                               ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
-                               dev->flags &= ~ATA_DFLAG_PIO;
-                       } else {
-                               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
-                               dev->xfer_mode = XFER_PIO_0;
-                               dev->xfer_shift = ATA_SHIFT_PIO;
-                               dev->flags |= ATA_DFLAG_PIO;
+               if (!ata_dev_enabled(dev))
+                       continue;
+
+               /* We don't really care */
+               dev->pio_mode = XFER_PIO_0;
+               dev->dma_mode = XFER_MW_DMA_0;
+               /* We do need the right mode information for DMA or PIO
+                  and this comes from the current configuration flags */
+               if (dma_enabled & (1 << (5 + dev->devno))) {
+                       unsigned int xfer_mask = ata_id_xfermask(dev->id);
+                       const char *name;
+
+                       if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA))
+                               name = ata_mode_string(xfer_mask);
+                       else {
+                               /* SWDMA perhaps? */
+                               name = "DMA";
+                               xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0);
                        }
+
+                       ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
+                                      name);
+
+                       dev->xfer_mode = ata_xfer_mask2mode(xfer_mask);
+                       dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode);
+                       dev->flags &= ~ATA_DFLAG_PIO;
+               } else {
+                       ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+                       dev->xfer_mode = XFER_PIO_0;
+                       dev->xfer_shift = ATA_SHIFT_PIO;
+                       dev->flags |= ATA_DFLAG_PIO;
                }
        }
        return 0;
@@ -185,6 +205,7 @@ static struct pci_device_id ata_generic[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE), },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561), },
        { PCI_DEVICE(PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558), },
+       { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), },
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
index bb62a588f489c566f5ae7d8d27158dd8eae6b341..a65c8ae5c461136bae02ccf766030d1c3ecb20e4 100644 (file)
@@ -101,38 +101,21 @@ enum {
        ICH5_PMR                = 0x90, /* port mapping register */
        ICH5_PCS                = 0x92, /* port control and status */
        PIIX_SCC                = 0x0A, /* sub-class code register */
+       PIIX_SIDPR_BAR          = 5,
+       PIIX_SIDPR_LEN          = 16,
+       PIIX_SIDPR_IDX          = 0,
+       PIIX_SIDPR_DATA         = 4,
 
-       PIIX_FLAG_SCR           = (1 << 26), /* SCR available */
        PIIX_FLAG_AHCI          = (1 << 27), /* AHCI possible */
        PIIX_FLAG_CHECKINTR     = (1 << 28), /* make sure PCI INTx enabled */
+       PIIX_FLAG_SIDPR         = (1 << 29), /* SATA idx/data pair regs */
 
        PIIX_PATA_FLAGS         = ATA_FLAG_SLAVE_POSS,
        PIIX_SATA_FLAGS         = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
 
-       /* combined mode.  if set, PATA is channel 0.
-        * if clear, PATA is channel 1.
-        */
-       PIIX_PORT_ENABLED       = (1 << 0),
-       PIIX_PORT_PRESENT       = (1 << 4),
-
        PIIX_80C_PRI            = (1 << 5) | (1 << 4),
        PIIX_80C_SEC            = (1 << 7) | (1 << 6),
 
-       /* controller IDs */
-       piix_pata_mwdma         = 0,    /* PIIX3 MWDMA only */
-       piix_pata_33,                   /* PIIX4 at 33Mhz */
-       ich_pata_33,                    /* ICH up to UDMA 33 only */
-       ich_pata_66,                    /* ICH up to 66 Mhz */
-       ich_pata_100,                   /* ICH up to UDMA 100 */
-       ich5_sata,
-       ich6_sata,
-       ich6_sata_ahci,
-       ich6m_sata_ahci,
-       ich8_sata_ahci,
-       ich8_2port_sata,
-       ich8m_apple_sata_ahci,          /* locks up on second port enable */
-       tolapai_sata_ahci,
-
        /* constants for mapping table */
        P0                      = 0,  /* port 0 */
        P1                      = 1,  /* port 1 */
@@ -148,6 +131,24 @@ enum {
        PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
 };
 
+enum piix_controller_ids {
+       /* controller IDs */
+       piix_pata_mwdma,        /* PIIX3 MWDMA only */
+       piix_pata_33,           /* PIIX4 at 33Mhz */
+       ich_pata_33,            /* ICH up to UDMA 33 only */
+       ich_pata_66,            /* ICH up to 66 Mhz */
+       ich_pata_100,           /* ICH up to UDMA 100 */
+       ich5_sata,
+       ich6_sata,
+       ich6_sata_ahci,
+       ich6m_sata_ahci,
+       ich8_sata_ahci,
+       ich8_2port_sata,
+       ich8m_apple_sata_ahci,  /* locks up on second port enable */
+       tolapai_sata_ahci,
+       piix_pata_vmw,                  /* PIIX4 for VMware, spurious DMA_ERR */
+};
+
 struct piix_map_db {
        const u32 mask;
        const u16 port_enable;
@@ -156,6 +157,7 @@ struct piix_map_db {
 
 struct piix_host_priv {
        const int *map;
+       void __iomem *sidpr;
 };
 
 static int piix_init_one(struct pci_dev *pdev,
@@ -165,6 +167,10 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev);
 static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
 static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
 static int ich_pata_cable_detect(struct ata_port *ap);
+static u8 piix_vmw_bmdma_status(struct ata_port *ap);
+static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
+static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
+static void piix_sidpr_error_handler(struct ata_port *ap);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -175,6 +181,8 @@ static unsigned int in_module_init = 1;
 static const struct pci_device_id piix_pci_tbl[] = {
        /* Intel PIIX3 for the 430HX etc */
        { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma },
+       /* VMware ICH4 */
+       { 0x8086, 0x7111, 0x15ad, 0x1976, 0, 0, piix_pata_vmw },
        /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
        /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
        { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
@@ -317,7 +325,6 @@ static const struct ata_port_operations piix_pata_ops = {
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .cable_detect           = ata_cable_40wire,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
 
@@ -349,7 +356,6 @@ static const struct ata_port_operations ich_pata_ops = {
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .cable_detect           = ich_pata_cable_detect,
 
-       .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
 
@@ -376,6 +382,37 @@ static const struct ata_port_operations piix_sata_ops = {
        .error_handler          = ata_bmdma_error_handler,
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
 
+       .irq_clear              = ata_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+
+       .port_start             = ata_port_start,
+};
+
+static const struct ata_port_operations piix_vmw_ops = {
+       .set_piomode            = piix_set_piomode,
+       .set_dmamode            = piix_set_dmamode,
+       .mode_filter            = ata_pci_default_filter,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = ata_exec_command,
+       .dev_select             = ata_std_dev_select,
+
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
+       .bmdma_stop             = ata_bmdma_stop,
+       .bmdma_status           = piix_vmw_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .data_xfer              = ata_data_xfer,
+
+       .freeze                 = ata_bmdma_freeze,
+       .thaw                   = ata_bmdma_thaw,
+       .error_handler          = piix_pata_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
+
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
@@ -383,6 +420,35 @@ static const struct ata_port_operations piix_sata_ops = {
        .port_start             = ata_port_start,
 };
 
+static const struct ata_port_operations piix_sidpr_sata_ops = {
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = ata_exec_command,
+       .dev_select             = ata_std_dev_select,
+
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
+       .bmdma_stop             = ata_bmdma_stop,
+       .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .data_xfer              = ata_data_xfer,
+
+       .scr_read               = piix_sidpr_scr_read,
+       .scr_write              = piix_sidpr_scr_write,
+
+       .freeze                 = ata_bmdma_freeze,
+       .thaw                   = ata_bmdma_thaw,
+       .error_handler          = piix_sidpr_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+
+       .irq_clear              = ata_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+
+       .port_start             = ata_port_start,
+};
+
 static const struct piix_map_db ich5_map_db = {
        .mask = 0x7,
        .port_enable = 0x3,
@@ -490,7 +556,6 @@ static const struct piix_map_db *piix_map_db_table[] = {
 static struct ata_port_info piix_port_info[] = {
        [piix_pata_mwdma] =     /* PIIX3 MWDMA only */
        {
-               .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
@@ -499,7 +564,6 @@ static struct ata_port_info piix_port_info[] = {
 
        [piix_pata_33] =        /* PIIX4 at 33MHz */
        {
-               .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
@@ -509,7 +573,6 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich_pata_33] =         /* ICH0 - ICH at 33Mhz*/
        {
-               .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
                .pio_mask       = 0x1f, /* pio 0-4 */
                .mwdma_mask     = 0x06, /* Check: maybe 0x07  */
@@ -519,7 +582,6 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich_pata_66] =         /* ICH controllers up to 66MHz */
        {
-               .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
                .pio_mask       = 0x1f, /* pio 0-4 */
                .mwdma_mask     = 0x06, /* MWDMA0 is broken on chip */
@@ -529,7 +591,6 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich_pata_100] =
        {
-               .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x06, /* mwdma1-2 */
@@ -539,7 +600,6 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich5_sata] =
        {
-               .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
@@ -549,8 +609,7 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich6_sata] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
+               .flags          = PIIX_SATA_FLAGS,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
@@ -559,9 +618,7 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich6_sata_ahci] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-                                 PIIX_FLAG_AHCI,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
@@ -570,9 +627,7 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich6m_sata_ahci] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-                                 PIIX_FLAG_AHCI,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
@@ -581,9 +636,8 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich8_sata_ahci] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-                                 PIIX_FLAG_AHCI,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
+                                 PIIX_FLAG_SIDPR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
@@ -592,9 +646,8 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich8_2port_sata] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-                                 PIIX_FLAG_AHCI,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
+                                 PIIX_FLAG_SIDPR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
@@ -603,9 +656,7 @@ static struct ata_port_info piix_port_info[] = {
 
        [tolapai_sata_ahci] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-                                 PIIX_FLAG_AHCI,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
@@ -614,15 +665,24 @@ static struct ata_port_info piix_port_info[] = {
 
        [ich8m_apple_sata_ahci] =
        {
-               .sht            = &piix_sht,
-               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-                                 PIIX_FLAG_AHCI,
+               .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
+                                 PIIX_FLAG_SIDPR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
 
+       [piix_pata_vmw] =
+       {
+               .sht            = &piix_sht,
+               .flags          = PIIX_PATA_FLAGS,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+               .udma_mask      = ATA_UDMA_MASK_40C,
+               .port_ops       = &piix_vmw_ops,
+       },
+
 };
 
 static struct pci_bits piix_enable_bits[] = {
@@ -955,6 +1015,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        do_pata_set_dmamode(ap, adev, 1);
 }
 
+/*
+ * Serial ATA Index/Data Pair Superset Registers access
+ *
+ * Beginning from ICH8, there's a sane way to access SCRs using index
+ * and data register pair located at BAR5.  This creates an
+ * interesting problem of mapping two SCRs to one port.
+ *
+ * Although they have separate SCRs, the master and slave aren't
+ * independent enough to be treated as separate links - e.g. softreset
+ * resets both.  Also, there's no protocol defined for hard resetting
+ * singled device sharing the virtual port (no defined way to acquire
+ * device signature).  This is worked around by merging the SCR values
+ * into one sensible value and requesting follow-up SRST after
+ * hardreset.
+ *
+ * SCR merging is perfomed in nibbles which is the unit contents in
+ * SCRs are organized.  If two values are equal, the value is used.
+ * When they differ, merge table which lists precedence of possible
+ * values is consulted and the first match or the last entry when
+ * nothing matches is used.  When there's no merge table for the
+ * specific nibble, value from the first port is used.
+ */
+static const int piix_sidx_map[] = {
+       [SCR_STATUS]    = 0,
+       [SCR_ERROR]     = 2,
+       [SCR_CONTROL]   = 1,
+};
+
+static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
+{
+       struct ata_port *ap = dev->link->ap;
+       struct piix_host_priv *hpriv = ap->host->private_data;
+
+       iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
+                 hpriv->sidpr + PIIX_SIDPR_IDX);
+}
+
+static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
+{
+       struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
+
+       piix_sidpr_sel(dev, reg);
+       return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
+}
+
+static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
+{
+       struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
+
+       piix_sidpr_sel(dev, reg);
+       iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
+}
+
+u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
+{
+       u32 val = 0;
+       int i, mi;
+
+       for (i = 0, mi = 0; i < 32 / 4; i++) {
+               u8 c0 = (val0 >> (i * 4)) & 0xf;
+               u8 c1 = (val1 >> (i * 4)) & 0xf;
+               u8 merged = c0;
+               const int *cur;
+
+               /* if no merge preference, assume the first value */
+               cur = merge_tbl[mi];
+               if (!cur)
+                       goto done;
+               mi++;
+
+               /* if two values equal, use it */
+               if (c0 == c1)
+                       goto done;
+
+               /* choose the first match or the last from the merge table */
+               while (*cur != -1) {
+                       if (c0 == *cur || c1 == *cur)
+                               break;
+                       cur++;
+               }
+               if (*cur == -1)
+                       cur--;
+               merged = *cur;
+       done:
+               val |= merged << (i * 4);
+       }
+
+       return val;
+}
+
+static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
+{
+       const int * const sstatus_merge_tbl[] = {
+               /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
+               /* SPD */ (const int []){ 2, 1, 0, -1 },
+               /* IPM */ (const int []){ 6, 2, 1, 0, -1 },
+               NULL,
+       };
+       const int * const scontrol_merge_tbl[] = {
+               /* DET */ (const int []){ 1, 0, 4, 0, -1 },
+               /* SPD */ (const int []){ 0, 2, 1, 0, -1 },
+               /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
+               NULL,
+       };
+       u32 v0, v1;
+
+       if (reg >= ARRAY_SIZE(piix_sidx_map))
+               return -EINVAL;
+
+       if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) {
+               *val = piix_sidpr_read(&ap->link.device[0], reg);
+               return 0;
+       }
+
+       v0 = piix_sidpr_read(&ap->link.device[0], reg);
+       v1 = piix_sidpr_read(&ap->link.device[1], reg);
+
+       switch (reg) {
+       case SCR_STATUS:
+               *val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
+               break;
+       case SCR_ERROR:
+               *val = v0 | v1;
+               break;
+       case SCR_CONTROL:
+               *val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
+               break;
+       }
+
+       return 0;
+}
+
+static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val)
+{
+       if (reg >= ARRAY_SIZE(piix_sidx_map))
+               return -EINVAL;
+
+       piix_sidpr_write(&ap->link.device[0], reg, val);
+
+       if (ap->flags & ATA_FLAG_SLAVE_POSS)
+               piix_sidpr_write(&ap->link.device[1], reg, val);
+
+       return 0;
+}
+
+static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class,
+                               unsigned long deadline)
+{
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       int rc;
+
+       /* do hardreset */
+       rc = sata_link_hardreset(link, timing, deadline);
+       if (rc) {
+               ata_link_printk(link, KERN_ERR,
+                               "COMRESET failed (errno=%d)\n", rc);
+               return rc;
+       }
+
+       /* TODO: phy layer with polling, timeouts, etc. */
+       if (ata_link_offline(link)) {
+               *class = ATA_DEV_NONE;
+               return 0;
+       }
+
+       return -EAGAIN;
+}
+
+static void piix_sidpr_error_handler(struct ata_port *ap)
+{
+       ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+                          piix_sidpr_hardreset, ata_std_postreset);
+}
+
 #ifdef CONFIG_PM
 static int piix_broken_suspend(void)
 {
@@ -987,6 +1221,13 @@ static int piix_broken_suspend(void)
                                DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"),
                        },
                },
+               {
+                       .ident = "TECRA M6",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M6"),
+                       },
+               },
                {
                        .ident = "TECRA M7",
                        .matches = {
@@ -1001,6 +1242,13 @@ static int piix_broken_suspend(void)
                                DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A8"),
                        },
                },
+               {
+                       .ident = "Satellite R20",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R20"),
+                       },
+               },
                {
                        .ident = "Satellite R25",
                        .matches = {
@@ -1135,6 +1383,11 @@ static int piix_pci_device_resume(struct pci_dev *pdev)
 }
 #endif
 
+static u8 piix_vmw_bmdma_status(struct ata_port *ap)
+{
+       return ata_bmdma_status(ap) & ~ATA_DMA_ERR;
+}
+
 #define AHCI_PCI_BAR 5
 #define AHCI_GLOBAL_CTL 0x04
 #define AHCI_ENABLE (1 << 31)
@@ -1202,10 +1455,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
        return no_piix_dma;
 }
 
-static void __devinit piix_init_pcs(struct pci_dev *pdev,
-                                   struct ata_port_info *pinfo,
+static void __devinit piix_init_pcs(struct ata_host *host,
                                    const struct piix_map_db *map_db)
 {
+       struct pci_dev *pdev = to_pci_dev(host->dev);
        u16 pcs, new_pcs;
 
        pci_read_config_word(pdev, ICH5_PCS, &pcs);
@@ -1219,11 +1472,10 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev,
        }
 }
 
-static void __devinit piix_init_sata_map(struct pci_dev *pdev,
-                                        struct ata_port_info *pinfo,
-                                        const struct piix_map_db *map_db)
+static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
+                                              struct ata_port_info *pinfo,
+                                              const struct piix_map_db *map_db)
 {
-       struct piix_host_priv *hpriv = pinfo[0].private_data;
        const int *map;
        int i, invalid_map = 0;
        u8 map_value;
@@ -1247,7 +1499,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
                case IDE:
                        WARN_ON((i & 1) || map[i + 1] != IDE);
                        pinfo[i / 2] = piix_port_info[ich_pata_100];
-                       pinfo[i / 2].private_data = hpriv;
                        i++;
                        printk(" IDE IDE");
                        break;
@@ -1265,7 +1516,33 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
                dev_printk(KERN_ERR, &pdev->dev,
                           "invalid MAP value %u\n", map_value);
 
-       hpriv->map = map;
+       return map;
+}
+
+static void __devinit piix_init_sidpr(struct ata_host *host)
+{
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+       struct piix_host_priv *hpriv = host->private_data;
+       int i;
+
+       /* check for availability */
+       for (i = 0; i < 4; i++)
+               if (hpriv->map[i] == IDE)
+                       return;
+
+       if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
+               return;
+
+       if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
+           pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
+               return;
+
+       if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
+               return;
+
+       hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
+       host->ports[0]->ops = &piix_sidpr_sata_ops;
+       host->ports[1]->ops = &piix_sidpr_sata_ops;
 }
 
 static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
@@ -1324,8 +1601,10 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct device *dev = &pdev->dev;
        struct ata_port_info port_info[2];
        const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
-       struct piix_host_priv *hpriv;
        unsigned long port_flags;
+       struct ata_host *host;
+       struct piix_host_priv *hpriv;
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
@@ -1335,17 +1614,31 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!in_module_init)
                return -ENODEV;
 
+       port_info[0] = piix_port_info[ent->driver_data];
+       port_info[1] = piix_port_info[ent->driver_data];
+
+       port_flags = port_info[0].flags;
+
+       /* enable device and prepare host */
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
+       /* SATA map init can change port_info, do it before prepping host */
        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
 
-       port_info[0] = piix_port_info[ent->driver_data];
-       port_info[1] = piix_port_info[ent->driver_data];
-       port_info[0].private_data = hpriv;
-       port_info[1].private_data = hpriv;
+       if (port_flags & ATA_FLAG_SATA)
+               hpriv->map = piix_init_sata_map(pdev, port_info,
+                                       piix_map_db_table[ent->driver_data]);
 
-       port_flags = port_info[0].flags;
+       rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
+       if (rc)
+               return rc;
+       host->private_data = hpriv;
 
+       /* initialize controller */
        if (port_flags & PIIX_FLAG_AHCI) {
                u8 tmp;
                pci_read_config_byte(pdev, PIIX_SCC, &tmp);
@@ -1356,12 +1649,9 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       /* Initialize SATA map */
        if (port_flags & ATA_FLAG_SATA) {
-               piix_init_sata_map(pdev, port_info,
-                                  piix_map_db_table[ent->driver_data]);
-               piix_init_pcs(pdev, port_info,
-                             piix_map_db_table[ent->driver_data]);
+               piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
+               piix_init_sidpr(host);
        }
 
        /* apply IOCFG bit18 quirk */
@@ -1380,12 +1670,14 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                /* This writes into the master table but it does not
                   really matter for this errata as we will apply it to
                   all the PIIX devices on the board */
-               port_info[0].mwdma_mask = 0;
-               port_info[0].udma_mask = 0;
-               port_info[1].mwdma_mask = 0;
-               port_info[1].udma_mask = 0;
+               host->ports[0]->mwdma_mask = 0;
+               host->ports[0]->udma_mask = 0;
+               host->ports[1]->mwdma_mask = 0;
+               host->ports[1]->udma_mask = 0;
        }
-       return ata_pci_init_one(pdev, ppi);
+
+       pci_set_master(pdev);
+       return ata_pci_activate_sff_host(host, ata_interrupt, &piix_sht);
 }
 
 static int __init piix_init(void)
index 7bf4befd96bced87785d35c6903b3c38c23d23bc..9e8ec19260afa71ae5426b943fb4c17db6a6da19 100644 (file)
@@ -441,41 +441,78 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
        return rc;
 }
 
+/**
+ * ata_acpi_gtm_xfermode - determine xfermode from GTM parameter
+ * @dev: target device
+ * @gtm: GTM parameter to use
+ *
+ * Determine xfermask for @dev from @gtm.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Determined xfermask.
+ */
+unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev,
+                                   const struct ata_acpi_gtm *gtm)
+{
+       unsigned long xfer_mask = 0;
+       unsigned int type;
+       int unit;
+       u8 mode;
+
+       /* we always use the 0 slot for crap hardware */
+       unit = dev->devno;
+       if (!(gtm->flags & 0x10))
+               unit = 0;
+
+       /* PIO */
+       mode = ata_timing_cycle2mode(ATA_SHIFT_PIO, gtm->drive[unit].pio);
+       xfer_mask |= ata_xfer_mode2mask(mode);
+
+       /* See if we have MWDMA or UDMA data. We don't bother with
+        * MWDMA if UDMA is available as this means the BIOS set UDMA
+        * and our error changedown if it works is UDMA to PIO anyway.
+        */
+       if (!(gtm->flags & (1 << (2 * unit))))
+               type = ATA_SHIFT_MWDMA;
+       else
+               type = ATA_SHIFT_UDMA;
+
+       mode = ata_timing_cycle2mode(type, gtm->drive[unit].dma);
+       xfer_mask |= ata_xfer_mode2mask(mode);
+
+       return xfer_mask;
+}
+EXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask);
+
 /**
  * ata_acpi_cbl_80wire         -       Check for 80 wire cable
  * @ap: Port to check
+ * @gtm: GTM data to use
  *
- * Return 1 if the ACPI mode data for this port indicates the BIOS selected
- * an 80wire mode.
+ * Return 1 if the @gtm indicates the BIOS selected an 80wire mode.
  */
-
-int ata_acpi_cbl_80wire(struct ata_port *ap)
+int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm)
 {
-       const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
-       int valid = 0;
+       struct ata_device *dev;
 
-       if (!gtm)
-               return 0;
+       ata_link_for_each_dev(dev, &ap->link) {
+               unsigned long xfer_mask, udma_mask;
+
+               if (!ata_dev_enabled(dev))
+                       continue;
+
+               xfer_mask = ata_acpi_gtm_xfermask(dev, gtm);
+               ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask);
+
+               if (udma_mask & ~ATA_UDMA_MASK_40C)
+                       return 1;
+       }
 
-       /* Split timing, DMA enabled */
-       if ((gtm->flags & 0x11) == 0x11 && gtm->drive[0].dma < 55)
-               valid |= 1;
-       if ((gtm->flags & 0x14) == 0x14 && gtm->drive[1].dma < 55)
-               valid |= 2;
-       /* Shared timing, DMA enabled */
-       if ((gtm->flags & 0x11) == 0x01 && gtm->drive[0].dma < 55)
-               valid |= 1;
-       if ((gtm->flags & 0x14) == 0x04 && gtm->drive[0].dma < 55)
-               valid |= 2;
-
-       /* Drive check */
-       if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
-               return 1;
-       if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
-               return 1;
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
 
 static void ata_acpi_gtf_to_tf(struct ata_device *dev,
@@ -775,6 +812,36 @@ void ata_acpi_on_resume(struct ata_port *ap)
        }
 }
 
+/**
+ * ata_acpi_set_state - set the port power state
+ * @ap: target ATA port
+ * @state: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+       struct ata_device *dev;
+
+       if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA))
+               return;
+
+       /* channel first and then drives for power on and vica versa
+          for power off */
+       if (state.event == PM_EVENT_ON)
+               acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0);
+
+       ata_link_for_each_dev(dev, &ap->link) {
+               if (dev->acpi_handle && ata_dev_enabled(dev))
+                       acpi_bus_set_power(dev->acpi_handle,
+                               state.event == PM_EVENT_ON ?
+                                       ACPI_STATE_D0 : ACPI_STATE_D3);
+       }
+       if (state.event != PM_EVENT_ON)
+               acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3);
+}
+
 /**
  * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration
  * @dev: target ATA device
index 4753a1831dbc483b874a8efed0e9da8adf3f7869..ce803d18e96af93bc58ab51b9ed9f5d9c87b827f 100644 (file)
@@ -119,6 +119,10 @@ 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");
 
+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_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -450,9 +454,9 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
  *     RETURNS:
  *     Packed xfer_mask.
  */
-static unsigned int ata_pack_xfermask(unsigned int pio_mask,
-                                     unsigned int mwdma_mask,
-                                     unsigned int udma_mask)
+unsigned long ata_pack_xfermask(unsigned long pio_mask,
+                               unsigned long mwdma_mask,
+                               unsigned long udma_mask)
 {
        return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
                ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
@@ -469,10 +473,8 @@ static unsigned int ata_pack_xfermask(unsigned int pio_mask,
  *     Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
  *     Any NULL distination masks will be ignored.
  */
-static void ata_unpack_xfermask(unsigned int xfer_mask,
-                               unsigned int *pio_mask,
-                               unsigned int *mwdma_mask,
-                               unsigned int *udma_mask)
+void ata_unpack_xfermask(unsigned long xfer_mask, unsigned long *pio_mask,
+                        unsigned long *mwdma_mask, unsigned long *udma_mask)
 {
        if (pio_mask)
                *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO;
@@ -486,9 +488,9 @@ static const struct ata_xfer_ent {
        int shift, bits;
        u8 base;
 } ata_xfer_tbl[] = {
-       { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
-       { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
-       { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+       { ATA_SHIFT_PIO, ATA_NR_PIO_MODES, XFER_PIO_0 },
+       { ATA_SHIFT_MWDMA, ATA_NR_MWDMA_MODES, XFER_MW_DMA_0 },
+       { ATA_SHIFT_UDMA, ATA_NR_UDMA_MODES, XFER_UDMA_0 },
        { -1, },
 };
 
@@ -503,9 +505,9 @@ static const struct ata_xfer_ent {
  *     None.
  *
  *     RETURNS:
- *     Matching XFER_* value, 0 if no match found.
+ *     Matching XFER_* value, 0xff if no match found.
  */
-static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+u8 ata_xfer_mask2mode(unsigned long xfer_mask)
 {
        int highbit = fls(xfer_mask) - 1;
        const struct ata_xfer_ent *ent;
@@ -513,7 +515,7 @@ static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
        for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
                if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
                        return ent->base + highbit - ent->shift;
-       return 0;
+       return 0xff;
 }
 
 /**
@@ -528,13 +530,14 @@ static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
  *     RETURNS:
  *     Matching xfer_mask, 0 if no match found.
  */
-static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+unsigned long ata_xfer_mode2mask(u8 xfer_mode)
 {
        const struct ata_xfer_ent *ent;
 
        for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
                if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
-                       return 1 << (ent->shift + xfer_mode - ent->base);
+                       return ((2 << (ent->shift + xfer_mode - ent->base)) - 1)
+                               & ~((1 << ent->shift) - 1);
        return 0;
 }
 
@@ -550,7 +553,7 @@ static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
  *     RETURNS:
  *     Matching xfer_shift, -1 if no match found.
  */
-static int ata_xfer_mode2shift(unsigned int xfer_mode)
+int ata_xfer_mode2shift(unsigned long xfer_mode)
 {
        const struct ata_xfer_ent *ent;
 
@@ -574,7 +577,7 @@ static int ata_xfer_mode2shift(unsigned int xfer_mode)
  *     Constant C string representing highest speed listed in
  *     @mode_mask, or the constant C string "<n/a>".
  */
-static const char *ata_mode_string(unsigned int xfer_mask)
+const char *ata_mode_string(unsigned long xfer_mask)
 {
        static const char * const xfer_mode_str[] = {
                "PIO0",
@@ -947,8 +950,8 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
        if (r_err)
                *r_err = err;
 
-       /* see if device passed diags: if master then continue and warn later */
-       if (err == 0 && dev->devno == 0)
+       /* see if device passed diags: continue and warn later */
+       if (err == 0)
                /* diagnostic fail : do nothing _YET_ */
                dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
        else if (err == 1)
@@ -1285,48 +1288,6 @@ static int ata_hpa_resize(struct ata_device *dev)
        return 0;
 }
 
-/**
- *     ata_id_to_dma_mode      -       Identify DMA mode from id block
- *     @dev: device to identify
- *     @unknown: mode to assume if we cannot tell
- *
- *     Set up the timing values for the device based upon the identify
- *     reported values for the DMA mode. This function is used by drivers
- *     which rely upon firmware configured modes, but wish to report the
- *     mode correctly when possible.
- *
- *     In addition we emit similarly formatted messages to the default
- *     ata_dev_set_mode handler, in order to provide consistency of
- *     presentation.
- */
-
-void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown)
-{
-       unsigned int mask;
-       u8 mode;
-
-       /* Pack the DMA modes */
-       mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA;
-       if (dev->id[53] & 0x04)
-               mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA;
-
-       /* Select the mode in use */
-       mode = ata_xfer_mask2mode(mask);
-
-       if (mode != 0) {
-               ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
-                      ata_mode_string(mask));
-       } else {
-               /* SWDMA perhaps ? */
-               mode = unknown;
-               ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
-       }
-
-       /* Configure the device reporting */
-       dev->xfer_mode = mode;
-       dev->xfer_shift = ata_xfer_mode2shift(mode);
-}
-
 /**
  *     ata_noop_dev_select - Select device 0/1 on ATA bus
  *     @ap: ATA channel to manipulate
@@ -1464,9 +1425,9 @@ static inline void ata_dump_id(const u16 *id)
  *     RETURNS:
  *     Computed xfermask
  */
-static unsigned int ata_id_xfermask(const u16 *id)
+unsigned long ata_id_xfermask(const u16 *id)
 {
-       unsigned int pio_mask, mwdma_mask, udma_mask;
+       unsigned long pio_mask, mwdma_mask, udma_mask;
 
        /* Usual case. Word 53 indicates word 64 is valid */
        if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
@@ -1519,7 +1480,7 @@ static unsigned int ata_id_xfermask(const u16 *id)
 }
 
 /**
- *     ata_port_queue_task - Queue port_task
+ *     ata_pio_queue_task - Queue port_task
  *     @ap: The ata_port to queue port_task for
  *     @fn: workqueue function to be scheduled
  *     @data: data for @fn to use
@@ -1531,16 +1492,15 @@ static unsigned int ata_id_xfermask(const u16 *id)
  *     one task is active at any given time.
  *
  *     libata core layer takes care of synchronization between
- *     port_task and EH.  ata_port_queue_task() may be ignored for EH
+ *     port_task and EH.  ata_pio_queue_task() may be ignored for EH
  *     synchronization.
  *
  *     LOCKING:
  *     Inherited from caller.
  */
-void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data,
-                        unsigned long delay)
+static void ata_pio_queue_task(struct ata_port *ap, void *data,
+                              unsigned long delay)
 {
-       PREPARE_DELAYED_WORK(&ap->port_task, fn);
        ap->port_task_data = data;
 
        /* may fail if ata_port_flush_task() in progress */
@@ -2090,7 +2050,7 @@ int ata_dev_configure(struct ata_device *dev)
        struct ata_eh_context *ehc = &dev->link->eh_context;
        int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
        const u16 *id = dev->id;
-       unsigned int xfer_mask;
+       unsigned long xfer_mask;
        char revbuf[7];         /* XYZ-99\0 */
        char fwrevbuf[ATA_ID_FW_REV_LEN+1];
        char modelbuf[ATA_ID_PROD_LEN+1];
@@ -2161,8 +2121,14 @@ int ata_dev_configure(struct ata_device *dev)
                                               "supports DRM functions and may "
                                               "not be fully accessable.\n");
                        snprintf(revbuf, 7, "CFA");
-               } else
+               } else {
                        snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
+                       /* Warn the user if the device has TPM extensions */
+                       if (ata_id_has_tpm(id))
+                               ata_dev_printk(dev, KERN_WARNING,
+                                              "supports DRM functions and may "
+                                              "not be fully accessable.\n");
+               }
 
                dev->n_sectors = ata_id_n_sectors(id);
 
@@ -2295,19 +2261,8 @@ int ata_dev_configure(struct ata_device *dev)
                        dev->flags |= ATA_DFLAG_DIPM;
        }
 
-       if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
-               /* Let the user know. We don't want to disallow opens for
-                  rescue purposes, or in case the vendor is just a blithering
-                  idiot */
-               if (print_info) {
-                       ata_dev_printk(dev, KERN_WARNING,
-"Drive reports diagnostics failure. This may indicate a drive\n");
-                       ata_dev_printk(dev, KERN_WARNING,
-"fault or invalid emulation. Contact drive vendor for information.\n");
-               }
-       }
-
-       /* limit bridge transfers to udma5, 200 sectors */
+       /* Limit PATA drive on SATA cable bridge transfers to udma5,
+          200 sectors */
        if (ata_dev_knobble(dev)) {
                if (ata_msg_drv(ap) && print_info)
                        ata_dev_printk(dev, KERN_INFO,
@@ -2336,6 +2291,21 @@ int ata_dev_configure(struct ata_device *dev)
        if (ap->ops->dev_config)
                ap->ops->dev_config(dev);
 
+       if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+               /* Let the user know. We don't want to disallow opens for
+                  rescue purposes, or in case the vendor is just a blithering
+                  idiot. Do this after the dev_config call as some controllers
+                  with buggy firmware may want to avoid reporting false device
+                  bugs */
+
+               if (print_info) {
+                       ata_dev_printk(dev, KERN_WARNING,
+"Drive reports diagnostics failure. This may indicate a drive\n");
+                       ata_dev_printk(dev, KERN_WARNING,
+"fault or invalid emulation. Contact drive vendor for information.\n");
+               }
+       }
+
        if (ata_msg_probe(ap))
                ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
                        __FUNCTION__, ata_chk_status(ap));
@@ -2386,6 +2356,18 @@ int ata_cable_unknown(struct ata_port *ap)
        return ATA_CBL_PATA_UNK;
 }
 
+/**
+ *     ata_cable_ignore        -       return ignored PATA cable.
+ *     @ap: port
+ *
+ *     Helper method for drivers which don't use cable type to limit
+ *     transfer mode.
+ */
+int ata_cable_ignore(struct ata_port *ap)
+{
+       return ATA_CBL_PATA_IGN;
+}
+
 /**
  *     ata_cable_sata  -       return SATA cable type
  *     @ap: port
@@ -2781,38 +2763,33 @@ int sata_set_spd(struct ata_link *link)
  */
 
 static const struct ata_timing ata_timing[] = {
+/*     { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 }, */
+       { XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
+       { XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
+       { XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
+       { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
+       { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
+       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
+       { XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
 
-       { XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
-       { XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
-       { XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
-       { XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
+       { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
+       { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
+       { XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
 
-       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
+       { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
+       { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
+       { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
        { XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 100,   0 },
-       { XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
-       { XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
-       { XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
+       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
 
 /*     { XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0,   0, 150 }, */
-
-       { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
-       { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
-       { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
-
-       { XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
-       { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
-       { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
-
-       { XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
-       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
-       { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
-       { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
-
-       { XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
-       { XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
-       { XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
-
-/*     { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 }, */
+       { XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
+       { XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
+       { XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
+       { XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
+       { XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
+       { XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
+       { XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
 
        { 0xFF }
 };
@@ -2845,14 +2822,16 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
        if (what & ATA_TIMING_UDMA   ) m->udma    = max(a->udma,    b->udma);
 }
 
-static const struct ata_timing *ata_timing_find_mode(unsigned short speed)
+const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
 {
-       const struct ata_timing *t;
+       const struct ata_timing *t = ata_timing;
+
+       while (xfer_mode > t->mode)
+               t++;
 
-       for (t = ata_timing; t->mode != speed; t++)
-               if (t->mode == 0xFF)
-                       return NULL;
-       return t;
+       if (xfer_mode == t->mode)
+               return t;
+       return NULL;
 }
 
 int ata_timing_compute(struct ata_device *adev, unsigned short speed,
@@ -2926,6 +2905,57 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
        return 0;
 }
 
+/**
+ *     ata_timing_cycle2mode - find xfer mode for the specified cycle duration
+ *     @xfer_shift: ATA_SHIFT_* value for transfer type to examine.
+ *     @cycle: cycle duration in ns
+ *
+ *     Return matching xfer mode for @cycle.  The returned mode is of
+ *     the transfer type specified by @xfer_shift.  If @cycle is too
+ *     slow for @xfer_shift, 0xff is returned.  If @cycle is faster
+ *     than the fastest known mode, the fasted mode is returned.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Matching xfer_mode, 0xff if no match found.
+ */
+u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle)
+{
+       u8 base_mode = 0xff, last_mode = 0xff;
+       const struct ata_xfer_ent *ent;
+       const struct ata_timing *t;
+
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (ent->shift == xfer_shift)
+                       base_mode = ent->base;
+
+       for (t = ata_timing_find_mode(base_mode);
+            t && ata_xfer_mode2shift(t->mode) == xfer_shift; t++) {
+               unsigned short this_cycle;
+
+               switch (xfer_shift) {
+               case ATA_SHIFT_PIO:
+               case ATA_SHIFT_MWDMA:
+                       this_cycle = t->cycle;
+                       break;
+               case ATA_SHIFT_UDMA:
+                       this_cycle = t->udma;
+                       break;
+               default:
+                       return 0xff;
+               }
+
+               if (cycle > this_cycle)
+                       break;
+
+               last_mode = t->mode;
+       }
+
+       return last_mode;
+}
+
 /**
  *     ata_down_xfermask_limit - adjust dev xfer masks downward
  *     @dev: Device to adjust xfer masks
@@ -2944,8 +2974,8 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
 int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
 {
        char buf[32];
-       unsigned int orig_mask, xfer_mask;
-       unsigned int pio_mask, mwdma_mask, udma_mask;
+       unsigned long orig_mask, xfer_mask;
+       unsigned long pio_mask, mwdma_mask, udma_mask;
        int quiet, highbit;
 
        quiet = !!(sel & ATA_DNXFER_QUIET);
@@ -3039,7 +3069,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
 
        /* Early MWDMA devices do DMA but don't allow DMA mode setting.
           Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */
-       if (dev->xfer_shift == ATA_SHIFT_MWDMA && 
+       if (dev->xfer_shift == ATA_SHIFT_MWDMA &&
            dev->dma_mode == XFER_MW_DMA_0 &&
            (dev->id[63] >> 8) & 1)
                err_mask &= ~AC_ERR_DEV;
@@ -3089,7 +3119,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 
        /* step 1: calculate xfer_mask */
        ata_link_for_each_dev(dev, link) {
-               unsigned int pio_mask, dma_mask;
+               unsigned long pio_mask, dma_mask;
                unsigned int mode_mask;
 
                if (!ata_dev_enabled(dev))
@@ -3115,7 +3145,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
                dev->dma_mode = ata_xfer_mask2mode(dma_mask);
 
                found = 1;
-               if (dev->dma_mode)
+               if (dev->dma_mode != 0xff)
                        used_dma = 1;
        }
        if (!found)
@@ -3126,7 +3156,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
                if (!ata_dev_enabled(dev))
                        continue;
 
-               if (!dev->pio_mode) {
+               if (dev->pio_mode == 0xff) {
                        ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
                        rc = -EINVAL;
                        goto out;
@@ -3140,7 +3170,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 
        /* step 3: set host DMA timings */
        ata_link_for_each_dev(dev, link) {
-               if (!ata_dev_enabled(dev) || !dev->dma_mode)
+               if (!ata_dev_enabled(dev) || dev->dma_mode == 0xff)
                        continue;
 
                dev->xfer_mode = dev->dma_mode;
@@ -3172,31 +3202,6 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        return rc;
 }
 
-/**
- *     ata_set_mode - Program timings and issue SET FEATURES - XFER
- *     @link: link on which timings will be programmed
- *     @r_failed_dev: out paramter for failed device
- *
- *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
- *     ata_set_mode() fails, pointer to the failing device is
- *     returned in @r_failed_dev.
- *
- *     LOCKING:
- *     PCI/etc. bus probe sem.
- *
- *     RETURNS:
- *     0 on success, negative errno otherwise
- */
-int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
-{
-       struct ata_port *ap = link->ap;
-
-       /* has private set_mode? */
-       if (ap->ops->set_mode)
-               return ap->ops->set_mode(link, r_failed_dev);
-       return ata_do_set_mode(link, r_failed_dev);
-}
-
 /**
  *     ata_tf_to_host - issue ATA taskfile to host controller
  *     @ap: port to which command is being issued
@@ -4363,7 +4368,14 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
        tf.feature = SETFEATURES_XFER;
        tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_POLLING;
        tf.protocol = ATA_PROT_NODATA;
-       tf.nsect = dev->xfer_mode;
+       /* If we are using IORDY we must send the mode setting command */
+       if (ata_pio_need_iordy(dev))
+               tf.nsect = dev->xfer_mode;
+       /* If the device has IORDY and the controller does not - turn it off */
+       else if (ata_id_has_iordy(dev->id))
+               tf.nsect = 0x01;
+       else /* In the ancient relic department - skip all of this */
+               return 0;
 
        err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
 
@@ -4462,17 +4474,13 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
 void ata_sg_clean(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       struct scatterlist *sg = qc->__sg;
+       struct scatterlist *sg = qc->sg;
        int dir = qc->dma_dir;
        void *pad_buf = NULL;
 
-       WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
        WARN_ON(sg == NULL);
 
-       if (qc->flags & ATA_QCFLAG_SINGLE)
-               WARN_ON(qc->n_elem > 1);
-
-       VPRINTK("unmapping %u sg elements\n", qc->n_elem);
+       VPRINTK("unmapping %u sg elements\n", qc->mapped_n_elem);
 
        /* if we padded the buffer out to 32-bit bound, and data
         * xfer direction is from-device, we must copy from the
@@ -4481,31 +4489,20 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
        if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
                pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
 
-       if (qc->flags & ATA_QCFLAG_SG) {
-               if (qc->n_elem)
-                       dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
-               /* restore last sg */
-               sg_last(sg, qc->orig_n_elem)->length += qc->pad_len;
-               if (pad_buf) {
-                       struct scatterlist *psg = &qc->pad_sgent;
-                       void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
-                       memcpy(addr + psg->offset, pad_buf, qc->pad_len);
-                       kunmap_atomic(addr, KM_IRQ0);
-               }
-       } else {
-               if (qc->n_elem)
-                       dma_unmap_single(ap->dev,
-                               sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
-                               dir);
-               /* restore sg */
-               sg->length += qc->pad_len;
-               if (pad_buf)
-                       memcpy(qc->buf_virt + sg->length - qc->pad_len,
-                              pad_buf, qc->pad_len);
+       if (qc->mapped_n_elem)
+               dma_unmap_sg(ap->dev, sg, qc->mapped_n_elem, dir);
+       /* restore last sg */
+       if (qc->last_sg)
+               *qc->last_sg = qc->saved_last_sg;
+       if (pad_buf) {
+               struct scatterlist *psg = &qc->extra_sg[1];
+               void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
+               memcpy(addr + psg->offset, pad_buf, qc->pad_len);
+               kunmap_atomic(addr, KM_IRQ0);
        }
 
        qc->flags &= ~ATA_QCFLAG_DMAMAP;
-       qc->__sg = NULL;
+       qc->sg = NULL;
 }
 
 /**
@@ -4523,13 +4520,10 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct scatterlist *sg;
-       unsigned int idx;
+       unsigned int si, pi;
 
-       WARN_ON(qc->__sg == NULL);
-       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
-       idx = 0;
-       ata_for_each_sg(sg, qc) {
+       pi = 0;
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u32 addr, offset;
                u32 sg_len, len;
 
@@ -4546,18 +4540,17 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
                        if ((offset + sg_len) > 0x10000)
                                len = 0x10000 - offset;
 
-                       ap->prd[idx].addr = cpu_to_le32(addr);
-                       ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
-                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+                       ap->prd[pi].addr = cpu_to_le32(addr);
+                       ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff);
+                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
 
-                       idx++;
+                       pi++;
                        sg_len -= len;
                        addr += len;
                }
        }
 
-       if (idx)
-               ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+       ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 /**
@@ -4577,13 +4570,10 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct scatterlist *sg;
-       unsigned int idx;
-
-       WARN_ON(qc->__sg == NULL);
-       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+       unsigned int si, pi;
 
-       idx = 0;
-       ata_for_each_sg(sg, qc) {
+       pi = 0;
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u32 addr, offset;
                u32 sg_len, len, blen;
 
@@ -4601,25 +4591,24 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
                                len = 0x10000 - offset;
 
                        blen = len & 0xffff;
-                       ap->prd[idx].addr = cpu_to_le32(addr);
+                       ap->prd[pi].addr = cpu_to_le32(addr);
                        if (blen == 0) {
                           /* Some PATA chipsets like the CS5530 can't
                              cope with 0x0000 meaning 64K as the spec says */
-                               ap->prd[idx].flags_len = cpu_to_le32(0x8000);
+                               ap->prd[pi].flags_len = cpu_to_le32(0x8000);
                                blen = 0x8000;
-                               ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000);
+                               ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000);
                        }
-                       ap->prd[idx].flags_len = cpu_to_le32(blen);
-                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+                       ap->prd[pi].flags_len = cpu_to_le32(blen);
+                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
 
-                       idx++;
+                       pi++;
                        sg_len -= len;
                        addr += len;
                }
        }
 
-       if (idx)
-               ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+       ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 /**
@@ -4669,8 +4658,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
  */
 static int atapi_qc_may_overflow(struct ata_queued_cmd *qc)
 {
-       if (qc->tf.protocol != ATA_PROT_ATAPI &&
-           qc->tf.protocol != ATA_PROT_ATAPI_DMA)
+       if (qc->tf.protocol != ATAPI_PROT_PIO &&
+           qc->tf.protocol != ATAPI_PROT_DMA)
                return 0;
 
        if (qc->tf.flags & ATA_TFLAG_WRITE)
@@ -4755,33 +4744,6 @@ void ata_dumb_qc_prep(struct ata_queued_cmd *qc)
 
 void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
 
-/**
- *     ata_sg_init_one - Associate command with memory buffer
- *     @qc: Command to be associated
- *     @buf: Memory buffer
- *     @buflen: Length of memory buffer, in bytes.
- *
- *     Initialize the data-related elements of queued_cmd @qc
- *     to point to a single memory buffer, @buf of byte length @buflen.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- */
-
-void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
-{
-       qc->flags |= ATA_QCFLAG_SINGLE;
-
-       qc->__sg = &qc->sgent;
-       qc->n_elem = 1;
-       qc->orig_n_elem = 1;
-       qc->buf_virt = buf;
-       qc->nbytes = buflen;
-       qc->cursg = qc->__sg;
-
-       sg_init_one(&qc->sgent, buf, buflen);
-}
-
 /**
  *     ata_sg_init - Associate command with scatter-gather table.
  *     @qc: Command to be associated
@@ -4795,84 +4757,103 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
  *     LOCKING:
  *     spin_lock_irqsave(host lock)
  */
-
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
                 unsigned int n_elem)
 {
-       qc->flags |= ATA_QCFLAG_SG;
-       qc->__sg = sg;
+       qc->sg = sg;
        qc->n_elem = n_elem;
-       qc->orig_n_elem = n_elem;
-       qc->cursg = qc->__sg;
+       qc->cursg = qc->sg;
 }
 
-/**
- *     ata_sg_setup_one - DMA-map the memory buffer associated with a command.
- *     @qc: Command with memory buffer to be mapped.
- *
- *     DMA-map the memory buffer associated with queued_cmd @qc.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     Zero on success, negative on error.
- */
-
-static int ata_sg_setup_one(struct ata_queued_cmd *qc)
+static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
+                                      unsigned int *n_elem_extra,
+                                      unsigned int *nbytes_extra)
 {
        struct ata_port *ap = qc->ap;
-       int dir = qc->dma_dir;
-       struct scatterlist *sg = qc->__sg;
-       dma_addr_t dma_address;
-       int trim_sg = 0;
+       unsigned int n_elem = qc->n_elem;
+       struct scatterlist *lsg, *copy_lsg = NULL, *tsg = NULL, *esg = NULL;
+
+       *n_elem_extra = 0;
+       *nbytes_extra = 0;
+
+       /* needs padding? */
+       qc->pad_len = qc->nbytes & 3;
+
+       if (likely(!qc->pad_len))
+               return n_elem;
+
+       /* locate last sg and save it */
+       lsg = sg_last(qc->sg, n_elem);
+       qc->last_sg = lsg;
+       qc->saved_last_sg = *lsg;
+
+       sg_init_table(qc->extra_sg, ARRAY_SIZE(qc->extra_sg));
 
-       /* we must lengthen transfers to end on a 32-bit boundary */
-       qc->pad_len = sg->length & 3;
        if (qc->pad_len) {
+               struct scatterlist *psg = &qc->extra_sg[1];
                void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
-               struct scatterlist *psg = &qc->pad_sgent;
+               unsigned int offset;
 
                WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
 
                memset(pad_buf, 0, ATA_DMA_PAD_SZ);
 
-               if (qc->tf.flags & ATA_TFLAG_WRITE)
-                       memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
-                              qc->pad_len);
+               /* psg->page/offset are used to copy to-be-written
+                * data in this function or read data in ata_sg_clean.
+                */
+               offset = lsg->offset + lsg->length - qc->pad_len;
+               sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT),
+                           qc->pad_len, offset_in_page(offset));
+
+               if (qc->tf.flags & ATA_TFLAG_WRITE) {
+                       void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
+                       memcpy(pad_buf, addr + psg->offset, qc->pad_len);
+                       kunmap_atomic(addr, KM_IRQ0);
+               }
 
                sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
                sg_dma_len(psg) = ATA_DMA_PAD_SZ;
-               /* trim sg */
-               sg->length -= qc->pad_len;
-               if (sg->length == 0)
-                       trim_sg = 1;
 
-               DPRINTK("padding done, sg->length=%u pad_len=%u\n",
-                       sg->length, qc->pad_len);
-       }
+               /* Trim the last sg entry and chain the original and
+                * padding sg lists.
+                *
+                * Because chaining consumes one sg entry, one extra
+                * sg entry is allocated and the last sg entry is
+                * copied to it if the length isn't zero after padded
+                * amount is removed.
+                *
+                * If the last sg entry is completely replaced by
+                * padding sg entry, the first sg entry is skipped
+                * while chaining.
+                */
+               lsg->length -= qc->pad_len;
+               if (lsg->length) {
+                       copy_lsg = &qc->extra_sg[0];
+                       tsg = &qc->extra_sg[0];
+               } else {
+                       n_elem--;
+                       tsg = &qc->extra_sg[1];
+               }
 
-       if (trim_sg) {
-               qc->n_elem--;
-               goto skip_map;
-       }
+               esg = &qc->extra_sg[1];
 
-       dma_address = dma_map_single(ap->dev, qc->buf_virt,
-                                    sg->length, dir);
-       if (dma_mapping_error(dma_address)) {
-               /* restore sg */
-               sg->length += qc->pad_len;
-               return -1;
+               (*n_elem_extra)++;
+               (*nbytes_extra) += 4 - qc->pad_len;
        }
 
-       sg_dma_address(sg) = dma_address;
-       sg_dma_len(sg) = sg->length;
+       if (copy_lsg)
+               sg_set_page(copy_lsg, sg_page(lsg), lsg->length, lsg->offset);
 
-skip_map:
-       DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
-               qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+       sg_chain(lsg, 1, tsg);
+       sg_mark_end(esg);
 
-       return 0;
+       /* sglist can't start with chaining sg entry, fast forward */
+       if (qc->sg == lsg) {
+               qc->sg = tsg;
+               qc->cursg = tsg;
+       }
+
+       return n_elem;
 }
 
 /**
@@ -4888,75 +4869,30 @@ skip_map:
  *     Zero on success, negative on error.
  *
  */
-
 static int ata_sg_setup(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       struct scatterlist *sg = qc->__sg;
-       struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem);
-       int n_elem, pre_n_elem, dir, trim_sg = 0;
+       unsigned int n_elem, n_elem_extra, nbytes_extra;
 
        VPRINTK("ENTER, ata%u\n", ap->print_id);
-       WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
 
-       /* we must lengthen transfers to end on a 32-bit boundary */
-       qc->pad_len = lsg->length & 3;
-       if (qc->pad_len) {
-               void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
-               struct scatterlist *psg = &qc->pad_sgent;
-               unsigned int offset;
-
-               WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
+       n_elem = ata_sg_setup_extra(qc, &n_elem_extra, &nbytes_extra);
 
-               memset(pad_buf, 0, ATA_DMA_PAD_SZ);
-
-               /*
-                * psg->page/offset are used to copy to-be-written
-                * data in this function or read data in ata_sg_clean.
-                */
-               offset = lsg->offset + lsg->length - qc->pad_len;
-               sg_init_table(psg, 1);
-               sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT),
-                               qc->pad_len, offset_in_page(offset));
-
-               if (qc->tf.flags & ATA_TFLAG_WRITE) {
-                       void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
-                       memcpy(pad_buf, addr + psg->offset, qc->pad_len);
-                       kunmap_atomic(addr, KM_IRQ0);
+       if (n_elem) {
+               n_elem = dma_map_sg(ap->dev, qc->sg, n_elem, qc->dma_dir);
+               if (n_elem < 1) {
+                       /* restore last sg */
+                       if (qc->last_sg)
+                               *qc->last_sg = qc->saved_last_sg;
+                       return -1;
                }
-
-               sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
-               sg_dma_len(psg) = ATA_DMA_PAD_SZ;
-               /* trim last sg */
-               lsg->length -= qc->pad_len;
-               if (lsg->length == 0)
-                       trim_sg = 1;
-
-               DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
-                       qc->n_elem - 1, lsg->length, qc->pad_len);
-       }
-
-       pre_n_elem = qc->n_elem;
-       if (trim_sg && pre_n_elem)
-               pre_n_elem--;
-
-       if (!pre_n_elem) {
-               n_elem = 0;
-               goto skip_map;
-       }
-
-       dir = qc->dma_dir;
-       n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir);
-       if (n_elem < 1) {
-               /* restore last sg */
-               lsg->length += qc->pad_len;
-               return -1;
+               DPRINTK("%d sg elements mapped\n", n_elem);
        }
 
-       DPRINTK("%d sg elements mapped\n", n_elem);
-
-skip_map:
-       qc->n_elem = n_elem;
+       qc->n_elem = qc->mapped_n_elem = n_elem;
+       qc->n_elem += n_elem_extra;
+       qc->nbytes += nbytes_extra;
+       qc->flags |= ATA_QCFLAG_DMAMAP;
 
        return 0;
 }
@@ -4985,7 +4921,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
 
 /**
  *     ata_data_xfer - Transfer data by PIO
- *     @adev: device to target
+ *     @dev: device to target
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @write_data: read/write
@@ -4994,37 +4930,44 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
  *
  *     LOCKING:
  *     Inherited from caller.
+ *
+ *     RETURNS:
+ *     Bytes consumed.
  */
-void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
-                  unsigned int buflen, int write_data)
+unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf,
+                          unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
+       struct ata_port *ap = dev->link->ap;
+       void __iomem *data_addr = ap->ioaddr.data_addr;
        unsigned int words = buflen >> 1;
 
        /* Transfer multiple of 2 bytes */
-       if (write_data)
-               iowrite16_rep(ap->ioaddr.data_addr, buf, words);
+       if (rw == READ)
+               ioread16_rep(data_addr, buf, words);
        else
-               ioread16_rep(ap->ioaddr.data_addr, buf, words);
+               iowrite16_rep(data_addr, buf, words);
 
        /* Transfer trailing 1 byte, if any. */
        if (unlikely(buflen & 0x01)) {
-               u16 align_buf[1] = { 0 };
+               __le16 align_buf[1] = { 0 };
                unsigned char *trailing_buf = buf + buflen - 1;
 
-               if (write_data) {
-                       memcpy(align_buf, trailing_buf, 1);
-                       iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
-               } else {
-                       align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr));
+               if (rw == READ) {
+                       align_buf[0] = cpu_to_le16(ioread16(data_addr));
                        memcpy(trailing_buf, align_buf, 1);
+               } else {
+                       memcpy(align_buf, trailing_buf, 1);
+                       iowrite16(le16_to_cpu(align_buf[0]), data_addr);
                }
+               words++;
        }
+
+       return words << 1;
 }
 
 /**
  *     ata_data_xfer_noirq - Transfer data by PIO
- *     @adev: device to target
+ *     @dev: device to target
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @write_data: read/write
@@ -5034,14 +4977,21 @@ void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
  *
  *     LOCKING:
  *     Inherited from caller.
+ *
+ *     RETURNS:
+ *     Bytes consumed.
  */
-void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
-                        unsigned int buflen, int write_data)
+unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
+                                unsigned int buflen, int rw)
 {
        unsigned long flags;
+       unsigned int consumed;
+
        local_irq_save(flags);
-       ata_data_xfer(adev, buf, buflen, write_data);
+       consumed = ata_data_xfer(dev, buf, buflen, rw);
        local_irq_restore(flags);
+
+       return consumed;
 }
 
 
@@ -5152,13 +5102,13 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
        ata_altstatus(ap); /* flush */
 
        switch (qc->tf.protocol) {
-       case ATA_PROT_ATAPI:
+       case ATAPI_PROT_PIO:
                ap->hsm_task_state = HSM_ST;
                break;
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_NODATA:
                ap->hsm_task_state = HSM_ST_LAST;
                break;
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                ap->hsm_task_state = HSM_ST_LAST;
                /* initiate bmdma */
                ap->ops->bmdma_start(qc);
@@ -5300,12 +5250,15 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
        bytes = (bc_hi << 8) | bc_lo;
 
        /* shall be cleared to zero, indicating xfer of data */
-       if (ireason & (1 << 0))
+       if (unlikely(ireason & (1 << 0)))
                goto err_out;
 
        /* make sure transfer direction matches expected */
        i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
-       if (do_write != i_write)
+       if (unlikely(do_write != i_write))
+               goto err_out;
+
+       if (unlikely(!bytes))
                goto err_out;
 
        VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
@@ -5341,7 +5294,7 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q
                    (qc->tf.flags & ATA_TFLAG_WRITE))
                    return 1;
 
-               if (is_atapi_taskfile(&qc->tf) &&
+               if (ata_is_atapi(qc->tf.protocol) &&
                    !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
                        return 1;
        }
@@ -5506,7 +5459,7 @@ fsm_start:
 
        case HSM_ST:
                /* complete command or read/write the data register */
-               if (qc->tf.protocol == ATA_PROT_ATAPI) {
+               if (qc->tf.protocol == ATAPI_PROT_PIO) {
                        /* ATAPI PIO protocol */
                        if ((status & ATA_DRQ) == 0) {
                                /* No more data to transfer or device error.
@@ -5664,7 +5617,7 @@ fsm_start:
                msleep(2);
                status = ata_busy_wait(ap, ATA_BUSY, 10);
                if (status & ATA_BUSY) {
-                       ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
+                       ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE);
                        return;
                }
        }
@@ -5805,6 +5758,22 @@ static void fill_result_tf(struct ata_queued_cmd *qc)
        ap->ops->tf_read(ap, &qc->result_tf);
 }
 
+static void ata_verify_xfer(struct ata_queued_cmd *qc)
+{
+       struct ata_device *dev = qc->dev;
+
+       if (ata_tag_internal(qc->tag))
+               return;
+
+       if (ata_is_nodata(qc->tf.protocol))
+               return;
+
+       if ((dev->mwdma_mask || dev->udma_mask) && ata_is_pio(qc->tf.protocol))
+               return;
+
+       dev->flags &= ~ATA_DFLAG_DUBIOUS_XFER;
+}
+
 /**
  *     ata_qc_complete - Complete an active ATA command
  *     @qc: Command to complete
@@ -5876,6 +5845,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
                        break;
                }
 
+               if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER))
+                       ata_verify_xfer(qc);
+
                __ata_qc_complete(qc);
        } else {
                if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
@@ -5938,30 +5910,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
        return nr_done;
 }
 
-static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-
-       switch (qc->tf.protocol) {
-       case ATA_PROT_NCQ:
-       case ATA_PROT_DMA:
-       case ATA_PROT_ATAPI_DMA:
-               return 1;
-
-       case ATA_PROT_ATAPI:
-       case ATA_PROT_PIO:
-               if (ap->flags & ATA_FLAG_PIO_DMA)
-                       return 1;
-
-               /* fall through */
-
-       default:
-               return 0;
-       }
-
-       /* never reached */
-}
-
 /**
  *     ata_qc_issue - issue taskfile to device
  *     @qc: command to issue to device
@@ -5978,6 +5926,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct ata_link *link = qc->dev->link;
+       u8 prot = qc->tf.protocol;
 
        /* Make sure only one non-NCQ command is outstanding.  The
         * check is skipped for old EH because it reuses active qc to
@@ -5985,7 +5934,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
         */
        WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
 
-       if (qc->tf.protocol == ATA_PROT_NCQ) {
+       if (ata_is_ncq(prot)) {
                WARN_ON(link->sactive & (1 << qc->tag));
 
                if (!link->sactive)
@@ -6001,17 +5950,18 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
        qc->flags |= ATA_QCFLAG_ACTIVE;
        ap->qc_active |= 1 << qc->tag;
 
-       if (ata_should_dma_map(qc)) {
-               if (qc->flags & ATA_QCFLAG_SG) {
-                       if (ata_sg_setup(qc))
-                               goto sg_err;
-               } else if (qc->flags & ATA_QCFLAG_SINGLE) {
-                       if (ata_sg_setup_one(qc))
-                               goto sg_err;
-               }
-       } else {
-               qc->flags &= ~ATA_QCFLAG_DMAMAP;
-       }
+       /* We guarantee to LLDs that they will have at least one
+        * non-zero sg if the command is a data command.
+        */
+       BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes));
+
+       /* ata_sg_setup() may update nbytes */
+       qc->raw_nbytes = qc->nbytes;
+
+       if (ata_is_dma(prot) || (ata_is_pio(prot) &&
+                                (ap->flags & ATA_FLAG_PIO_DMA)))
+               if (ata_sg_setup(qc))
+                       goto sg_err;
 
        /* if device is sleeping, schedule softreset and abort the link */
        if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) {
@@ -6029,7 +5979,6 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
        return;
 
 sg_err:
-       qc->flags &= ~ATA_QCFLAG_DMAMAP;
        qc->err_mask |= AC_ERR_SYSTEM;
 err:
        ata_qc_complete(qc);
@@ -6064,11 +6013,11 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                switch (qc->tf.protocol) {
                case ATA_PROT_PIO:
                case ATA_PROT_NODATA:
-               case ATA_PROT_ATAPI:
-               case ATA_PROT_ATAPI_NODATA:
+               case ATAPI_PROT_PIO:
+               case ATAPI_PROT_NODATA:
                        qc->tf.flags |= ATA_TFLAG_POLLING;
                        break;
-               case ATA_PROT_ATAPI_DMA:
+               case ATAPI_PROT_DMA:
                        if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
                                /* see ata_dma_blacklisted() */
                                BUG();
@@ -6091,7 +6040,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                ap->hsm_task_state = HSM_ST_LAST;
 
                if (qc->tf.flags & ATA_TFLAG_POLLING)
-                       ata_port_queue_task(ap, ata_pio_task, qc, 0);
+                       ata_pio_queue_task(ap, qc, 0);
 
                break;
 
@@ -6113,7 +6062,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                if (qc->tf.flags & ATA_TFLAG_WRITE) {
                        /* PIO data out protocol */
                        ap->hsm_task_state = HSM_ST_FIRST;
-                       ata_port_queue_task(ap, ata_pio_task, qc, 0);
+                       ata_pio_queue_task(ap, qc, 0);
 
                        /* always send first data block using
                         * the ata_pio_task() codepath.
@@ -6123,7 +6072,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                        ap->hsm_task_state = HSM_ST;
 
                        if (qc->tf.flags & ATA_TFLAG_POLLING)
-                               ata_port_queue_task(ap, ata_pio_task, qc, 0);
+                               ata_pio_queue_task(ap, qc, 0);
 
                        /* if polling, ata_pio_task() handles the rest.
                         * otherwise, interrupt handler takes over from here.
@@ -6132,8 +6081,8 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 
                break;
 
-       case ATA_PROT_ATAPI:
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_PIO:
+       case ATAPI_PROT_NODATA:
                if (qc->tf.flags & ATA_TFLAG_POLLING)
                        ata_qc_set_polling(qc);
 
@@ -6144,10 +6093,10 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                /* send cdb by polling if no cdb interrupt */
                if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
                    (qc->tf.flags & ATA_TFLAG_POLLING))
-                       ata_port_queue_task(ap, ata_pio_task, qc, 0);
+                       ata_pio_queue_task(ap, qc, 0);
                break;
 
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
 
                ap->ops->tf_load(ap, &qc->tf);   /* load tf registers */
@@ -6156,7 +6105,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 
                /* send cdb by polling if no cdb interrupt */
                if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
-                       ata_port_queue_task(ap, ata_pio_task, qc, 0);
+                       ata_pio_queue_task(ap, qc, 0);
                break;
 
        default:
@@ -6200,15 +6149,15 @@ inline unsigned int ata_host_intr(struct ata_port *ap,
                 */
 
                /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
-                * The flag was turned on only for atapi devices.
-                * No need to check is_atapi_taskfile(&qc->tf) again.
+                * The flag was turned on only for atapi devices.  No
+                * need to check ata_is_atapi(qc->tf.protocol) again.
                 */
                if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
                        goto idle_irq;
                break;
        case HSM_ST_LAST:
                if (qc->tf.protocol == ATA_PROT_DMA ||
-                   qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+                   qc->tf.protocol == ATAPI_PROT_DMA) {
                        /* check status of DMA engine */
                        host_stat = ap->ops->bmdma_status(ap);
                        VPRINTK("ata%u: host_stat 0x%X\n",
@@ -6250,7 +6199,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap,
        ata_hsm_move(ap, qc, status, 0);
 
        if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
-                                      qc->tf.protocol == ATA_PROT_ATAPI_DMA))
+                                      qc->tf.protocol == ATAPI_PROT_DMA))
                ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
 
        return 1;       /* irq handled */
@@ -6772,7 +6721,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
 #endif
 
-       INIT_DELAYED_WORK(&ap->port_task, NULL);
+       INIT_DELAYED_WORK(&ap->port_task, ata_pio_task);
        INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
        INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
        INIT_LIST_HEAD(&ap->eh_done_q);
@@ -6998,7 +6947,9 @@ int ata_host_start(struct ata_host *host)
                        rc = ap->ops->port_start(ap);
                        if (rc) {
                                if (rc != -ENODEV)
-                                       dev_printk(KERN_ERR, host->dev, "failed to start port %d (errno=%d)\n", i, rc);
+                                       dev_printk(KERN_ERR, host->dev,
+                                               "failed to start port %d "
+                                               "(errno=%d)\n", i, rc);
                                goto err_out;
                        }
                }
@@ -7587,7 +7538,6 @@ EXPORT_SYMBOL_GPL(ata_host_register);
 EXPORT_SYMBOL_GPL(ata_host_activate);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
-EXPORT_SYMBOL_GPL(ata_sg_init_one);
 EXPORT_SYMBOL_GPL(ata_hsm_move);
 EXPORT_SYMBOL_GPL(ata_qc_complete);
 EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
@@ -7599,6 +7549,13 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select);
 EXPORT_SYMBOL_GPL(sata_print_link_status);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+EXPORT_SYMBOL_GPL(ata_pack_xfermask);
+EXPORT_SYMBOL_GPL(ata_unpack_xfermask);
+EXPORT_SYMBOL_GPL(ata_xfer_mask2mode);
+EXPORT_SYMBOL_GPL(ata_xfer_mode2mask);
+EXPORT_SYMBOL_GPL(ata_xfer_mode2shift);
+EXPORT_SYMBOL_GPL(ata_mode_string);
+EXPORT_SYMBOL_GPL(ata_id_xfermask);
 EXPORT_SYMBOL_GPL(ata_check_status);
 EXPORT_SYMBOL_GPL(ata_altstatus);
 EXPORT_SYMBOL_GPL(ata_exec_command);
@@ -7641,7 +7598,6 @@ EXPORT_SYMBOL_GPL(ata_wait_register);
 EXPORT_SYMBOL_GPL(ata_busy_sleep);
 EXPORT_SYMBOL_GPL(ata_wait_after_reset);
 EXPORT_SYMBOL_GPL(ata_wait_ready);
-EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
@@ -7660,18 +7616,20 @@ EXPORT_SYMBOL_GPL(ata_host_resume);
 #endif /* CONFIG_PM */
 EXPORT_SYMBOL_GPL(ata_id_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
-EXPORT_SYMBOL_GPL(ata_id_to_dma_mode);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
 
 EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
+EXPORT_SYMBOL_GPL(ata_timing_find_mode);
 EXPORT_SYMBOL_GPL(ata_timing_compute);
 EXPORT_SYMBOL_GPL(ata_timing_merge);
+EXPORT_SYMBOL_GPL(ata_timing_cycle2mode);
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
 EXPORT_SYMBOL_GPL(ata_pci_init_sff_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_bmdma);
 EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host);
+EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
@@ -7713,4 +7671,5 @@ EXPORT_SYMBOL_GPL(ata_dev_try_classify);
 EXPORT_SYMBOL_GPL(ata_cable_40wire);
 EXPORT_SYMBOL_GPL(ata_cable_80wire);
 EXPORT_SYMBOL_GPL(ata_cable_unknown);
+EXPORT_SYMBOL_GPL(ata_cable_ignore);
 EXPORT_SYMBOL_GPL(ata_cable_sata);
index f0124a8d313427b655f33912d66bdc1612131139..4e31071acc02b15f270a2f76ea752b4a4896f822 100644 (file)
 #include "libata.h"
 
 enum {
+       /* speed down verdicts */
        ATA_EH_SPDN_NCQ_OFF             = (1 << 0),
        ATA_EH_SPDN_SPEED_DOWN          = (1 << 1),
        ATA_EH_SPDN_FALLBACK_TO_PIO     = (1 << 2),
+       ATA_EH_SPDN_KEEP_ERRORS         = (1 << 3),
+
+       /* error flags */
+       ATA_EFLAG_IS_IO                 = (1 << 0),
+       ATA_EFLAG_DUBIOUS_XFER          = (1 << 1),
+
+       /* error categories */
+       ATA_ECAT_NONE                   = 0,
+       ATA_ECAT_ATA_BUS                = 1,
+       ATA_ECAT_TOUT_HSM               = 2,
+       ATA_ECAT_UNK_DEV                = 3,
+       ATA_ECAT_DUBIOUS_NONE           = 4,
+       ATA_ECAT_DUBIOUS_ATA_BUS        = 5,
+       ATA_ECAT_DUBIOUS_TOUT_HSM       = 6,
+       ATA_ECAT_DUBIOUS_UNK_DEV        = 7,
+       ATA_ECAT_NR                     = 8,
 };
 
 /* Waiting in ->prereset can never be reliable.  It's sometimes nice
@@ -213,12 +230,13 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
        if (offset < 0)
                ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
        else
-               ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+               ata_port_desc(ap, "%s 0x%llx", name,
+                               start + (unsigned long long)offset);
 }
 
 #endif /* CONFIG_PCI */
 
-static void ata_ering_record(struct ata_ering *ering, int is_io,
+static void ata_ering_record(struct ata_ering *ering, unsigned int eflags,
                             unsigned int err_mask)
 {
        struct ata_ering_entry *ent;
@@ -229,11 +247,20 @@ static void ata_ering_record(struct ata_ering *ering, int is_io,
        ering->cursor %= ATA_ERING_SIZE;
 
        ent = &ering->ring[ering->cursor];
-       ent->is_io = is_io;
+       ent->eflags = eflags;
        ent->err_mask = err_mask;
        ent->timestamp = get_jiffies_64();
 }
 
+static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
+{
+       struct ata_ering_entry *ent = &ering->ring[ering->cursor];
+
+       if (ent->err_mask)
+               return ent;
+       return NULL;
+}
+
 static void ata_ering_clear(struct ata_ering *ering)
 {
        memset(ering, 0, sizeof(*ering));
@@ -445,9 +472,20 @@ void ata_scsi_error(struct Scsi_Host *host)
                spin_lock_irqsave(ap->lock, flags);
 
                __ata_port_for_each_link(link, ap) {
+                       struct ata_eh_context *ehc = &link->eh_context;
+                       struct ata_device *dev;
+
                        memset(&link->eh_context, 0, sizeof(link->eh_context));
                        link->eh_context.i = link->eh_info;
                        memset(&link->eh_info, 0, sizeof(link->eh_info));
+
+                       ata_link_for_each_dev(dev, link) {
+                               int devno = dev->devno;
+
+                               ehc->saved_xfer_mode[devno] = dev->xfer_mode;
+                               if (ata_ncq_enabled(dev))
+                                       ehc->saved_ncq_enabled |= 1 << devno;
+                       }
                }
 
                ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
@@ -1260,10 +1298,10 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
 
        /* is it pointless to prefer PIO for "safety reasons"? */
        if (ap->flags & ATA_FLAG_PIO_DMA) {
-               tf.protocol = ATA_PROT_ATAPI_DMA;
+               tf.protocol = ATAPI_PROT_DMA;
                tf.feature |= ATAPI_PKT_DMA;
        } else {
-               tf.protocol = ATA_PROT_ATAPI;
+               tf.protocol = ATAPI_PROT_PIO;
                tf.lbam = SCSI_SENSE_BUFFERSIZE;
                tf.lbah = 0;
        }
@@ -1451,20 +1489,29 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
        return action;
 }
 
-static int ata_eh_categorize_error(int is_io, unsigned int err_mask)
+static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask,
+                                  int *xfer_ok)
 {
+       int base = 0;
+
+       if (!(eflags & ATA_EFLAG_DUBIOUS_XFER))
+               *xfer_ok = 1;
+
+       if (!*xfer_ok)
+               base = ATA_ECAT_DUBIOUS_NONE;
+
        if (err_mask & AC_ERR_ATA_BUS)
-               return 1;
+               return base + ATA_ECAT_ATA_BUS;
 
        if (err_mask & AC_ERR_TIMEOUT)
-               return 2;
+               return base + ATA_ECAT_TOUT_HSM;
 
-       if (is_io) {
+       if (eflags & ATA_EFLAG_IS_IO) {
                if (err_mask & AC_ERR_HSM)
-                       return 2;
+                       return base + ATA_ECAT_TOUT_HSM;
                if ((err_mask &
                     (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
-                       return 3;
+                       return base + ATA_ECAT_UNK_DEV;
        }
 
        return 0;
@@ -1472,18 +1519,22 @@ static int ata_eh_categorize_error(int is_io, unsigned int err_mask)
 
 struct speed_down_verdict_arg {
        u64 since;
-       int nr_errors[4];
+       int xfer_ok;
+       int nr_errors[ATA_ECAT_NR];
 };
 
 static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
 {
        struct speed_down_verdict_arg *arg = void_arg;
-       int cat = ata_eh_categorize_error(ent->is_io, ent->err_mask);
+       int cat;
 
        if (ent->timestamp < arg->since)
                return -1;
 
+       cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
+                                     &arg->xfer_ok);
        arg->nr_errors[cat]++;
+
        return 0;
 }
 
@@ -1495,22 +1546,48 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
  *     whether NCQ needs to be turned off, transfer speed should be
  *     stepped down, or falling back to PIO is necessary.
  *
- *     Cat-1 is ATA_BUS error for any command.
+ *     ECAT_ATA_BUS    : ATA_BUS error for any command
+ *
+ *     ECAT_TOUT_HSM   : TIMEOUT for any command or HSM violation for
+ *                       IO commands
+ *
+ *     ECAT_UNK_DEV    : Unknown DEV error for IO commands
+ *
+ *     ECAT_DUBIOUS_*  : Identical to above three but occurred while
+ *                       data transfer hasn't been verified.
+ *
+ *     Verdicts are
+ *
+ *     NCQ_OFF         : Turn off NCQ.
+ *
+ *     SPEED_DOWN      : Speed down transfer speed but don't fall back
+ *                       to PIO.
+ *
+ *     FALLBACK_TO_PIO : Fall back to PIO.
+ *
+ *     Even if multiple verdicts are returned, only one action is
+ *     taken per error.  An action triggered by non-DUBIOUS errors
+ *     clears ering, while one triggered by DUBIOUS_* errors doesn't.
+ *     This is to expedite speed down decisions right after device is
+ *     initially configured.
+ *
+ *     The followings are speed down rules.  #1 and #2 deal with
+ *     DUBIOUS errors.
  *
- *     Cat-2 is TIMEOUT for any command or HSM violation for known
- *     supported commands.
+ *     1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors
+ *        occurred during last 5 mins, SPEED_DOWN and FALLBACK_TO_PIO.
  *
- *     Cat-3 is is unclassified DEV error for known supported
- *     command.
+ *     2. If more than one DUBIOUS_TOUT_HSM or DUBIOUS_UNK_DEV errors
+ *        occurred during last 5 mins, NCQ_OFF.
  *
- *     NCQ needs to be turned off if there have been more than 3
- *     Cat-2 + Cat-3 errors during last 10 minutes.
+ *     3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors
+ *        ocurred during last 5 mins, FALLBACK_TO_PIO
  *
- *     Speed down is necessary if there have been more than 3 Cat-1 +
- *     Cat-2 errors or 10 Cat-3 errors during last 10 minutes.
+ *     4. If more than 3 TOUT_HSM or UNK_DEV errors occurred
+ *        during last 10 mins, NCQ_OFF.
  *
- *     Falling back to PIO mode is necessary if there have been more
- *     than 10 Cat-1 + Cat-2 + Cat-3 errors during last 5 minutes.
+ *     5. If more than 3 ATA_BUS or TOUT_HSM errors, or more than 6
+ *        UNK_DEV errors occurred during last 10 mins, SPEED_DOWN.
  *
  *     LOCKING:
  *     Inherited from caller.
@@ -1525,23 +1602,38 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
        struct speed_down_verdict_arg arg;
        unsigned int verdict = 0;
 
-       /* scan past 10 mins of error history */
+       /* scan past 5 mins of error history */
        memset(&arg, 0, sizeof(arg));
-       arg.since = j64 - min(j64, j10mins);
+       arg.since = j64 - min(j64, j5mins);
        ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);
 
-       if (arg.nr_errors[2] + arg.nr_errors[3] > 3)
-               verdict |= ATA_EH_SPDN_NCQ_OFF;
-       if (arg.nr_errors[1] + arg.nr_errors[2] > 3 || arg.nr_errors[3] > 10)
-               verdict |= ATA_EH_SPDN_SPEED_DOWN;
+       if (arg.nr_errors[ATA_ECAT_DUBIOUS_ATA_BUS] +
+           arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] > 1)
+               verdict |= ATA_EH_SPDN_SPEED_DOWN |
+                       ATA_EH_SPDN_FALLBACK_TO_PIO | ATA_EH_SPDN_KEEP_ERRORS;
+
+       if (arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] +
+           arg.nr_errors[ATA_ECAT_DUBIOUS_UNK_DEV] > 1)
+               verdict |= ATA_EH_SPDN_NCQ_OFF | ATA_EH_SPDN_KEEP_ERRORS;
 
-       /* scan past 3 mins of error history */
+       if (arg.nr_errors[ATA_ECAT_ATA_BUS] +
+           arg.nr_errors[ATA_ECAT_TOUT_HSM] +
+           arg.nr_errors[ATA_ECAT_UNK_DEV] > 6)
+               verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO;
+
+       /* scan past 10 mins of error history */
        memset(&arg, 0, sizeof(arg));
-       arg.since = j64 - min(j64, j5mins);
+       arg.since = j64 - min(j64, j10mins);
        ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);
 
-       if (arg.nr_errors[1] + arg.nr_errors[2] + arg.nr_errors[3] > 10)
-               verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO;
+       if (arg.nr_errors[ATA_ECAT_TOUT_HSM] +
+           arg.nr_errors[ATA_ECAT_UNK_DEV] > 3)
+               verdict |= ATA_EH_SPDN_NCQ_OFF;
+
+       if (arg.nr_errors[ATA_ECAT_ATA_BUS] +
+           arg.nr_errors[ATA_ECAT_TOUT_HSM] > 3 ||
+           arg.nr_errors[ATA_ECAT_UNK_DEV] > 6)
+               verdict |= ATA_EH_SPDN_SPEED_DOWN;
 
        return verdict;
 }
@@ -1549,7 +1641,7 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
 /**
  *     ata_eh_speed_down - record error and speed down if necessary
  *     @dev: Failed device
- *     @is_io: Did the device fail during normal IO?
+ *     @eflags: mask of ATA_EFLAG_* flags
  *     @err_mask: err_mask of the error
  *
  *     Record error and examine error history to determine whether
@@ -1563,18 +1655,20 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
  *     RETURNS:
  *     Determined recovery action.
  */
-static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
-                                     unsigned int err_mask)
+static unsigned int ata_eh_speed_down(struct ata_device *dev,
+                               unsigned int eflags, unsigned int err_mask)
 {
+       struct ata_link *link = dev->link;
+       int xfer_ok = 0;
        unsigned int verdict;
        unsigned int action = 0;
 
        /* don't bother if Cat-0 error */
-       if (ata_eh_categorize_error(is_io, err_mask) == 0)
+       if (ata_eh_categorize_error(eflags, err_mask, &xfer_ok) == 0)
                return 0;
 
        /* record error and determine whether speed down is necessary */
-       ata_ering_record(&dev->ering, is_io, err_mask);
+       ata_ering_record(&dev->ering, eflags, err_mask);
        verdict = ata_eh_speed_down_verdict(dev);
 
        /* turn off NCQ? */
@@ -1590,7 +1684,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
        /* speed down? */
        if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
                /* speed down SATA link speed if possible */
-               if (sata_down_spd_limit(dev->link) == 0) {
+               if (sata_down_spd_limit(link) == 0) {
                        action |= ATA_EH_HARDRESET;
                        goto done;
                }
@@ -1618,10 +1712,10 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
        }
 
        /* Fall back to PIO?  Slowing down to PIO is meaningless for
-        * SATA.  Consider it only for PATA.
+        * SATA ATA devices.  Consider it only for PATA and SATAPI.
         */
        if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
-           (dev->link->ap->cbl != ATA_CBL_SATA) &&
+           (link->ap->cbl != ATA_CBL_SATA || dev->class == ATA_DEV_ATAPI) &&
            (dev->xfer_shift != ATA_SHIFT_PIO)) {
                if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
                        dev->spdn_cnt = 0;
@@ -1633,7 +1727,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
        return 0;
  done:
        /* device has been slowed down, blow error history */
-       ata_ering_clear(&dev->ering);
+       if (!(verdict & ATA_EH_SPDN_KEEP_ERRORS))
+               ata_ering_clear(&dev->ering);
        return action;
 }
 
@@ -1653,8 +1748,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
        struct ata_port *ap = link->ap;
        struct ata_eh_context *ehc = &link->eh_context;
        struct ata_device *dev;
-       unsigned int all_err_mask = 0;
-       int tag, is_io = 0;
+       unsigned int all_err_mask = 0, eflags = 0;
+       int tag;
        u32 serror;
        int rc;
 
@@ -1713,15 +1808,15 @@ static void ata_eh_link_autopsy(struct ata_link *link)
                ehc->i.dev = qc->dev;
                all_err_mask |= qc->err_mask;
                if (qc->flags & ATA_QCFLAG_IO)
-                       is_io = 1;
+                       eflags |= ATA_EFLAG_IS_IO;
        }
 
        /* enforce default EH actions */
        if (ap->pflags & ATA_PFLAG_FROZEN ||
            all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
                ehc->i.action |= ATA_EH_SOFTRESET;
-       else if ((is_io && all_err_mask) ||
-                (!is_io && (all_err_mask & ~AC_ERR_DEV)))
+       else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) ||
+                (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV)))
                ehc->i.action |= ATA_EH_REVALIDATE;
 
        /* If we have offending qcs and the associated failed device,
@@ -1733,14 +1828,21 @@ static void ata_eh_link_autopsy(struct ata_link *link)
                ehc->i.action &= ~ATA_EH_PERDEV_MASK;
        }
 
-       /* consider speeding down */
+       /* propagate timeout to host link */
+       if ((all_err_mask & AC_ERR_TIMEOUT) && !ata_is_host_link(link))
+               ap->link.eh_context.i.err_mask |= AC_ERR_TIMEOUT;
+
+       /* record error and consider speeding down */
        dev = ehc->i.dev;
-       if (!dev && ata_link_max_devices(link) == 1 &&
-           ata_dev_enabled(link->device))
-               dev = link->device;
+       if (!dev && ((ata_link_max_devices(link) == 1 &&
+                     ata_dev_enabled(link->device))))
+           dev = link->device;
 
-       if (dev)
-               ehc->i.action |= ata_eh_speed_down(dev, is_io, all_err_mask);
+       if (dev) {
+               if (dev->flags & ATA_DFLAG_DUBIOUS_XFER)
+                       eflags |= ATA_EFLAG_DUBIOUS_XFER;
+               ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
+       }
 
        DPRINTK("EXIT\n");
 }
@@ -1759,8 +1861,14 @@ void ata_eh_autopsy(struct ata_port *ap)
 {
        struct ata_link *link;
 
-       __ata_port_for_each_link(link, ap)
+       ata_port_for_each_link(link, ap)
                ata_eh_link_autopsy(link);
+
+       /* Autopsy of fanout ports can affect host link autopsy.
+        * Perform host link autopsy last.
+        */
+       if (ap->nr_pmp_links)
+               ata_eh_link_autopsy(&ap->link);
 }
 
 /**
@@ -1870,8 +1978,8 @@ static void ata_eh_link_report(struct ata_link *link)
                                [ATA_PROT_PIO]          = "pio",
                                [ATA_PROT_DMA]          = "dma",
                                [ATA_PROT_NCQ]          = "ncq",
-                               [ATA_PROT_ATAPI]        = "pio",
-                               [ATA_PROT_ATAPI_DMA]    = "dma",
+                               [ATAPI_PROT_PIO]        = "pio",
+                               [ATAPI_PROT_DMA]        = "dma",
                        };
 
                        snprintf(data_buf, sizeof(data_buf), " %s %u %s",
@@ -1879,7 +1987,7 @@ static void ata_eh_link_report(struct ata_link *link)
                                 dma_str[qc->dma_dir]);
                }
 
-               if (is_atapi_taskfile(&qc->tf))
+               if (ata_is_atapi(qc->tf.protocol))
                        snprintf(cdb_buf, sizeof(cdb_buf),
                                 "cdb %02x %02x %02x %02x %02x %02x %02x %02x  "
                                 "%02x %02x %02x %02x %02x %02x %02x %02x\n         ",
@@ -2157,13 +2265,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
                if (ata_link_offline(link))
                        continue;
 
-               /* apply class override and convert UNKNOWN to NONE */
+               /* apply class override */
                if (lflags & ATA_LFLAG_ASSUME_ATA)
                        classes[dev->devno] = ATA_DEV_ATA;
                else if (lflags & ATA_LFLAG_ASSUME_SEMB)
                        classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
-               else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
-                       classes[dev->devno] = ATA_DEV_NONE;
        }
 
        /* record current link speed */
@@ -2321,6 +2427,58 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
        return rc;
 }
 
+/**
+ *     ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *     @link: link on which timings will be programmed
+ *     @r_failed_dev: out paramter for failed device
+ *
+ *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
+ *     ata_set_mode() fails, pointer to the failing device is
+ *     returned in @r_failed_dev.
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *
+ *     RETURNS:
+ *     0 on success, negative errno otherwise
+ */
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
+{
+       struct ata_port *ap = link->ap;
+       struct ata_device *dev;
+       int rc;
+
+       /* if data transfer is verified, clear DUBIOUS_XFER on ering top */
+       ata_link_for_each_dev(dev, link) {
+               if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) {
+                       struct ata_ering_entry *ent;
+
+                       ent = ata_ering_top(&dev->ering);
+                       if (ent)
+                               ent->eflags &= ~ATA_EFLAG_DUBIOUS_XFER;
+               }
+       }
+
+       /* has private set_mode? */
+       if (ap->ops->set_mode)
+               rc = ap->ops->set_mode(link, r_failed_dev);
+       else
+               rc = ata_do_set_mode(link, r_failed_dev);
+
+       /* if transfer mode has changed, set DUBIOUS_XFER on device */
+       ata_link_for_each_dev(dev, link) {
+               struct ata_eh_context *ehc = &link->eh_context;
+               u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno];
+               u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno));
+
+               if (dev->xfer_mode != saved_xfer_mode ||
+                   ata_ncq_enabled(dev) != saved_ncq)
+                       dev->flags |= ATA_DFLAG_DUBIOUS_XFER;
+       }
+
+       return rc;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
        struct ata_device *dev;
@@ -2367,6 +2525,24 @@ static int ata_eh_skip_recovery(struct ata_link *link)
        return 1;
 }
 
+static int ata_eh_schedule_probe(struct ata_device *dev)
+{
+       struct ata_eh_context *ehc = &dev->link->eh_context;
+
+       if (!(ehc->i.probe_mask & (1 << dev->devno)) ||
+           (ehc->did_probe_mask & (1 << dev->devno)))
+               return 0;
+
+       ata_eh_detach_dev(dev);
+       ata_dev_init(dev);
+       ehc->did_probe_mask |= (1 << dev->devno);
+       ehc->i.action |= ATA_EH_SOFTRESET;
+       ehc->saved_xfer_mode[dev->devno] = 0;
+       ehc->saved_ncq_enabled &= ~(1 << dev->devno);
+
+       return 1;
+}
+
 static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
 {
        struct ata_eh_context *ehc = &dev->link->eh_context;
@@ -2398,16 +2574,9 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
                if (ata_link_offline(dev->link))
                        ata_eh_detach_dev(dev);
 
-               /* probe if requested */
-               if ((ehc->i.probe_mask & (1 << dev->devno)) &&
-                   !(ehc->did_probe_mask & (1 << dev->devno))) {
-                       ata_eh_detach_dev(dev);
-                       ata_dev_init(dev);
-
+               /* schedule probe if necessary */
+               if (ata_eh_schedule_probe(dev))
                        ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-                       ehc->did_probe_mask |= (1 << dev->devno);
-                       ehc->i.action |= ATA_EH_SOFTRESET;
-               }
 
                return 1;
        } else {
@@ -2484,14 +2653,9 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                        if (dev->flags & ATA_DFLAG_DETACH)
                                ata_eh_detach_dev(dev);
 
-                       if (!ata_dev_enabled(dev) &&
-                           ((ehc->i.probe_mask & (1 << dev->devno)) &&
-                            !(ehc->did_probe_mask & (1 << dev->devno)))) {
-                               ata_eh_detach_dev(dev);
-                               ata_dev_init(dev);
-                               ehc->did_probe_mask |= (1 << dev->devno);
-                               ehc->i.action |= ATA_EH_SOFTRESET;
-                       }
+                       /* schedule probe if necessary */
+                       if (!ata_dev_enabled(dev))
+                               ata_eh_schedule_probe(dev);
                }
        }
 
@@ -2739,6 +2903,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
        if (ap->ops->port_suspend)
                rc = ap->ops->port_suspend(ap, ap->pm_mesg);
 
+       ata_acpi_set_state(ap, PMSG_SUSPEND);
  out:
        /* report result */
        spin_lock_irqsave(ap->lock, flags);
@@ -2784,6 +2949,8 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 
        WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED));
 
+       ata_acpi_set_state(ap, PMSG_ON);
+
        if (ap->ops->port_resume)
                rc = ap->ops->port_resume(ap);
 
index c0c4dbcde091b5daf1805d2f4e180b0189e213b1..caef2bbd4a8a1525be252d6cfcf627901e52e261 100644 (file)
@@ -495,14 +495,12 @@ static void sata_pmp_quirks(struct ata_port *ap)
                        /* SError.N need a kick in the ass to get working */
                        link->flags |= ATA_LFLAG_HRST_TO_RESUME;
 
-                       /* class code report is unreliable */
-                       if (link->pmp < 5)
-                               link->flags |= ATA_LFLAG_ASSUME_ATA;
-
-                       /* The config device, which can be either at
-                        * port 0 or 5, locks up on SRST.
+                       /* Class code report is unreliable and SRST
+                        * times out under certain configurations.
+                        * Config device can be at port 0 or 5 and
+                        * locks up on SRST.
                         */
-                       if (link->pmp == 0 || link->pmp == 5)
+                       if (link->pmp <= 5)
                                link->flags |= ATA_LFLAG_NO_SRST |
                                               ATA_LFLAG_ASSUME_ATA;
 
index a883bb03d4c7762dc21605974740c3ff4014ae49..c02c490122dc0cfbb5492542b0c690552616a32d 100644 (file)
@@ -517,7 +517,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
                qc->scsicmd = cmd;
                qc->scsidone = done;
 
-               qc->__sg = scsi_sglist(cmd);
+               qc->sg = scsi_sglist(cmd);
                qc->n_elem = scsi_sg_count(cmd);
        } else {
                cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
@@ -839,7 +839,17 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
        if (dev->class == ATA_DEV_ATAPI) {
                struct request_queue *q = sdev->request_queue;
                blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
-       }
+
+               /* set the min alignment */
+               blk_queue_update_dma_alignment(sdev->request_queue,
+                                              ATA_DMA_PAD_SZ - 1);
+       } else
+               /* ATA devices must be sector aligned */
+               blk_queue_update_dma_alignment(sdev->request_queue,
+                                              ATA_SECT_SIZE - 1);
+
+       if (dev->class == ATA_DEV_ATA)
+               sdev->manage_start_stop = 1;
 
        if (dev->flags & ATA_DFLAG_AN)
                set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
@@ -872,12 +882,10 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
 
        ata_scsi_sdev_config(sdev);
 
-       sdev->manage_start_stop = 1;
-
        if (dev)
                ata_scsi_dev_config(sdev, dev);
 
-       return 0;       /* scsi layer doesn't check return value, sigh */
+       return 0;
 }
 
 /**
@@ -2209,7 +2217,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
 
                /* sector size */
                ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
-               ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE);
+               ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff);
        } else {
                /* sector count, 64-bit */
                ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
@@ -2223,7 +2231,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
 
                /* sector size */
                ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
-               ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE);
+               ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff);
        }
 
        return 0;
@@ -2330,7 +2338,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
        DPRINTK("ATAPI request sense\n");
 
        /* FIXME: is this needed? */
-       memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
        ap->ops->tf_read(ap, &qc->tf);
 
@@ -2340,7 +2348,9 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
 
        ata_qc_reinit(qc);
 
-       ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+       /* setup sg table and init transfer direction */
+       sg_init_one(&qc->sgent, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+       ata_sg_init(qc, &qc->sgent, 1);
        qc->dma_dir = DMA_FROM_DEVICE;
 
        memset(&qc->cdb, 0, qc->dev->cdb_len);
@@ -2351,10 +2361,10 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
        qc->tf.command = ATA_CMD_PACKET;
 
        if (ata_pio_use_silly(ap)) {
-               qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+               qc->tf.protocol = ATAPI_PROT_DMA;
                qc->tf.feature |= ATAPI_PKT_DMA;
        } else {
-               qc->tf.protocol = ATA_PROT_ATAPI;
+               qc->tf.protocol = ATAPI_PROT_PIO;
                qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
                qc->tf.lbah = 0;
        }
@@ -2525,12 +2535,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
        if (using_pio || nodata) {
                /* no data, or PIO data xfer */
                if (nodata)
-                       qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+                       qc->tf.protocol = ATAPI_PROT_NODATA;
                else
-                       qc->tf.protocol = ATA_PROT_ATAPI;
+                       qc->tf.protocol = ATAPI_PROT_PIO;
        } else {
                /* DMA data xfer */
-               qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+               qc->tf.protocol = ATAPI_PROT_DMA;
                qc->tf.feature |= ATAPI_PKT_DMA;
 
                if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE))
@@ -2689,6 +2699,24 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
                goto invalid_fld;
 
+       /*
+        * Filter TPM commands by default. These provide an
+        * essentially uncontrolled encrypted "back door" between
+        * applications and the disk. Set libata.allow_tpm=1 if you
+        * have a real reason for wanting to use them. This ensures
+        * that installed software cannot easily mess stuff up without
+        * user intent. DVR type users will probably ship with this enabled
+        * for movie content management.
+        *
+        * Note that for ATA8 we can issue a DCS change and DCS freeze lock
+        * for this and should do in future but that it is not sufficient as
+        * DCS is an optional feature set. Thus we also do the software filter
+        * so that we comply with the TC consortium stated goal that the user
+        * can turn off TC features of their system.
+        */
+       if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm)
+               goto invalid_fld;
+
        /* We may not issue DMA commands if no DMA mode is set */
        if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
                goto invalid_fld;
index 48acc09dab9687e93a247a96614cbc93002727f8..60cd4b179766e9683e82b39552c3a5546afa4b44 100644 (file)
@@ -147,7 +147,9 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
  *     @tf: ATA taskfile register set for storing input
  *
  *     Reads ATA taskfile registers for currently-selected device
- *     into @tf.
+ *     into @tf. Assumes the device has a fully SFF compliant task file
+ *     layout and behaviour. If you device does not (eg has a different
+ *     status method) then you will need to provide a replacement tf_read
  *
  *     LOCKING:
  *     Inherited from caller.
@@ -156,7 +158,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
 
-       tf->command = ata_chk_status(ap);
+       tf->command = ata_check_status(ap);
        tf->feature = ioread8(ioaddr->error_addr);
        tf->nsect = ioread8(ioaddr->nsect_addr);
        tf->lbal = ioread8(ioaddr->lbal_addr);
@@ -415,7 +417,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
        ap->hsm_task_state = HSM_ST_IDLE;
 
        if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
-                  qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+                  qc->tf.protocol == ATAPI_PROT_DMA)) {
                u8 host_stat;
 
                host_stat = ap->ops->bmdma_status(ap);
@@ -549,7 +551,7 @@ int ata_pci_init_bmdma(struct ata_host *host)
                return rc;
 
        /* request and iomap DMA region */
-       rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+       rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev));
        if (rc) {
                dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
                return -ENOMEM;
@@ -619,7 +621,8 @@ int ata_pci_init_sff_host(struct ata_host *host)
                        continue;
                }
 
-               rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME);
+               rc = pcim_iomap_regions(pdev, 0x3 << base,
+                                       dev_driver_string(gdev));
                if (rc) {
                        dev_printk(KERN_WARNING, gdev,
                                   "failed to request/iomap BARs for port %d "
@@ -710,6 +713,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev,
        return rc;
 }
 
+/**
+ *     ata_pci_activate_sff_host - start SFF host, request IRQ and register it
+ *     @host: target SFF ATA host
+ *     @irq_handler: irq_handler used when requesting IRQ(s)
+ *     @sht: scsi_host_template to use when registering the host
+ *
+ *     This is the counterpart of ata_host_activate() for SFF ATA
+ *     hosts.  This separate helper is necessary because SFF hosts
+ *     use two separate interrupts in legacy mode.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_pci_activate_sff_host(struct ata_host *host,
+                             irq_handler_t irq_handler,
+                             struct scsi_host_template *sht)
+{
+       struct device *dev = host->dev;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       const char *drv_name = dev_driver_string(host->dev);
+       int legacy_mode = 0, rc;
+
+       rc = ata_host_start(host);
+       if (rc)
+               return rc;
+
+       if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+               u8 tmp8, mask;
+
+               /* TODO: What if one channel is in native mode ... */
+               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+               mask = (1 << 2) | (1 << 0);
+               if ((tmp8 & mask) != mask)
+                       legacy_mode = 1;
+#if defined(CONFIG_NO_ATA_LEGACY)
+               /* Some platforms with PCI limits cannot address compat
+                  port space. In that case we punt if their firmware has
+                  left a device in compatibility mode */
+               if (legacy_mode) {
+                       printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
+                       return -EOPNOTSUPP;
+               }
+#endif
+       }
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       if (!legacy_mode && pdev->irq) {
+               rc = devm_request_irq(dev, pdev->irq, irq_handler,
+                                     IRQF_SHARED, drv_name, host);
+               if (rc)
+                       goto out;
+
+               ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+               ata_port_desc(host->ports[1], "irq %d", pdev->irq);
+       } else if (legacy_mode) {
+               if (!ata_port_is_dummy(host->ports[0])) {
+                       rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
+                                             irq_handler, IRQF_SHARED,
+                                             drv_name, host);
+                       if (rc)
+                               goto out;
+
+                       ata_port_desc(host->ports[0], "irq %d",
+                                     ATA_PRIMARY_IRQ(pdev));
+               }
+
+               if (!ata_port_is_dummy(host->ports[1])) {
+                       rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
+                                             irq_handler, IRQF_SHARED,
+                                             drv_name, host);
+                       if (rc)
+                               goto out;
+
+                       ata_port_desc(host->ports[1], "irq %d",
+                                     ATA_SECONDARY_IRQ(pdev));
+               }
+       }
+
+       rc = ata_host_register(host, sht);
+ out:
+       if (rc == 0)
+               devres_remove_group(dev, NULL);
+       else
+               devres_release_group(dev, NULL);
+
+       return rc;
+}
+
 /**
  *     ata_pci_init_one - Initialize/register PCI IDE host controller
  *     @pdev: Controller to be initialized
@@ -739,8 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev,
        struct device *dev = &pdev->dev;
        const struct ata_port_info *pi = NULL;
        struct ata_host *host = NULL;
-       u8 mask;
-       int legacy_mode = 0;
        int i, rc;
 
        DPRINTK("ENTER\n");
@@ -762,92 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev,
        if (!devres_open_group(dev, NULL, GFP_KERNEL))
                return -ENOMEM;
 
-       /* FIXME: Really for ATA it isn't safe because the device may be
-          multi-purpose and we want to leave it alone if it was already
-          enabled. Secondly for shared use as Arjan says we want refcounting
-
-          Checking dev->is_enabled is insufficient as this is not set at
-          boot for the primary video which is BIOS enabled
-         */
-
        rc = pcim_enable_device(pdev);
        if (rc)
-               goto err_out;
-
-       if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-               u8 tmp8;
-
-               /* TODO: What if one channel is in native mode ... */
-               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
-               mask = (1 << 2) | (1 << 0);
-               if ((tmp8 & mask) != mask)
-                       legacy_mode = 1;
-#if defined(CONFIG_NO_ATA_LEGACY)
-               /* Some platforms with PCI limits cannot address compat
-                  port space. In that case we punt if their firmware has
-                  left a device in compatibility mode */
-               if (legacy_mode) {
-                       printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
-                       rc = -EOPNOTSUPP;
-                       goto err_out;
-               }
-#endif
-       }
+               goto out;
 
-       /* prepare host */
+       /* prepare and activate SFF host */
        rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
        if (rc)
-               goto err_out;
+               goto out;
 
        pci_set_master(pdev);
+       rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler,
+                                      pi->sht);
+ out:
+       if (rc == 0)
+               devres_remove_group(&pdev->dev, NULL);
+       else
+               devres_release_group(&pdev->dev, NULL);
 
-       /* start host and request IRQ */
-       rc = ata_host_start(host);
-       if (rc)
-               goto err_out;
-
-       if (!legacy_mode) {
-               rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler,
-                                     IRQF_SHARED, DRV_NAME, host);
-               if (rc)
-                       goto err_out;
-
-               ata_port_desc(host->ports[0], "irq %d", pdev->irq);
-               ata_port_desc(host->ports[1], "irq %d", pdev->irq);
-       } else {
-               if (!ata_port_is_dummy(host->ports[0])) {
-                       rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
-                                             pi->port_ops->irq_handler,
-                                             IRQF_SHARED, DRV_NAME, host);
-                       if (rc)
-                               goto err_out;
-
-                       ata_port_desc(host->ports[0], "irq %d",
-                                     ATA_PRIMARY_IRQ(pdev));
-               }
-
-               if (!ata_port_is_dummy(host->ports[1])) {
-                       rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
-                                             pi->port_ops->irq_handler,
-                                             IRQF_SHARED, DRV_NAME, host);
-                       if (rc)
-                               goto err_out;
-
-                       ata_port_desc(host->ports[1], "irq %d",
-                                     ATA_SECONDARY_IRQ(pdev));
-               }
-       }
-
-       /* register */
-       rc = ata_host_register(host, pi->sht);
-       if (rc)
-               goto err_out;
-
-       devres_remove_group(dev, NULL);
-       return 0;
-
-err_out:
-       devres_release_group(dev, NULL);
        return rc;
 }
 
index bbe59c2fd1e2210d7538e271398ee23465df7f19..409ffb9af16321ead378f8554bfbf9684c6ca5ce 100644 (file)
@@ -60,6 +60,7 @@ extern int atapi_dmadir;
 extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;
+extern int libata_allow_tpm;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
 extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
                           u64 block, u32 n_block, unsigned int tf_flags,
@@ -85,7 +86,6 @@ extern int ata_dev_configure(struct ata_device *dev);
 extern int sata_down_spd_limit(struct ata_link *link);
 extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -113,6 +113,7 @@ extern int ata_acpi_on_suspend(struct ata_port *ap);
 extern void ata_acpi_on_resume(struct ata_port *ap);
 extern int ata_acpi_on_devcfg(struct ata_device *dev);
 extern void ata_acpi_on_disable(struct ata_device *dev);
+extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
 #else
 static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
 static inline void ata_acpi_associate(struct ata_host *host) { }
@@ -121,6 +122,8 @@ static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
 static inline void ata_acpi_on_resume(struct ata_port *ap) { }
 static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; }
 static inline void ata_acpi_on_disable(struct ata_device *dev) { }
+static inline void ata_acpi_set_state(struct ata_port *ap,
+                                     pm_message_t state) { }
 #endif
 
 /* libata-scsi.c */
@@ -183,6 +186,7 @@ extern void ata_eh_report(struct ata_port *ap);
 extern int ata_eh_reset(struct ata_link *link, int classify,
                        ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
                        ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                          ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
                          ata_postreset_fn_t postreset,
index e4542ab9c7f840fcf59102c8e92bb6422f79ff48..244098a80ce48c43e81c803f16ccb5fe9a60d3a6 100644 (file)
@@ -81,17 +81,6 @@ static void pacpi_error_handler(struct ata_port *ap)
                                  NULL, ata_std_postreset);
 }
 
-/* Welcome to ACPI, bring a bucket */
-static const unsigned int pio_cycle[7] = {
-       600, 383, 240, 180, 120, 100, 80
-};
-static const unsigned int mwdma_cycle[5] = {
-       480, 150, 120, 100, 80
-};
-static const unsigned int udma_cycle[7] = {
-       120, 80, 60, 45, 30, 20, 15
-};
-
 /**
  *     pacpi_discover_modes    -       filter non ACPI modes
  *     @adev: ATA device
@@ -103,56 +92,20 @@ static const unsigned int udma_cycle[7] = {
 
 static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
 {
-       int unit = adev->devno;
        struct pata_acpi *acpi = ap->private_data;
-       int i;
-       u32 t;
-       unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
-
        struct ata_acpi_gtm probe;
+       unsigned int xfer_mask;
 
        probe = acpi->gtm;
 
-       /* We always use the 0 slot for crap hardware */
-       if (!(probe.flags & 0x10))
-               unit = 0;
-
        ata_acpi_gtm(ap, &probe);
 
-       /* Start by scanning for PIO modes */
-       for (i = 0; i < 7; i++) {
-               t = probe.drive[unit].pio;
-               if (t <= pio_cycle[i]) {
-                       mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
-                       break;
-               }
-       }
+       xfer_mask = ata_acpi_gtm_xfermask(adev, &probe);
 
-       /* See if we have MWDMA or UDMA data. We don't bother with MWDMA
-          if UDMA is availabe as this means the BIOS set UDMA and our
-          error changedown if it works is UDMA to PIO anyway */
-       if (probe.flags & (1 << (2 * unit))) {
-               /* MWDMA */
-               for (i = 0; i < 5; i++) {
-                       t = probe.drive[unit].dma;
-                       if (t <= mwdma_cycle[i]) {
-                               mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
-                               break;
-                       }
-               }
-       } else {
-               /* UDMA */
-               for (i = 0; i < 7; i++) {
-                       t = probe.drive[unit].dma;
-                       if (t <= udma_cycle[i]) {
-                               mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
-                               break;
-                       }
-               }
-       }
-       if (mask & (0xF8 << ATA_SHIFT_UDMA))
+       if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
                ap->cbl = ATA_CBL_PATA80;
-       return mask;
+
+       return xfer_mask;
 }
 
 /**
@@ -180,12 +133,14 @@ static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
        int unit = adev->devno;
        struct pata_acpi *acpi = ap->private_data;
+       const struct ata_timing *t;
 
        if (!(acpi->gtm.flags & 0x10))
                unit = 0;
 
        /* Now stuff the nS values into the structure */
-       acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+       t = ata_timing_find_mode(adev->pio_mode);
+       acpi->gtm.drive[unit].pio = t->cycle;
        ata_acpi_stm(ap, &acpi->gtm);
        /* See what mode we actually got */
        ata_acpi_gtm(ap, &acpi->gtm);
@@ -201,16 +156,18 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
        int unit = adev->devno;
        struct pata_acpi *acpi = ap->private_data;
+       const struct ata_timing *t;
 
        if (!(acpi->gtm.flags & 0x10))
                unit = 0;
 
        /* Now stuff the nS values into the structure */
+       t = ata_timing_find_mode(adev->dma_mode);
        if (adev->dma_mode >= XFER_UDMA_0) {
-               acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+               acpi->gtm.drive[unit].dma = t->udma;
                acpi->gtm.flags |= (1 << (2 * unit));
        } else {
-               acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+               acpi->gtm.drive[unit].dma = t->cycle;
                acpi->gtm.flags &= ~(1 << (2 * unit));
        }
        ata_acpi_stm(ap, &acpi->gtm);
index 8caf9afc8b905061097d10fedbd4627cabc88084..7e68edf3c0f3fe9c5133396c698c96159956d646 100644 (file)
@@ -64,7 +64,7 @@ static int ali_cable_override(struct pci_dev *pdev)
        if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF)
                return 1;
        /* Mitac 8317 (Winbook-A) and relatives */
-       if (pdev->subsystem_vendor == 0x1071  && pdev->subsystem_device == 0x8317)
+       if (pdev->subsystem_vendor == 0x1071 && pdev->subsystem_device == 0x8317)
                return 1;
        /* Systems by DMI */
        if (dmi_check_system(cable_dmi_table))
index 3cc27b514654ad8219dae8941eb258f4147d072b..761a66608d7bd9ce7478a7daf4db6e02f8bd3e7a 100644 (file)
@@ -220,6 +220,62 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        timing_setup(ap, adev, 0x40, adev->dma_mode, 4);
 }
 
+/* Both host-side and drive-side detection results are worthless on NV
+ * PATAs.  Ignore them and just follow what BIOS configured.  Both the
+ * current configuration in PCI config reg and ACPI GTM result are
+ * cached during driver attach and are consulted to select transfer
+ * mode.
+ */
+static unsigned long nv_mode_filter(struct ata_device *dev,
+                                   unsigned long xfer_mask)
+{
+       static const unsigned int udma_mask_map[] =
+               { ATA_UDMA2, ATA_UDMA1, ATA_UDMA0, 0,
+                 ATA_UDMA3, ATA_UDMA4, ATA_UDMA5, ATA_UDMA6 };
+       struct ata_port *ap = dev->link->ap;
+       char acpi_str[32] = "";
+       u32 saved_udma, udma;
+       const struct ata_acpi_gtm *gtm;
+       unsigned long bios_limit = 0, acpi_limit = 0, limit;
+
+       /* find out what BIOS configured */
+       udma = saved_udma = (unsigned long)ap->host->private_data;
+
+       if (ap->port_no == 0)
+               udma >>= 16;
+       if (dev->devno == 0)
+               udma >>= 8;
+
+       if ((udma & 0xc0) == 0xc0)
+               bios_limit = ata_pack_xfermask(0, 0, udma_mask_map[udma & 0x7]);
+
+       /* consult ACPI GTM too */
+       gtm = ata_acpi_init_gtm(ap);
+       if (gtm) {
+               acpi_limit = ata_acpi_gtm_xfermask(dev, gtm);
+
+               snprintf(acpi_str, sizeof(acpi_str), " (%u:%u:0x%x)",
+                        gtm->drive[0].dma, gtm->drive[1].dma, gtm->flags);
+       }
+
+       /* be optimistic, EH can take care of things if something goes wrong */
+       limit = bios_limit | acpi_limit;
+
+       /* If PIO or DMA isn't configured at all, don't limit.  Let EH
+        * handle it.
+        */
+       if (!(limit & ATA_MASK_PIO))
+               limit |= ATA_MASK_PIO;
+       if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA)))
+               limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA;
+
+       ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, "
+                       "BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n",
+                       xfer_mask, limit, xfer_mask & limit, bios_limit,
+                       saved_udma, acpi_limit, acpi_str);
+
+       return xfer_mask & limit;
+}
 
 /**
  *     nv_probe_init   -       cable detection
@@ -252,31 +308,6 @@ static void nv_error_handler(struct ata_port *ap)
                               ata_std_postreset);
 }
 
-static int nv_cable_detect(struct ata_port *ap)
-{
-       static const u8 bitmask[2] = {0x03, 0x0C};
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u8 ata66;
-       u16 udma;
-       int cbl;
-
-       pci_read_config_byte(pdev, 0x52, &ata66);
-       if (ata66 & bitmask[ap->port_no])
-               cbl = ATA_CBL_PATA80;
-       else
-               cbl = ATA_CBL_PATA40;
-
-       /* We now have to double check because the Nvidia boxes BIOS
-          doesn't always set the cable bits but does set mode bits */
-       pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
-       if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
-               cbl = ATA_CBL_PATA80;
-       /* And a triple check across suspend/resume with ACPI around */
-       if (ata_acpi_cbl_80wire(ap))
-               cbl = ATA_CBL_PATA80;
-       return cbl;
-}
-
 /**
  *     nv100_set_piomode       -       set initial PIO mode data
  *     @ap: ATA interface
@@ -314,6 +345,14 @@ static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        timing_setup(ap, adev, 0x50, adev->dma_mode, 4);
 }
 
+static void nv_host_stop(struct ata_host *host)
+{
+       u32 udma = (unsigned long)host->private_data;
+
+       /* restore PCI config register 0x60 */
+       pci_write_config_dword(to_pci_dev(host->dev), 0x60, udma);
+}
+
 static struct scsi_host_template amd_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -478,7 +517,8 @@ static struct ata_port_operations nv100_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = nv_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
-       .cable_detect   = nv_cable_detect,
+       .cable_detect   = ata_cable_ignore,
+       .mode_filter    = nv_mode_filter,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -495,6 +535,7 @@ static struct ata_port_operations nv100_port_ops = {
        .irq_on         = ata_irq_on,
 
        .port_start     = ata_sff_port_start,
+       .host_stop      = nv_host_stop,
 };
 
 static struct ata_port_operations nv133_port_ops = {
@@ -511,7 +552,8 @@ static struct ata_port_operations nv133_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = nv_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
-       .cable_detect   = nv_cable_detect,
+       .cable_detect   = ata_cable_ignore,
+       .mode_filter    = nv_mode_filter,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
@@ -528,6 +570,7 @@ static struct ata_port_operations nv133_port_ops = {
        .irq_on         = ata_irq_on,
 
        .port_start     = ata_sff_port_start,
+       .host_stop      = nv_host_stop,
 };
 
 static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -614,7 +657,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                        .port_ops = &amd100_port_ops
                }
        };
-       const struct ata_port_info *ppi[] = { NULL, NULL };
+       struct ata_port_info pi;
+       const struct ata_port_info *ppi[] = { &pi, NULL };
        static int printed_version;
        int type = id->driver_data;
        u8 fifo;
@@ -628,6 +672,19 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (type == 1 && pdev->revision > 0x7)
                type = 2;
 
+       /* Serenade ? */
+       if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+                        pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+               type = 6;       /* UDMA 100 only */
+
+       /*
+        * Okay, type is determined now.  Apply type-specific workarounds.
+        */
+       pi = info[type];
+
+       if (type < 3)
+               ata_pci_clear_simplex(pdev);
+
        /* Check for AMD7411 */
        if (type == 3)
                /* FIFO is broken */
@@ -635,16 +692,17 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        else
                pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
 
-       /* Serenade ? */
-       if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
-                        pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
-               type = 6;       /* UDMA 100 only */
+       /* Cable detection on Nvidia chips doesn't work too well,
+        * cache BIOS programmed UDMA mode.
+        */
+       if (type == 7 || type == 8) {
+               u32 udma;
 
-       if (type < 3)
-               ata_pci_clear_simplex(pdev);
+               pci_read_config_dword(pdev, 0x60, &udma);
+               pi.private_data = (void *)(unsigned long)udma;
+       }
 
        /* And fire it up */
-       ppi[0] = &info[type];
        return ata_pci_init_one(pdev, ppi);
 }
 
index 088a41f4e656ce57ebc36481e7b916f3df873440..a32e3c44a606f2f78d5169f6d11103b47749d1f6 100644 (file)
@@ -832,6 +832,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
 {
        unsigned short config = WDSIZE_16;
        struct scatterlist *sg;
+       unsigned int si;
 
        pr_debug("in atapi dma setup\n");
        /* Program the ATA_CTRL register with dir */
@@ -839,7 +840,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
                /* fill the ATAPI DMA controller */
                set_dma_config(CH_ATAPI_TX, config);
                set_dma_x_modify(CH_ATAPI_TX, 2);
-               ata_for_each_sg(sg, qc) {
+               for_each_sg(qc->sg, sg, qc->n_elem, si) {
                        set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
                        set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
                }
@@ -848,7 +849,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
                /* fill the ATAPI DMA controller */
                set_dma_config(CH_ATAPI_RX, config);
                set_dma_x_modify(CH_ATAPI_RX, 2);
-               ata_for_each_sg(sg, qc) {
+               for_each_sg(qc->sg, sg, qc->n_elem, si) {
                        set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
                        set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
                }
@@ -867,6 +868,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
        struct ata_port *ap = qc->ap;
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        struct scatterlist *sg;
+       unsigned int si;
 
        pr_debug("in atapi dma start\n");
        if (!(ap->udma_mask || ap->mwdma_mask))
@@ -881,7 +883,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
                 * data cache is enabled. Otherwise, this loop
                 * is an empty loop and optimized out.
                 */
-               ata_for_each_sg(sg, qc) {
+               for_each_sg(qc->sg, sg, qc->n_elem, si) {
                        flush_dcache_range(sg_dma_address(sg),
                                sg_dma_address(sg) + sg_dma_len(sg));
                }
@@ -910,7 +912,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
        ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
 
                /* Set transfer length to buffer len */
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
        }
 
@@ -932,6 +934,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct scatterlist *sg;
+       unsigned int si;
 
        pr_debug("in atapi dma stop\n");
        if (!(ap->udma_mask || ap->mwdma_mask))
@@ -950,7 +953,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
                         * data cache is enabled. Otherwise, this loop
                         * is an empty loop and optimized out.
                         */
-                       ata_for_each_sg(sg, qc) {
+                       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                                invalidate_dcache_range(
                                        sg_dma_address(sg),
                                        sg_dma_address(sg)
@@ -1167,34 +1170,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
  *     Note: Original code is ata_data_xfer().
  */
 
-static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
-                          unsigned int buflen, int write_data)
+static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
+                                  unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
-       unsigned int words = buflen >> 1;
-       unsigned short *buf16 = (u16 *) buf;
+       struct ata_port *ap = dev->link->ap;
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int words = buflen >> 1;
+       unsigned short *buf16 = (u16 *)buf;
 
        /* Transfer multiple of 2 bytes */
-       if (write_data) {
-               write_atapi_data(base, words, buf16);
-       } else {
+       if (rw == READ)
                read_atapi_data(base, words, buf16);
-       }
+       else
+               write_atapi_data(base, words, buf16);
 
        /* Transfer trailing 1 byte, if any. */
        if (unlikely(buflen & 0x01)) {
                unsigned short align_buf[1] = { 0 };
                unsigned char *trailing_buf = buf + buflen - 1;
 
-               if (write_data) {
-                       memcpy(align_buf, trailing_buf, 1);
-                       write_atapi_data(base, 1, align_buf);
-               } else {
+               if (rw == READ) {
                        read_atapi_data(base, 1, align_buf);
                        memcpy(trailing_buf, align_buf, 1);
+               } else {
+                       memcpy(align_buf, trailing_buf, 1);
+                       write_atapi_data(base, 1, align_buf);
                }
+               words++;
        }
+
+       return words << 1;
 }
 
 /**
@@ -1509,7 +1514,8 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
        if (res == NULL)
                return -EINVAL;
 
-       while (bfin_port_info[board_idx].udma_mask>0 && udma_fsclk[udma_mode] > fsclk) {
+       while (bfin_port_info[board_idx].udma_mask > 0 &&
+                       udma_fsclk[udma_mode] > fsclk) {
                udma_mode--;
                bfin_port_info[board_idx].udma_mask >>= 1;
        }
index 33f7f0843f4f21f95b4684725c6e505888abdd09..d4590f546c497c7aa2ae2a365bc1d2a0232b4bff 100644 (file)
@@ -198,7 +198,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
        };
        const struct ata_port_info *ppi[2];
        u8 pcicfg;
-       void *iomap[5];
+       void __iomem *iomap[5];
        struct ata_host *host;
        struct ata_ioports *ioaddr;
        int i, rc;
index c79f066c2bc9ed796e35b1b6b3816d42d8c824ff..68eb34929cecde9c7ed149f3fa5e1dc15c65fd3a 100644 (file)
@@ -847,15 +847,16 @@ static u32 hpt374_read_freq(struct pci_dev *pdev)
        u32 freq;
        unsigned long io_base = pci_resource_start(pdev, 4);
        if (PCI_FUNC(pdev->devfn) & 1) {
-               struct pci_dev *pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1);
+               struct pci_dev *pdev_0;
+
+               pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1);
                /* Someone hot plugged the controller on us ? */
                if (pdev_0 == NULL)
                        return 0;
                io_base = pci_resource_start(pdev_0, 4);
                freq = inl(io_base + 0x90);
                pci_dev_put(pdev_0);
-       }
-       else
+       } else
                freq = inl(io_base + 0x90);
        return freq;
 }
index 842fe08a3c1310188f735a12b1d8b73e3a505f72..5b8586dac63b155e974ab950292d501fc5fffcab 100644 (file)
@@ -224,6 +224,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
        struct pata_icside_state *state = ap->host->private_data;
        struct scatterlist *sg, *rsg = state->sg;
        unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
+       unsigned int si;
 
        /*
         * We are simplex; BUG if we try to fiddle with DMA
@@ -234,7 +235,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
        /*
         * Copy ATAs scattered sg list into a contiguous array of sg
         */
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                memcpy(rsg, sg, sizeof(*sg));
                rsg++;
        }
index ca9aae09daed17b5dacfbf7b23e964a77b3d6077..109ddd42c266ba0447b42b801dbee853b9ca16a5 100644 (file)
@@ -430,7 +430,7 @@ static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc)
                        return ata_qc_issue_prot(qc);
        }
        printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
-       return AC_ERR_INVALID;
+       return AC_ERR_DEV;
 }
 
 /**
@@ -516,6 +516,37 @@ static void it821x_dev_config(struct ata_device *adev)
                        printk("(%dK stripe)", adev->id[146]);
                printk(".\n");
        }
+       /* This is a controller firmware triggered funny, don't
+          report the drive faulty! */
+       adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC;
+}
+
+/**
+ *     it821x_ident_hack       -       Hack identify data up
+ *     @ap: Port
+ *
+ *     Walk the devices on this firmware driven port and slightly
+ *     mash the identify data to stop us and common tools trying to
+ *     use features not firmware supported. The firmware itself does
+ *     some masking (eg SMART) but not enough.
+ *
+ *     This is a bit of an abuse of the cable method, but it is the
+ *     only method called at the right time. We could modify the libata
+ *     core specifically for ident hacking but while we have one offender
+ *     it seems better to keep the fallout localised.
+ */
+
+static int it821x_ident_hack(struct ata_port *ap)
+{
+       struct ata_device *adev;
+       ata_link_for_each_dev(adev, &ap->link) {
+               if (ata_dev_enabled(adev)) {
+                       adev->id[84] &= ~(1 << 6);      /* No FUA */
+                       adev->id[85] &= ~(1 << 10);     /* No HPA */
+                       adev->id[76] = 0;               /* No NCQ/AN etc */
+               }
+       }
+       return ata_cable_unknown(ap);
 }
 
 
@@ -634,7 +665,7 @@ static struct ata_port_operations it821x_smart_port_ops = {
        .thaw           = ata_bmdma_thaw,
        .error_handler  = ata_bmdma_error_handler,
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
-       .cable_detect   = ata_cable_unknown,
+       .cable_detect   = it821x_ident_hack,
 
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = ata_bmdma_start,
index fcd532afbf2e011c9b4d5183430945d409c702eb..030878fedeb5c655641803a96108819b111b6c95 100644 (file)
@@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
        return 0;
 }
 
-static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
-                               unsigned int buflen, int write_data)
+static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
+                               unsigned char *buf, unsigned int buflen, int rw)
 {
        unsigned int i;
        unsigned int words = buflen >> 1;
        u16 *buf16 = (u16 *) buf;
-       struct ata_port *ap = adev->link->ap;
+       struct ata_port *ap = dev->link->ap;
        void __iomem *mmio = ap->ioaddr.data_addr;
        struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
 
@@ -59,30 +59,32 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
        udelay(100);
 
        /* Transfer multiple of 2 bytes */
-       if (write_data) {
-               for (i = 0; i < words; i++)
-                       writew(buf16[i], mmio);
-       } else {
+       if (rw == READ)
                for (i = 0; i < words; i++)
                        buf16[i] = readw(mmio);
-       }
+       else
+               for (i = 0; i < words; i++)
+                       writew(buf16[i], mmio);
 
        /* Transfer trailing 1 byte, if any. */
        if (unlikely(buflen & 0x01)) {
                u16 align_buf[1] = { 0 };
                unsigned char *trailing_buf = buf + buflen - 1;
 
-               if (write_data) {
-                       memcpy(align_buf, trailing_buf, 1);
-                       writew(align_buf[0], mmio);
-               } else {
+               if (rw == READ) {
                        align_buf[0] = readw(mmio);
                        memcpy(trailing_buf, align_buf, 1);
+               } else {
+                       memcpy(align_buf, trailing_buf, 1);
+                       writew(align_buf[0], mmio);
                }
+               words++;
        }
 
        udelay(100);
        *data->cs0_cfg |= 0x01;
+
+       return words << 1;
 }
 
 static struct scsi_host_template ixp4xx_sht = {
@@ -130,10 +132,11 @@ static struct ata_port_operations ixp4xx_port_ops = {
        .port_start             = ata_port_start,
 };
 
-static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
+static void ixp4xx_setup_port(struct ata_port *ap,
                              struct ixp4xx_pata_data *data,
                              unsigned long raw_cs0, unsigned long raw_cs1)
 {
+       struct ata_ioports *ioaddr = &ap->ioaddr;
        unsigned long raw_cmd = raw_cs0;
        unsigned long raw_ctl = raw_cs1 + 0x06;
 
index 7bed8d806381eb45b83f6d47c91ddfaf7c754f90..333dc15f8ccf2d69d574a097448a079d44294200 100644 (file)
@@ -28,7 +28,6 @@
  *
  *  Unsupported but docs exist:
  *     Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
- *     Winbond W83759A
  *
  *  This driver handles legacy (that is "ISA/VLB side") IDE ports found
  *  on PC class systems. There are three hybrid devices that are exceptions
@@ -36,7 +35,7 @@
  *  the MPIIX where the tuning is PCI side but the IDE is "ISA side".
  *
  *  Specific support is included for the ht6560a/ht6560b/opti82c611a/
- *  opti82c465mv/promise 20230c/20630
+ *  opti82c465mv/promise 20230c/20630/winbond83759A
  *
  *  Use the autospeed and pio_mask options with:
  *     Appian ADI/2 aka CLPD7220 or AIC25VL01.
@@ -47,9 +46,6 @@
  *  For now use autospeed and pio_mask as above with the W83759A. This may
  *  change.
  *
- *  TODO
- *     Merge existing pata_qdi driver
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 
 #define DRV_NAME "pata_legacy"
-#define DRV_VERSION "0.5.5"
+#define DRV_VERSION "0.6.5"
 
 #define NR_HOST 6
 
-static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
-static int legacy_irq[NR_HOST] = { 14, 15, 11, 10, 8, 12 };
+static int all;
+module_param(all, int, 0444);
+MODULE_PARM_DESC(all, "Grab all legacy port devices, even if PCI(0=off, 1=on)");
 
 struct legacy_data {
        unsigned long timing;
@@ -80,20 +77,106 @@ struct legacy_data {
 
 };
 
+enum controller {
+       BIOS = 0,
+       SNOOP = 1,
+       PDC20230 = 2,
+       HT6560A = 3,
+       HT6560B = 4,
+       OPTI611A = 5,
+       OPTI46X = 6,
+       QDI6500 = 7,
+       QDI6580 = 8,
+       QDI6580DP = 9,          /* Dual channel mode is different */
+       W83759A = 10,
+
+       UNKNOWN = -1
+};
+
+
+struct legacy_probe {
+       unsigned char *name;
+       unsigned long port;
+       unsigned int irq;
+       unsigned int slot;
+       enum controller type;
+       unsigned long private;
+};
+
+struct legacy_controller {
+       const char *name;
+       struct ata_port_operations *ops;
+       unsigned int pio_mask;
+       unsigned int flags;
+       int (*setup)(struct platform_device *, struct legacy_probe *probe,
+               struct legacy_data *data);
+};
+
+static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+
+static struct legacy_probe probe_list[NR_HOST];
 static struct legacy_data legacy_data[NR_HOST];
 static struct ata_host *legacy_host[NR_HOST];
 static int nr_legacy_host;
 
 
-static int probe_all;                  /* Set to check all ISA port ranges */
-static int ht6560a;                    /* HT 6560A on primary 1, secondary 2, both 3 */
-static int ht6560b;                    /* HT 6560A on primary 1, secondary 2, both 3 */
-static int opti82c611a;                        /* Opti82c611A on primary 1, secondary 2, both 3 */
-static int opti82c46x;                 /* Opti 82c465MV present (pri/sec autodetect) */
-static int autospeed;                  /* Chip present which snoops speed changes */
-static int pio_mask = 0x1F;            /* PIO range for autospeed devices */
+static int probe_all;          /* Set to check all ISA port ranges */
+static int ht6560a;            /* HT 6560A on primary 1, second 2, both 3 */
+static int ht6560b;            /* HT 6560A on primary 1, second 2, both 3 */
+static int opti82c611a;                /* Opti82c611A on primary 1, sec 2, both 3 */
+static int opti82c46x;         /* Opti 82c465MV present(pri/sec autodetect) */
+static int qdi;                        /* Set to probe QDI controllers */
+static int winbond;            /* Set to probe Winbond controllers,
+                                       give I/O port if non stdanard */
+static int autospeed;          /* Chip present which snoops speed changes */
+static int pio_mask = 0x1F;    /* PIO range for autospeed devices */
 static int iordy_mask = 0xFFFFFFFF;    /* Use iordy if available */
 
+/**
+ *     legacy_probe_add        -       Add interface to probe list
+ *     @port: Controller port
+ *     @irq: IRQ number
+ *     @type: Controller type
+ *     @private: Controller specific info
+ *
+ *     Add an entry into the probe list for ATA controllers. This is used
+ *     to add the default ISA slots and then to build up the table
+ *     further according to other ISA/VLB/Weird device scans
+ *
+ *     An I/O port list is used to keep ordering stable and sane, as we
+ *     don't have any good way to talk about ordering otherwise
+ */
+
+static int legacy_probe_add(unsigned long port, unsigned int irq,
+                               enum controller type, unsigned long private)
+{
+       struct legacy_probe *lp = &probe_list[0];
+       int i;
+       struct legacy_probe *free = NULL;
+
+       for (i = 0; i < NR_HOST; i++) {
+               if (lp->port == 0 && free == NULL)
+                       free = lp;
+               /* Matching port, or the correct slot for ordering */
+               if (lp->port == port || legacy_port[i] == port) {
+                       free = lp;
+                       break;
+               }
+               lp++;
+       }
+       if (free == NULL) {
+               printk(KERN_ERR "pata_legacy: Too many interfaces.\n");
+               return -1;
+       }
+       /* Fill in the entry for later probing */
+       free->port = port;
+       free->irq = irq;
+       free->type = type;
+       free->private = private;
+       return 0;
+}
+
+
 /**
  *     legacy_set_mode         -       mode setting
  *     @link: IDE link
@@ -113,7 +196,8 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
 
        ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
-                       ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+                       ata_dev_printk(dev, KERN_INFO,
+                                               "configured for PIO\n");
                        dev->pio_mode = XFER_PIO_0;
                        dev->xfer_mode = XFER_PIO_0;
                        dev->xfer_shift = ATA_SHIFT_PIO;
@@ -171,7 +255,7 @@ static struct ata_port_operations simple_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations legacy_port_ops = {
@@ -198,15 +282,16 @@ static struct ata_port_operations legacy_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
  *     Promise 20230C and 20620 support
  *
- *     This controller supports PIO0 to PIO2. We set PIO timings conservatively to
- *     allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to
- *     controller and PIO'd to the host and not supported.
+ *     This controller supports PIO0 to PIO2. We set PIO timings
+ *     conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA
+ *     support is weird being DMA to controller and PIO'd to the host
+ *     and not supported.
  */
 
 static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -221,8 +306,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
        local_irq_save(flags);
 
        /* Unlock the control interface */
-       do
-       {
+       do {
                inb(0x1F5);
                outb(inb(0x1F2) | 0x80, 0x1F2);
                inb(0x1F2);
@@ -231,7 +315,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
                inb(0x1F2);
                inb(0x1F2);
        }
-       while((inb(0x1F2) & 0x80) && --tries);
+       while ((inb(0x1F2) & 0x80) && --tries);
 
        local_irq_restore(flags);
 
@@ -249,13 +333,14 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
 }
 
-static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
+                       unsigned char *buf, unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
-       int slop = buflen & 3;
-       unsigned long flags;
+       if (ata_id_has_dword_io(dev->id)) {
+               struct ata_port *ap = dev->link->ap;
+               int slop = buflen & 3;
+               unsigned long flags;
 
-       if (ata_id_has_dword_io(adev->id)) {
                local_irq_save(flags);
 
                /* Perform the 32bit I/O synchronization sequence */
@@ -264,28 +349,27 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
                ioread8(ap->ioaddr.nsect_addr);
 
                /* Now the data */
-
-               if (write_data)
-                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-               else
+               if (rw == READ)
                        ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+               else
+                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
                if (unlikely(slop)) {
                        u32 pad;
-                       if (write_data) {
-                               memcpy(&pad, buf + buflen - slop, slop);
-                               pad = le32_to_cpu(pad);
-                               iowrite32(pad, ap->ioaddr.data_addr);
-                       } else {
-                               pad = ioread32(ap->ioaddr.data_addr);
-                               pad = cpu_to_le16(pad);
+                       if (rw == READ) {
+                               pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
                                memcpy(buf + buflen - slop, &pad, slop);
+                       } else {
+                               memcpy(&pad, buf + buflen - slop, slop);
+                               iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
                        }
+                       buflen += 4 - slop;
                }
                local_irq_restore(flags);
-       }
-       else
-               ata_data_xfer_noirq(adev, buf, buflen, write_data);
+       } else
+               buflen = ata_data_xfer_noirq(dev, buf, buflen, rw);
+
+       return buflen;
 }
 
 static struct ata_port_operations pdc20230_port_ops = {
@@ -312,14 +396,14 @@ static struct ata_port_operations pdc20230_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
  *     Holtek 6560A support
  *
- *     This controller supports PIO0 to PIO2 (no IORDY even though higher timings
- *     can be loaded).
+ *     This controller supports PIO0 to PIO2 (no IORDY even though higher
+ *     timings can be loaded).
  */
 
 static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -366,14 +450,14 @@ static struct ata_port_operations ht6560a_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
  *     Holtek 6560B support
  *
- *     This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting
- *     unless we see an ATAPI device in which case we force it off.
+ *     This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO
+ *     setting unless we see an ATAPI device in which case we force it off.
  *
  *     FIXME: need to implement 2nd channel support.
  */
@@ -400,7 +484,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
        if (adev->class != ATA_DEV_ATA) {
                u8 rconf = inb(0x3E6);
                if (rconf & 0x24) {
-                       rconf &= ~ 0x24;
+                       rconf &= ~0x24;
                        outb(rconf, 0x3E6);
                }
        }
@@ -425,13 +509,13 @@ static struct ata_port_operations ht6560b_port_ops = {
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
 
-       .data_xfer      = ata_data_xfer,        /* FIXME: Check 32bit and noirq */
+       .data_xfer      = ata_data_xfer,    /* FIXME: Check 32bit and noirq */
 
        .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
@@ -464,7 +548,8 @@ static u8 opti_syscfg(u8 reg)
  *     This controller supports PIO0 to PIO3.
  */
 
-static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void opti82c611a_set_piomode(struct ata_port *ap,
+                                               struct ata_device *adev)
 {
        u8 active, recover, setup;
        struct ata_timing t;
@@ -551,7 +636,7 @@ static struct ata_port_operations opti82c611a_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
@@ -683,77 +768,398 @@ static struct ata_port_operations opti82c46x_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
+static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct ata_timing t;
+       struct legacy_data *qdi = ap->host->private_data;
+       int active, recovery;
+       u8 timing;
+
+       /* Get the timing data in cycles */
+       ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+       if (qdi->fast) {
+               active = 8 - FIT(t.active, 1, 8);
+               recovery = 18 - FIT(t.recover, 3, 18);
+       } else {
+               active = 9 - FIT(t.active, 2, 9);
+               recovery = 15 - FIT(t.recover, 0, 15);
+       }
+       timing = (recovery << 4) | active | 0x08;
+
+       qdi->clock[adev->devno] = timing;
+
+       outb(timing, qdi->timing);
+}
 
 /**
- *     legacy_init_one         -       attach a legacy interface
- *     @port: port number
- *     @io: I/O port start
- *     @ctrl: control port
+ *     qdi6580dp_set_piomode           -       PIO setup for dual channel
+ *     @ap: Port
+ *     @adev: Device
  *     @irq: interrupt line
  *
- *     Register an ISA bus IDE interface. Such interfaces are PIO and we
- *     assume do not support IRQ sharing.
+ *     In dual channel mode the 6580 has one clock per channel and we have
+ *     to software clockswitch in qc_issue_prot.
  */
 
-static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
+static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
-       struct legacy_data *ld = &legacy_data[nr_legacy_host];
-       struct ata_host *host;
-       struct ata_port *ap;
-       struct platform_device *pdev;
-       struct ata_port_operations *ops = &legacy_port_ops;
-       void __iomem *io_addr, *ctrl_addr;
-       int pio_modes = pio_mask;
-       u32 mask = (1 << port);
-       u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;
-       int ret;
+       struct ata_timing t;
+       struct legacy_data *qdi = ap->host->private_data;
+       int active, recovery;
+       u8 timing;
 
-       pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
+       /* Get the timing data in cycles */
+       ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+       if (qdi->fast) {
+               active = 8 - FIT(t.active, 1, 8);
+               recovery = 18 - FIT(t.recover, 3, 18);
+       } else {
+               active = 9 - FIT(t.active, 2, 9);
+               recovery = 15 - FIT(t.recover, 0, 15);
+       }
+       timing = (recovery << 4) | active | 0x08;
 
-       ret = -EBUSY;
-       if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
-           devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL)
-               goto fail;
+       qdi->clock[adev->devno] = timing;
 
-       ret = -ENOMEM;
-       io_addr = devm_ioport_map(&pdev->dev, io, 8);
-       ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1);
-       if (!io_addr || !ctrl_addr)
-               goto fail;
+       outb(timing, qdi->timing + 2 * ap->port_no);
+       /* Clear the FIFO */
+       if (adev->class != ATA_DEV_ATA)
+               outb(0x5F, qdi->timing + 3);
+}
 
-       if (ht6560a & mask) {
-               ops = &ht6560a_port_ops;
-               pio_modes = 0x07;
-               iordy = ATA_FLAG_NO_IORDY;
-       }
-       if (ht6560b & mask) {
-               ops = &ht6560b_port_ops;
-               pio_modes = 0x1F;
-       }
-       if (opti82c611a & mask) {
-               ops = &opti82c611a_port_ops;
-               pio_modes = 0x0F;
+/**
+ *     qdi6580_set_piomode             -       PIO setup for single channel
+ *     @ap: Port
+ *     @adev: Device
+ *
+ *     In single channel mode the 6580 has one clock per device and we can
+ *     avoid the requirement to clock switch. We also have to load the timing
+ *     into the right clock according to whether we are master or slave.
+ */
+
+static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct ata_timing t;
+       struct legacy_data *qdi = ap->host->private_data;
+       int active, recovery;
+       u8 timing;
+
+       /* Get the timing data in cycles */
+       ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+       if (qdi->fast) {
+               active = 8 - FIT(t.active, 1, 8);
+               recovery = 18 - FIT(t.recover, 3, 18);
+       } else {
+               active = 9 - FIT(t.active, 2, 9);
+               recovery = 15 - FIT(t.recover, 0, 15);
        }
-       if (opti82c46x & mask) {
-               ops = &opti82c46x_port_ops;
-               pio_modes = 0x0F;
+       timing = (recovery << 4) | active | 0x08;
+       qdi->clock[adev->devno] = timing;
+       outb(timing, qdi->timing + 2 * adev->devno);
+       /* Clear the FIFO */
+       if (adev->class != ATA_DEV_ATA)
+               outb(0x5F, qdi->timing + 3);
+}
+
+/**
+ *     qdi_qc_issue_prot       -       command issue
+ *     @qc: command pending
+ *
+ *     Called when the libata layer is about to issue a command. We wrap
+ *     this interface so that we can load the correct ATA timings.
+ */
+
+static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct ata_device *adev = qc->dev;
+       struct legacy_data *qdi = ap->host->private_data;
+
+       if (qdi->clock[adev->devno] != qdi->last) {
+               if (adev->pio_mode) {
+                       qdi->last = qdi->clock[adev->devno];
+                       outb(qdi->clock[adev->devno], qdi->timing +
+                                                       2 * ap->port_no);
+               }
        }
+       return ata_qc_issue_prot(qc);
+}
 
-       /* Probe for automatically detectable controllers */
+static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
+                                       unsigned int buflen, int rw)
+{
+       struct ata_port *ap = adev->link->ap;
+       int slop = buflen & 3;
 
-       if (io == 0x1F0 && ops == &legacy_port_ops) {
-               unsigned long flags;
+       if (ata_id_has_dword_io(adev->id)) {
+               if (rw == WRITE)
+                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+               else
+                       ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
-               local_irq_save(flags);
+               if (unlikely(slop)) {
+                       u32 pad;
+                       if (rw == WRITE) {
+                               memcpy(&pad, buf + buflen - slop, slop);
+                               pad = le32_to_cpu(pad);
+                               iowrite32(pad, ap->ioaddr.data_addr);
+                       } else {
+                               pad = ioread32(ap->ioaddr.data_addr);
+                               pad = cpu_to_le32(pad);
+                               memcpy(buf + buflen - slop, &pad, slop);
+                       }
+               }
+               return (buflen + 3) & ~3;
+       } else
+               return ata_data_xfer(adev, buf, buflen, rw);
+}
+
+static int qdi_port(struct platform_device *dev,
+                       struct legacy_probe *lp, struct legacy_data *ld)
+{
+       if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL)
+               return -EBUSY;
+       ld->timing = lp->private;
+       return 0;
+}
+
+static struct ata_port_operations qdi6500_port_ops = {
+       .set_piomode    = qdi6500_set_piomode,
+
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ata_std_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
 
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = qdi_qc_issue_prot,
+
+       .data_xfer      = vlb32_data_xfer,
+
+       .irq_handler    = ata_interrupt,
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+
+       .port_start     = ata_sff_port_start,
+};
+
+static struct ata_port_operations qdi6580_port_ops = {
+       .set_piomode    = qdi6580_set_piomode,
+
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ata_std_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
+
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = ata_qc_issue_prot,
+
+       .data_xfer      = vlb32_data_xfer,
+
+       .irq_handler    = ata_interrupt,
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+
+       .port_start     = ata_sff_port_start,
+};
+
+static struct ata_port_operations qdi6580dp_port_ops = {
+       .set_piomode    = qdi6580dp_set_piomode,
+
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ata_std_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
+
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = qdi_qc_issue_prot,
+
+       .data_xfer      = vlb32_data_xfer,
+
+       .irq_handler    = ata_interrupt,
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+
+       .port_start     = ata_sff_port_start,
+};
+
+static DEFINE_SPINLOCK(winbond_lock);
+
+static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&winbond_lock, flags);
+       outb(reg, port + 0x01);
+       outb(val, port + 0x02);
+       spin_unlock_irqrestore(&winbond_lock, flags);
+}
+
+static u8 winbond_readcfg(unsigned long port, u8 reg)
+{
+       u8 val;
+
+       unsigned long flags;
+       spin_lock_irqsave(&winbond_lock, flags);
+       outb(reg, port + 0x01);
+       val = inb(port + 0x02);
+       spin_unlock_irqrestore(&winbond_lock, flags);
+
+       return val;
+}
+
+static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct ata_timing t;
+       struct legacy_data *winbond = ap->host->private_data;
+       int active, recovery;
+       u8 reg;
+       int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
+
+       reg = winbond_readcfg(winbond->timing, 0x81);
+
+       /* Get the timing data in cycles */
+       if (reg & 0x40)         /* Fast VLB bus, assume 50MHz */
+               ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+       else
+               ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+       active = (FIT(t.active, 3, 17) - 1) & 0x0F;
+       recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+       timing = (active << 4) | recovery;
+       winbond_writecfg(winbond->timing, timing, reg);
+
+       /* Load the setup timing */
+
+       reg = 0x35;
+       if (adev->class != ATA_DEV_ATA)
+               reg |= 0x08;    /* FIFO off */
+       if (!ata_pio_need_iordy(adev))
+               reg |= 0x02;    /* IORDY off */
+       reg |= (FIT(t.setup, 0, 3) << 6);
+       winbond_writecfg(winbond->timing, timing + 1, reg);
+}
+
+static int winbond_port(struct platform_device *dev,
+                       struct legacy_probe *lp, struct legacy_data *ld)
+{
+       if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL)
+               return -EBUSY;
+       ld->timing = lp->private;
+       return 0;
+}
+
+static struct ata_port_operations winbond_port_ops = {
+       .set_piomode    = winbond_set_piomode,
+
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ata_std_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
+
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = ata_qc_issue_prot,
+
+       .data_xfer      = vlb32_data_xfer,
+
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+
+       .port_start     = ata_sff_port_start,
+};
+
+static struct legacy_controller controllers[] = {
+       {"BIOS",        &legacy_port_ops,       0x1F,
+                                               ATA_FLAG_NO_IORDY,      NULL },
+       {"Snooping",    &simple_port_ops,       0x1F,
+                                               0              ,        NULL },
+       {"PDC20230",    &pdc20230_port_ops,     0x7,
+                                               ATA_FLAG_NO_IORDY,      NULL },
+       {"HT6560A",     &ht6560a_port_ops,      0x07,
+                                               ATA_FLAG_NO_IORDY,      NULL },
+       {"HT6560B",     &ht6560b_port_ops,      0x1F,
+                                               ATA_FLAG_NO_IORDY,      NULL },
+       {"OPTI82C611A", &opti82c611a_port_ops,  0x0F,
+                                               0              ,        NULL },
+       {"OPTI82C46X",  &opti82c46x_port_ops,   0x0F,
+                                               0              ,        NULL },
+       {"QDI6500",     &qdi6500_port_ops,      0x07,
+                                       ATA_FLAG_NO_IORDY,      qdi_port },
+       {"QDI6580",     &qdi6580_port_ops,      0x1F,
+                                       0              ,        qdi_port },
+       {"QDI6580DP",   &qdi6580dp_port_ops,    0x1F,
+                                       0              ,        qdi_port },
+       {"W83759A",     &winbond_port_ops,      0x1F,
+                                       0              ,        winbond_port }
+};
+
+/**
+ *     probe_chip_type         -       Discover controller
+ *     @probe: Probe entry to check
+ *
+ *     Probe an ATA port and identify the type of controller. We don't
+ *     check if the controller appears to be driveless at this point.
+ */
+
+static __init int probe_chip_type(struct legacy_probe *probe)
+{
+       int mask = 1 << probe->slot;
+
+       if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) {
+               u8 reg = winbond_readcfg(winbond, 0x81);
+               reg |= 0x80;    /* jumpered mode off */
+               winbond_writecfg(winbond, 0x81, reg);
+               reg = winbond_readcfg(winbond, 0x83);
+               reg |= 0xF0;    /* local control */
+               winbond_writecfg(winbond, 0x83, reg);
+               reg = winbond_readcfg(winbond, 0x85);
+               reg |= 0xF0;    /* programmable timing */
+               winbond_writecfg(winbond, 0x85, reg);
+
+               reg = winbond_readcfg(winbond, 0x81);
+
+               if (reg & mask)
+                       return W83759A;
+       }
+       if (probe->port == 0x1F0) {
+               unsigned long flags;
+               local_irq_save(flags);
                /* Probes */
-               inb(0x1F5);
                outb(inb(0x1F2) | 0x80, 0x1F2);
+               inb(0x1F5);
                inb(0x1F2);
                inb(0x3F6);
                inb(0x3F6);
@@ -762,29 +1168,83 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
 
                if ((inb(0x1F2) & 0x80) == 0) {
                        /* PDC20230c or 20630 ? */
-                       printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");
-                               pio_modes = 0x07;
-                       ops = &pdc20230_port_ops;
-                       iordy = ATA_FLAG_NO_IORDY;
+                       printk(KERN_INFO  "PDC20230-C/20630 VLB ATA controller"
+                                                       " detected.\n");
                        udelay(100);
                        inb(0x1F5);
+                       local_irq_restore(flags);
+                       return PDC20230;
                } else {
                        outb(0x55, 0x1F2);
                        inb(0x1F2);
                        inb(0x1F2);
-                       if (inb(0x1F2) == 0x00) {
-                               printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n");
-                       }
+                       if (inb(0x1F2) == 0x00)
+                               printk(KERN_INFO "PDC20230-B VLB ATA "
+                                                    "controller detected.\n");
+                       local_irq_restore(flags);
+                       return BIOS;
                }
                local_irq_restore(flags);
        }
 
+       if (ht6560a & mask)
+               return HT6560A;
+       if (ht6560b & mask)
+               return HT6560B;
+       if (opti82c611a & mask)
+               return OPTI611A;
+       if (opti82c46x & mask)
+               return OPTI46X;
+       if (autospeed & mask)
+               return SNOOP;
+       return BIOS;
+}
 
-       /* Chip does mode setting by command snooping */
-       if (ops == &legacy_port_ops && (autospeed & mask))
-               ops = &simple_port_ops;
+
+/**
+ *     legacy_init_one         -       attach a legacy interface
+ *     @pl: probe record
+ *
+ *     Register an ISA bus IDE interface. Such interfaces are PIO and we
+ *     assume do not support IRQ sharing.
+ */
+
+static __init int legacy_init_one(struct legacy_probe *probe)
+{
+       struct legacy_controller *controller = &controllers[probe->type];
+       int pio_modes = controller->pio_mask;
+       unsigned long io = probe->port;
+       u32 mask = (1 << probe->slot);
+       struct ata_port_operations *ops = controller->ops;
+       struct legacy_data *ld = &legacy_data[probe->slot];
+       struct ata_host *host = NULL;
+       struct ata_port *ap;
+       struct platform_device *pdev;
+       struct ata_device *dev;
+       void __iomem *io_addr, *ctrl_addr;
+       u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;
+       int ret;
+
+       iordy |= controller->flags;
+
+       pdev = platform_device_register_simple(DRV_NAME, probe->slot, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       ret = -EBUSY;
+       if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
+           devm_request_region(&pdev->dev, io + 0x0206, 1,
+                                                       "pata_legacy") == NULL)
+               goto fail;
 
        ret = -ENOMEM;
+       io_addr = devm_ioport_map(&pdev->dev, io, 8);
+       ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1);
+       if (!io_addr || !ctrl_addr)
+               goto fail;
+       if (controller->setup)
+               if (controller->setup(pdev, probe, ld) < 0)
+                       goto fail;
        host = ata_host_alloc(&pdev->dev, 1);
        if (!host)
                goto fail;
@@ -797,19 +1257,29 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
        ap->ioaddr.altstatus_addr = ctrl_addr;
        ap->ioaddr.ctl_addr = ctrl_addr;
        ata_std_ports(&ap->ioaddr);
-       ap->private_data = ld;
+       ap->host->private_data = ld;
 
-       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206);
 
-       ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+       ret = ata_host_activate(host, probe->irq, ata_interrupt, 0,
+                                                               &legacy_sht);
        if (ret)
                goto fail;
-
-       legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
        ld->platform_dev = pdev;
-       return 0;
 
+       /* Nothing found means we drop the port as its probably not there */
+
+       ret = -ENODEV;
+       ata_link_for_each_dev(dev, &ap->link) {
+               if (!ata_dev_absent(dev)) {
+                       legacy_host[probe->slot] = host;
+                       ld->platform_dev = pdev;
+                       return 0;
+               }
+       }
 fail:
+       if (host)
+               ata_host_detach(host);
        platform_device_unregister(pdev);
        return ret;
 }
@@ -820,13 +1290,15 @@ fail:
  *     @master: set this if we find an ATA master
  *     @master: set this if we find an ATA secondary
  *
- *     A small number of vendors implemented early PCI ATA interfaces on bridge logic
- *     without the ATA interface being PCI visible. Where we have a matching PCI driver
- *     we must skip the relevant device here. If we don't know about it then the legacy
- *     driver is the right driver anyway.
+ *     A small number of vendors implemented early PCI ATA interfaces
+ *     on bridge logic without the ATA interface being PCI visible.
+ *     Where we have a matching PCI driver we must skip the relevant
+ *     device here. If we don't know about it then the legacy driver
+ *     is the right driver anyway.
  */
 
-static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary)
+static void __init legacy_check_special_cases(struct pci_dev *p, int *primary,
+                                                               int *secondary)
 {
        /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */
        if (p->vendor == 0x1078 && p->device == 0x0000) {
@@ -842,7 +1314,8 @@ static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *sec
        if (p->vendor == 0x8086 && p->device == 0x1234) {
                u16 r;
                pci_read_config_word(p, 0x6C, &r);
-               if (r & 0x8000) {       /* ATA port enabled */
+               if (r & 0x8000) {
+                       /* ATA port enabled */
                        if (r & 0x4000)
                                *secondary = 1;
                        else
@@ -852,6 +1325,114 @@ static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *sec
        }
 }
 
+static __init void probe_opti_vlb(void)
+{
+       /* If an OPTI 82C46X is present find out where the channels are */
+       static const char *optis[4] = {
+               "3/463MV", "5MV",
+               "5MVA", "5MVB"
+       };
+       u8 chans = 1;
+       u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
+
+       opti82c46x = 3; /* Assume master and slave first */
+       printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n",
+                                                               optis[ctrl]);
+       if (ctrl == 3)
+               chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
+       ctrl = opti_syscfg(0xAC);
+       /* Check enabled and this port is the 465MV port. On the
+          MVB we may have two channels */
+       if (ctrl & 8) {
+               if (chans == 2) {
+                       legacy_probe_add(0x1F0, 14, OPTI46X, 0);
+                       legacy_probe_add(0x170, 15, OPTI46X, 0);
+               }
+               if (ctrl & 4)
+                       legacy_probe_add(0x170, 15, OPTI46X, 0);
+               else
+                       legacy_probe_add(0x1F0, 14, OPTI46X, 0);
+       } else
+               legacy_probe_add(0x1F0, 14, OPTI46X, 0);
+}
+
+static __init void qdi65_identify_port(u8 r, u8 res, unsigned long port)
+{
+       static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
+       /* Check card type */
+       if ((r & 0xF0) == 0xC0) {
+               /* QD6500: single channel */
+               if (r & 8)
+                       /* Disabled ? */
+                       return;
+               legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01),
+                                                               QDI6500, port);
+       }
+       if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
+               /* QD6580: dual channel */
+               if (!request_region(port + 2 , 2, "pata_qdi")) {
+                       release_region(port, 2);
+                       return;
+               }
+               res = inb(port + 3);
+               /* Single channel mode ? */
+               if (res & 1)
+                       legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01),
+                                                               QDI6580, port);
+               else { /* Dual channel mode */
+                       legacy_probe_add(0x1F0, 14, QDI6580DP, port);
+                       /* port + 0x02, r & 0x04 */
+                       legacy_probe_add(0x170, 15, QDI6580DP, port + 2);
+               }
+               release_region(port + 2, 2);
+       }
+}
+
+static __init void probe_qdi_vlb(void)
+{
+       unsigned long flags;
+       static const unsigned long qd_port[2] = { 0x30, 0xB0 };
+       int i;
+
+       /*
+        *      Check each possible QD65xx base address
+        */
+
+       for (i = 0; i < 2; i++) {
+               unsigned long port = qd_port[i];
+               u8 r, res;
+
+
+               if (request_region(port, 2, "pata_qdi")) {
+                       /* Check for a card */
+                       local_irq_save(flags);
+                       /* I have no h/w that needs this delay but it
+                          is present in the historic code */
+                       r = inb(port);
+                       udelay(1);
+                       outb(0x19, port);
+                       udelay(1);
+                       res = inb(port);
+                       udelay(1);
+                       outb(r, port);
+                       udelay(1);
+                       local_irq_restore(flags);
+
+                       /* Fail */
+                       if (res == 0x19) {
+                               release_region(port, 2);
+                               continue;
+                       }
+                       /* Passes the presence test */
+                       r = inb(port + 1);
+                       udelay(1);
+                       /* Check port agrees with port set */
+                       if ((r & 2) >> 1 == i)
+                               qdi65_identify_port(r, res, port);
+                       release_region(port, 2);
+               }
+       }
+}
 
 /**
  *     legacy_init             -       attach legacy interfaces
@@ -869,15 +1450,17 @@ static __init int legacy_init(void)
        int ct = 0;
        int primary = 0;
        int secondary = 0;
-       int last_port = NR_HOST;
+       int pci_present = 0;
+       struct legacy_probe *pl = &probe_list[0];
+       int slot = 0;
 
        struct pci_dev *p = NULL;
 
        for_each_pci_dev(p) {
                int r;
-               /* Check for any overlap of the system ATA mappings. Native mode controllers
-                  stuck on these addresses or some devices in 'raid' mode won't be found by
-                  the storage class test */
+               /* Check for any overlap of the system ATA mappings. Native
+                  mode controllers stuck on these addresses or some devices
+                  in 'raid' mode won't be found by the storage class test */
                for (r = 0; r < 6; r++) {
                        if (pci_resource_start(p, r) == 0x1f0)
                                primary = 1;
@@ -887,49 +1470,39 @@ static __init int legacy_init(void)
                /* Check for special cases */
                legacy_check_special_cases(p, &primary, &secondary);
 
-               /* If PCI bus is present then don't probe for tertiary legacy ports */
-               if (probe_all == 0)
-                       last_port = 2;
+               /* If PCI bus is present then don't probe for tertiary
+                  legacy ports */
+               pci_present = 1;
        }
 
-       /* If an OPTI 82C46X is present find out where the channels are */
-       if (opti82c46x) {
-               static const char *optis[4] = {
-                       "3/463MV", "5MV",
-                       "5MVA", "5MVB"
-               };
-               u8 chans = 1;
-               u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
-
-               opti82c46x = 3; /* Assume master and slave first */
-               printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]);
-               if (ctrl == 3)
-                       chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
-               ctrl = opti_syscfg(0xAC);
-               /* Check enabled and this port is the 465MV port. On the
-                  MVB we may have two channels */
-               if (ctrl & 8) {
-                       if (ctrl & 4)
-                               opti82c46x = 2; /* Slave */
-                       else
-                               opti82c46x = 1; /* Master */
-                       if (chans == 2)
-                               opti82c46x = 3; /* Master and Slave */
-               }       /* Slave only */
-               else if (chans == 1)
-                       opti82c46x = 1;
+       if (winbond == 1)
+               winbond = 0x130;        /* Default port, alt is 1B0 */
+
+       if (primary == 0 || all)
+               legacy_probe_add(0x1F0, 14, UNKNOWN, 0);
+       if (secondary == 0 || all)
+               legacy_probe_add(0x170, 15, UNKNOWN, 0);
+
+       if (probe_all || !pci_present) {
+               /* ISA/VLB extra ports */
+               legacy_probe_add(0x1E8, 11, UNKNOWN, 0);
+               legacy_probe_add(0x168, 10, UNKNOWN, 0);
+               legacy_probe_add(0x1E0, 8, UNKNOWN, 0);
+               legacy_probe_add(0x160, 12, UNKNOWN, 0);
        }
 
-       for (i = 0; i < last_port; i++) {
-               /* Skip primary if we have seen a PCI one */
-               if (i == 0 && primary == 1)
-                       continue;
-               /* Skip secondary if we have seen a PCI one */
-               if (i == 1 && secondary == 1)
+       if (opti82c46x)
+               probe_opti_vlb();
+       if (qdi)
+               probe_qdi_vlb();
+
+       for (i = 0; i < NR_HOST; i++, pl++) {
+               if (pl->port == 0)
                        continue;
-               if (legacy_init_one(i, legacy_port[i],
-                                  legacy_port[i] + 0x0206,
-                                  legacy_irq[i]) == 0)
+               if (pl->type == UNKNOWN)
+                       pl->type = probe_chip_type(pl);
+               pl->slot = slot++;
+               if (legacy_init_one(pl) == 0)
                        ct++;
        }
        if (ct != 0)
@@ -943,11 +1516,8 @@ static __exit void legacy_exit(void)
 
        for (i = 0; i < nr_legacy_host; i++) {
                struct legacy_data *ld = &legacy_data[i];
-
                ata_host_detach(legacy_host[i]);
                platform_device_unregister(ld->platform_dev);
-               if (ld->timing)
-                       release_region(ld->timing, 2);
        }
 }
 
@@ -962,9 +1532,9 @@ module_param(ht6560a, int, 0);
 module_param(ht6560b, int, 0);
 module_param(opti82c611a, int, 0);
 module_param(opti82c46x, int, 0);
+module_param(qdi, int, 0);
 module_param(pio_mask, int, 0);
 module_param(iordy_mask, int, 0);
 
 module_init(legacy_init);
 module_exit(legacy_exit);
-
index 50c56e2814c1e0c6a777ed7ef80534d8e9012d73..dc401626cdb2a01eaa206eddbed33e9175dc24ea 100644 (file)
@@ -364,7 +364,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
 {
        unsigned int ipb_freq;
        struct resource res_mem;
-       int ata_irq = NO_IRQ;
+       int ata_irq;
        struct mpc52xx_ata __iomem *ata_regs;
        struct mpc52xx_ata_priv *priv;
        int rv;
diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c
new file mode 100644 (file)
index 0000000..1c1b835
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * pata_ninja32.c      - Ninja32 PATA for new ATA layer
+ *                       (C) 2007 Red Hat Inc
+ *                       Alan Cox <alan@redhat.com>
+ *
+ * Note: The controller like many controllers has shared timings for
+ * PIO and DMA. We thus flip to the DMA timings in dma_start and flip back
+ * in the dma_stop function. Thus we actually don't need a set_dmamode
+ * method as the PIO method is always called and will set the right PIO
+ * timing parameters.
+ *
+ * The Ninja32 Cardbus is not a generic SFF controller. Instead it is
+ * laid out as follows off BAR 0. This is based upon Mark Lord's delkin
+ * driver and the extensive analysis done by the BSD developers, notably
+ * ITOH Yasufumi.
+ *
+ *     Base + 0x00 IRQ Status
+ *     Base + 0x01 IRQ control
+ *     Base + 0x02 Chipset control
+ *     Base + 0x04 VDMA and reset control + wait bits
+ *     Base + 0x08 BMIMBA
+ *     Base + 0x0C DMA Length
+ *     Base + 0x10 Taskfile
+ *     Base + 0x18 BMDMA Status ?
+ *     Base + 0x1C
+ *     Base + 0x1D Bus master control
+ *             bit 0 = enable
+ *             bit 1 = 0 write/1 read
+ *             bit 2 = 1 sgtable
+ *             bit 3 = go
+ *             bit 4-6 wait bits
+ *             bit 7 = done
+ *     Base + 0x1E AltStatus
+ *     Base + 0x1F timing register
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_ninja32"
+#define DRV_VERSION "0.0.1"
+
+
+/**
+ *     ninja32_set_piomode     -       set initial PIO mode data
+ *     @ap: ATA interface
+ *     @adev: ATA device
+ *
+ *     Called to do the PIO mode setup. Our timing registers are shared
+ *     but we want to set the PIO timing by default.
+ */
+
+static void ninja32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       static u16 pio_timing[5] = {
+               0xd6, 0x85, 0x44, 0x33, 0x13
+       };
+       iowrite8(pio_timing[adev->pio_mode - XFER_PIO_0],
+                ap->ioaddr.bmdma_addr + 0x1f);
+       ap->private_data = adev;
+}
+
+
+static void ninja32_dev_select(struct ata_port *ap, unsigned int device)
+{
+       struct ata_device *adev = &ap->link.device[device];
+       if (ap->private_data != adev) {
+               iowrite8(0xd6, ap->ioaddr.bmdma_addr + 0x1f);
+               ata_std_dev_select(ap, device);
+               ninja32_set_piomode(ap, adev);
+       }
+}
+
+static struct scsi_host_template ninja32_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .ioctl                  = ata_scsi_ioctl,
+       .queuecommand           = ata_scsi_queuecmd,
+       .can_queue              = ATA_DEF_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+       .sg_tablesize           = LIBATA_MAX_PRD,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+       .proc_name              = DRV_NAME,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .slave_configure        = ata_scsi_slave_config,
+       .slave_destroy          = ata_scsi_slave_destroy,
+       .bios_param             = ata_std_bios_param,
+};
+
+static struct ata_port_operations ninja32_port_ops = {
+       .set_piomode    = ninja32_set_piomode,
+       .mode_filter    = ata_pci_default_filter,
+
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ninja32_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
+
+       .bmdma_setup    = ata_bmdma_setup,
+       .bmdma_start    = ata_bmdma_start,
+       .bmdma_stop     = ata_bmdma_stop,
+       .bmdma_status   = ata_bmdma_status,
+
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = ata_qc_issue_prot,
+
+       .data_xfer      = ata_data_xfer,
+
+       .irq_handler    = ata_interrupt,
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+
+       .port_start     = ata_sff_port_start,
+};
+
+static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct ata_host *host;
+       struct ata_port *ap;
+       void __iomem *base;
+       int rc;
+
+       host = ata_host_alloc(&dev->dev, 1);
+       if (!host)
+               return -ENOMEM;
+       ap = host->ports[0];
+
+       /* Set up the PCI device */
+       rc = pcim_enable_device(dev);
+       if (rc)
+               return rc;
+       rc = pcim_iomap_regions(dev, 1 << 0, DRV_NAME);
+       if (rc == -EBUSY)
+               pcim_pin_device(dev);
+       if (rc)
+               return rc;
+
+       host->iomap = pcim_iomap_table(dev);
+       rc = pci_set_dma_mask(dev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(dev, ATA_DMA_MASK);
+       if (rc)
+               return rc;
+       pci_set_master(dev);
+
+       /* Set up the register mappings */
+       base = host->iomap[0];
+       if (!base)
+               return -ENOMEM;
+       ap->ops = &ninja32_port_ops;
+       ap->pio_mask = 0x1F;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+       ap->ioaddr.cmd_addr = base + 0x10;
+       ap->ioaddr.ctl_addr = base + 0x1E;
+       ap->ioaddr.altstatus_addr = base + 0x1E;
+       ap->ioaddr.bmdma_addr = base;
+       ata_std_ports(&ap->ioaddr);
+
+       iowrite8(0x05, base + 0x01);    /* Enable interrupt lines */
+       iowrite8(0xB3, base + 0x02);    /* Burst, ?? setup */
+       iowrite8(0x00, base + 0x04);    /* WAIT0 ? */
+       /* FIXME: Should we disable them at remove ? */
+       return ata_host_activate(host, dev->irq, ata_interrupt,
+                                IRQF_SHARED, &ninja32_sht);
+}
+
+static const struct pci_device_id ninja32[] = {
+       { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { },
+};
+
+static struct pci_driver ninja32_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = ninja32,
+       .probe          = ninja32_init_one,
+       .remove         = ata_pci_remove_one
+};
+
+static int __init ninja32_init(void)
+{
+       return pci_register_driver(&ninja32_pci_driver);
+}
+
+static void __exit ninja32_exit(void)
+{
+       pci_unregister_driver(&ninja32_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Ninja32 ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ninja32);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ninja32_init);
+module_exit(ninja32_exit);
index fd36099428a45cbf85b84a46d457bcef57a56209..3e7f6a9da28bd941965c1d5fd887be1054347a7c 100644 (file)
@@ -42,7 +42,7 @@
 
 
 #define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.2"
+#define DRV_VERSION "0.3.3"
 
 /*
  *     Private data structure to glue stuff together
@@ -86,6 +86,47 @@ static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_d
        return ata_do_set_mode(link, r_failed_dev);
 }
 
+/**
+ *     pcmcia_set_mode_8bit    -       PCMCIA specific mode setup
+ *     @link: link
+ *     @r_failed_dev: Return pointer for failed device
+ *
+ *     For the simple emulated 8bit stuff the less we do the better.
+ */
+
+static int pcmcia_set_mode_8bit(struct ata_link *link,
+                               struct ata_device **r_failed_dev)
+{
+       return 0;
+}
+
+/**
+ *     ata_data_xfer_8bit       -      Transfer data by 8bit PIO
+ *     @dev: device to target
+ *     @buf: data buffer
+ *     @buflen: buffer length
+ *     @rw: read/write
+ *
+ *     Transfer data from/to the device data register by 8 bit PIO.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
+                               unsigned char *buf, unsigned int buflen, int rw)
+{
+       struct ata_port *ap = dev->link->ap;
+
+       if (rw == READ)
+               ioread8_rep(ap->ioaddr.data_addr, buf, buflen);
+       else
+               iowrite8_rep(ap->ioaddr.data_addr, buf, buflen);
+
+       return buflen;
+}
+
+
 static struct scsi_host_template pcmcia_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -129,6 +170,31 @@ static struct ata_port_operations pcmcia_port_ops = {
        .port_start     = ata_sff_port_start,
 };
 
+static struct ata_port_operations pcmcia_8bit_port_ops = {
+       .set_mode       = pcmcia_set_mode_8bit,
+       .tf_load        = ata_tf_load,
+       .tf_read        = ata_tf_read,
+       .check_status   = ata_check_status,
+       .exec_command   = ata_exec_command,
+       .dev_select     = ata_std_dev_select,
+
+       .freeze         = ata_bmdma_freeze,
+       .thaw           = ata_bmdma_thaw,
+       .error_handler  = ata_bmdma_error_handler,
+       .post_internal_cmd = ata_bmdma_post_internal_cmd,
+       .cable_detect   = ata_cable_40wire,
+
+       .qc_prep        = ata_qc_prep,
+       .qc_issue       = ata_qc_issue_prot,
+
+       .data_xfer      = ata_data_xfer_8bit,
+
+       .irq_clear      = ata_bmdma_irq_clear,
+       .irq_on         = ata_irq_on,
+
+       .port_start     = ata_sff_port_start,
+};
+
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
@@ -153,9 +219,12 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
                cistpl_cftable_entry_t dflt;
        } *stk = NULL;
        cistpl_cftable_entry_t *cfg;
-       int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
+       int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
        unsigned long io_base, ctl_base;
        void __iomem *io_addr, *ctl_addr;
+       int n_ports = 1;
+
+       struct ata_port_operations *ops = &pcmcia_port_ops;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (info == NULL)
@@ -282,27 +351,32 @@ next_entry:
        /* FIXME: Could be more ports at base + 0x10 but we only deal with
           one right now */
        if (pdev->io.NumPorts1 >= 0x20)
-               printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n");
+               n_ports = 2;
 
+       if (pdev->manf_id == 0x0097 && pdev->card_id == 0x1620)
+               ops = &pcmcia_8bit_port_ops;
        /*
         *      Having done the PCMCIA plumbing the ATA side is relatively
         *      sane.
         */
        ret = -ENOMEM;
-       host = ata_host_alloc(&pdev->dev, 1);
+       host = ata_host_alloc(&pdev->dev, n_ports);
        if (!host)
                goto failed;
-       ap = host->ports[0];
 
-       ap->ops = &pcmcia_port_ops;
-       ap->pio_mask = 1;               /* ISA so PIO 0 cycles */
-       ap->flags |= ATA_FLAG_SLAVE_POSS;
-       ap->ioaddr.cmd_addr = io_addr;
-       ap->ioaddr.altstatus_addr = ctl_addr;
-       ap->ioaddr.ctl_addr = ctl_addr;
-       ata_std_ports(&ap->ioaddr);
+       for (p = 0; p < n_ports; p++) {
+               ap = host->ports[p];
 
-       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+               ap->ops = ops;
+               ap->pio_mask = 1;               /* ISA so PIO 0 cycles */
+               ap->flags |= ATA_FLAG_SLAVE_POSS;
+               ap->ioaddr.cmd_addr = io_addr + 0x10 * p;
+               ap->ioaddr.altstatus_addr = ctl_addr + 0x10 * p;
+               ap->ioaddr.ctl_addr = ctl_addr + 0x10 * p;
+               ata_std_ports(&ap->ioaddr);
+
+               ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+       }
 
        /* activate */
        ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
@@ -360,6 +434,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
        PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
+       PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620),        /* TI emulated */
        PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
        PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
        PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),        /* Samsung */
index 2622577521a13386f655aa70d922f2a94596efd2..028af5dbeed6a596c4e59fc259dabc28f98436de 100644 (file)
@@ -348,7 +348,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long
        ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
                          ATA_ID_PROD_LEN + 1);
        /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
-       if (strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+       if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6)
                mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
 
        return ata_pci_default_filter(adev, mask);
index bc7c2d5d8d5ecee9fbc5fa93e98b19d7fb783e26..3ed866723e0c3c3187ca8071e28857a3672b4412 100644 (file)
@@ -168,8 +168,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
        pdc202xx_set_dmamode(ap, qc->dev);
 
        /* Cases the state machine will not complete correctly without help */
-       if ((tf->flags & ATA_TFLAG_LBA48) ||  tf->protocol == ATA_PROT_ATAPI_DMA)
-       {
+       if ((tf->flags & ATA_TFLAG_LBA48) ||  tf->protocol == ATAPI_PROT_DMA) {
                len = qc->nbytes / 2;
 
                if (tf->flags & ATA_TFLAG_WRITE)
@@ -208,15 +207,15 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
        void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
 
        /* Cases the state machine will not complete correctly */
-       if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
+       if (tf->protocol == ATAPI_PROT_DMA || (tf->flags & ATA_TFLAG_LBA48)) {
                iowrite32(0, atapi_reg);
                iowrite8(ioread8(clock) & ~sel66, clock);
        }
        /* Flip back to 33Mhz for PIO */
        if (adev->dma_mode >= XFER_UDMA_2)
                iowrite8(ioread8(clock) & ~sel66, clock);
-
        ata_bmdma_stop(qc);
+       pdc202xx_set_piomode(ap, adev);
 }
 
 /**
@@ -233,6 +232,35 @@ static void pdc2026x_dev_config(struct ata_device *adev)
        adev->max_sectors = 256;
 }
 
+static int pdc2026x_port_start(struct ata_port *ap)
+{
+       void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+       if (bmdma) {
+               /* Enable burst mode */
+               u8 burst = ioread8(bmdma + 0x1f);
+               iowrite8(burst | 0x01, bmdma + 0x1f);
+       }
+       return ata_sff_port_start(ap);
+}
+
+/**
+ *     pdc2026x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command
+ *     @qc: Metadata associated with taskfile to check
+ *
+ *     Just say no - not supported on older Promise.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ *
+ *     RETURNS: 0 when ATAPI DMA can be used
+ *              1 otherwise
+ */
+
+static int pdc2026x_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+       return 1;
+}
+
 static struct scsi_host_template pdc202xx_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -300,6 +328,7 @@ static struct ata_port_operations pdc2026x_port_ops = {
        .post_internal_cmd = ata_bmdma_post_internal_cmd,
        .cable_detect   = pdc2026x_cable_detect,
 
+       .check_atapi_dma= pdc2026x_check_atapi_dma,
        .bmdma_setup    = ata_bmdma_setup,
        .bmdma_start    = pdc2026x_bmdma_start,
        .bmdma_stop     = pdc2026x_bmdma_stop,
@@ -313,7 +342,7 @@ static struct ata_port_operations pdc2026x_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
 
-       .port_start     = ata_sff_port_start,
+       .port_start     = pdc2026x_port_start,
 };
 
 static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 7d4c696c4cb6b8cb5ccaa86a6ed893856ae3497f..9f308ed76cc83fc3070469d491033d9f4ef92299 100644 (file)
@@ -124,31 +124,33 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
        return ata_qc_issue_prot(qc);
 }
 
-static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf,
+                                 unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
-       int slop = buflen & 3;
+       if (ata_id_has_dword_io(dev->id)) {
+               struct ata_port *ap = dev->link->ap;
+               int slop = buflen & 3;
 
-       if (ata_id_has_dword_io(adev->id)) {
-               if (write_data)
-                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-               else
+               if (rw == READ)
                        ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+               else
+                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
                if (unlikely(slop)) {
                        u32 pad;
-                       if (write_data) {
-                               memcpy(&pad, buf + buflen - slop, slop);
-                               pad = le32_to_cpu(pad);
-                               iowrite32(pad, ap->ioaddr.data_addr);
-                       } else {
-                               pad = ioread32(ap->ioaddr.data_addr);
-                               pad = cpu_to_le32(pad);
+                       if (rw == READ) {
+                               pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
                                memcpy(buf + buflen - slop, &pad, slop);
+                       } else {
+                               memcpy(&pad, buf + buflen - slop, slop);
+                               iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
                        }
+                       buflen += 4 - slop;
                }
        } else
-               ata_data_xfer(adev, buf, buflen, write_data);
+               buflen = ata_data_xfer(dev, buf, buflen, rw);
+
+       return buflen;
 }
 
 static struct scsi_host_template qdi_sht = {
index ea2ef9fc15be6e2aa131497cc387b613c9466066..55055b27524cfa9efd2771a96d1d44fe7dcc624b 100644 (file)
@@ -768,45 +768,47 @@ static u8 scc_bmdma_status (struct ata_port *ap)
 
 /**
  *     scc_data_xfer - Transfer data by PIO
- *     @adev: device for this I/O
+ *     @dev: device for this I/O
  *     @buf: data buffer
  *     @buflen: buffer length
- *     @write_data: read/write
+ *     @rw: read/write
  *
  *     Note: Original code is ata_data_xfer().
  */
 
-static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
-                          unsigned int buflen, int write_data)
+static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
+                                  unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
+       struct ata_port *ap = dev->link->ap;
        unsigned int words = buflen >> 1;
        unsigned int i;
        u16 *buf16 = (u16 *) buf;
        void __iomem *mmio = ap->ioaddr.data_addr;
 
        /* Transfer multiple of 2 bytes */
-       if (write_data) {
-               for (i = 0; i < words; i++)
-                       out_be32(mmio, cpu_to_le16(buf16[i]));
-       } else {
+       if (rw == READ)
                for (i = 0; i < words; i++)
                        buf16[i] = le16_to_cpu(in_be32(mmio));
-       }
+       else
+               for (i = 0; i < words; i++)
+                       out_be32(mmio, cpu_to_le16(buf16[i]));
 
        /* Transfer trailing 1 byte, if any. */
        if (unlikely(buflen & 0x01)) {
                u16 align_buf[1] = { 0 };
                unsigned char *trailing_buf = buf + buflen - 1;
 
-               if (write_data) {
-                       memcpy(align_buf, trailing_buf, 1);
-                       out_be32(mmio, cpu_to_le16(align_buf[0]));
-               } else {
+               if (rw == READ) {
                        align_buf[0] = le16_to_cpu(in_be32(mmio));
                        memcpy(trailing_buf, align_buf, 1);
+               } else {
+                       memcpy(align_buf, trailing_buf, 1);
+                       out_be32(mmio, cpu_to_le16(align_buf[0]));
                }
+               words++;
        }
+
+       return words << 1;
 }
 
 /**
index 8bed888737206cae257c43ae9f0a600568bf91cc..9c523fbf529ead0d92fe8c8d60356be5f0c5cbbd 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_serverworks"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
 
 #define SVWKS_CSB5_REVISION_NEW        0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 #define SVWKS_CSB6_REVISION    0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
@@ -102,7 +102,7 @@ static int osb4_cable(struct ata_port *ap) {
 }
 
 /**
- *     csb4_cable      -       CSB5/6 cable detect
+ *     csb_cable       -       CSB5/6 cable detect
  *     @ap: ATA port to check
  *
  *     Serverworks default arrangement is to use the drive side detection
@@ -110,7 +110,7 @@ static int osb4_cable(struct ata_port *ap) {
  */
 
 static int csb_cable(struct ata_port *ap) {
-       return ATA_CBL_PATA80;
+       return ATA_CBL_PATA_UNK;
 }
 
 struct sv_cable_table {
@@ -231,7 +231,6 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo
        return ata_pci_default_filter(adev, mask);
 }
 
-
 /**
  *     serverworks_set_piomode -       set initial PIO mode data
  *     @ap: ATA interface
@@ -243,7 +242,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo
 static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
        static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-       int offset = 1 + (2 * ap->port_no) - adev->devno;
+       int offset = 1 + 2 * ap->port_no - adev->devno;
        int devbits = (2 * ap->port_no + adev->devno) * 4;
        u16 csb5_pio;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
index 453d72bf259831f532fe32804edaea56438ec1c9..39627ab684bf9dc8d2bf55ff94443b834bcf863e 100644 (file)
@@ -185,7 +185,8 @@ static int via_cable_detect(struct ata_port *ap) {
        if (ata66 & (0x10100000 >> (16 * ap->port_no)))
                return ATA_CBL_PATA80;
        /* Check with ACPI so we can spot BIOS reported SATA bridges */
-       if (ata_acpi_cbl_80wire(ap))
+       if (ata_acpi_init_gtm(ap) &&
+           ata_acpi_cbl_80wire(ap, ata_acpi_init_gtm(ap)))
                return ATA_CBL_PATA80;
        return ATA_CBL_PATA40;
 }
index 311cdb3a5566caec1d60e788327f3004fc662b8d..99c92eda217b730c12994c24422debddcd14154f 100644 (file)
@@ -92,31 +92,33 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
 }
 
 
-static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int winbond_data_xfer(struct ata_device *dev,
+                       unsigned char *buf, unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
+       struct ata_port *ap = dev->link->ap;
        int slop = buflen & 3;
 
-       if (ata_id_has_dword_io(adev->id)) {
-               if (write_data)
-                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-               else
+       if (ata_id_has_dword_io(dev->id)) {
+               if (rw == READ)
                        ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+               else
+                       iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
                if (unlikely(slop)) {
                        u32 pad;
-                       if (write_data) {
-                               memcpy(&pad, buf + buflen - slop, slop);
-                               pad = le32_to_cpu(pad);
-                               iowrite32(pad, ap->ioaddr.data_addr);
-                       } else {
-                               pad = ioread32(ap->ioaddr.data_addr);
-                               pad = cpu_to_le16(pad);
+                       if (rw == READ) {
+                               pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
                                memcpy(buf + buflen - slop, &pad, slop);
+                       } else {
+                               memcpy(&pad, buf + buflen - slop, slop);
+                               iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
                        }
+                       buflen += 4 - slop;
                }
        } else
-               ata_data_xfer(adev, buf, buflen, write_data);
+               buflen = ata_data_xfer(dev, buf, buflen, rw);
+
+       return buflen;
 }
 
 static struct scsi_host_template winbond_sht = {
@@ -193,7 +195,7 @@ static __init int winbond_init_one(unsigned long port)
        reg = winbond_readcfg(port, 0x81);
 
        if (!(reg & 0x03))              /* Disabled */
-               return 0;
+               return -ENODEV;
 
        for (i = 0; i < 2 ; i ++) {
                unsigned long cmd_port = 0x1F0 - (0x80 * i);
index bd4c2a3c88d7f17794b3505794ff69c1f6c7c895..8e1b7e9c0ae42b7fe66ed4fb047234dbeee10c46 100644 (file)
@@ -321,8 +321,9 @@ static int adma_fill_sg(struct ata_queued_cmd *qc)
        u8  *buf = pp->pkt, *last_buf = NULL;
        int i = (2 + buf[3]) * 8;
        u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
+       unsigned int si;
 
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u32 addr;
                u32 len;
 
@@ -455,7 +456,7 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
                adma_packet_start(qc);
                return 0;
 
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                BUG();
                break;
 
index d015b4adcfe098402fd9e8b307a829f580e36636..922d7b2efba8cf50b6d2a1b8bb144630474623e1 100644 (file)
@@ -333,13 +333,14 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
        struct prde *prd_ptr_to_indirect_ext = NULL;
        unsigned indirect_ext_segment_sz = 0;
        dma_addr_t indirect_ext_segment_paddr;
+       unsigned int si;
 
        VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd);
 
        indirect_ext_segment_paddr = cmd_desc_paddr +
            SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16;
 
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                dma_addr_t sg_addr = sg_dma_address(sg);
                u32 sg_len = sg_dma_len(sg);
 
@@ -417,7 +418,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
        }
 
        /* setup "ACMD - atapi command" in cmd. desc. if this is ATAPI cmd */
-       if (is_atapi_taskfile(&qc->tf)) {
+       if (ata_is_atapi(qc->tf.protocol)) {
                desc_info |= ATAPI_CMD;
                memset((void *)&cd->acmd, 0, 32);
                memcpy((void *)&cd->acmd, qc->cdb, qc->dev->cdb_len);
index 323c087e8cc122bb04189ee361952147c6b8faa8..96e614a1c1692c896c52d6a6fb71c13bb03470d9 100644 (file)
@@ -585,7 +585,7 @@ static struct ata_port_operations inic_port_ops = {
 };
 
 static struct ata_port_info inic_port_info = {
-       /* For some reason, ATA_PROT_ATAPI is broken on this
+       /* For some reason, ATAPI_PROT_PIO is broken on this
         * controller, and no, PIO_POLLING does't fix it.  It somehow
         * manages to report the wrong ireason and ignoring ireason
         * results in machine lock up.  Tell libata to always prefer
index 37b850ae084559d573e125a096cbdfe0eac3f958..7e72463a90eb8b84a9ea76ad13e91aea2b5249d8 100644 (file)
@@ -1136,9 +1136,10 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
        struct mv_port_priv *pp = qc->ap->private_data;
        struct scatterlist *sg;
        struct mv_sg *mv_sg, *last_sg = NULL;
+       unsigned int si;
 
        mv_sg = pp->sg_tbl;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                dma_addr_t addr = sg_dma_address(sg);
                u32 sg_len = sg_dma_len(sg);
 
index ed5dc7cb50cd58d408c53dea9fe7d06de7eef947..a0f98fdab7a0c04da379acd19f72add501e69aa0 100644 (file)
@@ -1336,21 +1336,18 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
 static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
 {
        struct nv_adma_port_priv *pp = qc->ap->private_data;
-       unsigned int idx;
        struct nv_adma_prd *aprd;
        struct scatterlist *sg;
+       unsigned int si;
 
        VPRINTK("ENTER\n");
 
-       idx = 0;
-
-       ata_for_each_sg(sg, qc) {
-               aprd = (idx < 5) ? &cpb->aprd[idx] :
-                              &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];
-               nv_adma_fill_aprd(qc, sg, idx, aprd);
-               idx++;
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               aprd = (si < 5) ? &cpb->aprd[si] :
+                              &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (si-5)];
+               nv_adma_fill_aprd(qc, sg, si, aprd);
        }
-       if (idx > 5)
+       if (si > 5)
                cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
        else
                cpb->next_aprd = cpu_to_le64(0);
@@ -1995,17 +1992,14 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct scatterlist *sg;
-       unsigned int idx;
        struct nv_swncq_port_priv *pp = ap->private_data;
        struct ata_prd *prd;
-
-       WARN_ON(qc->__sg == NULL);
-       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+       unsigned int si, idx;
 
        prd = pp->prd + ATA_MAX_PRD * qc->tag;
 
        idx = 0;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u32 addr, offset;
                u32 sg_len, len;
 
@@ -2027,8 +2021,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
                }
        }
 
-       if (idx)
-               prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+       prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
index 7914def54fa3552fcbd2134d97f469eaccd859b6..a07d319f6e8cc1d6e2b42d12c5d7d3c6105e7d4a 100644 (file)
@@ -450,19 +450,19 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
        struct pdc_port_priv *pp = ap->private_data;
        u8 *buf = pp->pkt;
        u32 *buf32 = (u32 *) buf;
-       unsigned int dev_sel, feature, nbytes;
+       unsigned int dev_sel, feature;
 
        /* set control bits (byte 0), zero delay seq id (byte 3),
         * and seq id (byte 2)
         */
        switch (qc->tf.protocol) {
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                if (!(qc->tf.flags & ATA_TFLAG_WRITE))
                        buf32[0] = cpu_to_le32(PDC_PKT_READ);
                else
                        buf32[0] = 0;
                break;
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_NODATA:
                buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
                break;
        default:
@@ -473,45 +473,37 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
        buf32[2] = 0;                           /* no next-packet */
 
        /* select drive */
-       if (sata_scr_valid(&ap->link)) {
+       if (sata_scr_valid(&ap->link))
                dev_sel = PDC_DEVICE_SATA;
-       } else {
-               dev_sel = ATA_DEVICE_OBS;
-               if (qc->dev->devno != 0)
-                       dev_sel |= ATA_DEV1;
-       }
+       else
+               dev_sel = qc->tf.device;
+
        buf[12] = (1 << 5) | ATA_REG_DEVICE;
        buf[13] = dev_sel;
        buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY;
        buf[15] = dev_sel; /* once more, waiting for BSY to clear */
 
        buf[16] = (1 << 5) | ATA_REG_NSECT;
-       buf[17] = 0x00;
+       buf[17] = qc->tf.nsect;
        buf[18] = (1 << 5) | ATA_REG_LBAL;
-       buf[19] = 0x00;
+       buf[19] = qc->tf.lbal;
 
        /* set feature and byte counter registers */
-       if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) {
+       if (qc->tf.protocol != ATAPI_PROT_DMA)
                feature = PDC_FEATURE_ATAPI_PIO;
-               /* set byte counter register to real transfer byte count */
-               nbytes = qc->nbytes;
-               if (nbytes > 0xffff)
-                       nbytes = 0xffff;
-       } else {
+       else
                feature = PDC_FEATURE_ATAPI_DMA;
-               /* set byte counter register to 0 */
-               nbytes = 0;
-       }
+
        buf[20] = (1 << 5) | ATA_REG_FEATURE;
        buf[21] = feature;
        buf[22] = (1 << 5) | ATA_REG_BYTEL;
-       buf[23] = nbytes & 0xFF;
+       buf[23] = qc->tf.lbam;
        buf[24] = (1 << 5) | ATA_REG_BYTEH;
-       buf[25] = (nbytes >> 8) & 0xFF;
+       buf[25] = qc->tf.lbah;
 
        /* send ATAPI packet command 0xA0 */
        buf[26] = (1 << 5) | ATA_REG_CMD;
-       buf[27] = ATA_CMD_PACKET;
+       buf[27] = qc->tf.command;
 
        /* select drive and check DRQ */
        buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY;
@@ -541,17 +533,15 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct scatterlist *sg;
-       unsigned int idx;
        const u32 SG_COUNT_ASIC_BUG = 41*4;
+       unsigned int si, idx;
+       u32 len;
 
        if (!(qc->flags & ATA_QCFLAG_DMAMAP))
                return;
 
-       WARN_ON(qc->__sg == NULL);
-       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
        idx = 0;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u32 addr, offset;
                u32 sg_len, len;
 
@@ -578,29 +568,27 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
                }
        }
 
-       if (idx) {
-               u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
+       len = le32_to_cpu(ap->prd[idx - 1].flags_len);
 
-               if (len > SG_COUNT_ASIC_BUG) {
-                       u32 addr;
+       if (len > SG_COUNT_ASIC_BUG) {
+               u32 addr;
 
-                       VPRINTK("Splitting last PRD.\n");
+               VPRINTK("Splitting last PRD.\n");
 
-                       addr = le32_to_cpu(ap->prd[idx - 1].addr);
-                       ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
-                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
+               addr = le32_to_cpu(ap->prd[idx - 1].addr);
+               ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
+               VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
 
-                       addr = addr + len - SG_COUNT_ASIC_BUG;
-                       len = SG_COUNT_ASIC_BUG;
-                       ap->prd[idx].addr = cpu_to_le32(addr);
-                       ap->prd[idx].flags_len = cpu_to_le32(len);
-                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+               addr = addr + len - SG_COUNT_ASIC_BUG;
+               len = SG_COUNT_ASIC_BUG;
+               ap->prd[idx].addr = cpu_to_le32(addr);
+               ap->prd[idx].flags_len = cpu_to_le32(len);
+               VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
 
-                       idx++;
-               }
-
-               ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+               idx++;
        }
+
+       ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 static void pdc_qc_prep(struct ata_queued_cmd *qc)
@@ -627,14 +615,14 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
                pdc_pkt_footer(&qc->tf, pp->pkt, i);
                break;
 
-       case ATA_PROT_ATAPI:
+       case ATAPI_PROT_PIO:
                pdc_fill_sg(qc);
                break;
 
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                pdc_fill_sg(qc);
                /*FALLTHROUGH*/
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_NODATA:
                pdc_atapi_pkt(qc);
                break;
 
@@ -754,8 +742,8 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
        case ATA_PROT_NODATA:
-       case ATA_PROT_ATAPI_DMA:
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_DMA:
+       case ATAPI_PROT_NODATA:
                qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
                ata_qc_complete(qc);
                handled = 1;
@@ -900,7 +888,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
 static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 {
        switch (qc->tf.protocol) {
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_NODATA:
                if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
                        break;
                /*FALLTHROUGH*/
@@ -908,7 +896,7 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
                if (qc->tf.flags & ATA_TFLAG_POLLING)
                        break;
                /*FALLTHROUGH*/
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
        case ATA_PROT_DMA:
                pdc_packet_start(qc);
                return 0;
@@ -922,16 +910,14 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
 {
-       WARN_ON(tf->protocol == ATA_PROT_DMA ||
-               tf->protocol == ATA_PROT_ATAPI_DMA);
+       WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA);
        ata_tf_load(ap, tf);
 }
 
 static void pdc_exec_command_mmio(struct ata_port *ap,
                                  const struct ata_taskfile *tf)
 {
-       WARN_ON(tf->protocol == ATA_PROT_DMA ||
-               tf->protocol == ATA_PROT_ATAPI_DMA);
+       WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA);
        ata_exec_command(ap, tf);
 }
 
index 6ee5e190262de8d55f9689450e8fb08aea67eb77..00d6000e546ff5ba1b3b2bdaa08b66bc130b8555 100644 (file)
@@ -46,7 +46,7 @@ static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
                                          unsigned int devno, u8 *buf)
 {
        u8 dev_reg;
-       u32 *buf32 = (u32 *) buf;
+       __le32 *buf32 = (__le32 *) buf;
 
        /* set control bits (byte 0), zero delay seq id (byte 3),
         * and seq id (byte 2)
index 2f1de6ec044c52f2dd5a4318ba5d2812e00db382..91cc12c82040d0bb4117649737c46dcc75f7bb31 100644 (file)
@@ -270,7 +270,7 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 static void qs_error_handler(struct ata_port *ap)
 {
        qs_enter_reg_mode(ap);
-       ata_do_eh(ap, qs_prereset, ata_std_softreset, NULL,
+       ata_do_eh(ap, qs_prereset, NULL, sata_std_hardreset,
                  ata_std_postreset);
 }
 
@@ -287,14 +287,10 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
        struct scatterlist *sg;
        struct ata_port *ap = qc->ap;
        struct qs_port_priv *pp = ap->private_data;
-       unsigned int nelem;
        u8 *prd = pp->pkt + QS_CPB_BYTES;
+       unsigned int si;
 
-       WARN_ON(qc->__sg == NULL);
-       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
-       nelem = 0;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u64 addr;
                u32 len;
 
@@ -306,12 +302,11 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
                *(__le32 *)prd = cpu_to_le32(len);
                prd += sizeof(u64);
 
-               VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
+               VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", si,
                                        (unsigned long long)addr, len);
-               nelem++;
        }
 
-       return nelem;
+       return si;
 }
 
 static void qs_qc_prep(struct ata_queued_cmd *qc)
@@ -376,7 +371,7 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
                qs_packet_start(qc);
                return 0;
 
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                BUG();
                break;
 
index f5119bf40c24f0e9e65219208e2fd65a47137e1f..0b8191b52f97b8e3b1d032eca7a01e6d7069e898 100644 (file)
@@ -416,15 +416,14 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                 */
 
                /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
-                * The flag was turned on only for atapi devices.
-                * No need to check is_atapi_taskfile(&qc->tf) again.
+                * The flag was turned on only for atapi devices.  No
+                * need to check ata_is_atapi(qc->tf.protocol) again.
                 */
                if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
                        goto err_hsm;
                break;
        case HSM_ST_LAST:
-               if (qc->tf.protocol == ATA_PROT_DMA ||
-                   qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+               if (ata_is_dma(qc->tf.protocol)) {
                        /* clear DMA-Start bit */
                        ap->ops->bmdma_stop(qc);
 
@@ -451,8 +450,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
        /* kick HSM in the ass */
        ata_hsm_move(ap, qc, status, 0);
 
-       if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
-                                      qc->tf.protocol == ATA_PROT_ATAPI_DMA))
+       if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
                ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2);
 
        return;
index 96fd5260446db812dbe938c903b4e47779dfc363..b4b1f91ea693942f3292bcdbb885e11405c89376 100644 (file)
@@ -301,7 +301,7 @@ static struct sil24_cerr_info {
        [PORT_CERR_PKT_PROT]    = { AC_ERR_HSM, ATA_EH_SOFTRESET,
                                    "invalid data directon for ATAPI CDB" },
        [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
-                                    "SGT no on qword boundary" },
+                                    "SGT not on qword boundary" },
        [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
                                    "PCI target abort while fetching SGT" },
        [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
@@ -813,8 +813,9 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
 {
        struct scatterlist *sg;
        struct sil24_sge *last_sge = NULL;
+       unsigned int si;
 
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                sge->addr = cpu_to_le64(sg_dma_address(sg));
                sge->cnt = cpu_to_le32(sg_dma_len(sg));
                sge->flags = 0;
@@ -823,8 +824,7 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
                sge++;
        }
 
-       if (likely(last_sge))
-               last_sge->flags = cpu_to_le32(SGE_TRM);
+       last_sge->flags = cpu_to_le32(SGE_TRM);
 }
 
 static int sil24_qc_defer(struct ata_queued_cmd *qc)
@@ -832,16 +832,29 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc)
        struct ata_link *link = qc->dev->link;
        struct ata_port *ap = link->ap;
        u8 prot = qc->tf.protocol;
-       int is_atapi = (prot == ATA_PROT_ATAPI ||
-                       prot == ATA_PROT_ATAPI_NODATA ||
-                       prot == ATA_PROT_ATAPI_DMA);
-
-       /* ATAPI commands completing with CHECK_SENSE cause various
-        * weird problems if other commands are active.  PMP DMA CS
-        * errata doesn't cover all and HSM violation occurs even with
-        * only one other device active.  Always run an ATAPI command
-        * by itself.
-        */
+
+       /*
+        * There is a bug in the chip:
+        * Port LRAM Causes the PRB/SGT Data to be Corrupted
+        * If the host issues a read request for LRAM and SActive registers
+        * while active commands are available in the port, PRB/SGT data in
+        * the LRAM can become corrupted. This issue applies only when
+        * reading from, but not writing to, the LRAM.
+        *
+        * Therefore, reading LRAM when there is no particular error [and
+        * other commands may be outstanding] is prohibited.
+        *
+        * To avoid this bug there are two situations where a command must run
+        * exclusive of any other commands on the port:
+        *
+        * - ATAPI commands which check the sense data
+        * - Passthrough ATA commands which always have ATA_QCFLAG_RESULT_TF
+        *   set.
+        *
+        */
+       int is_excl = (ata_is_atapi(prot) ||
+                      (qc->flags & ATA_QCFLAG_RESULT_TF));
+
        if (unlikely(ap->excl_link)) {
                if (link == ap->excl_link) {
                        if (ap->nr_active_links)
@@ -849,7 +862,7 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc)
                        qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
                } else
                        return ATA_DEFER_PORT;
-       } else if (unlikely(is_atapi)) {
+       } else if (unlikely(is_excl)) {
                ap->excl_link = link;
                if (ap->nr_active_links)
                        return ATA_DEFER_PORT;
@@ -870,35 +883,21 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
 
        cb = &pp->cmd_block[sil24_tag(qc->tag)];
 
-       switch (qc->tf.protocol) {
-       case ATA_PROT_PIO:
-       case ATA_PROT_DMA:
-       case ATA_PROT_NCQ:
-       case ATA_PROT_NODATA:
+       if (!ata_is_atapi(qc->tf.protocol)) {
                prb = &cb->ata.prb;
                sge = cb->ata.sge;
-               break;
-
-       case ATA_PROT_ATAPI:
-       case ATA_PROT_ATAPI_DMA:
-       case ATA_PROT_ATAPI_NODATA:
+       } else {
                prb = &cb->atapi.prb;
                sge = cb->atapi.sge;
                memset(cb->atapi.cdb, 0, 32);
                memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
 
-               if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
+               if (ata_is_data(qc->tf.protocol)) {
                        if (qc->tf.flags & ATA_TFLAG_WRITE)
                                ctrl = PRB_CTRL_PACKET_WRITE;
                        else
                                ctrl = PRB_CTRL_PACKET_READ;
                }
-               break;
-
-       default:
-               prb = NULL;     /* shut up, gcc */
-               sge = NULL;
-               BUG();
        }
 
        prb->ctrl = cpu_to_le16(ctrl);
@@ -1079,10 +1078,13 @@ static void sil24_error_intr(struct ata_port *ap)
                if (ci && ci->desc) {
                        err_mask |= ci->err_mask;
                        action |= ci->action;
+                       if (action & ATA_EH_RESET_MASK)
+                               freeze = 1;
                        ata_ehi_push_desc(ehi, "%s", ci->desc);
                } else {
                        err_mask |= AC_ERR_OTHER;
                        action |= ATA_EH_SOFTRESET;
+                       freeze = 1;
                        ata_ehi_push_desc(ehi, "unknown command error %d",
                                          cerr);
                }
index 4d857185f33b2627cdfc43b52cea1b2f9848ecac..e3d56bc6726db30eb3916d3a4821c890bbf86ebc 100644 (file)
@@ -334,7 +334,7 @@ static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
 {
        u32 addr;
        unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
-       u32 *buf32 = (u32 *) buf;
+       __le32 *buf32 = (__le32 *) buf;
 
        /* output ATA packet S/G table */
        addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
@@ -356,7 +356,7 @@ static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
 {
        u32 addr;
        unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
-       u32 *buf32 = (u32 *) buf;
+       __le32 *buf32 = (__le32 *) buf;
 
        /* output Host DMA packet S/G table */
        addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
@@ -377,7 +377,7 @@ static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
                                            unsigned int portno)
 {
        unsigned int i, dw;
-       u32 *buf32 = (u32 *) buf;
+       __le32 *buf32 = (__le32 *) buf;
        u8 dev_reg;
 
        unsigned int dimm_sg = PDC_20621_DIMM_BASE +
@@ -429,7 +429,8 @@ static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
                                     unsigned int portno)
 {
        unsigned int dw;
-       u32 tmp, *buf32 = (u32 *) buf;
+       u32 tmp;
+       __le32 *buf32 = (__le32 *) buf;
 
        unsigned int host_sg = PDC_20621_DIMM_BASE +
                               (PDC_DIMM_WINDOW_STEP * portno) +
@@ -473,7 +474,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
        void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
        void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
        unsigned int portno = ap->port_no;
-       unsigned int i, idx, total_len = 0, sgt_len;
+       unsigned int i, si, idx, total_len = 0, sgt_len;
        u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
 
        WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
@@ -487,7 +488,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
         * Build S/G table
         */
        idx = 0;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                buf[idx++] = cpu_to_le32(sg_dma_address(sg));
                buf[idx++] = cpu_to_le32(sg_dma_len(sg));
                total_len += sg_dma_len(sg);
@@ -700,7 +701,7 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
                pdc20621_packet_start(qc);
                return 0;
 
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                BUG();
                break;
 
index 0bd657f5dd2a4554134e15c92b59b404c95a073b..84672dc57f7afdebd84dbb760cfb3979d590dd97 100644 (file)
@@ -357,7 +357,7 @@ static const struct atmphy_ops idt77105_ops = {
 };
 
 
-int __devinit idt77105_init(struct atm_dev *dev)
+int idt77105_init(struct atm_dev *dev)
 {
        dev->phy = &idt77105_ops;
        return 0;
index 14ced85b3f54d9b087a5dab90dea6914cd17da9e..0c205b000e8b9038e6f175e2f6455e107df71c55 100644 (file)
@@ -625,14 +625,6 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
    if (mac[i] == NULL)
       nicstar_init_eprom(card->membase);
 
-   if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
-   {
-      printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
-      error = 9;
-      ns_init_card_error(card, error);
-      return error;
-   }
-
    /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
    writel(0x00000000, card->membase + VPM);
       
@@ -858,8 +850,6 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
       card->iovpool.count++;
    }
 
-   card->intcnt = 0;
-
    /* Configure NICStAR */
    if (card->rct_size == 4096)
       ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
@@ -868,6 +858,15 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
 
    card->efbie = 1;
 
+   card->intcnt = 0;
+   if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
+   {
+      printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+      error = 9;
+      ns_init_card_error(card, error);
+      return error;
+   }
+
    /* Register device */
    card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
    if (card->atmdev == NULL)
index f04f39c00833cc86dc572f6b00e32e8f0204c903..b1d063cc4fbe0f6903359bf3328566e0e50aee93 100644 (file)
@@ -289,7 +289,7 @@ static const struct atmphy_ops suni_ops = {
 };
 
 
-int __devinit suni_init(struct atm_dev *dev)
+int suni_init(struct atm_dev *dev)
 {
        unsigned char mri;
 
index b39ea3f59c9b77edc9ec636383bcc3f3f3225f4e..63e09c015ca02305e6bb475d3ba8ca78c5677e63 100644 (file)
@@ -11,6 +11,9 @@ obj-$(CONFIG_FW_LOADER)       += firmware_class.o
 obj-$(CONFIG_NUMA)     += node.o
 obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
 obj-$(CONFIG_SMP)      += topology.o
+ifeq ($(CONFIG_SYSFS),y)
+obj-$(CONFIG_MODULES)  += module.o
+endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
index 7370d7cf59888050d374d7a48a03185a06f0df7c..3b43e8a9f87e45e0763c8ae3d7b7d5b539616151 100644 (file)
@@ -61,7 +61,7 @@ attribute_container_classdev_to_container(struct class_device *classdev)
 }
 EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
 
-static struct list_head attribute_container_list;
+static LIST_HEAD(attribute_container_list);
 
 static DEFINE_MUTEX(attribute_container_mutex);
 
@@ -320,9 +320,14 @@ attribute_container_add_attrs(struct class_device *classdev)
        struct class_device_attribute **attrs = cont->attrs;
        int i, error;
 
-       if (!attrs)
+       BUG_ON(attrs && cont->grp);
+
+       if (!attrs && !cont->grp)
                return 0;
 
+       if (cont->grp)
+               return sysfs_create_group(&classdev->kobj, cont->grp);
+
        for (i = 0; attrs[i]; i++) {
                error = class_device_create_file(classdev, attrs[i]);
                if (error)
@@ -378,9 +383,14 @@ attribute_container_remove_attrs(struct class_device *classdev)
        struct class_device_attribute **attrs = cont->attrs;
        int i;
 
-       if (!attrs)
+       if (!attrs && !cont->grp)
                return;
 
+       if (cont->grp) {
+               sysfs_remove_group(&classdev->kobj, cont->grp);
+               return ;
+       }
+
        for (i = 0; attrs[i]; i++)
                class_device_remove_file(classdev, attrs[i]);
 }
@@ -429,10 +439,3 @@ attribute_container_find_class_device(struct attribute_container *cont,
        return cdev;
 }
 EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
-
-int __init
-attribute_container_init(void)
-{
-       INIT_LIST_HEAD(&attribute_container_list);
-       return 0;
-}
index 10b2fb6c9ce68fdbae4a9a4822a298ead5c3732b..c0444146c09a880a51e1b514e9fe8710119a2f67 100644 (file)
@@ -1,6 +1,42 @@
 
-/* initialisation functions */
+/**
+ * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
+ *
+ * @subsys - the struct kset that defines this bus.  This is the main kobject
+ * @drivers_kset - the list of drivers associated with this bus
+ * @devices_kset - the list of devices associated with this bus
+ * @klist_devices - the klist to iterate over the @devices_kset
+ * @klist_drivers - the klist to iterate over the @drivers_kset
+ * @bus_notifier - the bus notifier list for anything that cares about things
+ * on this bus.
+ * @bus - pointer back to the struct bus_type that this structure is associated
+ * with.
+ *
+ * This structure is the one that is the actual kobject allowing struct
+ * bus_type to be statically allocated safely.  Nothing outside of the driver
+ * core should ever touch these fields.
+ */
+struct bus_type_private {
+       struct kset subsys;
+       struct kset *drivers_kset;
+       struct kset *devices_kset;
+       struct klist klist_devices;
+       struct klist klist_drivers;
+       struct blocking_notifier_head bus_notifier;
+       unsigned int drivers_autoprobe:1;
+       struct bus_type *bus;
+};
+
+struct driver_private {
+       struct kobject kobj;
+       struct klist klist_devices;
+       struct klist_node knode_bus;
+       struct module_kobject *mkobj;
+       struct device_driver *driver;
+};
+#define to_driver(obj) container_of(obj, struct driver_private, kobj)
 
+/* initialisation functions */
 extern int devices_init(void);
 extern int buses_init(void);
 extern int classes_init(void);
@@ -13,17 +49,16 @@ static inline int hypervisor_init(void) { return 0; }
 extern int platform_bus_init(void);
 extern int system_bus_init(void);
 extern int cpu_dev_init(void);
-extern int attribute_container_init(void);
 
-extern int bus_add_device(struct device * dev);
-extern void bus_attach_device(struct device * dev);
-extern void bus_remove_device(struct device * dev);
+extern int bus_add_device(struct device *dev);
+extern void bus_attach_device(struct device *dev);
+extern void bus_remove_device(struct device *dev);
 
-extern int bus_add_driver(struct device_driver *);
-extern void bus_remove_driver(struct device_driver *);
+extern int bus_add_driver(struct device_driver *drv);
+extern void bus_remove_driver(struct device_driver *drv);
 
-extern void driver_detach(struct device_driver * drv);
-extern int driver_probe_device(struct device_driver *, struct device *);
+extern void driver_detach(struct device_driver *drv);
+extern int driver_probe_device(struct device_driver *drv, struct device *dev);
 
 extern void sysdev_shutdown(void);
 extern int sysdev_suspend(pm_message_t state);
@@ -44,4 +79,13 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
 
-extern struct kset devices_subsys;
+extern struct kset *devices_kset;
+
+#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)
+extern void module_add_driver(struct module *mod, struct device_driver *drv);
+extern void module_remove_driver(struct device_driver *drv);
+#else
+static inline void module_add_driver(struct module *mod,
+                                    struct device_driver *drv) { }
+static inline void module_remove_driver(struct device_driver *drv) { }
+#endif
index 9a19b071c573aaa7d6fc17cdaa1f86e4a1d38580..f484495b2ad1bd27d83fae5cc661349e9cbdb78c 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  *
 #include "power/power.h"
 
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
-#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
+#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj)
 
 /*
  * sysfs bindings for drivers
  */
 
 #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
-#define to_driver(obj) container_of(obj, struct device_driver, kobj)
 
 
 static int __must_check bus_rescan_devices_helper(struct device *dev,
@@ -32,37 +33,40 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
 
 static struct bus_type *bus_get(struct bus_type *bus)
 {
-       return bus ? container_of(kset_get(&bus->subsys),
-                               struct bus_type, subsys) : NULL;
+       if (bus) {
+               kset_get(&bus->p->subsys);
+               return bus;
+       }
+       return NULL;
 }
 
 static void bus_put(struct bus_type *bus)
 {
-       kset_put(&bus->subsys);
+       if (bus)
+               kset_put(&bus->p->subsys);
 }
 
-static ssize_t
-drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
+                            char *buf)
 {
-       struct driver_attribute * drv_attr = to_drv_attr(attr);
-       struct device_driver * drv = to_driver(kobj);
+       struct driver_attribute *drv_attr = to_drv_attr(attr);
+       struct driver_private *drv_priv = to_driver(kobj);
        ssize_t ret = -EIO;
 
        if (drv_attr->show)
-               ret = drv_attr->show(drv, buf);
+               ret = drv_attr->show(drv_priv->driver, buf);
        return ret;
 }
 
-static ssize_t
-drv_attr_store(struct kobject * kobj, struct attribute * attr,
-              const char * buf, size_t count)
+static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
+                             const char *buf, size_t count)
 {
-       struct driver_attribute * drv_attr = to_drv_attr(attr);
-       struct device_driver * drv = to_driver(kobj);
+       struct driver_attribute *drv_attr = to_drv_attr(attr);
+       struct driver_private *drv_priv = to_driver(kobj);
        ssize_t ret = -EIO;
 
        if (drv_attr->store)
-               ret = drv_attr->store(drv, buf, count);
+               ret = drv_attr->store(drv_priv->driver, buf, count);
        return ret;
 }
 
@@ -71,22 +75,12 @@ static struct sysfs_ops driver_sysfs_ops = {
        .store  = drv_attr_store,
 };
 
-
-static void driver_release(struct kobject * kobj)
+static void driver_release(struct kobject *kobj)
 {
-       /*
-        * Yes this is an empty release function, it is this way because struct
-        * device is always a static object, not a dynamic one.  Yes, this is
-        * not nice and bad, but remember, drivers are code, reference counted
-        * by the module count, not a device, which is really data.  And yes,
-        * in the future I do want to have all drivers be created dynamically,
-        * and am working toward that goal, but it will take a bit longer...
-        *
-        * But do not let this example give _anyone_ the idea that they can
-        * create a release function without any code in it at all, to do that
-        * is almost always wrong.  If you have any questions about this,
-        * please send an email to <greg@kroah.com>
-        */
+       struct driver_private *drv_priv = to_driver(kobj);
+
+       pr_debug("driver: '%s': %s\n", kobject_name(kobj), __FUNCTION__);
+       kfree(drv_priv);
 }
 
 static struct kobj_type driver_ktype = {
@@ -94,34 +88,30 @@ static struct kobj_type driver_ktype = {
        .release        = driver_release,
 };
 
-
 /*
  * sysfs bindings for buses
  */
-
-
-static ssize_t
-bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
+                            char *buf)
 {
-       struct bus_attribute * bus_attr = to_bus_attr(attr);
-       struct bus_type * bus = to_bus(kobj);
+       struct bus_attribute *bus_attr = to_bus_attr(attr);
+       struct bus_type_private *bus_priv = to_bus(kobj);
        ssize_t ret = 0;
 
        if (bus_attr->show)
-               ret = bus_attr->show(bus, buf);
+               ret = bus_attr->show(bus_priv->bus, buf);
        return ret;
 }
 
-static ssize_t
-bus_attr_store(struct kobject * kobj, struct attribute * attr,
-              const char * buf, size_t count)
+static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
+                             const char *buf, size_t count)
 {
-       struct bus_attribute * bus_attr = to_bus_attr(attr);
-       struct bus_type * bus = to_bus(kobj);
+       struct bus_attribute *bus_attr = to_bus_attr(attr);
+       struct bus_type_private *bus_priv = to_bus(kobj);
        ssize_t ret = 0;
 
        if (bus_attr->store)
-               ret = bus_attr->store(bus, buf, count);
+               ret = bus_attr->store(bus_priv->bus, buf, count);
        return ret;
 }
 
@@ -130,24 +120,26 @@ static struct sysfs_ops bus_sysfs_ops = {
        .store  = bus_attr_store,
 };
 
-int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
+int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
 {
        int error;
        if (bus_get(bus)) {
-               error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
+               error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
                bus_put(bus);
        } else
                error = -EINVAL;
        return error;
 }
+EXPORT_SYMBOL_GPL(bus_create_file);
 
-void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
+void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
 {
        if (bus_get(bus)) {
-               sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
+               sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);
                bus_put(bus);
        }
 }
+EXPORT_SYMBOL_GPL(bus_remove_file);
 
 static struct kobj_type bus_ktype = {
        .sysfs_ops      = &bus_sysfs_ops,
@@ -166,7 +158,7 @@ static struct kset_uevent_ops bus_uevent_ops = {
        .filter = bus_uevent_filter,
 };
 
-static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
+static struct kset *bus_kset;
 
 
 #ifdef CONFIG_HOTPLUG
@@ -224,10 +216,13 @@ static ssize_t driver_bind(struct device_driver *drv,
                if (dev->parent)
                        up(&dev->parent->sem);
 
-               if (err > 0)            /* success */
+               if (err > 0) {
+                       /* success */
                        err = count;
-               else if (err == 0)      /* driver didn't accept device */
+               } else if (err == 0) {
+                       /* driver didn't accept device */
                        err = -ENODEV;
+               }
        }
        put_device(dev);
        bus_put(bus);
@@ -237,16 +232,16 @@ static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
 
 static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
 {
-       return sprintf(buf, "%d\n", bus->drivers_autoprobe);
+       return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
 }
 
 static ssize_t store_drivers_autoprobe(struct bus_type *bus,
                                       const char *buf, size_t count)
 {
        if (buf[0] == '0')
-               bus->drivers_autoprobe = 0;
+               bus->p->drivers_autoprobe = 0;
        else
-               bus->drivers_autoprobe = 1;
+               bus->p->drivers_autoprobe = 1;
        return count;
 }
 
@@ -264,49 +259,49 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
 }
 #endif
 
-static struct device * next_device(struct klist_iter * i)
+static struct device *next_device(struct klist_iter *i)
 {
-       struct klist_node * n = klist_next(i);
+       struct klist_node *n = klist_next(i);
        return n ? container_of(n, struct device, knode_bus) : NULL;
 }
 
 /**
- *     bus_for_each_dev - device iterator.
- *     @bus:   bus type.
- *     @start: device to start iterating from.
- *     @data:  data for the callback.
- *     @fn:    function to be called for each device.
+ * bus_for_each_dev - device iterator.
+ * @bus: bus type.
+ * @start: device to start iterating from.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
  *
- *     Iterate over @bus's list of devices, and call @fn for each,
- *     passing it @data. If @start is not NULL, we use that device to
- *     begin iterating from.
+ * Iterate over @bus's list of devices, and call @fn for each,
+ * passing it @data. If @start is not NULL, we use that device to
+ * begin iterating from.
  *
- *     We check the return of @fn each time. If it returns anything
- *     other than 0, we break out and return that value.
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
  *
- *     NOTE: The device that returns a non-zero value is not retained
- *     in any way, nor is its refcount incremented. If the caller needs
- *     to retain this data, it should do, and increment the reference
- *     count in the supplied callback.
+ * NOTE: The device that returns a non-zero value is not retained
+ * in any way, nor is its refcount incremented. If the caller needs
+ * to retain this data, it should do, and increment the reference
+ * count in the supplied callback.
  */
-
-int bus_for_each_dev(struct bus_type * bus, struct device * start,
-                    void * data, int (*fn)(struct device *, void *))
+int bus_for_each_dev(struct bus_type *bus, struct device *start,
+                    void *data, int (*fn)(struct device *, void *))
 {
        struct klist_iter i;
-       struct device * dev;
+       struct device *dev;
        int error = 0;
 
        if (!bus)
                return -EINVAL;
 
-       klist_iter_init_node(&bus->klist_devices, &i,
+       klist_iter_init_node(&bus->p->klist_devices, &i,
                             (start ? &start->knode_bus : NULL));
        while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
        klist_iter_exit(&i);
        return error;
 }
+EXPORT_SYMBOL_GPL(bus_for_each_dev);
 
 /**
  * bus_find_device - device iterator for locating a particular device.
@@ -323,9 +318,9 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
  * if it does.  If the callback returns non-zero, this function will
  * return to the caller and not iterate over any more devices.
  */
-struct device * bus_find_device(struct bus_type *bus,
-                               struct device *start, void *data,
-                               int (*match)(struct device *, void *))
+struct device *bus_find_device(struct bus_type *bus,
+                              struct device *start, void *data,
+                              int (*match)(struct device *dev, void *data))
 {
        struct klist_iter i;
        struct device *dev;
@@ -333,7 +328,7 @@ struct device * bus_find_device(struct bus_type *bus,
        if (!bus)
                return NULL;
 
-       klist_iter_init_node(&bus->klist_devices, &i,
+       klist_iter_init_node(&bus->p->klist_devices, &i,
                             (start ? &start->knode_bus : NULL));
        while ((dev = next_device(&i)))
                if (match(dev, data) && get_device(dev))
@@ -341,51 +336,57 @@ struct device * bus_find_device(struct bus_type *bus,
        klist_iter_exit(&i);
        return dev;
 }
+EXPORT_SYMBOL_GPL(bus_find_device);
 
-
-static struct device_driver * next_driver(struct klist_iter * i)
+static struct device_driver *next_driver(struct klist_iter *i)
 {
-       struct klist_node * n = klist_next(i);
-       return n ? container_of(n, struct device_driver, knode_bus) : NULL;
+       struct klist_node *n = klist_next(i);
+       struct driver_private *drv_priv;
+
+       if (n) {
+               drv_priv = container_of(n, struct driver_private, knode_bus);
+               return drv_priv->driver;
+       }
+       return NULL;
 }
 
 /**
- *     bus_for_each_drv - driver iterator
- *     @bus:   bus we're dealing with.
- *     @start: driver to start iterating on.
- *     @data:  data to pass to the callback.
- *     @fn:    function to call for each driver.
+ * bus_for_each_drv - driver iterator
+ * @bus: bus we're dealing with.
+ * @start: driver to start iterating on.
+ * @data: data to pass to the callback.
+ * @fn: function to call for each driver.
  *
- *     This is nearly identical to the device iterator above.
- *     We iterate over each driver that belongs to @bus, and call
- *     @fn for each. If @fn returns anything but 0, we break out
- *     and return it. If @start is not NULL, we use it as the head
- *     of the list.
+ * This is nearly identical to the device iterator above.
+ * We iterate over each driver that belongs to @bus, and call
+ * @fn for each. If @fn returns anything but 0, we break out
+ * and return it. If @start is not NULL, we use it as the head
+ * of the list.
  *
- *     NOTE: we don't return the driver that returns a non-zero
- *     value, nor do we leave the reference count incremented for that
- *     driver. If the caller needs to know that info, it must set it
- *     in the callback. It must also be sure to increment the refcount
- *     so it doesn't disappear before returning to the caller.
+ * NOTE: we don't return the driver that returns a non-zero
+ * value, nor do we leave the reference count incremented for that
+ * driver. If the caller needs to know that info, it must set it
+ * in the callback. It must also be sure to increment the refcount
+ * so it doesn't disappear before returning to the caller.
  */
-
-int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
-                    void * data, int (*fn)(struct device_driver *, void *))
+int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
+                    void *data, int (*fn)(struct device_driver *, void *))
 {
        struct klist_iter i;
-       struct device_driver * drv;
+       struct device_driver *drv;
        int error = 0;
 
        if (!bus)
                return -EINVAL;
 
-       klist_iter_init_node(&bus->klist_drivers, &i,
-                            start ? &start->knode_bus : NULL);
+       klist_iter_init_node(&bus->p->klist_drivers, &i,
+                            start ? &start->p->knode_bus : NULL);
        while ((drv = next_driver(&i)) && !error)
                error = fn(drv, data);
        klist_iter_exit(&i);
        return error;
 }
+EXPORT_SYMBOL_GPL(bus_for_each_drv);
 
 static int device_add_attrs(struct bus_type *bus, struct device *dev)
 {
@@ -396,7 +397,7 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev)
                return 0;
 
        for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
-               error = device_create_file(dev,&bus->dev_attrs[i]);
+               error = device_create_file(dev, &bus->dev_attrs[i]);
                if (error) {
                        while (--i >= 0)
                                device_remove_file(dev, &bus->dev_attrs[i]);
@@ -406,13 +407,13 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev)
        return error;
 }
 
-static void device_remove_attrs(struct bus_type * bus, struct device * dev)
+static void device_remove_attrs(struct bus_type *bus, struct device *dev)
 {
        int i;
 
        if (bus->dev_attrs) {
                for (i = 0; attr_name(bus->dev_attrs[i]); i++)
-                       device_remove_file(dev,&bus->dev_attrs[i]);
+                       device_remove_file(dev, &bus->dev_attrs[i]);
        }
 }
 
@@ -420,7 +421,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev)
 static int make_deprecated_bus_links(struct device *dev)
 {
        return sysfs_create_link(&dev->kobj,
-                                &dev->bus->subsys.kobj, "bus");
+                                &dev->bus->p->subsys.kobj, "bus");
 }
 
 static void remove_deprecated_bus_links(struct device *dev)
@@ -433,28 +434,28 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
 #endif
 
 /**
- *     bus_add_device - add device to bus
- *     @dev:   device being added
+ * bus_add_device - add device to bus
+ * @dev: device being added
  *
- *     - Add the device to its bus's list of devices.
- *     - Create link to device's bus.
+ * - Add the device to its bus's list of devices.
+ * - Create link to device's bus.
  */
-int bus_add_device(struct device * dev)
+int bus_add_device(struct device *dev)
 {
-       struct bus_type * bus = bus_get(dev->bus);
+       struct bus_type *bus = bus_get(dev->bus);
        int error = 0;
 
        if (bus) {
-               pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
+               pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id);
                error = device_add_attrs(bus, dev);
                if (error)
                        goto out_put;
-               error = sysfs_create_link(&bus->devices.kobj,
+               error = sysfs_create_link(&bus->p->devices_kset->kobj,
                                                &dev->kobj, dev->bus_id);
                if (error)
                        goto out_id;
                error = sysfs_create_link(&dev->kobj,
-                               &dev->bus->subsys.kobj, "subsystem");
+                               &dev->bus->p->subsys.kobj, "subsystem");
                if (error)
                        goto out_subsys;
                error = make_deprecated_bus_links(dev);
@@ -466,7 +467,7 @@ int bus_add_device(struct device * dev)
 out_deprecated:
        sysfs_remove_link(&dev->kobj, "subsystem");
 out_subsys:
-       sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
+       sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id);
 out_id:
        device_remove_attrs(bus, dev);
 out_put:
@@ -475,56 +476,58 @@ out_put:
 }
 
 /**
- *     bus_attach_device - add device to bus
- *     @dev:   device tried to attach to a driver
+ * bus_attach_device - add device to bus
+ * @dev: device tried to attach to a driver
  *
- *     - Add device to bus's list of devices.
- *     - Try to attach to driver.
+ * - Add device to bus's list of devices.
+ * - Try to attach to driver.
  */
-void bus_attach_device(struct device * dev)
+void bus_attach_device(struct device *dev)
 {
        struct bus_type *bus = dev->bus;
        int ret = 0;
 
        if (bus) {
                dev->is_registered = 1;
-               if (bus->drivers_autoprobe)
+               if (bus->p->drivers_autoprobe)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
-                       klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+                       klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
                else
                        dev->is_registered = 0;
        }
 }
 
 /**
- *     bus_remove_device - remove device from bus
- *     @dev:   device to be removed
+ * bus_remove_device - remove device from bus
+ * @dev: device to be removed
  *
- *     - Remove symlink from bus's directory.
- *     - Delete device from bus's list.
- *     - Detach from its driver.
- *     - Drop reference taken in bus_add_device().
+ * - Remove symlink from bus's directory.
+ * - Delete device from bus's list.
+ * - Detach from its driver.
+ * - Drop reference taken in bus_add_device().
  */
-void bus_remove_device(struct device * dev)
+void bus_remove_device(struct device *dev)
 {
        if (dev->bus) {
                sysfs_remove_link(&dev->kobj, "subsystem");
                remove_deprecated_bus_links(dev);
-               sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
+               sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
+                                 dev->bus_id);
                device_remove_attrs(dev->bus, dev);
                if (dev->is_registered) {
                        dev->is_registered = 0;
                        klist_del(&dev->knode_bus);
                }
-               pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
+               pr_debug("bus: '%s': remove device %s\n",
+                        dev->bus->name, dev->bus_id);
                device_release_driver(dev);
                bus_put(dev->bus);
        }
 }
 
-static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
+static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)
 {
        int error = 0;
        int i;
@@ -533,19 +536,19 @@ static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
                for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
                        error = driver_create_file(drv, &bus->drv_attrs[i]);
                        if (error)
-                               goto Err;
+                               goto err;
                }
        }
- Done:
+done:
        return error;
- Err:
+err:
        while (--i >= 0)
                driver_remove_file(drv, &bus->drv_attrs[i]);
-       goto Done;
+       goto done;
 }
 
-
-static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv)
+static void driver_remove_attrs(struct bus_type *bus,
+                               struct device_driver *drv)
 {
        int i;
 
@@ -616,39 +619,46 @@ static ssize_t driver_uevent_store(struct device_driver *drv,
        enum kobject_action action;
 
        if (kobject_action_type(buf, count, &action) == 0)
-               kobject_uevent(&drv->kobj, action);
+               kobject_uevent(&drv->p->kobj, action);
        return count;
 }
 static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
 
 /**
- *     bus_add_driver - Add a driver to the bus.
- *     @drv:   driver.
- *
+ * bus_add_driver - Add a driver to the bus.
+ * @drv: driver.
  */
 int bus_add_driver(struct device_driver *drv)
 {
-       struct bus_type * bus = bus_get(drv->bus);
+       struct bus_type *bus;
+       struct driver_private *priv;
        int error = 0;
 
+       bus = bus_get(drv->bus);
        if (!bus)
                return -EINVAL;
 
-       pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
-       error = kobject_set_name(&drv->kobj, "%s", drv->name);
-       if (error)
-               goto out_put_bus;
-       drv->kobj.kset = &bus->drivers;
-       error = kobject_register(&drv->kobj);
+       pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       klist_init(&priv->klist_devices, NULL, NULL);
+       priv->driver = drv;
+       drv->p = priv;
+       priv->kobj.kset = bus->p->drivers_kset;
+       error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
+                                    "%s", drv->name);
        if (error)
                goto out_put_bus;
 
-       if (drv->bus->drivers_autoprobe) {
+       if (drv->bus->p->drivers_autoprobe) {
                error = driver_attach(drv);
                if (error)
                        goto out_unregister;
        }
-       klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
+       klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        module_add_driver(drv->owner, drv);
 
        error = driver_create_file(drv, &driver_attr_uevent);
@@ -669,24 +679,24 @@ int bus_add_driver(struct device_driver *drv)
                        __FUNCTION__, drv->name);
        }
 
+       kobject_uevent(&priv->kobj, KOBJ_ADD);
        return error;
 out_unregister:
-       kobject_unregister(&drv->kobj);
+       kobject_put(&priv->kobj);
 out_put_bus:
        bus_put(bus);
        return error;
 }
 
 /**
- *     bus_remove_driver - delete driver from bus's knowledge.
- *     @drv:   driver.
+ * bus_remove_driver - delete driver from bus's knowledge.
+ * @drv: driver.
  *
- *     Detach the driver from the devices it controls, and remove
- *     it from its bus's list of drivers. Finally, we drop the reference
- *     to the bus we took in bus_add_driver().
+ * Detach the driver from the devices it controls, and remove
+ * it from its bus's list of drivers. Finally, we drop the reference
+ * to the bus we took in bus_add_driver().
  */
-
-void bus_remove_driver(struct device_driver * drv)
+void bus_remove_driver(struct device_driver *drv)
 {
        if (!drv->bus)
                return;
@@ -694,18 +704,17 @@ void bus_remove_driver(struct device_driver * drv)
        remove_bind_files(drv);
        driver_remove_attrs(drv->bus, drv);
        driver_remove_file(drv, &driver_attr_uevent);
-       klist_remove(&drv->knode_bus);
-       pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
+       klist_remove(&drv->p->knode_bus);
+       pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
        driver_detach(drv);
        module_remove_driver(drv);
-       kobject_unregister(&drv->kobj);
+       kobject_put(&drv->p->kobj);
        bus_put(drv->bus);
 }
 
-
 /* Helper for bus_rescan_devices's iter */
 static int __must_check bus_rescan_devices_helper(struct device *dev,
-                                               void *data)
+                                                 void *data)
 {
        int ret = 0;
 
@@ -727,10 +736,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
  * attached and rescan it against existing drivers to see if it matches
  * any by calling device_attach() for the unbound devices.
  */
-int bus_rescan_devices(struct bus_type * bus)
+int bus_rescan_devices(struct bus_type *bus)
 {
        return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
 }
+EXPORT_SYMBOL_GPL(bus_rescan_devices);
 
 /**
  * device_reprobe - remove driver for a device and probe for a new driver
@@ -755,55 +765,55 @@ int device_reprobe(struct device *dev)
 EXPORT_SYMBOL_GPL(device_reprobe);
 
 /**
- *     find_bus - locate bus by name.
- *     @name:  name of bus.
+ * find_bus - locate bus by name.
+ * @name: name of bus.
  *
- *     Call kset_find_obj() to iterate over list of buses to
- *     find a bus by name. Return bus if found.
+ * Call kset_find_obj() to iterate over list of buses to
+ * find a bus by name. Return bus if found.
  *
- *     Note that kset_find_obj increments bus' reference count.
+ * Note that kset_find_obj increments bus' reference count.
  */
 #if 0
-struct bus_type * find_bus(char * name)
+struct bus_type *find_bus(char *name)
 {
-       struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
+       struct kobject *k = kset_find_obj(bus_kset, name);
        return k ? to_bus(k) : NULL;
 }
 #endif  /*  0  */
 
 
 /**
- *     bus_add_attrs - Add default attributes for this bus.
- *     @bus:   Bus that has just been registered.
+ * bus_add_attrs - Add default attributes for this bus.
+ * @bus: Bus that has just been registered.
  */
 
-static int bus_add_attrs(struct bus_type * bus)
+static int bus_add_attrs(struct bus_type *bus)
 {
        int error = 0;
        int i;
 
        if (bus->bus_attrs) {
                for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
-                       error = bus_create_file(bus,&bus->bus_attrs[i]);
+                       error = bus_create_file(bus, &bus->bus_attrs[i]);
                        if (error)
-                               goto Err;
+                               goto err;
                }
        }
- Done:
+done:
        return error;
- Err:
+err:
        while (--i >= 0)
-               bus_remove_file(bus,&bus->bus_attrs[i]);
-       goto Done;
+               bus_remove_file(bus, &bus->bus_attrs[i]);
+       goto done;
 }
 
-static void bus_remove_attrs(struct bus_type * bus)
+static void bus_remove_attrs(struct bus_type *bus)
 {
        int i;
 
        if (bus->bus_attrs) {
                for (i = 0; attr_name(bus->bus_attrs[i]); i++)
-                       bus_remove_file(bus,&bus->bus_attrs[i]);
+                       bus_remove_file(bus, &bus->bus_attrs[i]);
        }
 }
 
@@ -827,32 +837,42 @@ static ssize_t bus_uevent_store(struct bus_type *bus,
        enum kobject_action action;
 
        if (kobject_action_type(buf, count, &action) == 0)
-               kobject_uevent(&bus->subsys.kobj, action);
+               kobject_uevent(&bus->p->subsys.kobj, action);
        return count;
 }
 static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
 
 /**
- *     bus_register - register a bus with the system.
- *     @bus:   bus.
+ * bus_register - register a bus with the system.
+ * @bus: bus.
  *
- *     Once we have that, we registered the bus with the kobject
- *     infrastructure, then register the children subsystems it has:
- *     the devices and drivers that belong to the bus.
+ * Once we have that, we registered the bus with the kobject
+ * infrastructure, then register the children subsystems it has:
+ * the devices and drivers that belong to the bus.
  */
-int bus_register(struct bus_type * bus)
+int bus_register(struct bus_type *bus)
 {
        int retval;
+       struct bus_type_private *priv;
+
+       priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
-       BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
+       priv->bus = bus;
+       bus->p = priv;
 
-       retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
+       BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
+
+       retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
        if (retval)
                goto out;
 
-       bus->subsys.kobj.kset = &bus_subsys;
+       priv->subsys.kobj.kset = bus_kset;
+       priv->subsys.kobj.ktype = &bus_ktype;
+       priv->drivers_autoprobe = 1;
 
-       retval = subsystem_register(&bus->subsys);
+       retval = kset_register(&priv->subsys);
        if (retval)
                goto out;
 
@@ -860,23 +880,23 @@ int bus_register(struct bus_type * bus)
        if (retval)
                goto bus_uevent_fail;
 
-       kobject_set_name(&bus->devices.kobj, "devices");
-       bus->devices.kobj.parent = &bus->subsys.kobj;
-       retval = kset_register(&bus->devices);
-       if (retval)
+       priv->devices_kset = kset_create_and_add("devices", NULL,
+                                                &priv->subsys.kobj);
+       if (!priv->devices_kset) {
+               retval = -ENOMEM;
                goto bus_devices_fail;
+       }
 
-       kobject_set_name(&bus->drivers.kobj, "drivers");
-       bus->drivers.kobj.parent = &bus->subsys.kobj;
-       bus->drivers.ktype = &driver_ktype;
-       retval = kset_register(&bus->drivers);
-       if (retval)
+       priv->drivers_kset = kset_create_and_add("drivers", NULL,
+                                                &priv->subsys.kobj);
+       if (!priv->drivers_kset) {
+               retval = -ENOMEM;
                goto bus_drivers_fail;
+       }
 
-       klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
-       klist_init(&bus->klist_drivers, NULL, NULL);
+       klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
+       klist_init(&priv->klist_drivers, NULL, NULL);
 
-       bus->drivers_autoprobe = 1;
        retval = add_probe_files(bus);
        if (retval)
                goto bus_probe_files_fail;
@@ -885,66 +905,73 @@ int bus_register(struct bus_type * bus)
        if (retval)
                goto bus_attrs_fail;
 
-       pr_debug("bus type '%s' registered\n", bus->name);
+       pr_debug("bus: '%s': registered\n", bus->name);
        return 0;
 
 bus_attrs_fail:
        remove_probe_files(bus);
 bus_probe_files_fail:
-       kset_unregister(&bus->drivers);
+       kset_unregister(bus->p->drivers_kset);
 bus_drivers_fail:
-       kset_unregister(&bus->devices);
+       kset_unregister(bus->p->devices_kset);
 bus_devices_fail:
        bus_remove_file(bus, &bus_attr_uevent);
 bus_uevent_fail:
-       subsystem_unregister(&bus->subsys);
+       kset_unregister(&bus->p->subsys);
+       kfree(bus->p);
 out:
        return retval;
 }
+EXPORT_SYMBOL_GPL(bus_register);
 
 /**
- *     bus_unregister - remove a bus from the system
- *     @bus:   bus.
+ * bus_unregister - remove a bus from the system
+ * @bus: bus.
  *
- *     Unregister the child subsystems and the bus itself.
- *     Finally, we call bus_put() to release the refcount
+ * Unregister the child subsystems and the bus itself.
+ * Finally, we call bus_put() to release the refcount
  */
-void bus_unregister(struct bus_type * bus)
+void bus_unregister(struct bus_type *bus)
 {
-       pr_debug("bus %s: unregistering\n", bus->name);
+       pr_debug("bus: '%s': unregistering\n", bus->name);
        bus_remove_attrs(bus);
        remove_probe_files(bus);
-       kset_unregister(&bus->drivers);
-       kset_unregister(&bus->devices);
+       kset_unregister(bus->p->drivers_kset);
+       kset_unregister(bus->p->devices_kset);
        bus_remove_file(bus, &bus_attr_uevent);
-       subsystem_unregister(&bus->subsys);
+       kset_unregister(&bus->p->subsys);
+       kfree(bus->p);
 }
+EXPORT_SYMBOL_GPL(bus_unregister);
 
 int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
-       return blocking_notifier_chain_register(&bus->bus_notifier, nb);
+       return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
 }
 EXPORT_SYMBOL_GPL(bus_register_notifier);
 
 int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
-       return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);
+       return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb);
 }
 EXPORT_SYMBOL_GPL(bus_unregister_notifier);
 
-int __init buses_init(void)
+struct kset *bus_get_kset(struct bus_type *bus)
 {
-       return subsystem_register(&bus_subsys);
+       return &bus->p->subsys;
 }
+EXPORT_SYMBOL_GPL(bus_get_kset);
 
+struct klist *bus_get_device_klist(struct bus_type *bus)
+{
+       return &bus->p->klist_devices;
+}
+EXPORT_SYMBOL_GPL(bus_get_device_klist);
 
-EXPORT_SYMBOL_GPL(bus_for_each_dev);
-EXPORT_SYMBOL_GPL(bus_find_device);
-EXPORT_SYMBOL_GPL(bus_for_each_drv);
-
-EXPORT_SYMBOL_GPL(bus_register);
-EXPORT_SYMBOL_GPL(bus_unregister);
-EXPORT_SYMBOL_GPL(bus_rescan_devices);
-
-EXPORT_SYMBOL_GPL(bus_create_file);
-EXPORT_SYMBOL_GPL(bus_remove_file);
+int __init buses_init(void)
+{
+       bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
+       if (!bus_kset)
+               return -ENOMEM;
+       return 0;
+}
index a863bb091e11db26e6e996dfa6fb341285d11991..59cf35894cfce832c814128baa495a2e35f4971b 100644 (file)
 #include <linux/kdev_t.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/genhd.h>
 #include "base.h"
 
 #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
 #define to_class(obj) container_of(obj, struct class, subsys.kobj)
 
-static ssize_t
-class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
+                              char *buf)
 {
-       struct class_attribute * class_attr = to_class_attr(attr);
-       struct class * dc = to_class(kobj);
+       struct class_attribute *class_attr = to_class_attr(attr);
+       struct class *dc = to_class(kobj);
        ssize_t ret = -EIO;
 
        if (class_attr->show)
@@ -34,12 +35,11 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
        return ret;
 }
 
-static ssize_t
-class_attr_store(struct kobject * kobj, struct attribute * attr,
-                const char * buf, size_t count)
+static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
+                               const char *buf, size_t count)
 {
-       struct class_attribute * class_attr = to_class_attr(attr);
-       struct class * dc = to_class(kobj);
+       struct class_attribute *class_attr = to_class_attr(attr);
+       struct class *dc = to_class(kobj);
        ssize_t ret = -EIO;
 
        if (class_attr->store)
@@ -47,7 +47,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr,
        return ret;
 }
 
-static void class_release(struct kobject * kobj)
+static void class_release(struct kobject *kobj)
 {
        struct class *class = to_class(kobj);
 
@@ -71,20 +71,20 @@ static struct kobj_type class_ktype = {
 };
 
 /* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &class_ktype, NULL);
+static struct kset *class_kset;
 
 
-int class_create_file(struct class * cls, const struct class_attribute * attr)
+int class_create_file(struct class *cls, const struct class_attribute *attr)
 {
        int error;
-       if (cls) {
+       if (cls)
                error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);
-       else
+       else
                error = -EINVAL;
        return error;
 }
 
-void class_remove_file(struct class * cls, const struct class_attribute * attr)
+void class_remove_file(struct class *cls, const struct class_attribute *attr)
 {
        if (cls)
                sysfs_remove_file(&cls->subsys.kobj, &attr->attr);
@@ -93,48 +93,48 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
 static struct class *class_get(struct class *cls)
 {
        if (cls)
-               return container_of(kset_get(&cls->subsys), struct class, subsys);
+               return container_of(kset_get(&cls->subsys),
+                                   struct class, subsys);
        return NULL;
 }
 
-static void class_put(struct class * cls)
+static void class_put(struct class *cls)
 {
        if (cls)
                kset_put(&cls->subsys);
 }
 
-
-static int add_class_attrs(struct class * cls)
+static int add_class_attrs(struct class *cls)
 {
        int i;
        int error = 0;
 
        if (cls->class_attrs) {
                for (i = 0; attr_name(cls->class_attrs[i]); i++) {
-                       error = class_create_file(cls,&cls->class_attrs[i]);
+                       error = class_create_file(cls, &cls->class_attrs[i]);
                        if (error)
-                               goto Err;
+                               goto error;
                }
        }
- Done:
+done:
        return error;
- Err:
+error:
        while (--i >= 0)
-               class_remove_file(cls,&cls->class_attrs[i]);
-       goto Done;
+               class_remove_file(cls, &cls->class_attrs[i]);
+       goto done;
 }
 
-static void remove_class_attrs(struct class * cls)
+static void remove_class_attrs(struct class *cls)
 {
        int i;
 
        if (cls->class_attrs) {
                for (i = 0; attr_name(cls->class_attrs[i]); i++)
-                       class_remove_file(cls,&cls->class_attrs[i]);
+                       class_remove_file(cls, &cls->class_attrs[i]);
        }
 }
 
-int class_register(struct class * cls)
+int class_register(struct class *cls)
 {
        int error;
 
@@ -149,9 +149,16 @@ int class_register(struct class * cls)
        if (error)
                return error;
 
-       cls->subsys.kobj.kset = &class_subsys;
+#ifdef CONFIG_SYSFS_DEPRECATED
+       /* let the block class directory show up in the root of sysfs */
+       if (cls != &block_class)
+               cls->subsys.kobj.kset = class_kset;
+#else
+       cls->subsys.kobj.kset = class_kset;
+#endif
+       cls->subsys.kobj.ktype = &class_ktype;
 
-       error = subsystem_register(&cls->subsys);
+       error = kset_register(&cls->subsys);
        if (!error) {
                error = add_class_attrs(class_get(cls));
                class_put(cls);
@@ -159,11 +166,11 @@ int class_register(struct class * cls)
        return error;
 }
 
-void class_unregister(struct class * cls)
+void class_unregister(struct class *cls)
 {
        pr_debug("device class '%s': unregistering\n", cls->name);
        remove_class_attrs(cls);
-       subsystem_unregister(&cls->subsys);
+       kset_unregister(&cls->subsys);
 }
 
 static void class_create_release(struct class *cls)
@@ -241,8 +248,8 @@ void class_destroy(struct class *cls)
 
 /* Class Device Stuff */
 
-int class_device_create_file(struct class_device * class_dev,
-                            const struct class_device_attribute * attr)
+int class_device_create_file(struct class_device *class_dev,
+                            const struct class_device_attribute *attr)
 {
        int error = -EINVAL;
        if (class_dev)
@@ -250,8 +257,8 @@ int class_device_create_file(struct class_device * class_dev,
        return error;
 }
 
-void class_device_remove_file(struct class_device * class_dev,
-                             const struct class_device_attribute * attr)
+void class_device_remove_file(struct class_device *class_dev,
+                             const struct class_device_attribute *attr)
 {
        if (class_dev)
                sysfs_remove_file(&class_dev->kobj, &attr->attr);
@@ -273,12 +280,11 @@ void class_device_remove_bin_file(struct class_device *class_dev,
                sysfs_remove_bin_file(&class_dev->kobj, attr);
 }
 
-static ssize_t
-class_device_attr_show(struct kobject * kobj, struct attribute * attr,
-                      char * buf)
+static ssize_t class_device_attr_show(struct kobject *kobj,
+                                     struct attribute *attr, char *buf)
 {
-       struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
-       struct class_device * cd = to_class_dev(kobj);
+       struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
+       struct class_device *cd = to_class_dev(kobj);
        ssize_t ret = 0;
 
        if (class_dev_attr->show)
@@ -286,12 +292,12 @@ class_device_attr_show(struct kobject * kobj, struct attribute * attr,
        return ret;
 }
 
-static ssize_t
-class_device_attr_store(struct kobject * kobj, struct attribute * attr,
-                       const char * buf, size_t count)
+static ssize_t class_device_attr_store(struct kobject *kobj,
+                                      struct attribute *attr,
+                                      const char *buf, size_t count)
 {
-       struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
-       struct class_device * cd = to_class_dev(kobj);
+       struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
+       struct class_device *cd = to_class_dev(kobj);
        ssize_t ret = 0;
 
        if (class_dev_attr->store)
@@ -304,10 +310,10 @@ static struct sysfs_ops class_dev_sysfs_ops = {
        .store  = class_device_attr_store,
 };
 
-static void class_dev_release(struct kobject * kobj)
+static void class_dev_release(struct kobject *kobj)
 {
        struct class_device *cd = to_class_dev(kobj);
-       struct class * cls = cd->class;
+       struct class *cls = cd->class;
 
        pr_debug("device class '%s': release.\n", cd->class_id);
 
@@ -316,8 +322,8 @@ static void class_dev_release(struct kobject * kobj)
        else if (cls->release)
                cls->release(cd);
        else {
-               printk(KERN_ERR "Class Device '%s' does not have a release() function, "
-                       "it is broken and must be fixed.\n",
+               printk(KERN_ERR "Class Device '%s' does not have a release() "
+                       "function, it is broken and must be fixed.\n",
                        cd->class_id);
                WARN_ON(1);
        }
@@ -428,7 +434,8 @@ static int class_uevent(struct kset *kset, struct kobject *kobj,
                        add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
                if (dev->driver)
-                       add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
+                       add_uevent_var(env, "PHYSDEVDRIVER=%s",
+                                      dev->driver->name);
        }
 
        if (class_dev->uevent) {
@@ -452,43 +459,49 @@ static struct kset_uevent_ops class_uevent_ops = {
        .uevent =       class_uevent,
 };
 
-static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
-
+/*
+ * DO NOT copy how this is created, kset_create_and_add() should be
+ * called, but this is a hold-over from the old-way and will be deleted
+ * entirely soon.
+ */
+static struct kset class_obj_subsys = {
+       .uevent_ops = &class_uevent_ops,
+};
 
-static int class_device_add_attrs(struct class_device * cd)
+static int class_device_add_attrs(struct class_device *cd)
 {
        int i;
        int error = 0;
-       struct class * cls = cd->class;
+       struct class *cls = cd->class;
 
        if (cls->class_dev_attrs) {
                for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
                        error = class_device_create_file(cd,
-                                                        &cls->class_dev_attrs[i]);
+                                               &cls->class_dev_attrs[i]);
                        if (error)
-                               goto Err;
+                               goto err;
                }
        }
- Done:
+done:
        return error;
- Err:
+err:
        while (--i >= 0)
-               class_device_remove_file(cd,&cls->class_dev_attrs[i]);
-       goto Done;
+               class_device_remove_file(cd, &cls->class_dev_attrs[i]);
+       goto done;
 }
 
-static void class_device_remove_attrs(struct class_device * cd)
+static void class_device_remove_attrs(struct class_device *cd)
 {
        int i;
-       struct class * cls = cd->class;
+       struct class *cls = cd->class;
 
        if (cls->class_dev_attrs) {
                for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
-                       class_device_remove_file(cd,&cls->class_dev_attrs[i]);
+                       class_device_remove_file(cd, &cls->class_dev_attrs[i]);
        }
 }
 
-static int class_device_add_groups(struct class_device * cd)
+static int class_device_add_groups(struct class_device *cd)
 {
        int i;
        int error = 0;
@@ -498,7 +511,8 @@ static int class_device_add_groups(struct class_device * cd)
                        error = sysfs_create_group(&cd->kobj, cd->groups[i]);
                        if (error) {
                                while (--i >= 0)
-                                       sysfs_remove_group(&cd->kobj, cd->groups[i]);
+                                       sysfs_remove_group(&cd->kobj,
+                                                          cd->groups[i]);
                                goto out;
                        }
                }
@@ -507,14 +521,12 @@ out:
        return error;
 }
 
-static void class_device_remove_groups(struct class_device * cd)
+static void class_device_remove_groups(struct class_device *cd)
 {
        int i;
-       if (cd->groups) {
-               for (i = 0; cd->groups[i]; i++) {
+       if (cd->groups)
+               for (i = 0; cd->groups[i]; i++)
                        sysfs_remove_group(&cd->kobj, cd->groups[i]);
-               }
-       }
 }
 
 static ssize_t show_dev(struct class_device *class_dev, char *buf)
@@ -537,8 +549,8 @@ static struct class_device_attribute class_uevent_attr =
 
 void class_device_initialize(struct class_device *class_dev)
 {
-       kobj_set_kset_s(class_dev, class_obj_subsys);
-       kobject_init(&class_dev->kobj);
+       class_dev->kobj.kset = &class_obj_subsys;
+       kobject_init(&class_dev->kobj, &class_device_ktype);
        INIT_LIST_HEAD(&class_dev->node);
 }
 
@@ -566,16 +578,13 @@ int class_device_add(struct class_device *class_dev)
                 class_dev->class_id);
 
        /* first, register with generic layer. */
-       error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
-       if (error)
-               goto out2;
-
        if (parent_class_dev)
                class_dev->kobj.parent = &parent_class_dev->kobj;
        else
                class_dev->kobj.parent = &parent_class->subsys.kobj;
 
-       error = kobject_add(&class_dev->kobj);
+       error = kobject_add(&class_dev->kobj, class_dev->kobj.parent,
+                           "%s", class_dev->class_id);
        if (error)
                goto out2;
 
@@ -642,7 +651,7 @@ int class_device_add(struct class_device *class_dev)
  out3:
        kobject_del(&class_dev->kobj);
  out2:
-       if(parent_class_dev)
+       if (parent_class_dev)
                class_device_put(parent_class_dev);
        class_put(parent_class);
  out1:
@@ -659,9 +668,11 @@ int class_device_register(struct class_device *class_dev)
 /**
  * class_device_create - creates a class device and registers it with sysfs
  * @cls: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct class_device of this new device, if any.
+ * @parent: pointer to the parent struct class_device of this new device, if
+ * any.
  * @devt: the dev_t for the char device to be added.
- * @device: a pointer to a struct device that is assiociated with this class device.
+ * @device: a pointer to a struct device that is assiociated with this class
+ * device.
  * @fmt: string for the class device's name
  *
  * This function can be used by char device classes.  A struct
@@ -785,7 +796,7 @@ void class_device_destroy(struct class *cls, dev_t devt)
                class_device_unregister(class_dev);
 }
 
-struct class_device * class_device_get(struct class_device *class_dev)
+struct class_device *class_device_get(struct class_device *class_dev)
 {
        if (class_dev)
                return to_class_dev(kobject_get(&class_dev->kobj));
@@ -798,6 +809,139 @@ void class_device_put(struct class_device *class_dev)
                kobject_put(&class_dev->kobj);
 }
 
+/**
+ * class_for_each_device - device iterator
+ * @class: the class we're iterating
+ * @data: data for the callback
+ * @fn: function to be called for each device
+ *
+ * Iterate over @class's list of devices, and call @fn for each,
+ * passing it @data.
+ *
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
+ *
+ * Note, we hold class->sem in this function, so it can not be
+ * re-acquired in @fn, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+int class_for_each_device(struct class *class, void *data,
+                          int (*fn)(struct device *, void *))
+{
+       struct device *dev;
+       int error = 0;
+
+       if (!class)
+               return -EINVAL;
+       down(&class->sem);
+       list_for_each_entry(dev, &class->devices, node) {
+               dev = get_device(dev);
+               if (dev) {
+                       error = fn(dev, data);
+                       put_device(dev);
+               } else
+                       error = -ENODEV;
+               if (error)
+                       break;
+       }
+       up(&class->sem);
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(class_for_each_device);
+
+/**
+ * class_find_device - device iterator for locating a particular device
+ * @class: the class we're iterating
+ * @data: data for the match function
+ * @match: function to check device
+ *
+ * This is similar to the class_for_each_dev() function above, but it
+ * returns a reference to a device that is 'found' for later use, as
+ * determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+
+ * Note, you will need to drop the reference with put_device() after use.
+ *
+ * We hold class->sem in this function, so it can not be
+ * re-acquired in @match, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+struct device *class_find_device(struct class *class, void *data,
+                                  int (*match)(struct device *, void *))
+{
+       struct device *dev;
+       int found = 0;
+
+       if (!class)
+               return NULL;
+
+       down(&class->sem);
+       list_for_each_entry(dev, &class->devices, node) {
+               dev = get_device(dev);
+               if (dev) {
+                       if (match(dev, data)) {
+                               found = 1;
+                               break;
+                       } else
+                               put_device(dev);
+               } else
+                       break;
+       }
+       up(&class->sem);
+
+       return found ? dev : NULL;
+}
+EXPORT_SYMBOL_GPL(class_find_device);
+
+/**
+ * class_find_child - device iterator for locating a particular class_device
+ * @class: the class we're iterating
+ * @data: data for the match function
+ * @match: function to check class_device
+ *
+ * This function returns a reference to a class_device that is 'found' for
+ * later use, as determined by the @match callback.
+ *
+ * The callback should return 0 if the class_device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more class_devices.
+ *
+ * Note, you will need to drop the reference with class_device_put() after use.
+ *
+ * We hold class->sem in this function, so it can not be
+ * re-acquired in @match, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+struct class_device *class_find_child(struct class *class, void *data,
+                                  int (*match)(struct class_device *, void *))
+{
+       struct class_device *dev;
+       int found = 0;
+
+       if (!class)
+               return NULL;
+
+       down(&class->sem);
+       list_for_each_entry(dev, &class->children, node) {
+               dev = class_device_get(dev);
+               if (dev) {
+                       if (match(dev, data)) {
+                               found = 1;
+                               break;
+                       } else
+                               class_device_put(dev);
+               } else
+                       break;
+       }
+       up(&class->sem);
+
+       return found ? dev : NULL;
+}
+EXPORT_SYMBOL_GPL(class_find_child);
 
 int class_interface_register(struct class_interface *class_intf)
 {
@@ -829,7 +973,7 @@ int class_interface_register(struct class_interface *class_intf)
 
 void class_interface_unregister(struct class_interface *class_intf)
 {
-       struct class * parent = class_intf->class;
+       struct class *parent = class_intf->class;
        struct class_device *class_dev;
        struct device *dev;
 
@@ -853,15 +997,14 @@ void class_interface_unregister(struct class_interface *class_intf)
 
 int __init classes_init(void)
 {
-       int retval;
-
-       retval = subsystem_register(&class_subsys);
-       if (retval)
-               return retval;
+       class_kset = kset_create_and_add("class", NULL, NULL);
+       if (!class_kset)
+               return -ENOMEM;
 
        /* ick, this is ugly, the things we go through to keep from showing up
         * in sysfs... */
        kset_init(&class_obj_subsys);
+       kobject_set_name(&class_obj_subsys.kobj, "class_obj");
        if (!class_obj_subsys.kobj.parent)
                class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
        return 0;
index 2683eac30c68138220500217ddfdc550a7b24e81..edf3bbeb8d6a0af7438119b915aafb3f0111617d 100644 (file)
 #include <linux/string.h>
 #include <linux/kdev_t.h>
 #include <linux/notifier.h>
-
+#include <linux/genhd.h>
 #include <asm/semaphore.h>
 
 #include "base.h"
 #include "power/power.h"
 
-int (*platform_notify)(struct device * dev) = NULL;
-int (*platform_notify_remove)(struct device * dev) = NULL;
+int (*platform_notify)(struct device *dev) = NULL;
+int (*platform_notify_remove)(struct device *dev) = NULL;
 
 /*
  * sysfs bindings for devices.
@@ -51,11 +51,11 @@ EXPORT_SYMBOL(dev_driver_string);
 #define to_dev(obj) container_of(obj, struct device, kobj)
 #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
-static ssize_t
-dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
+                            char *buf)
 {
-       struct device_attribute * dev_attr = to_dev_attr(attr);
-       struct device * dev = to_dev(kobj);
+       struct device_attribute *dev_attr = to_dev_attr(attr);
+       struct device *dev = to_dev(kobj);
        ssize_t ret = -EIO;
 
        if (dev_attr->show)
@@ -63,12 +63,11 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
        return ret;
 }
 
-static ssize_t
-dev_attr_store(struct kobject * kobj, struct attribute * attr,
-              const char * buf, size_t count)
+static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
+                             const char *buf, size_t count)
 {
-       struct device_attribute * dev_attr = to_dev_attr(attr);
-       struct device * dev = to_dev(kobj);
+       struct device_attribute *dev_attr = to_dev_attr(attr);
+       struct device *dev = to_dev(kobj);
        ssize_t ret = -EIO;
 
        if (dev_attr->store)
@@ -90,9 +89,9 @@ static struct sysfs_ops dev_sysfs_ops = {
  *     reaches 0. We forward the call to the device's release
  *     method, which should handle actually freeing the structure.
  */
-static void device_release(struct kobject * kobj)
+static void device_release(struct kobject *kobj)
 {
-       struct device * dev = to_dev(kobj);
+       struct device *dev = to_dev(kobj);
 
        if (dev->release)
                dev->release(dev);
@@ -101,8 +100,8 @@ static void device_release(struct kobject * kobj)
        else if (dev->class && dev->class->dev_release)
                dev->class->dev_release(dev);
        else {
-               printk(KERN_ERR "Device '%s' does not have a release() function, "
-                       "it is broken and must be fixed.\n",
+               printk(KERN_ERR "Device '%s' does not have a release() "
+                       "function, it is broken and must be fixed.\n",
                        dev->bus_id);
                WARN_ON(1);
        }
@@ -185,7 +184,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
                add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
                if (dev->driver)
-                       add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
+                       add_uevent_var(env, "PHYSDEVDRIVER=%s",
+                                      dev->driver->name);
        }
 #endif
 
@@ -193,15 +193,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (dev->bus && dev->bus->uevent) {
                retval = dev->bus->uevent(dev, env);
                if (retval)
-                       pr_debug ("%s: bus uevent() returned %d\n",
-                                 __FUNCTION__, retval);
+                       pr_debug("device: '%s': %s: bus uevent() returned %d\n",
+                                dev->bus_id, __FUNCTION__, retval);
        }
 
        /* have the class specific function add its stuff */
        if (dev->class && dev->class->dev_uevent) {
                retval = dev->class->dev_uevent(dev, env);
                if (retval)
-                       pr_debug("%s: class uevent() returned %d\n",
+                       pr_debug("device: '%s': %s: class uevent() "
+                                "returned %d\n", dev->bus_id,
                                 __FUNCTION__, retval);
        }
 
@@ -209,7 +210,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (dev->type && dev->type->uevent) {
                retval = dev->type->uevent(dev, env);
                if (retval)
-                       pr_debug("%s: dev_type uevent() returned %d\n",
+                       pr_debug("device: '%s': %s: dev_type uevent() "
+                                "returned %d\n", dev->bus_id,
                                 __FUNCTION__, retval);
        }
 
@@ -325,7 +327,8 @@ static int device_add_groups(struct device *dev,
                        error = sysfs_create_group(&dev->kobj, groups[i]);
                        if (error) {
                                while (--i >= 0)
-                                       sysfs_remove_group(&dev->kobj, groups[i]);
+                                       sysfs_remove_group(&dev->kobj,
+                                                          groups[i]);
                                break;
                        }
                }
@@ -401,20 +404,15 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
 static struct device_attribute devt_attr =
        __ATTR(dev, S_IRUGO, show_dev, NULL);
 
-/*
- *     devices_subsys - structure to be registered with kobject core.
- */
-
-decl_subsys(devices, &device_ktype, &device_uevent_ops);
-
+/* kset to create /sys/devices/  */
+struct kset *devices_kset;
 
 /**
- *     device_create_file - create sysfs attribute file for device.
- *     @dev:   device.
- *     @attr:  device attribute descriptor.
+ * device_create_file - create sysfs attribute file for device.
+ * @dev: device.
+ * @attr: device attribute descriptor.
  */
-
-int device_create_file(struct device * dev, struct device_attribute * attr)
+int device_create_file(struct device *dev, struct device_attribute *attr)
 {
        int error = 0;
        if (get_device(dev)) {
@@ -425,12 +423,11 @@ int device_create_file(struct device * dev, struct device_attribute * attr)
 }
 
 /**
- *     device_remove_file - remove sysfs attribute file.
- *     @dev:   device.
- *     @attr:  device attribute descriptor.
+ * device_remove_file - remove sysfs attribute file.
+ * @dev: device.
+ * @attr: device attribute descriptor.
  */
-
-void device_remove_file(struct device * dev, struct device_attribute * attr)
+void device_remove_file(struct device *dev, struct device_attribute *attr)
 {
        if (get_device(dev)) {
                sysfs_remove_file(&dev->kobj, &attr->attr);
@@ -511,22 +508,20 @@ static void klist_children_put(struct klist_node *n)
        put_device(dev);
 }
 
-
 /**
- *     device_initialize - init device structure.
- *     @dev:   device.
+ * device_initialize - init device structure.
+ * @dev: device.
  *
- *     This prepares the device for use by other layers,
- *     including adding it to the device hierarchy.
- *     It is the first half of device_register(), if called by
- *     that, though it can also be called separately, so one
- *     may use @dev's fields (e.g. the refcount).
+ * This prepares the device for use by other layers,
+ * including adding it to the device hierarchy.
+ * It is the first half of device_register(), if called by
+ * that, though it can also be called separately, so one
+ * may use @dev's fields (e.g. the refcount).
  */
-
 void device_initialize(struct device *dev)
 {
-       kobj_set_kset_s(dev, devices_subsys);
-       kobject_init(&dev->kobj);
+       dev->kobj.kset = devices_kset;
+       kobject_init(&dev->kobj, &device_ktype);
        klist_init(&dev->klist_children, klist_children_get,
                   klist_children_put);
        INIT_LIST_HEAD(&dev->dma_pools);
@@ -539,36 +534,39 @@ void device_initialize(struct device *dev)
 }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
-static struct kobject * get_device_parent(struct device *dev,
-                                         struct device *parent)
+static struct kobject *get_device_parent(struct device *dev,
+                                        struct device *parent)
 {
-       /*
-        * Set the parent to the class, not the parent device
-        * for topmost devices in class hierarchy.
-        * This keeps sysfs from having a symlink to make old
-        * udevs happy
-        */
+       /* class devices without a parent live in /sys/class/<classname>/ */
        if (dev->class && (!parent || parent->class != dev->class))
                return &dev->class->subsys.kobj;
+       /* all other devices keep their parent */
        else if (parent)
                return &parent->kobj;
 
        return NULL;
 }
+
+static inline void cleanup_device_parent(struct device *dev) {}
+static inline void cleanup_glue_dir(struct device *dev,
+                                   struct kobject *glue_dir) {}
 #else
 static struct kobject *virtual_device_parent(struct device *dev)
 {
        static struct kobject *virtual_dir = NULL;
 
        if (!virtual_dir)
-               virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
+               virtual_dir = kobject_create_and_add("virtual",
+                                                    &devices_kset->kobj);
 
        return virtual_dir;
 }
 
-static struct kobject * get_device_parent(struct device *dev,
-                                         struct device *parent)
+static struct kobject *get_device_parent(struct device *dev,
+                                        struct device *parent)
 {
+       int retval;
+
        if (dev->class) {
                struct kobject *kobj = NULL;
                struct kobject *parent_kobj;
@@ -576,8 +574,8 @@ static struct kobject * get_device_parent(struct device *dev,
 
                /*
                 * If we have no parent, we live in "virtual".
-                * Class-devices with a bus-device as parent, live
-                * in a class-directory to prevent namespace collisions.
+                * Class-devices with a non class-device as parent, live
+                * in a "glue" directory to prevent namespace collisions.
                 */
                if (parent == NULL)
                        parent_kobj = virtual_device_parent(dev);
@@ -598,25 +596,45 @@ static struct kobject * get_device_parent(struct device *dev,
                        return kobj;
 
                /* or create a new class-directory at the parent device */
-               return kobject_kset_add_dir(&dev->class->class_dirs,
-                                           parent_kobj, dev->class->name);
+               k = kobject_create();
+               if (!k)
+                       return NULL;
+               k->kset = &dev->class->class_dirs;
+               retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
+               if (retval < 0) {
+                       kobject_put(k);
+                       return NULL;
+               }
+               /* do not emit an uevent for this simple "glue" directory */
+               return k;
        }
 
        if (parent)
                return &parent->kobj;
        return NULL;
 }
+
+static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
+{
+       /* see if we live in a "glue" directory */
+       if (!dev->class || glue_dir->kset != &dev->class->class_dirs)
+               return;
+
+       kobject_put(glue_dir);
+}
+
+static void cleanup_device_parent(struct device *dev)
+{
+       cleanup_glue_dir(dev, dev->kobj.parent);
+}
 #endif
 
-static int setup_parent(struct device *dev, struct device *parent)
+static void setup_parent(struct device *dev, struct device *parent)
 {
        struct kobject *kobj;
        kobj = get_device_parent(dev, parent);
-       if (IS_ERR(kobj))
-               return PTR_ERR(kobj);
        if (kobj)
                dev->kobj.parent = kobj;
-       return 0;
 }
 
 static int device_add_class_symlinks(struct device *dev)
@@ -625,65 +643,76 @@ static int device_add_class_symlinks(struct device *dev)
 
        if (!dev->class)
                return 0;
+
        error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
                                  "subsystem");
        if (error)
                goto out;
-       /*
-        * If this is not a "fake" compatible device, then create the
-        * symlink from the class to the device.
-        */
-       if (dev->kobj.parent != &dev->class->subsys.kobj) {
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+       /* stacked class devices need a symlink in the class directory */
+       if (dev->kobj.parent != &dev->class->subsys.kobj &&
+           dev->type != &part_type) {
                error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
                                          dev->bus_id);
                if (error)
                        goto out_subsys;
        }
-       if (dev->parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-               {
-                       struct device *parent = dev->parent;
-                       char *class_name;
-
-                       /*
-                        * In old sysfs stacked class devices had 'device'
-                        * link pointing to real device instead of parent
-                        */
-                       while (parent->class && !parent->bus && parent->parent)
-                               parent = parent->parent;
-
-                       error = sysfs_create_link(&dev->kobj,
-                                                 &parent->kobj,
-                                                 "device");
-                       if (error)
-                               goto out_busid;
 
-                       class_name = make_class_name(dev->class->name,
-                                                       &dev->kobj);
-                       if (class_name)
-                               error = sysfs_create_link(&dev->parent->kobj,
-                                                       &dev->kobj, class_name);
-                       kfree(class_name);
-                       if (error)
-                               goto out_device;
-               }
-#else
-               error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+       if (dev->parent && dev->type != &part_type) {
+               struct device *parent = dev->parent;
+               char *class_name;
+
+               /*
+                * stacked class devices have the 'device' link
+                * pointing to the bus device instead of the parent
+                */
+               while (parent->class && !parent->bus && parent->parent)
+                       parent = parent->parent;
+
+               error = sysfs_create_link(&dev->kobj,
+                                         &parent->kobj,
                                          "device");
                if (error)
                        goto out_busid;
-#endif
+
+               class_name = make_class_name(dev->class->name,
+                                               &dev->kobj);
+               if (class_name)
+                       error = sysfs_create_link(&dev->parent->kobj,
+                                               &dev->kobj, class_name);
+               kfree(class_name);
+               if (error)
+                       goto out_device;
        }
        return 0;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
 out_device:
-       if (dev->parent)
+       if (dev->parent && dev->type != &part_type)
                sysfs_remove_link(&dev->kobj, "device");
-#endif
 out_busid:
-       if (dev->kobj.parent != &dev->class->subsys.kobj)
+       if (dev->kobj.parent != &dev->class->subsys.kobj &&
+           dev->type != &part_type)
                sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#else
+       /* link in the class directory pointing to the device */
+       error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+                                 dev->bus_id);
+       if (error)
+               goto out_subsys;
+
+       if (dev->parent && dev->type != &part_type) {
+               error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+                                         "device");
+               if (error)
+                       goto out_busid;
+       }
+       return 0;
+
+out_busid:
+       sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#endif
+
 out_subsys:
        sysfs_remove_link(&dev->kobj, "subsystem");
 out:
@@ -694,8 +723,9 @@ static void device_remove_class_symlinks(struct device *dev)
 {
        if (!dev->class)
                return;
-       if (dev->parent) {
+
 #ifdef CONFIG_SYSFS_DEPRECATED
+       if (dev->parent && dev->type != &part_type) {
                char *class_name;
 
                class_name = make_class_name(dev->class->name, &dev->kobj);
@@ -703,45 +733,59 @@ static void device_remove_class_symlinks(struct device *dev)
                        sysfs_remove_link(&dev->parent->kobj, class_name);
                        kfree(class_name);
                }
-#endif
                sysfs_remove_link(&dev->kobj, "device");
        }
-       if (dev->kobj.parent != &dev->class->subsys.kobj)
+
+       if (dev->kobj.parent != &dev->class->subsys.kobj &&
+           dev->type != &part_type)
                sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#else
+       if (dev->parent && dev->type != &part_type)
+               sysfs_remove_link(&dev->kobj, "device");
+
+       sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#endif
+
        sysfs_remove_link(&dev->kobj, "subsystem");
 }
 
 /**
- *     device_add - add device to device hierarchy.
- *     @dev:   device.
+ * device_add - add device to device hierarchy.
+ * @dev: device.
  *
- *     This is part 2 of device_register(), though may be called
- *     separately _iff_ device_initialize() has been called separately.
+ * This is part 2 of device_register(), though may be called
+ * separately _iff_ device_initialize() has been called separately.
  *
- *     This adds it to the kobject hierarchy via kobject_add(), adds it
- *     to the global and sibling lists for the device, then
- *     adds it to the other relevant subsystems of the driver model.
+ * This adds it to the kobject hierarchy via kobject_add(), adds it
+ * to the global and sibling lists for the device, then
+ * adds it to the other relevant subsystems of the driver model.
  */
 int device_add(struct device *dev)
 {
        struct device *parent = NULL;
        struct class_interface *class_intf;
-       int error = -EINVAL;
+       int error;
+
+       error = pm_sleep_lock();
+       if (error) {
+               dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__);
+               dump_stack();
+               return error;
+       }
 
        dev = get_device(dev);
-       if (!dev || !strlen(dev->bus_id))
+       if (!dev || !strlen(dev->bus_id)) {
+               error = -EINVAL;
                goto Error;
+       }
 
-       pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
+       pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
 
        parent = get_device(dev->parent);
-       error = setup_parent(dev, parent);
-       if (error)
-               goto Error;
+       setup_parent(dev, parent);
 
        /* first, register with generic layer. */
-       kobject_set_name(&dev->kobj, "%s", dev->bus_id);
-       error = kobject_add(&dev->kobj);
+       error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
        if (error)
                goto Error;
 
@@ -751,7 +795,7 @@ int device_add(struct device *dev)
 
        /* notify clients of device entry (new way) */
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_ADD_DEVICE, dev);
 
        error = device_create_file(dev, &uevent_attr);
@@ -795,13 +839,14 @@ int device_add(struct device *dev)
        }
  Done:
        put_device(dev);
+       pm_sleep_unlock();
        return error;
  BusError:
        device_pm_remove(dev);
        dpm_sysfs_remove(dev);
  PMError:
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_attrs(dev);
  AttrsError:
@@ -809,124 +854,84 @@ int device_add(struct device *dev)
  SymlinkError:
        if (MAJOR(dev->devt))
                device_remove_file(dev, &devt_attr);
-
-       if (dev->class) {
-               sysfs_remove_link(&dev->kobj, "subsystem");
-               /* If this is not a "fake" compatible device, remove the
-                * symlink from the class to the device. */
-               if (dev->kobj.parent != &dev->class->subsys.kobj)
-                       sysfs_remove_link(&dev->class->subsys.kobj,
-                                         dev->bus_id);
-               if (parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-                       char *class_name = make_class_name(dev->class->name,
-                                                          &dev->kobj);
-                       if (class_name)
-                               sysfs_remove_link(&dev->parent->kobj,
-                                                 class_name);
-                       kfree(class_name);
-#endif
-                       sysfs_remove_link(&dev->kobj, "device");
-               }
-       }
  ueventattrError:
        device_remove_file(dev, &uevent_attr);
  attrError:
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        kobject_del(&dev->kobj);
  Error:
+       cleanup_device_parent(dev);
        if (parent)
                put_device(parent);
        goto Done;
 }
 
-
 /**
- *     device_register - register a device with the system.
- *     @dev:   pointer to the device structure
+ * device_register - register a device with the system.
+ * @dev: pointer to the device structure
  *
- *     This happens in two clean steps - initialize the device
- *     and add it to the system. The two steps can be called
- *     separately, but this is the easiest and most common.
- *     I.e. you should only call the two helpers separately if
- *     have a clearly defined need to use and refcount the device
- *     before it is added to the hierarchy.
+ * This happens in two clean steps - initialize the device
+ * and add it to the system. The two steps can be called
+ * separately, but this is the easiest and most common.
+ * I.e. you should only call the two helpers separately if
+ * have a clearly defined need to use and refcount the device
+ * before it is added to the hierarchy.
  */
-
 int device_register(struct device *dev)
 {
        device_initialize(dev);
        return device_add(dev);
 }
 
-
 /**
- *     get_device - increment reference count for device.
- *     @dev:   device.
+ * get_device - increment reference count for device.
+ * @dev: device.
  *
- *     This simply forwards the call to kobject_get(), though
- *     we do take care to provide for the case that we get a NULL
- *     pointer passed in.
+ * This simply forwards the call to kobject_get(), though
+ * we do take care to provide for the case that we get a NULL
+ * pointer passed in.
  */
-
-struct device * get_device(struct device * dev)
+struct device *get_device(struct device *dev)
 {
        return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;
 }
 
-
 /**
- *     put_device - decrement reference count.
- *     @dev:   device in question.
+ * put_device - decrement reference count.
+ * @dev: device in question.
  */
-void put_device(struct device * dev)
+void put_device(struct device *dev)
 {
+       /* might_sleep(); */
        if (dev)
                kobject_put(&dev->kobj);
 }
 
-
 /**
- *     device_del - delete device from system.
- *     @dev:   device.
+ * device_del - delete device from system.
+ * @dev: device.
  *
- *     This is the first part of the device unregistration
- *     sequence. This removes the device from the lists we control
- *     from here, has it removed from the other driver model
- *     subsystems it was added to in device_add(), and removes it
- *     from the kobject hierarchy.
+ * This is the first part of the device unregistration
+ * sequence. This removes the device from the lists we control
+ * from here, has it removed from the other driver model
+ * subsystems it was added to in device_add(), and removes it
+ * from the kobject hierarchy.
  *
- *     NOTE: this should be called manually _iff_ device_add() was
- *     also called manually.
+ * NOTE: this should be called manually _iff_ device_add() was
+ * also called manually.
  */
-
-void device_del(struct device * dev)
+void device_del(struct device *dev)
 {
-       struct device * parent = dev->parent;
+       struct device *parent = dev->parent;
        struct class_interface *class_intf;
 
+       device_pm_remove(dev);
        if (parent)
                klist_del(&dev->knode_parent);
        if (MAJOR(dev->devt))
                device_remove_file(dev, &devt_attr);
        if (dev->class) {
-               sysfs_remove_link(&dev->kobj, "subsystem");
-               /* If this is not a "fake" compatible device, remove the
-                * symlink from the class to the device. */
-               if (dev->kobj.parent != &dev->class->subsys.kobj)
-                       sysfs_remove_link(&dev->class->subsys.kobj,
-                                         dev->bus_id);
-               if (parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-                       char *class_name = make_class_name(dev->class->name,
-                                                          &dev->kobj);
-                       if (class_name)
-                               sysfs_remove_link(&dev->parent->kobj,
-                                                 class_name);
-                       kfree(class_name);
-#endif
-                       sysfs_remove_link(&dev->kobj, "device");
-               }
+               device_remove_class_symlinks(dev);
 
                down(&dev->class->sem);
                /* notify any interfaces that the device is now gone */
@@ -936,31 +941,6 @@ void device_del(struct device * dev)
                /* remove the device from the class list */
                list_del_init(&dev->node);
                up(&dev->class->sem);
-
-               /* If we live in a parent class-directory, unreference it */
-               if (dev->kobj.parent->kset == &dev->class->class_dirs) {
-                       struct device *d;
-                       int other = 0;
-
-                       /*
-                        * if we are the last child of our class, delete
-                        * our class-directory at this parent
-                        */
-                       down(&dev->class->sem);
-                       list_for_each_entry(d, &dev->class->devices, node) {
-                               if (d == dev)
-                                       continue;
-                               if (d->kobj.parent == dev->kobj.parent) {
-                                       other = 1;
-                                       break;
-                               }
-                       }
-                       if (!other)
-                               kobject_del(dev->kobj.parent);
-
-                       kobject_put(dev->kobj.parent);
-                       up(&dev->class->sem);
-               }
        }
        device_remove_file(dev, &uevent_attr);
        device_remove_attrs(dev);
@@ -979,57 +959,55 @@ void device_del(struct device * dev)
        if (platform_notify_remove)
                platform_notify_remove(dev);
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DEL_DEVICE, dev);
-       device_pm_remove(dev);
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
+       cleanup_device_parent(dev);
        kobject_del(&dev->kobj);
-       if (parent)
-               put_device(parent);
+       put_device(parent);
 }
 
 /**
- *     device_unregister - unregister device from system.
- *     @dev:   device going away.
+ * device_unregister - unregister device from system.
+ * @dev: device going away.
  *
- *     We do this in two parts, like we do device_register(). First,
- *     we remove it from all the subsystems with device_del(), then
- *     we decrement the reference count via put_device(). If that
- *     is the final reference count, the device will be cleaned up
- *     via device_release() above. Otherwise, the structure will
- *     stick around until the final reference to the device is dropped.
+ * We do this in two parts, like we do device_register(). First,
+ * we remove it from all the subsystems with device_del(), then
+ * we decrement the reference count via put_device(). If that
+ * is the final reference count, the device will be cleaned up
+ * via device_release() above. Otherwise, the structure will
+ * stick around until the final reference to the device is dropped.
  */
-void device_unregister(struct device * dev)
+void device_unregister(struct device *dev)
 {
-       pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id);
+       pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
        device_del(dev);
        put_device(dev);
 }
 
-
-static struct device * next_device(struct klist_iter * i)
+static struct device *next_device(struct klist_iter *i)
 {
-       struct klist_node * n = klist_next(i);
+       struct klist_node *n = klist_next(i);
        return n ? container_of(n, struct device, knode_parent) : NULL;
 }
 
 /**
- *     device_for_each_child - device child iterator.
- *     @parent: parent struct device.
- *     @data:  data for the callback.
- *     @fn:    function to be called for each device.
+ * device_for_each_child - device child iterator.
+ * @parent: parent struct device.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
  *
- *     Iterate over @parent's child devices, and call @fn for each,
- *     passing it @data.
+ * Iterate over @parent's child devices, and call @fn for each,
+ * passing it @data.
  *
- *     We check the return of @fn each time. If it returns anything
- *     other than 0, we break out and return that value.
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
  */
-int device_for_each_child(struct device * parent, void * data,
-                    int (*fn)(struct device *, void *))
+int device_for_each_child(struct device *parent, void *data,
+                         int (*fn)(struct device *dev, void *data))
 {
        struct klist_iter i;
-       struct device * child;
+       struct device *child;
        int error = 0;
 
        klist_iter_init(&parent->klist_children, &i);
@@ -1054,8 +1032,8 @@ int device_for_each_child(struct device * parent, void * data,
  * current device can be obtained, this function will return to the caller
  * and not iterate over any more devices.
  */
-struct device * device_find_child(struct device *parent, void *data,
-                                 int (*match)(struct device *, void *))
+struct device *device_find_child(struct device *parent, void *data,
+                                int (*match)(struct device *dev, void *data))
 {
        struct klist_iter i;
        struct device *child;
@@ -1073,7 +1051,10 @@ struct device * device_find_child(struct device *parent, void *data,
 
 int __init devices_init(void)
 {
-       return subsystem_register(&devices_subsys);
+       devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
+       if (!devices_kset)
+               return -ENOMEM;
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(device_for_each_child);
@@ -1094,7 +1075,7 @@ EXPORT_SYMBOL_GPL(device_remove_file);
 
 static void device_create_release(struct device *dev)
 {
-       pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
+       pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
        kfree(dev);
 }
 
@@ -1156,14 +1137,11 @@ error:
 EXPORT_SYMBOL_GPL(device_create);
 
 /**
- * device_destroy - removes a device that was created with device_create()
+ * find_device - finds a device that was created with device_create()
  * @class: pointer to the struct class that this device was registered with
  * @devt: the dev_t of the device that was previously registered
- *
- * This call unregisters and cleans up a device that was created with a
- * call to device_create().
  */
-void device_destroy(struct class *class, dev_t devt)
+static struct device *find_device(struct class *class, dev_t devt)
 {
        struct device *dev = NULL;
        struct device *dev_tmp;
@@ -1176,12 +1154,54 @@ void device_destroy(struct class *class, dev_t devt)
                }
        }
        up(&class->sem);
+       return dev;
+}
+
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
+ */
+void device_destroy(struct class *class, dev_t devt)
+{
+       struct device *dev;
 
+       dev = find_device(class, devt);
        if (dev)
                device_unregister(dev);
 }
 EXPORT_SYMBOL_GPL(device_destroy);
 
+#ifdef CONFIG_PM_SLEEP
+/**
+ * destroy_suspended_device - asks the PM core to remove a suspended device
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call notifies the PM core of the necessity to unregister a suspended
+ * device created with a call to device_create() (devices cannot be
+ * unregistered directly while suspended, since the PM core holds their
+ * semaphores at that time).
+ *
+ * It can only be called within the scope of a system sleep transition.  In
+ * practice this means it has to be directly or indirectly invoked either by
+ * a suspend or resume method, or by the PM core (e.g. via
+ * disable_nonboot_cpus() or enable_nonboot_cpus()).
+ */
+void destroy_suspended_device(struct class *class, dev_t devt)
+{
+       struct device *dev;
+
+       dev = find_device(class, devt);
+       if (dev)
+               device_pm_schedule_removal(dev);
+}
+EXPORT_SYMBOL_GPL(destroy_suspended_device);
+#endif /* CONFIG_PM_SLEEP */
+
 /**
  * device_rename - renames a device
  * @dev: the pointer to the struct device to be renamed
@@ -1198,7 +1218,8 @@ int device_rename(struct device *dev, char *new_name)
        if (!dev)
                return -EINVAL;
 
-       pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name);
+       pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id,
+                __FUNCTION__, new_name);
 
 #ifdef CONFIG_SYSFS_DEPRECATED
        if ((dev->class) && (dev->parent))
@@ -1279,8 +1300,7 @@ static int device_move_class_links(struct device *dev,
                                          class_name);
                if (error)
                        sysfs_remove_link(&dev->kobj, "device");
-       }
-       else
+       } else
                error = 0;
 out:
        kfree(class_name);
@@ -1311,16 +1331,13 @@ int device_move(struct device *dev, struct device *new_parent)
                return -EINVAL;
 
        new_parent = get_device(new_parent);
-       new_parent_kobj = get_device_parent (dev, new_parent);
-       if (IS_ERR(new_parent_kobj)) {
-               error = PTR_ERR(new_parent_kobj);
-               put_device(new_parent);
-               goto out;
-       }
-       pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
-                new_parent ? new_parent->bus_id : "<NULL>");
+       new_parent_kobj = get_device_parent(dev, new_parent);
+
+       pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id,
+                __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>");
        error = kobject_move(&dev->kobj, new_parent_kobj);
        if (error) {
+               cleanup_glue_dir(dev, new_parent_kobj);
                put_device(new_parent);
                goto out;
        }
@@ -1343,6 +1360,7 @@ int device_move(struct device *dev, struct device *new_parent)
                                klist_add_tail(&dev->knode_parent,
                                               &old_parent->klist_children);
                }
+               cleanup_glue_dir(dev, new_parent_kobj);
                put_device(new_parent);
                goto out;
        }
@@ -1352,5 +1370,23 @@ out:
        put_device(dev);
        return error;
 }
-
 EXPORT_SYMBOL_GPL(device_move);
+
+/**
+ * device_shutdown - call ->shutdown() on each device to shutdown.
+ */
+void device_shutdown(void)
+{
+       struct device *dev, *devn;
+
+       list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
+                               kobj.entry) {
+               if (dev->bus && dev->bus->shutdown) {
+                       dev_dbg(dev, "shutdown\n");
+                       dev->bus->shutdown(dev);
+               } else if (dev->driver && dev->driver->shutdown) {
+                       dev_dbg(dev, "shutdown\n");
+                       dev->driver->shutdown(dev);
+               }
+       }
+}
index 40545071e3c93adc625bb51cb87e007333f06417..c5885f5ce0ac9bc44b8bfdb37068360305133ed0 100644 (file)
@@ -14,7 +14,7 @@
 #include "base.h"
 
 struct sysdev_class cpu_sysdev_class = {
-       set_kset_name("cpu"),
+       .name = "cpu",
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
index 7ac474db88c525f46a0846810ca5f384fa07b104..a5cde94bb982aacc2b111e0c65773d8be8378351 100644 (file)
@@ -1,18 +1,20 @@
 /*
- *     drivers/base/dd.c - The core device/driver interactions.
+ * drivers/base/dd.c - The core device/driver interactions.
  *
- *     This file contains the (sometimes tricky) code that controls the
- *     interactions between devices and drivers, which primarily includes
- *     driver binding and unbinding.
+ * This file contains the (sometimes tricky) code that controls the
+ * interactions between devices and drivers, which primarily includes
+ * driver binding and unbinding.
  *
- *     All of this code used to exist in drivers/base/bus.c, but was
- *     relocated to here in the name of compartmentalization (since it wasn't
- *     strictly code just for the 'struct bus_type'.
+ * All of this code used to exist in drivers/base/bus.c, but was
+ * relocated to here in the name of compartmentalization (since it wasn't
+ * strictly code just for the 'struct bus_type'.
  *
- *     Copyright (c) 2002-5 Patrick Mochel
- *     Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2002-5 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
- *     This file is released under the GPLv2
+ * This file is released under the GPLv2
  */
 
 #include <linux/device.h>
@@ -23,8 +25,6 @@
 #include "base.h"
 #include "power/power.h"
 
-#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
-
 
 static void driver_bound(struct device *dev)
 {
@@ -34,27 +34,27 @@ static void driver_bound(struct device *dev)
                return;
        }
 
-       pr_debug("bound device '%s' to driver '%s'\n",
-                dev->bus_id, dev->driver->name);
+       pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id,
+                __FUNCTION__, dev->driver->name);
 
        if (dev->bus)
-               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+               blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_BOUND_DRIVER, dev);
 
-       klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
+       klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
 }
 
 static int driver_sysfs_add(struct device *dev)
 {
        int ret;
 
-       ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
+       ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
                          kobject_name(&dev->kobj));
        if (ret == 0) {
-               ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj,
+               ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
                                        "driver");
                if (ret)
-                       sysfs_remove_link(&dev->driver->kobj,
+                       sysfs_remove_link(&dev->driver->p->kobj,
                                        kobject_name(&dev->kobj));
        }
        return ret;
@@ -65,24 +65,24 @@ static void driver_sysfs_remove(struct device *dev)
        struct device_driver *drv = dev->driver;
 
        if (drv) {
-               sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+               sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));
                sysfs_remove_link(&dev->kobj, "driver");
        }
 }
 
 /**
- *     device_bind_driver - bind a driver to one device.
- *     @dev:   device.
+ * device_bind_driver - bind a driver to one device.
+ * @dev: device.
  *
- *     Allow manual attachment of a driver to a device.
- *     Caller must have already set @dev->driver.
+ * Allow manual attachment of a driver to a device.
+ * Caller must have already set @dev->driver.
  *
- *     Note that this does not modify the bus reference count
- *     nor take the bus's rwsem. Please verify those are accounted
- *     for before calling this. (It is ok to call with no other effort
- *     from a driver's probe() method.)
+ * Note that this does not modify the bus reference count
+ * nor take the bus's rwsem. Please verify those are accounted
+ * for before calling this. (It is ok to call with no other effort
+ * from a driver's probe() method.)
  *
- *     This function must be called with @dev->sem held.
+ * This function must be called with @dev->sem held.
  */
 int device_bind_driver(struct device *dev)
 {
@@ -93,6 +93,7 @@ int device_bind_driver(struct device *dev)
                driver_bound(dev);
        return ret;
 }
+EXPORT_SYMBOL_GPL(device_bind_driver);
 
 static atomic_t probe_count = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
@@ -102,8 +103,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
        int ret = 0;
 
        atomic_inc(&probe_count);
-       pr_debug("%s: Probing driver %s with device %s\n",
-                drv->bus->name, drv->name, dev->bus_id);
+       pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
+                drv->bus->name, __FUNCTION__, drv->name, dev->bus_id);
        WARN_ON(!list_empty(&dev->devres_head));
 
        dev->driver = drv;
@@ -125,8 +126,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
 
        driver_bound(dev);
        ret = 1;
-       pr_debug("%s: Bound Device %s to Driver %s\n",
-                drv->bus->name, dev->bus_id, drv->name);
+       pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
+                drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
        goto done;
 
 probe_failed:
@@ -183,7 +184,7 @@ int driver_probe_done(void)
  * This function must be called with @dev->sem held.  When called for a
  * USB interface, @dev->parent->sem must be held as well.
  */
-int driver_probe_device(struct device_driver * drv, struct device * dev)
+int driver_probe_device(struct device_driver *drv, struct device *dev)
 {
        int ret = 0;
 
@@ -192,8 +193,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
        if (drv->bus->match && !drv->bus->match(dev, drv))
                goto done;
 
-       pr_debug("%s: Matched Device %s with Driver %s\n",
-                drv->bus->name, dev->bus_id, drv->name);
+       pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
+                drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
 
        ret = really_probe(dev, drv);
 
@@ -201,27 +202,27 @@ done:
        return ret;
 }
 
-static int __device_attach(struct device_driver * drv, void * data)
+static int __device_attach(struct device_driver *drv, void *data)
 {
-       struct device * dev = data;
+       struct device *dev = data;
        return driver_probe_device(drv, dev);
 }
 
 /**
- *     device_attach - try to attach device to a driver.
- *     @dev:   device.
+ * device_attach - try to attach device to a driver.
+ * @dev: device.
  *
- *     Walk the list of drivers that the bus has and call
- *     driver_probe_device() for each pair. If a compatible
- *     pair is found, break out and return.
+ * Walk the list of drivers that the bus has and call
+ * driver_probe_device() for each pair. If a compatible
+ * pair is found, break out and return.
  *
- *     Returns 1 if the device was bound to a driver;
- *     0 if no matching device was found;
- *     -ENODEV if the device is not registered.
+ * Returns 1 if the device was bound to a driver;
+ * 0 if no matching device was found;
+ * -ENODEV if the device is not registered.
  *
- *     When called for a USB interface, @dev->parent->sem must be held.
+ * When called for a USB interface, @dev->parent->sem must be held.
  */
-int device_attach(struct device * dev)
+int device_attach(struct device *dev)
 {
        int ret = 0;
 
@@ -240,10 +241,11 @@ int device_attach(struct device * dev)
        up(&dev->sem);
        return ret;
 }
+EXPORT_SYMBOL_GPL(device_attach);
 
-static int __driver_attach(struct device * dev, void * data)
+static int __driver_attach(struct device *dev, void *data)
 {
-       struct device_driver * drv = data;
+       struct device_driver *drv = data;
 
        /*
         * Lock device and try to bind to it. We drop the error
@@ -268,35 +270,35 @@ static int __driver_attach(struct device * dev, void * data)
 }
 
 /**
- *     driver_attach - try to bind driver to devices.
- *     @drv:   driver.
+ * driver_attach - try to bind driver to devices.
+ * @drv: driver.
  *
- *     Walk the list of devices that the bus has on it and try to
- *     match the driver with each one.  If driver_probe_device()
- *     returns 0 and the @dev->driver is set, we've found a
- *     compatible pair.
+ * Walk the list of devices that the bus has on it and try to
+ * match the driver with each one.  If driver_probe_device()
+ * returns 0 and the @dev->driver is set, we've found a
+ * compatible pair.
  */
-int driver_attach(struct device_driver * drv)
+int driver_attach(struct device_driver *drv)
 {
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
 }
+EXPORT_SYMBOL_GPL(driver_attach);
 
 /*
- *     __device_release_driver() must be called with @dev->sem held.
- *     When called for a USB interface, @dev->parent->sem must be held as well.
+ * __device_release_driver() must be called with @dev->sem held.
+ * When called for a USB interface, @dev->parent->sem must be held as well.
  */
-static void __device_release_driver(struct device * dev)
+static void __device_release_driver(struct device *dev)
 {
-       struct device_driver * drv;
+       struct device_driver *drv;
 
-       drv = get_driver(dev->driver);
+       drv = dev->driver;
        if (drv) {
                driver_sysfs_remove(dev);
                sysfs_remove_link(&dev->kobj, "driver");
-               klist_remove(&dev->knode_driver);
 
                if (dev->bus)
-                       blocking_notifier_call_chain(&dev->bus->bus_notifier,
+                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                                     BUS_NOTIFY_UNBIND_DRIVER,
                                                     dev);
 
@@ -306,18 +308,18 @@ static void __device_release_driver(struct device * dev)
                        drv->remove(dev);
                devres_release_all(dev);
                dev->driver = NULL;
-               put_driver(drv);
+               klist_remove(&dev->knode_driver);
        }
 }
 
 /**
- *     device_release_driver - manually detach device from driver.
- *     @dev:   device.
+ * device_release_driver - manually detach device from driver.
+ * @dev: device.
  *
- *     Manually detach device from driver.
- *     When called for a USB interface, @dev->parent->sem must be held.
+ * Manually detach device from driver.
+ * When called for a USB interface, @dev->parent->sem must be held.
  */
-void device_release_driver(struct device * dev)
+void device_release_driver(struct device *dev)
 {
        /*
         * If anyone calls device_release_driver() recursively from
@@ -328,26 +330,26 @@ void device_release_driver(struct device * dev)
        __device_release_driver(dev);
        up(&dev->sem);
 }
-
+EXPORT_SYMBOL_GPL(device_release_driver);
 
 /**
  * driver_detach - detach driver from all devices it controls.
  * @drv: driver.
  */
-void driver_detach(struct device_driver * drv)
+void driver_detach(struct device_driver *drv)
 {
-       struct device * dev;
+       struct device *dev;
 
        for (;;) {
-               spin_lock(&drv->klist_devices.k_lock);
-               if (list_empty(&drv->klist_devices.k_list)) {
-                       spin_unlock(&drv->klist_devices.k_lock);
+               spin_lock(&drv->p->klist_devices.k_lock);
+               if (list_empty(&drv->p->klist_devices.k_list)) {
+                       spin_unlock(&drv->p->klist_devices.k_lock);
                        break;
                }
-               dev = list_entry(drv->klist_devices.k_list.prev,
+               dev = list_entry(drv->p->klist_devices.k_list.prev,
                                struct device, knode_driver.n_node);
                get_device(dev);
-               spin_unlock(&drv->klist_devices.k_lock);
+               spin_unlock(&drv->p->klist_devices.k_lock);
 
                if (dev->parent)        /* Needed for USB */
                        down(&dev->parent->sem);
@@ -360,9 +362,3 @@ void driver_detach(struct device_driver * drv)
                put_device(dev);
        }
 }
-
-EXPORT_SYMBOL_GPL(device_bind_driver);
-EXPORT_SYMBOL_GPL(device_release_driver);
-EXPORT_SYMBOL_GPL(device_attach);
-EXPORT_SYMBOL_GPL(driver_attach);
-
index eb11475293ed614ea381589296db607381099cc2..a35f04121a00f938503f3b585c4e792e8a578d8f 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  *
 #include "base.h"
 
 #define to_dev(node) container_of(node, struct device, driver_list)
-#define to_drv(obj) container_of(obj, struct device_driver, kobj)
 
 
-static struct device * next_device(struct klist_iter * i)
+static struct device *next_device(struct klist_iter *i)
 {
-       struct klist_node * n = klist_next(i);
+       struct klist_node *n = klist_next(i);
        return n ? container_of(n, struct device, knode_driver) : NULL;
 }
 
 /**
- *     driver_for_each_device - Iterator for devices bound to a driver.
- *     @drv:   Driver we're iterating.
- *     @start: Device to begin with
- *     @data:  Data to pass to the callback.
- *     @fn:    Function to call for each device.
+ * driver_for_each_device - Iterator for devices bound to a driver.
+ * @drv: Driver we're iterating.
+ * @start: Device to begin with
+ * @data: Data to pass to the callback.
+ * @fn: Function to call for each device.
  *
- *     Iterate over the @drv's list of devices calling @fn for each one.
+ * Iterate over the @drv's list of devices calling @fn for each one.
  */
-
-int driver_for_each_device(struct device_driver * drv, struct device * start, 
-                          void * data, int (*fn)(struct device *, void *))
+int driver_for_each_device(struct device_driver *drv, struct device *start,
+                          void *data, int (*fn)(struct device *, void *))
 {
        struct klist_iter i;
-       struct device * dev;
+       struct device *dev;
        int error = 0;
 
        if (!drv)
                return -EINVAL;
 
-       klist_iter_init_node(&drv->klist_devices, &i,
+       klist_iter_init_node(&drv->p->klist_devices, &i,
                             start ? &start->knode_driver : NULL);
        while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
        klist_iter_exit(&i);
        return error;
 }
-
 EXPORT_SYMBOL_GPL(driver_for_each_device);
 
-
 /**
  * driver_find_device - device iterator for locating a particular device.
  * @drv: The device's driver
@@ -70,9 +68,9 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
  * if it does.  If the callback returns non-zero, this function will
  * return to the caller and not iterate over any more devices.
  */
-struct device * driver_find_device(struct device_driver *drv,
-                                  struct device * start, void * data,
-                                  int (*match)(struct device *, void *))
+struct device *driver_find_device(struct device_driver *drv,
+                                 struct device *start, void *data,
+                                 int (*match)(struct device *dev, void *data))
 {
        struct klist_iter i;
        struct device *dev;
@@ -80,7 +78,7 @@ struct device * driver_find_device(struct device_driver *drv,
        if (!drv)
                return NULL;
 
-       klist_iter_init_node(&drv->klist_devices, &i,
+       klist_iter_init_node(&drv->p->klist_devices, &i,
                             (start ? &start->knode_driver : NULL));
        while ((dev = next_device(&i)))
                if (match(dev, data) && get_device(dev))
@@ -91,111 +89,179 @@ struct device * driver_find_device(struct device_driver *drv,
 EXPORT_SYMBOL_GPL(driver_find_device);
 
 /**
- *     driver_create_file - create sysfs file for driver.
- *     @drv:   driver.
- *     @attr:  driver attribute descriptor.
+ * driver_create_file - create sysfs file for driver.
+ * @drv: driver.
+ * @attr: driver attribute descriptor.
  */
-
-int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
+int driver_create_file(struct device_driver *drv,
+                      struct driver_attribute *attr)
 {
        int error;
        if (get_driver(drv)) {
-               error = sysfs_create_file(&drv->kobj, &attr->attr);
+               error = sysfs_create_file(&drv->p->kobj, &attr->attr);
                put_driver(drv);
        } else
                error = -EINVAL;
        return error;
 }
-
+EXPORT_SYMBOL_GPL(driver_create_file);
 
 /**
- *     driver_remove_file - remove sysfs file for driver.
- *     @drv:   driver.
- *     @attr:  driver attribute descriptor.
+ * driver_remove_file - remove sysfs file for driver.
+ * @drv: driver.
+ * @attr: driver attribute descriptor.
  */
-
-void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
+void driver_remove_file(struct device_driver *drv,
+                       struct driver_attribute *attr)
 {
        if (get_driver(drv)) {
-               sysfs_remove_file(&drv->kobj, &attr->attr);
+               sysfs_remove_file(&drv->p->kobj, &attr->attr);
                put_driver(drv);
        }
 }
-
+EXPORT_SYMBOL_GPL(driver_remove_file);
 
 /**
- *     get_driver - increment driver reference count.
- *     @drv:   driver.
+ * driver_add_kobj - add a kobject below the specified driver
+ *
+ * You really don't want to do this, this is only here due to one looney
+ * iseries driver, go poke those developers if you are annoyed about
+ * this...
  */
-struct device_driver * get_driver(struct device_driver * drv)
+int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
+                   const char *fmt, ...)
 {
-       return drv ? to_drv(kobject_get(&drv->kobj)) : NULL;
+       va_list args;
+       char *name;
+
+       va_start(args, fmt);
+       name = kvasprintf(GFP_KERNEL, fmt, args);
+       va_end(args);
+
+       if (!name)
+               return -ENOMEM;
+
+       return kobject_add(kobj, &drv->p->kobj, "%s", name);
 }
+EXPORT_SYMBOL_GPL(driver_add_kobj);
+
+/**
+ * get_driver - increment driver reference count.
+ * @drv: driver.
+ */
+struct device_driver *get_driver(struct device_driver *drv)
+{
+       if (drv) {
+               struct driver_private *priv;
+               struct kobject *kobj;
 
+               kobj = kobject_get(&drv->p->kobj);
+               priv = to_driver(kobj);
+               return priv->driver;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(get_driver);
 
 /**
- *     put_driver - decrement driver's refcount.
- *     @drv:   driver.
+ * put_driver - decrement driver's refcount.
+ * @drv: driver.
  */
-void put_driver(struct device_driver * drv)
+void put_driver(struct device_driver *drv)
+{
+       kobject_put(&drv->p->kobj);
+}
+EXPORT_SYMBOL_GPL(put_driver);
+
+static int driver_add_groups(struct device_driver *drv,
+                            struct attribute_group **groups)
 {
-       kobject_put(&drv->kobj);
+       int error = 0;
+       int i;
+
+       if (groups) {
+               for (i = 0; groups[i]; i++) {
+                       error = sysfs_create_group(&drv->p->kobj, groups[i]);
+                       if (error) {
+                               while (--i >= 0)
+                                       sysfs_remove_group(&drv->p->kobj,
+                                                          groups[i]);
+                               break;
+                       }
+               }
+       }
+       return error;
+}
+
+static void driver_remove_groups(struct device_driver *drv,
+                                struct attribute_group **groups)
+{
+       int i;
+
+       if (groups)
+               for (i = 0; groups[i]; i++)
+                       sysfs_remove_group(&drv->p->kobj, groups[i]);
 }
 
 /**
- *     driver_register - register driver with bus
- *     @drv:   driver to register
+ * driver_register - register driver with bus
+ * @drv: driver to register
  *
- *     We pass off most of the work to the bus_add_driver() call,
- *     since most of the things we have to do deal with the bus
- *     structures.
+ * We pass off most of the work to the bus_add_driver() call,
+ * since most of the things we have to do deal with the bus
+ * structures.
  */
-int driver_register(struct device_driver * drv)
+int driver_register(struct device_driver *drv)
 {
+       int ret;
+
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
-           (drv->bus->shutdown && drv->shutdown)) {
-               printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
-       }
-       klist_init(&drv->klist_devices, NULL, NULL);
-       return bus_add_driver(drv);
+           (drv->bus->shutdown && drv->shutdown))
+               printk(KERN_WARNING "Driver '%s' needs updating - please use "
+                       "bus_type methods\n", drv->name);
+       ret = bus_add_driver(drv);
+       if (ret)
+               return ret;
+       ret = driver_add_groups(drv, drv->groups);
+       if (ret)
+               bus_remove_driver(drv);
+       return ret;
 }
+EXPORT_SYMBOL_GPL(driver_register);
 
 /**
- *     driver_unregister - remove driver from system.
- *     @drv:   driver.
+ * driver_unregister - remove driver from system.
+ * @drv: driver.
  *
- *     Again, we pass off most of the work to the bus-level call.
+ * Again, we pass off most of the work to the bus-level call.
  */
-
-void driver_unregister(struct device_driver * drv)
+void driver_unregister(struct device_driver *drv)
 {
+       driver_remove_groups(drv, drv->groups);
        bus_remove_driver(drv);
 }
+EXPORT_SYMBOL_GPL(driver_unregister);
 
 /**
- *     driver_find - locate driver on a bus by its name.
- *     @name:  name of the driver.
- *     @bus:   bus to scan for the driver.
+ * driver_find - locate driver on a bus by its name.
+ * @name: name of the driver.
+ * @bus: bus to scan for the driver.
  *
- *     Call kset_find_obj() to iterate over list of drivers on
- *     a bus to find driver by name. Return driver if found.
+ * Call kset_find_obj() to iterate over list of drivers on
+ * a bus to find driver by name. Return driver if found.
  *
- *     Note that kset_find_obj increments driver's reference count.
+ * Note that kset_find_obj increments driver's reference count.
  */
 struct device_driver *driver_find(const char *name, struct bus_type *bus)
 {
-       struct kobject *k = kset_find_obj(&bus->drivers, name);
-       if (k)
-               return to_drv(k);
+       struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
+       struct driver_private *priv;
+
+       if (k) {
+               priv = to_driver(k);
+               return priv->driver;
+       }
        return NULL;
 }
-
-EXPORT_SYMBOL_GPL(driver_register);
-EXPORT_SYMBOL_GPL(driver_unregister);
-EXPORT_SYMBOL_GPL(get_driver);
-EXPORT_SYMBOL_GPL(put_driver);
 EXPORT_SYMBOL_GPL(driver_find);
-
-EXPORT_SYMBOL_GPL(driver_create_file);
-EXPORT_SYMBOL_GPL(driver_remove_file);
index 90c8629321698b8a697d84b47f04eb67ded96b89..11381555680943616bbc82a734f4e0e860ee5024 100644 (file)
@@ -3,11 +3,11 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
- *
  */
-
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
 #include "base.h"
 
-static decl_subsys(firmware, NULL, NULL);
-
-int firmware_register(struct kset *s)
-{
-       kobj_set_kset_s(s, firmware_subsys);
-       return subsystem_register(s);
-}
-
-void firmware_unregister(struct kset *s)
-{
-       subsystem_unregister(s);
-}
+struct kobject *firmware_kobj;
+EXPORT_SYMBOL_GPL(firmware_kobj);
 
 int __init firmware_init(void)
 {
-       return subsystem_register(&firmware_subsys);
+       firmware_kobj = kobject_create_and_add("firmware", NULL);
+       if (!firmware_kobj)
+               return -ENOMEM;
+       return 0;
 }
-
-EXPORT_SYMBOL_GPL(firmware_register);
-EXPORT_SYMBOL_GPL(firmware_unregister);
index 7080b413ddc9f6c475056adf161cf248321c9927..6428cba3aadddf51081926671143504e5a9247e8 100644 (file)
@@ -2,19 +2,23 @@
  * hypervisor.c - /sys/hypervisor subsystem.
  *
  * Copyright (C) IBM Corp. 2006
+ * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  */
 
 #include <linux/kobject.h>
 #include <linux/device.h>
-
 #include "base.h"
 
-decl_subsys(hypervisor, NULL, NULL);
-EXPORT_SYMBOL_GPL(hypervisor_subsys);
+struct kobject *hypervisor_kobj;
+EXPORT_SYMBOL_GPL(hypervisor_kobj);
 
 int __init hypervisor_init(void)
 {
-       return subsystem_register(&hypervisor_subsys);
+       hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);
+       if (!hypervisor_kobj)
+               return -ENOMEM;
+       return 0;
 }
index 37138154f9e824b353f322022ba8c41017ae3c3e..7bd9b6a5b01f9497fcb2c35fccae144860299f93 100644 (file)
@@ -1,10 +1,8 @@
 /*
- *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
  *
  * This file is released under the GPLv2
- *
  */
 
 #include <linux/device.h>
 #include "base.h"
 
 /**
- *     driver_init - initialize driver model.
+ * driver_init - initialize driver model.
  *
- *     Call the driver model init functions to initialize their
- *     subsystems. Called early from init/main.c.
+ * Call the driver model init functions to initialize their
+ * subsystems. Called early from init/main.c.
  */
-
 void __init driver_init(void)
 {
        /* These are the core pieces */
@@ -36,5 +33,4 @@ void __init driver_init(void)
        system_bus_init();
        cpu_dev_init();
        memory_dev_init();
-       attribute_container_init();
 }
index 7868707c7eda30035ea2eff7e3309011c11a2669..7ae413fdd5fc4bd1f0d1b0941316df52dbe8e11f 100644 (file)
@@ -26,7 +26,7 @@
 #define MEMORY_CLASS_NAME      "memory"
 
 static struct sysdev_class memory_sysdev_class = {
-       set_kset_name(MEMORY_CLASS_NAME),
+       .name = MEMORY_CLASS_NAME,
 };
 
 static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
diff --git a/drivers/base/module.c b/drivers/base/module.c
new file mode 100644 (file)
index 0000000..103be9c
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * module.c - module sysfs fun for drivers
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include "base.h"
+
+static char *make_driver_name(struct device_driver *drv)
+{
+       char *driver_name;
+
+       driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
+                             GFP_KERNEL);
+       if (!driver_name)
+               return NULL;
+
+       sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
+       return driver_name;
+}
+
+static void module_create_drivers_dir(struct module_kobject *mk)
+{
+       if (!mk || mk->drivers_dir)
+               return;
+
+       mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
+}
+
+void module_add_driver(struct module *mod, struct device_driver *drv)
+{
+       char *driver_name;
+       int no_warn;
+       struct module_kobject *mk = NULL;
+
+       if (!drv)
+               return;
+
+       if (mod)
+               mk = &mod->mkobj;
+       else if (drv->mod_name) {
+               struct kobject *mkobj;
+
+               /* Lookup built-in module entry in /sys/modules */
+               mkobj = kset_find_obj(module_kset, drv->mod_name);
+               if (mkobj) {
+                       mk = container_of(mkobj, struct module_kobject, kobj);
+                       /* remember our module structure */
+                       drv->p->mkobj = mk;
+                       /* kset_find_obj took a reference */
+                       kobject_put(mkobj);
+               }
+       }
+
+       if (!mk)
+               return;
+
+       /* Don't check return codes; these calls are idempotent */
+       no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
+       driver_name = make_driver_name(drv);
+       if (driver_name) {
+               module_create_drivers_dir(mk);
+               no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
+                                           driver_name);
+               kfree(driver_name);
+       }
+}
+
+void module_remove_driver(struct device_driver *drv)
+{
+       struct module_kobject *mk = NULL;
+       char *driver_name;
+
+       if (!drv)
+               return;
+
+       sysfs_remove_link(&drv->p->kobj, "module");
+
+       if (drv->owner)
+               mk = &drv->owner->mkobj;
+       else if (drv->p->mkobj)
+               mk = drv->p->mkobj;
+       if (mk && mk->drivers_dir) {
+               driver_name = make_driver_name(drv);
+               if (driver_name) {
+                       sysfs_remove_link(mk->drivers_dir, driver_name);
+                       kfree(driver_name);
+               }
+       }
+}
index 88eeed72b5d6557289392202a21338496676e55b..e59861f18ce55616981e7ca9fbc5ad2a6698f04f 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/device.h>
 
 static struct sysdev_class node_class = {
-       set_kset_name("node"),
+       .name = "node",
 };
 
 
index fb56092414821645342071f5c0da32ef2a486b4b..efaf282c438c4108b1f01c41dc6b873c0fde669d 100644 (file)
@@ -20,7 +20,8 @@
 
 #include "base.h"
 
-#define to_platform_driver(drv)        (container_of((drv), struct platform_driver, driver))
+#define to_platform_driver(drv)        (container_of((drv), struct platform_driver, \
+                                driver))
 
 struct device platform_bus = {
        .bus_id         = "platform",
@@ -28,14 +29,13 @@ struct device platform_bus = {
 EXPORT_SYMBOL_GPL(platform_bus);
 
 /**
- *     platform_get_resource - get a resource for a device
- *     @dev: platform device
- *     @type: resource type
- *     @num: resource index
+ * platform_get_resource - get a resource for a device
+ * @dev: platform device
+ * @type: resource type
+ * @num: resource index
  */
-struct resource *
-platform_get_resource(struct platform_device *dev, unsigned int type,
-                     unsigned int num)
+struct resource *platform_get_resource(struct platform_device *dev,
+                                      unsigned int type, unsigned int num)
 {
        int i;
 
@@ -43,8 +43,7 @@ platform_get_resource(struct platform_device *dev, unsigned int type,
                struct resource *r = &dev->resource[i];
 
                if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
-                                IORESOURCE_IRQ|IORESOURCE_DMA))
-                   == type)
+                                IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
                        if (num-- == 0)
                                return r;
        }
@@ -53,9 +52,9 @@ platform_get_resource(struct platform_device *dev, unsigned int type,
 EXPORT_SYMBOL_GPL(platform_get_resource);
 
 /**
- *     platform_get_irq - get an IRQ for a device
- *     @dev: platform device
- *     @num: IRQ number index
+ * platform_get_irq - get an IRQ for a device
+ * @dev: platform device
+ * @num: IRQ number index
  */
 int platform_get_irq(struct platform_device *dev, unsigned int num)
 {
@@ -66,14 +65,13 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
 /**
- *     platform_get_resource_byname - get a resource for a device by name
- *     @dev: platform device
- *     @type: resource type
- *     @name: resource name
+ * platform_get_resource_byname - get a resource for a device by name
+ * @dev: platform device
+ * @type: resource type
+ * @name: resource name
  */
-struct resource *
-platform_get_resource_byname(struct platform_device *dev, unsigned int type,
-                     char *name)
+struct resource *platform_get_resource_byname(struct platform_device *dev,
+                                             unsigned int type, char *name)
 {
        int i;
 
@@ -90,22 +88,23 @@ platform_get_resource_byname(struct platform_device *dev, unsigned int type,
 EXPORT_SYMBOL_GPL(platform_get_resource_byname);
 
 /**
- *     platform_get_irq - get an IRQ for a device
- *     @dev: platform device
- *     @name: IRQ name
+ * platform_get_irq - get an IRQ for a device
+ * @dev: platform device
+ * @name: IRQ name
  */
 int platform_get_irq_byname(struct platform_device *dev, char *name)
 {
-       struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
+       struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
+                                                         name);
 
        return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq_byname);
 
 /**
- *     platform_add_devices - add a numbers of platform devices
- *     @devs: array of platform devices to add
- *     @num: number of platform devices in array
+ * platform_add_devices - add a numbers of platform devices
+ * @devs: array of platform devices to add
+ * @num: number of platform devices in array
  */
 int platform_add_devices(struct platform_device **devs, int num)
 {
@@ -130,12 +129,11 @@ struct platform_object {
 };
 
 /**
- *     platform_device_put
- *     @pdev:  platform device to free
+ * platform_device_put
+ * @pdev: platform device to free
  *
- *     Free all memory associated with a platform device.  This function
- *     must _only_ be externally called in error cases.  All other usage
- *     is a bug.
+ * Free all memory associated with a platform device.  This function must
+ * _only_ be externally called in error cases.  All other usage is a bug.
  */
 void platform_device_put(struct platform_device *pdev)
 {
@@ -146,7 +144,8 @@ EXPORT_SYMBOL_GPL(platform_device_put);
 
 static void platform_device_release(struct device *dev)
 {
-       struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev);
+       struct platform_object *pa = container_of(dev, struct platform_object,
+                                                 pdev.dev);
 
        kfree(pa->pdev.dev.platform_data);
        kfree(pa->pdev.resource);
@@ -154,12 +153,12 @@ static void platform_device_release(struct device *dev)
 }
 
 /**
- *     platform_device_alloc
- *     @name:  base name of the device we're adding
- *     @id:    instance id
+ * platform_device_alloc
+ * @name: base name of the device we're adding
+ * @id: instance id
  *
- *     Create a platform device object which can have other objects attached
- *     to it, and which will have attached objects freed when it is released.
+ * Create a platform device object which can have other objects attached
+ * to it, and which will have attached objects freed when it is released.
  */
 struct platform_device *platform_device_alloc(const char *name, int id)
 {
@@ -179,16 +178,17 @@ struct platform_device *platform_device_alloc(const char *name, int id)
 EXPORT_SYMBOL_GPL(platform_device_alloc);
 
 /**
- *     platform_device_add_resources
- *     @pdev:  platform device allocated by platform_device_alloc to add resources to
- *     @res:   set of resources that needs to be allocated for the device
- *     @num:   number of resources
+ * platform_device_add_resources
+ * @pdev: platform device allocated by platform_device_alloc to add resources to
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
  *
- *     Add a copy of the resources to the platform device.  The memory
- *     associated with the resources will be freed when the platform
- *     device is released.
+ * Add a copy of the resources to the platform device.  The memory
+ * associated with the resources will be freed when the platform device is
+ * released.
  */
-int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num)
+int platform_device_add_resources(struct platform_device *pdev,
+                                 struct resource *res, unsigned int num)
 {
        struct resource *r;
 
@@ -203,16 +203,17 @@ int platform_device_add_resources(struct platform_device *pdev, struct resource
 EXPORT_SYMBOL_GPL(platform_device_add_resources);
 
 /**
- *     platform_device_add_data
- *     @pdev:  platform device allocated by platform_device_alloc to add resources to
- *     @data:  platform specific data for this platform device
- *     @size:  size of platform specific data
+ * platform_device_add_data
+ * @pdev: platform device allocated by platform_device_alloc to add resources to
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
  *
- *     Add a copy of platform specific data to the platform device's platform_data
- *     pointer.  The memory associated with the platform data will be freed
- *     when the platform device is released.
+ * Add a copy of platform specific data to the platform device's
+ * platform_data pointer.  The memory associated with the platform data
+ * will be freed when the platform device is released.
  */
-int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size)
+int platform_device_add_data(struct platform_device *pdev, const void *data,
+                            size_t size)
 {
        void *d;
 
@@ -226,11 +227,11 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, siz
 EXPORT_SYMBOL_GPL(platform_device_add_data);
 
 /**
- *     platform_device_add - add a platform device to device hierarchy
- *     @pdev:  platform device we're adding
+ * platform_device_add - add a platform device to device hierarchy
+ * @pdev: platform device we're adding
  *
- *     This is part 2 of platform_device_register(), though may be called
- *     separately _iff_ pdev was allocated by platform_device_alloc().
+ * This is part 2 of platform_device_register(), though may be called
+ * separately _iff_ pdev was allocated by platform_device_alloc().
  */
 int platform_device_add(struct platform_device *pdev)
 {
@@ -289,13 +290,12 @@ int platform_device_add(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(platform_device_add);
 
 /**
- *     platform_device_del - remove a platform-level device
- *     @pdev:  platform device we're removing
+ * platform_device_del - remove a platform-level device
+ * @pdev: platform device we're removing
  *
- *     Note that this function will also release all memory- and port-based
- *     resources owned by the device (@dev->resource).  This function
- *     must _only_ be externally called in error cases.  All other usage
- *     is a bug.
+ * Note that this function will also release all memory- and port-based
+ * resources owned by the device (@dev->resource).  This function must
+ * _only_ be externally called in error cases.  All other usage is a bug.
  */
 void platform_device_del(struct platform_device *pdev)
 {
@@ -314,11 +314,10 @@ void platform_device_del(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(platform_device_del);
 
 /**
- *     platform_device_register - add a platform-level device
- *     @pdev:  platform device we're adding
- *
+ * platform_device_register - add a platform-level device
+ * @pdev: platform device we're adding
  */
-int platform_device_register(struct platform_device * pdev)
+int platform_device_register(struct platform_device *pdev)
 {
        device_initialize(&pdev->dev);
        return platform_device_add(pdev);
@@ -326,14 +325,14 @@ int platform_device_register(struct platform_device * pdev)
 EXPORT_SYMBOL_GPL(platform_device_register);
 
 /**
- *     platform_device_unregister - unregister a platform-level device
- *     @pdev:  platform device we're unregistering
+ * platform_device_unregister - unregister a platform-level device
+ * @pdev: platform device we're unregistering
  *
- *     Unregistration is done in 2 steps. First we release all resources
- *     and remove it from the subsystem, then we drop reference count by
- *     calling platform_device_put().
+ * Unregistration is done in 2 steps. First we release all resources
+ * and remove it from the subsystem, then we drop reference count by
+ * calling platform_device_put().
  */
-void platform_device_unregister(struct platform_device * pdev)
+void platform_device_unregister(struct platform_device *pdev)
 {
        platform_device_del(pdev);
        platform_device_put(pdev);
@@ -341,27 +340,29 @@ void platform_device_unregister(struct platform_device * pdev)
 EXPORT_SYMBOL_GPL(platform_device_unregister);
 
 /**
- *     platform_device_register_simple
- *     @name:  base name of the device we're adding
- *     @id:    instance id
- *     @res:   set of resources that needs to be allocated for the device
- *     @num:   number of resources
+ * platform_device_register_simple
+ * @name: base name of the device we're adding
+ * @id: instance id
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
  *
- *     This function creates a simple platform device that requires minimal
- *     resource and memory management. Canned release function freeing
- *     memory allocated for the device allows drivers using such devices
- *     to be unloaded without waiting for the last reference to the device
- *     to be dropped.
+ * This function creates a simple platform device that requires minimal
+ * resource and memory management. Canned release function freeing memory
+ * allocated for the device allows drivers using such devices to be
+ * unloaded without waiting for the last reference to the device to be
+ * dropped.
  *
- *     This interface is primarily intended for use with legacy drivers
- *     which probe hardware directly.  Because such drivers create sysfs
- *     device nodes themselves, rather than letting system infrastructure
- *     handle such device enumeration tasks, they don't fully conform to
- *     the Linux driver model.  In particular, when such drivers are built
- *     as modules, they can't be "hotplugged".
+ * This interface is primarily intended for use with legacy drivers which
+ * probe hardware directly.  Because such drivers create sysfs device nodes
+ * themselves, rather than letting system infrastructure handle such device
+ * enumeration tasks, they don't fully conform to the Linux driver model.
+ * In particular, when such drivers are built as modules, they can't be
+ * "hotplugged".
  */
-struct platform_device *platform_device_register_simple(char *name, int id,
-                                                       struct resource *res, unsigned int num)
+struct platform_device *platform_device_register_simple(const char *name,
+                                                       int id,
+                                                       struct resource *res,
+                                                       unsigned int num)
 {
        struct platform_device *pdev;
        int retval;
@@ -436,8 +437,8 @@ static int platform_drv_resume(struct device *_dev)
 }
 
 /**
- *     platform_driver_register
- *     @drv: platform driver structure
+ * platform_driver_register
+ * @drv: platform driver structure
  */
 int platform_driver_register(struct platform_driver *drv)
 {
@@ -457,8 +458,8 @@ int platform_driver_register(struct platform_driver *drv)
 EXPORT_SYMBOL_GPL(platform_driver_register);
 
 /**
- *     platform_driver_unregister
- *     @drv: platform driver structure
+ * platform_driver_unregister
+ * @drv: platform driver structure
  */
 void platform_driver_unregister(struct platform_driver *drv)
 {
@@ -497,12 +498,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
         * if the probe was successful, and make sure any forced probes of
         * new devices fail.
         */
-       spin_lock(&platform_bus_type.klist_drivers.k_lock);
+       spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
        drv->probe = NULL;
-       if (code == 0 && list_empty(&drv->driver.klist_devices.k_list))
+       if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
                retval = -ENODEV;
        drv->driver.probe = platform_drv_probe_fail;
-       spin_unlock(&platform_bus_type.klist_drivers.k_lock);
+       spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
 
        if (code != retval)
                platform_driver_unregister(drv);
@@ -516,8 +517,8 @@ EXPORT_SYMBOL_GPL(platform_driver_probe);
  * (b) sysfs attribute lets new-style coldplug recover from hotplug events
  *     mishandled before system is fully running:  "modprobe $(cat modalias)"
  */
-static ssize_t
-modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
 {
        struct platform_device  *pdev = to_platform_device(dev);
        int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
@@ -538,26 +539,24 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-
 /**
- *     platform_match - bind platform device to platform driver.
- *     @dev:   device.
- *     @drv:   driver.
+ * platform_match - bind platform device to platform driver.
+ * @dev: device.
+ * @drv: driver.
  *
- *     Platform device IDs are assumed to be encoded like this:
- *     "<name><instance>", where <name> is a short description of the
- *     type of device, like "pci" or "floppy", and <instance> is the
- *     enumerated instance of the device, like '0' or '42'.
- *     Driver IDs are simply "<name>".
- *     So, extract the <name> from the platform_device structure,
- *     and compare it against the name of the driver. Return whether
- *     they match or not.
+ * Platform device IDs are assumed to be encoded like this:
+ * "<name><instance>", where <name> is a short description of the type of
+ * device, like "pci" or "floppy", and <instance> is the enumerated
+ * instance of the device, like '0' or '42'.  Driver IDs are simply
+ * "<name>".  So, extract the <name> from the platform_device structure,
+ * and compare it against the name of the driver. Return whether they match
+ * or not.
  */
-
-static int platform_match(struct device * dev, struct device_driver * drv)
+static int platform_match(struct device *dev, struct device_driver *drv)
 {
-       struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+       struct platform_device *pdev;
 
+       pdev = container_of(dev, struct platform_device, dev);
        return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
 }
 
@@ -574,9 +573,10 @@ static int platform_suspend(struct device *dev, pm_message_t mesg)
 static int platform_suspend_late(struct device *dev, pm_message_t mesg)
 {
        struct platform_driver *drv = to_platform_driver(dev->driver);
-       struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+       struct platform_device *pdev;
        int ret = 0;
 
+       pdev = container_of(dev, struct platform_device, dev);
        if (dev->driver && drv->suspend_late)
                ret = drv->suspend_late(pdev, mesg);
 
@@ -586,16 +586,17 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg)
 static int platform_resume_early(struct device *dev)
 {
        struct platform_driver *drv = to_platform_driver(dev->driver);
-       struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+       struct platform_device *pdev;
        int ret = 0;
 
+       pdev = container_of(dev, struct platform_device, dev);
        if (dev->driver && drv->resume_early)
                ret = drv->resume_early(pdev);
 
        return ret;
 }
 
-static int platform_resume(struct device * dev)
+static int platform_resume(struct device *dev)
 {
        int ret = 0;
 
index 44504e6618fbb0006e369cf39ff75d55578057bb..06a86fe6a78d77a1c2d0a3b7e84003456c430933 100644 (file)
@@ -1,4 +1,3 @@
-obj-y                  := shutdown.o
 obj-$(CONFIG_PM)       += sysfs.o
 obj-$(CONFIG_PM_SLEEP) += main.o
 obj-$(CONFIG_PM_TRACE) += trace.o
index 691ffb64cc3724461fa3d877f3a8aae10dca96d9..200ed5fafd505ad0e18fff1131500e2a2fd4ba9c 100644 (file)
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/resume-trace.h>
+#include <linux/rwsem.h>
 
 #include "../base.h"
 #include "power.h"
 
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All the other lists are kept in the same order, for consistency.
+ * However the lists aren't always traversed in the same order.
+ * Semaphores must be acquired from the top (i.e., front) down
+ * and released in the opposite order.  Devices must be suspended
+ * from the bottom (i.e., end) up and resumed in the opposite order.
+ * That way no parent will be suspended while it still has an active
+ * child.
+ *
+ * Since device_pm_add() may be called with a device semaphore held,
+ * we must never try to acquire a device semaphore while holding
+ * dpm_list_mutex.
+ */
+
 LIST_HEAD(dpm_active);
+static LIST_HEAD(dpm_locked);
 static LIST_HEAD(dpm_off);
 static LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_destroy);
 
-static DEFINE_MUTEX(dpm_mtx);
 static DEFINE_MUTEX(dpm_list_mtx);
 
-int (*platform_enable_wakeup)(struct device *dev, int is_on);
+static DECLARE_RWSEM(pm_sleep_rwsem);
 
+int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
+/**
+ *     device_pm_add - add a device to the list of active devices
+ *     @dev:   Device to be added to the list
+ */
 void device_pm_add(struct device *dev)
 {
        pr_debug("PM: Adding info for %s:%s\n",
@@ -48,8 +73,36 @@ void device_pm_add(struct device *dev)
        mutex_unlock(&dpm_list_mtx);
 }
 
+/**
+ *     device_pm_remove - remove a device from the list of active devices
+ *     @dev:   Device to be removed from the list
+ *
+ *     This function also removes the device's PM-related sysfs attributes.
+ */
 void device_pm_remove(struct device *dev)
 {
+       /*
+        * If this function is called during a suspend, it will be blocked,
+        * because we're holding the device's semaphore at that time, which may
+        * lead to a deadlock.  In that case we want to print a warning.
+        * However, it may also be called by unregister_dropped_devices() with
+        * the device's semaphore released, in which case the warning should
+        * not be printed.
+        */
+       if (down_trylock(&dev->sem)) {
+               if (down_read_trylock(&pm_sleep_rwsem)) {
+                       /* No suspend in progress, wait on dev->sem */
+                       down(&dev->sem);
+                       up_read(&pm_sleep_rwsem);
+               } else {
+                       /* Suspend in progress, we may deadlock */
+                       dev_warn(dev, "Suspicious %s during suspend\n",
+                               __FUNCTION__);
+                       dump_stack();
+                       /* The user has been warned ... */
+                       down(&dev->sem);
+               }
+       }
        pr_debug("PM: Removing info for %s:%s\n",
                 dev->bus ? dev->bus->name : "No Bus",
                 kobject_name(&dev->kobj));
@@ -57,25 +110,124 @@ void device_pm_remove(struct device *dev)
        dpm_sysfs_remove(dev);
        list_del_init(&dev->power.entry);
        mutex_unlock(&dpm_list_mtx);
+       up(&dev->sem);
+}
+
+/**
+ *     device_pm_schedule_removal - schedule the removal of a suspended device
+ *     @dev:   Device to destroy
+ *
+ *     Moves the device to the dpm_destroy list for further processing by
+ *     unregister_dropped_devices().
+ */
+void device_pm_schedule_removal(struct device *dev)
+{
+       pr_debug("PM: Preparing for removal: %s:%s\n",
+               dev->bus ? dev->bus->name : "No Bus",
+               kobject_name(&dev->kobj));
+       mutex_lock(&dpm_list_mtx);
+       list_move_tail(&dev->power.entry, &dpm_destroy);
+       mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ *     pm_sleep_lock - mutual exclusion for registration and suspend
+ *
+ *     Returns 0 if no suspend is underway and device registration
+ *     may proceed, otherwise -EBUSY.
+ */
+int pm_sleep_lock(void)
+{
+       if (down_read_trylock(&pm_sleep_rwsem))
+               return 0;
+
+       return -EBUSY;
+}
+
+/**
+ *     pm_sleep_unlock - mutual exclusion for registration and suspend
+ *
+ *     This routine undoes the effect of device_pm_add_lock
+ *     when a device's registration is complete.
+ */
+void pm_sleep_unlock(void)
+{
+       up_read(&pm_sleep_rwsem);
 }
 
 
 /*------------------------- Resume routines -------------------------*/
 
 /**
- *     resume_device - Restore state for one device.
+ *     resume_device_early - Power on one device (early resume).
  *     @dev:   Device.
  *
+ *     Must be called with interrupts disabled.
  */
-
-static int resume_device(struct device * dev)
+static int resume_device_early(struct device *dev)
 {
        int error = 0;
 
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
-       down(&dev->sem);
+       if (dev->bus && dev->bus->resume_early) {
+               dev_dbg(dev, "EARLY resume\n");
+               error = dev->bus->resume_early(dev);
+       }
+
+       TRACE_RESUME(error);
+       return error;
+}
+
+/**
+ *     dpm_power_up - Power on all regular (non-sysdev) devices.
+ *
+ *     Walk the dpm_off_irq list and power each device up. This
+ *     is used for devices that required they be powered down with
+ *     interrupts disabled. As devices are powered on, they are moved
+ *     to the dpm_off list.
+ *
+ *     Must be called with interrupts disabled and only one CPU running.
+ */
+static void dpm_power_up(void)
+{
+
+       while (!list_empty(&dpm_off_irq)) {
+               struct list_head *entry = dpm_off_irq.next;
+               struct device *dev = to_device(entry);
+
+               list_move_tail(entry, &dpm_off);
+               resume_device_early(dev);
+       }
+}
+
+/**
+ *     device_power_up - Turn on all devices that need special attention.
+ *
+ *     Power on system devices, then devices that required we shut them down
+ *     with interrupts disabled.
+ *
+ *     Must be called with interrupts disabled.
+ */
+void device_power_up(void)
+{
+       sysdev_resume();
+       dpm_power_up();
+}
+EXPORT_SYMBOL_GPL(device_power_up);
+
+/**
+ *     resume_device - Restore state for one device.
+ *     @dev:   Device.
+ *
+ */
+static int resume_device(struct device *dev)
+{
+       int error = 0;
+
+       TRACE_DEVICE(dev);
+       TRACE_RESUME(0);
 
        if (dev->bus && dev->bus->resume) {
                dev_dbg(dev,"resuming\n");
@@ -92,126 +244,94 @@ static int resume_device(struct device * dev)
                error = dev->class->resume(dev);
        }
 
-       up(&dev->sem);
-
        TRACE_RESUME(error);
        return error;
 }
 
-
-static int resume_device_early(struct device * dev)
-{
-       int error = 0;
-
-       TRACE_DEVICE(dev);
-       TRACE_RESUME(0);
-       if (dev->bus && dev->bus->resume_early) {
-               dev_dbg(dev,"EARLY resume\n");
-               error = dev->bus->resume_early(dev);
-       }
-       TRACE_RESUME(error);
-       return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
+/**
+ *     dpm_resume - Resume every device.
+ *
+ *     Resume the devices that have either not gone through
+ *     the late suspend, or that did go through it but also
+ *     went through the early resume.
+ *
+ *     Take devices from the dpm_off_list, resume them,
+ *     and put them on the dpm_locked list.
  */
 static void dpm_resume(void)
 {
        mutex_lock(&dpm_list_mtx);
        while(!list_empty(&dpm_off)) {
-               struct list_head * entry = dpm_off.next;
-               struct device * dev = to_device(entry);
-
-               get_device(dev);
-               list_move_tail(entry, &dpm_active);
+               struct list_head *entry = dpm_off.next;
+               struct device *dev = to_device(entry);
 
+               list_move_tail(entry, &dpm_locked);
                mutex_unlock(&dpm_list_mtx);
                resume_device(dev);
                mutex_lock(&dpm_list_mtx);
-               put_device(dev);
        }
        mutex_unlock(&dpm_list_mtx);
 }
 
-
 /**
- *     device_resume - Restore state of each device in system.
+ *     unlock_all_devices - Release each device's semaphore
  *
- *     Walk the dpm_off list, remove each entry, resume the device,
- *     then add it to the dpm_active list.
+ *     Go through the dpm_off list.  Put each device on the dpm_active
+ *     list and unlock it.
  */
-
-void device_resume(void)
+static void unlock_all_devices(void)
 {
-       might_sleep();
-       mutex_lock(&dpm_mtx);
-       dpm_resume();
-       mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
+       mutex_lock(&dpm_list_mtx);
+       while (!list_empty(&dpm_locked)) {
+               struct list_head *entry = dpm_locked.prev;
+               struct device *dev = to_device(entry);
 
+               list_move(entry, &dpm_active);
+               up(&dev->sem);
+       }
+       mutex_unlock(&dpm_list_mtx);
+}
 
 /**
- *     dpm_power_up - Power on some devices.
- *
- *     Walk the dpm_off_irq list and power each device up. This
- *     is used for devices that required they be powered down with
- *     interrupts disabled. As devices are powered on, they are moved
- *     to the dpm_active list.
+ *     unregister_dropped_devices - Unregister devices scheduled for removal
  *
- *     Interrupts must be disabled when calling this.
+ *     Unregister all devices on the dpm_destroy list.
  */
-
-static void dpm_power_up(void)
+static void unregister_dropped_devices(void)
 {
-       while(!list_empty(&dpm_off_irq)) {
-               struct list_head * entry = dpm_off_irq.next;
-               struct device * dev = to_device(entry);
+       mutex_lock(&dpm_list_mtx);
+       while (!list_empty(&dpm_destroy)) {
+               struct list_head *entry = dpm_destroy.next;
+               struct device *dev = to_device(entry);
 
-               list_move_tail(entry, &dpm_off);
-               resume_device_early(dev);
+               up(&dev->sem);
+               mutex_unlock(&dpm_list_mtx);
+               /* This also removes the device from the list */
+               device_unregister(dev);
+               mutex_lock(&dpm_list_mtx);
        }
+       mutex_unlock(&dpm_list_mtx);
 }
 
-
 /**
- *     device_power_up - Turn on all devices that need special attention.
+ *     device_resume - Restore state of each device in system.
  *
- *     Power on system devices then devices that required we shut them down
- *     with interrupts disabled.
- *     Called with interrupts disabled.
+ *     Resume all the devices, unlock them all, and allow new
+ *     devices to be registered once again.
  */
-
-void device_power_up(void)
+void device_resume(void)
 {
-       sysdev_resume();
-       dpm_power_up();
+       might_sleep();
+       dpm_resume();
+       unlock_all_devices();
+       unregister_dropped_devices();
+       up_write(&pm_sleep_rwsem);
 }
-
-EXPORT_SYMBOL_GPL(device_power_up);
+EXPORT_SYMBOL_GPL(device_resume);
 
 
 /*------------------------- Suspend routines -------------------------*/
 
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
 static inline char *suspend_verb(u32 event)
 {
        switch (event) {
@@ -222,7 +342,6 @@ static inline char *suspend_verb(u32 event)
        }
 }
 
-
 static void
 suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
 {
@@ -232,16 +351,73 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
 }
 
 /**
- *     suspend_device - Save state of one device.
+ *     suspend_device_late - Shut down one device (late suspend).
  *     @dev:   Device.
  *     @state: Power state device is entering.
+ *
+ *     This is called with interrupts off and only a single CPU running.
  */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+       int error = 0;
 
-static int suspend_device(struct device * dev, pm_message_t state)
+       if (dev->bus && dev->bus->suspend_late) {
+               suspend_device_dbg(dev, state, "LATE ");
+               error = dev->bus->suspend_late(dev, state);
+               suspend_report_result(dev->bus->suspend_late, error);
+       }
+       return error;
+}
+
+/**
+ *     device_power_down - Shut down special devices.
+ *     @state:         Power state to enter.
+ *
+ *     Power down devices that require interrupts to be disabled
+ *     and move them from the dpm_off list to the dpm_off_irq list.
+ *     Then power down system devices.
+ *
+ *     Must be called with interrupts disabled and only one CPU running.
+ */
+int device_power_down(pm_message_t state)
+{
+       int error = 0;
+
+       while (!list_empty(&dpm_off)) {
+               struct list_head *entry = dpm_off.prev;
+               struct device *dev = to_device(entry);
+
+               list_del_init(&dev->power.entry);
+               error = suspend_device_late(dev, state);
+               if (error) {
+                       printk(KERN_ERR "Could not power down device %s: "
+                                       "error %d\n",
+                                       kobject_name(&dev->kobj), error);
+                       if (list_empty(&dev->power.entry))
+                               list_add(&dev->power.entry, &dpm_off);
+                       break;
+               }
+               if (list_empty(&dev->power.entry))
+                       list_add(&dev->power.entry, &dpm_off_irq);
+       }
+
+       if (!error)
+               error = sysdev_suspend(state);
+       if (error)
+               dpm_power_up();
+       return error;
+}
+EXPORT_SYMBOL_GPL(device_power_down);
+
+/**
+ *     suspend_device - Save state of one device.
+ *     @dev:   Device.
+ *     @state: Power state device is entering.
+ */
+int suspend_device(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
-       down(&dev->sem);
        if (dev->power.power_state.event) {
                dev_dbg(dev, "PM: suspend %d-->%d\n",
                        dev->power.power_state.event, state.event);
@@ -264,123 +440,105 @@ static int suspend_device(struct device * dev, pm_message_t state)
                error = dev->bus->suspend(dev, state);
                suspend_report_result(dev->bus->suspend, error);
        }
-       up(&dev->sem);
-       return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
-       int error = 0;
-
-       if (dev->bus && dev->bus->suspend_late) {
-               suspend_device_dbg(dev, state, "LATE ");
-               error = dev->bus->suspend_late(dev, state);
-               suspend_report_result(dev->bus->suspend_late, error);
-       }
        return error;
 }
 
 /**
- *     device_suspend - Save state and stop all devices in system.
- *     @state:         Power state to put each device in.
+ *     dpm_suspend - Suspend every device.
+ *     @state: Power state to put each device in.
  *
- *     Walk the dpm_active list, call ->suspend() for each device, and move
- *     it to the dpm_off list.
+ *     Walk the dpm_locked list.  Suspend each device and move it
+ *     to the dpm_off list.
  *
  *     (For historical reasons, if it returns -EAGAIN, that used to mean
  *     that the device would be called again with interrupts disabled.
  *     These days, we use the "suspend_late()" callback for that, so we
  *     print a warning and consider it an error).
- *
- *     If we get a different error, try and back out.
- *
- *     If we hit a failure with any of the devices, call device_resume()
- *     above to bring the suspended devices back to life.
- *
  */
-
-int device_suspend(pm_message_t state)
+static int dpm_suspend(pm_message_t state)
 {
        int error = 0;
 
-       might_sleep();
-       mutex_lock(&dpm_mtx);
        mutex_lock(&dpm_list_mtx);
-       while (!list_empty(&dpm_active) && error == 0) {
-               struct list_head * entry = dpm_active.prev;
-               struct device * dev = to_device(entry);
+       while (!list_empty(&dpm_locked)) {
+               struct list_head *entry = dpm_locked.prev;
+               struct device *dev = to_device(entry);
 
-               get_device(dev);
+               list_del_init(&dev->power.entry);
                mutex_unlock(&dpm_list_mtx);
-
                error = suspend_device(dev, state);
-
-               mutex_lock(&dpm_list_mtx);
-
-               /* Check if the device got removed */
-               if (!list_empty(&dev->power.entry)) {
-                       /* Move it to the dpm_off list */
-                       if (!error)
-                               list_move(&dev->power.entry, &dpm_off);
-               }
-               if (error)
+               if (error) {
                        printk(KERN_ERR "Could not suspend device %s: "
-                               "error %d%s\n",
-                               kobject_name(&dev->kobj), error,
-                               error == -EAGAIN ? " (please convert to suspend_late)" : "");
-               put_device(dev);
+                                       "error %d%s\n",
+                                       kobject_name(&dev->kobj),
+                                       error,
+                                       (error == -EAGAIN ?
+                                       " (please convert to suspend_late)" :
+                                       ""));
+                       mutex_lock(&dpm_list_mtx);
+                       if (list_empty(&dev->power.entry))
+                               list_add(&dev->power.entry, &dpm_locked);
+                       mutex_unlock(&dpm_list_mtx);
+                       break;
+               }
+               mutex_lock(&dpm_list_mtx);
+               if (list_empty(&dev->power.entry))
+                       list_add(&dev->power.entry, &dpm_off);
        }
        mutex_unlock(&dpm_list_mtx);
-       if (error)
-               dpm_resume();
 
-       mutex_unlock(&dpm_mtx);
        return error;
 }
 
-EXPORT_SYMBOL_GPL(device_suspend);
-
 /**
- *     device_power_down - Shut down special devices.
- *     @state:         Power state to enter.
+ *     lock_all_devices - Acquire every device's semaphore
  *
- *     Walk the dpm_off_irq list, calling ->power_down() for each device that
- *     couldn't power down the device with interrupts enabled. When we're
- *     done, power down system devices.
+ *     Go through the dpm_active list. Carefully lock each device's
+ *     semaphore and put it in on the dpm_locked list.
  */
-
-int device_power_down(pm_message_t state)
+static void lock_all_devices(void)
 {
-       int error = 0;
-       struct device * dev;
+       mutex_lock(&dpm_list_mtx);
+       while (!list_empty(&dpm_active)) {
+               struct list_head *entry = dpm_active.next;
+               struct device *dev = to_device(entry);
 
-       while (!list_empty(&dpm_off)) {
-               struct list_head * entry = dpm_off.prev;
+               /* Required locking order is dev->sem first,
+                * then dpm_list_mutex.  Hence this awkward code.
+                */
+               get_device(dev);
+               mutex_unlock(&dpm_list_mtx);
+               down(&dev->sem);
+               mutex_lock(&dpm_list_mtx);
 
-               dev = to_device(entry);
-               error = suspend_device_late(dev, state);
-               if (error)
-                       goto Error;
-               list_move(&dev->power.entry, &dpm_off_irq);
+               if (list_empty(entry))
+                       up(&dev->sem);          /* Device was removed */
+               else
+                       list_move_tail(entry, &dpm_locked);
+               put_device(dev);
        }
+       mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ *     device_suspend - Save state and stop all devices in system.
+ *
+ *     Prevent new devices from being registered, then lock all devices
+ *     and suspend them.
+ */
+int device_suspend(pm_message_t state)
+{
+       int error;
 
-       error = sysdev_suspend(state);
- Done:
+       might_sleep();
+       down_write(&pm_sleep_rwsem);
+       lock_all_devices();
+       error = dpm_suspend(state);
+       if (error)
+               device_resume();
        return error;
- Error:
-       printk(KERN_ERR "Could not power down device %s: "
-               "error %d\n", kobject_name(&dev->kobj), error);
-       dpm_power_up();
-       goto Done;
 }
-
-EXPORT_SYMBOL_GPL(device_power_down);
+EXPORT_SYMBOL_GPL(device_suspend);
 
 void __suspend_report_result(const char *function, void *fn, int ret)
 {
index 379da4e958e0d00fc637b00cac5215f41fb6cd45..6f0dfca8ebdd2437da619ab7a0c89abd7a60dcca 100644 (file)
@@ -1,10 +1,3 @@
-/*
- * shutdown.c
- */
-
-extern void device_shutdown(void);
-
-
 #ifdef CONFIG_PM_SLEEP
 
 /*
@@ -20,6 +13,9 @@ static inline struct device *to_device(struct list_head *entry)
 
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
+extern void device_pm_schedule_removal(struct device *);
+extern int pm_sleep_lock(void);
+extern void pm_sleep_unlock(void);
 
 #else /* CONFIG_PM_SLEEP */
 
@@ -32,6 +28,15 @@ static inline void device_pm_remove(struct device *dev)
 {
 }
 
+static inline int pm_sleep_lock(void)
+{
+       return 0;
+}
+
+static inline void pm_sleep_unlock(void)
+{
+}
+
 #endif
 
 #ifdef CONFIG_PM
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
deleted file mode 100644 (file)
index 56e8eaa..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * shutdown.c - power management functions for the device tree.
- *
- * Copyright (c) 2002-3 Patrick Mochel
- *              2002-3 Open Source Development Lab
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <asm/semaphore.h>
-
-#include "../base.h"
-#include "power.h"
-
-#define to_dev(node) container_of(node, struct device, kobj.entry)
-
-
-/**
- * We handle system devices differently - we suspend and shut them
- * down last and resume them first. That way, we don't do anything stupid like
- * shutting down the interrupt controller before any devices..
- *
- * Note that there are not different stages for power management calls -
- * they only get one called once when interrupts are disabled.
- */
-
-
-/**
- * device_shutdown - call ->shutdown() on each device to shutdown.
- */
-void device_shutdown(void)
-{
-       struct device * dev, *devn;
-
-       list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list,
-                               kobj.entry) {
-               if (dev->bus && dev->bus->shutdown) {
-                       dev_dbg(dev, "shutdown\n");
-                       dev->bus->shutdown(dev);
-               } else if (dev->driver && dev->driver->shutdown) {
-                       dev_dbg(dev, "shutdown\n");
-                       dev->driver->shutdown(dev);
-               }
-       }
-}
-
index ac7ff6d0c6e5c34460cfd1fcf4d76678b3e0533f..2f79c55acdcc6af406a9e03b469a4853eefee808 100644 (file)
@@ -25,8 +25,6 @@
 
 #include "base.h"
 
-extern struct kset devices_subsys;
-
 #define to_sysdev(k) container_of(k, struct sys_device, kobj)
 #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
 
@@ -128,18 +126,17 @@ void sysdev_class_remove_file(struct sysdev_class *c,
 }
 EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
 
-/*
- * declare system_subsys
- */
-static decl_subsys(system, &ktype_sysdev_class, NULL);
+static struct kset *system_kset;
 
 int sysdev_class_register(struct sysdev_class * cls)
 {
        pr_debug("Registering sysdev class '%s'\n",
                 kobject_name(&cls->kset.kobj));
        INIT_LIST_HEAD(&cls->drivers);
-       cls->kset.kobj.parent = &system_subsys.kobj;
-       cls->kset.kobj.kset = &system_subsys;
+       cls->kset.kobj.parent = &system_kset->kobj;
+       cls->kset.kobj.ktype = &ktype_sysdev_class;
+       cls->kset.kobj.kset = system_kset;
+       kobject_set_name(&cls->kset.kobj, cls->name);
        return kset_register(&cls->kset);
 }
 
@@ -228,20 +225,15 @@ int sysdev_register(struct sys_device * sysdev)
        if (!cls)
                return -EINVAL;
 
+       pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
+
        /* Make sure the kset is set */
        sysdev->kobj.kset = &cls->kset;
 
-       /* But make sure we point to the right type for sysfs translation */
-       sysdev->kobj.ktype = &ktype_sysdev;
-       error = kobject_set_name(&sysdev->kobj, "%s%d",
-                        kobject_name(&cls->kset.kobj), sysdev->id);
-       if (error)
-               return error;
-
-       pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
-
        /* Register the object */
-       error = kobject_register(&sysdev->kobj);
+       error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL,
+                                    "%s%d", kobject_name(&cls->kset.kobj),
+                                    sysdev->id);
 
        if (!error) {
                struct sysdev_driver * drv;
@@ -258,6 +250,7 @@ int sysdev_register(struct sys_device * sysdev)
                }
                mutex_unlock(&sysdev_drivers_lock);
        }
+       kobject_uevent(&sysdev->kobj, KOBJ_ADD);
        return error;
 }
 
@@ -272,7 +265,7 @@ void sysdev_unregister(struct sys_device * sysdev)
        }
        mutex_unlock(&sysdev_drivers_lock);
 
-       kobject_unregister(&sysdev->kobj);
+       kobject_put(&sysdev->kobj);
 }
 
 
@@ -298,8 +291,7 @@ void sysdev_shutdown(void)
        pr_debug("Shutting Down System Devices\n");
 
        mutex_lock(&sysdev_drivers_lock);
-       list_for_each_entry_reverse(cls, &system_subsys.list,
-                                   kset.kobj.entry) {
+       list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
                struct sys_device * sysdev;
 
                pr_debug("Shutting down type '%s':\n",
@@ -361,9 +353,7 @@ int sysdev_suspend(pm_message_t state)
 
        pr_debug("Suspending System Devices\n");
 
-       list_for_each_entry_reverse(cls, &system_subsys.list,
-                                   kset.kobj.entry) {
-
+       list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
                pr_debug("Suspending type '%s':\n",
                         kobject_name(&cls->kset.kobj));
 
@@ -414,8 +404,7 @@ aux_driver:
        }
 
        /* resume other classes */
-       list_for_each_entry_continue(cls, &system_subsys.list,
-                                       kset.kobj.entry) {
+       list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) {
                list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
                        pr_debug(" %s\n", kobject_name(&err_dev->kobj));
                        __sysdev_resume(err_dev);
@@ -440,7 +429,7 @@ int sysdev_resume(void)
 
        pr_debug("Resuming System Devices\n");
 
-       list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) {
+       list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
                struct sys_device * sysdev;
 
                pr_debug("Resuming type '%s':\n",
@@ -458,8 +447,10 @@ int sysdev_resume(void)
 
 int __init system_bus_init(void)
 {
-       system_subsys.kobj.parent = &devices_subsys.kobj;
-       return subsystem_register(&system_subsys);
+       system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
+       if (!system_kset)
+               return -ENOMEM;
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(sysdev_register);
index ad00b3d94711d09b6344ea36cd73ce21418932a1..826d12381e21f546c099be3079604ca5412868f0 100644 (file)
 
 static struct kmem_cache *buf_pool_cache;
 
-static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_state(struct device *dev,
+                                 struct device_attribute *attr, char *page)
 {
+       struct gendisk *disk = dev_to_disk(dev);
        struct aoedev *d = disk->private_data;
 
        return snprintf(page, PAGE_SIZE,
@@ -26,50 +28,47 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
                        (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
        /* I'd rather see nopen exported so we can ditch closewait */
 }
-static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_mac(struct device *dev,
+                               struct device_attribute *attr, char *page)
 {
+       struct gendisk *disk = dev_to_disk(dev);
        struct aoedev *d = disk->private_data;
 
        return snprintf(page, PAGE_SIZE, "%012llx\n",
                        (unsigned long long)mac_addr(d->addr));
 }
-static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_netif(struct device *dev,
+                                 struct device_attribute *attr, char *page)
 {
+       struct gendisk *disk = dev_to_disk(dev);
        struct aoedev *d = disk->private_data;
 
        return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
 }
 /* firmware version */
-static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_fwver(struct device *dev,
+                                 struct device_attribute *attr, char *page)
 {
+       struct gendisk *disk = dev_to_disk(dev);
        struct aoedev *d = disk->private_data;
 
        return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
 }
 
-static struct disk_attribute disk_attr_state = {
-       .attr = {.name = "state", .mode = S_IRUGO },
-       .show = aoedisk_show_state
-};
-static struct disk_attribute disk_attr_mac = {
-       .attr = {.name = "mac", .mode = S_IRUGO },
-       .show = aoedisk_show_mac
-};
-static struct disk_attribute disk_attr_netif = {
-       .attr = {.name = "netif", .mode = S_IRUGO },
-       .show = aoedisk_show_netif
-};
-static struct disk_attribute disk_attr_fwver = {
-       .attr = {.name = "firmware-version", .mode = S_IRUGO },
-       .show = aoedisk_show_fwver
+static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
+static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
+static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
+static struct device_attribute dev_attr_firmware_version = {
+       .attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE },
+       .show = aoedisk_show_fwver,
 };
 
 static struct attribute *aoe_attrs[] = {
-       &disk_attr_state.attr,
-       &disk_attr_mac.attr,
-       &disk_attr_netif.attr,
-       &disk_attr_fwver.attr,
-       NULL
+       &dev_attr_state.attr,
+       &dev_attr_mac.attr,
+       &dev_attr_netif.attr,
+       &dev_attr_firmware_version.attr,
+       NULL,
 };
 
 static const struct attribute_group attr_group = {
@@ -79,12 +78,12 @@ static const struct attribute_group attr_group = {
 static int
 aoedisk_add_sysfs(struct aoedev *d)
 {
-       return sysfs_create_group(&d->gd->kobj, &attr_group);
+       return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
 }
 void
 aoedisk_rm_sysfs(struct aoedev *d)
 {
-       sysfs_remove_group(&d->gd->kobj, &attr_group);
+       sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
 }
 
 static int
index 39e563ea08782cf242972b42d3b8c4795e5a83a4..d5480e34cb22fbc27b88275a3cfec71ca3714484 100644 (file)
@@ -259,9 +259,8 @@ aoechr_init(void)
                return PTR_ERR(aoe_class);
        }
        for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-               class_device_create(aoe_class, NULL,
-                                       MKDEV(AOE_MAJOR, chardevs[i].minor),
-                                       NULL, chardevs[i].name);
+               device_create(aoe_class, NULL,
+                             MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name);
 
        return 0;
 }
@@ -272,7 +271,7 @@ aoechr_exit(void)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-               class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
+               device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
        class_destroy(aoe_class);
        unregister_chrdev(AOE_MAJOR, "aoechr");
 }
index 7d704968765f308ac87726e310c64242e96db8fc..509b6490413b9cbc614c7bea6f0ed2b36bade674 100644 (file)
@@ -2927,7 +2927,7 @@ default_int_mode:
        return;
 }
 
-static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
+static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 {
        ushort subsystem_vendor_id, subsystem_device_id, command;
        __u32 board_id, scratchpad = 0;
index 56e23042728ae093776a86a499da310511d51a91..b8af22e610dfe4f90ac1b637f0670ec5f9e6bfee 100644 (file)
@@ -610,7 +610,7 @@ static int loop_thread(void *data)
 static int loop_switch(struct loop_device *lo, struct file *file)
 {
        struct switch_request w;
-       struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+       struct bio *bio = bio_alloc(GFP_KERNEL, 0);
        if (!bio)
                return -ENOMEM;
        init_completion(&w.wait);
index b4c0888aedc3113c8eb442726a4237c9f7d9dd92..ba9b17e507e000efb3f37c644373f43812eabd2e 100644 (file)
@@ -375,14 +375,17 @@ harderror:
        return NULL;
 }
 
-static ssize_t pid_show(struct gendisk *disk, char *page)
+static ssize_t pid_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
 {
-       return sprintf(page, "%ld\n",
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%ld\n",
                (long) ((struct nbd_device *)disk->private_data)->pid);
 }
 
-static struct disk_attribute pid_attr = {
-       .attr = { .name = "pid", .mode = S_IRUGO },
+static struct device_attribute pid_attr = {
+       .attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE },
        .show = pid_show,
 };
 
@@ -394,7 +397,7 @@ static int nbd_do_it(struct nbd_device *lo)
        BUG_ON(lo->magic != LO_MAGIC);
 
        lo->pid = current->pid;
-       ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+       ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr);
        if (ret) {
                printk(KERN_ERR "nbd: sysfs_create_file failed!");
                return ret;
@@ -403,7 +406,7 @@ static int nbd_do_it(struct nbd_device *lo)
        while ((req = nbd_read_stat(lo)) != NULL)
                nbd_end_request(req);
 
-       sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
+       sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr);
        return 0;
 }
 
index d89e7d32a3b604716a63a03edf7ad0fd3492f6a5..ab86e23ddc69dc36272c6bf60ebe915168177b58 100644 (file)
@@ -676,8 +676,8 @@ static int __init pg_init(void)
        for (unit = 0; unit < PG_UNITS; unit++) {
                struct pg *dev = &devices[unit];
                if (dev->present)
-                       class_device_create(pg_class, NULL, MKDEV(major, unit),
-                                       NULL, "pg%u", unit);
+                       device_create(pg_class, NULL, MKDEV(major, unit),
+                                     "pg%u", unit);
        }
        err = 0;
        goto out;
@@ -695,7 +695,7 @@ static void __exit pg_exit(void)
        for (unit = 0; unit < PG_UNITS; unit++) {
                struct pg *dev = &devices[unit];
                if (dev->present)
-                       class_device_destroy(pg_class, MKDEV(major, unit));
+                       device_destroy(pg_class, MKDEV(major, unit));
        }
        class_destroy(pg_class);
        unregister_chrdev(major, name);
index b91accf12656581066811fa68c18e78cfb655018..76096cad798f1c54708a498a90d5eb85eb105f83 100644 (file)
@@ -972,10 +972,10 @@ static int __init pt_init(void)
 
        for (unit = 0; unit < PT_UNITS; unit++)
                if (pt[unit].present) {
-                       class_device_create(pt_class, NULL, MKDEV(major, unit),
-                                       NULL, "pt%d", unit);
-                       class_device_create(pt_class, NULL, MKDEV(major, unit + 128),
-                                       NULL, "pt%dn", unit);
+                       device_create(pt_class, NULL, MKDEV(major, unit),
+                                     "pt%d", unit);
+                       device_create(pt_class, NULL, MKDEV(major, unit + 128),
+                                     "pt%dn", unit);
                }
        goto out;
 
@@ -990,8 +990,8 @@ static void __exit pt_exit(void)
        int unit;
        for (unit = 0; unit < PT_UNITS; unit++)
                if (pt[unit].present) {
-                       class_device_destroy(pt_class, MKDEV(major, unit));
-                       class_device_destroy(pt_class, MKDEV(major, unit + 128));
+                       device_destroy(pt_class, MKDEV(major, unit));
+                       device_destroy(pt_class, MKDEV(major, unit + 128));
                }
        class_destroy(pt_class);
        unregister_chrdev(major, name);
index 3535ef896677a28dcc352654c880587e9bc463c2..e9de1712e5a0b1b98b8cc1ce95d59d8daf0b615e 100644 (file)
@@ -110,17 +110,18 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
                                        struct kobj_type* ktype)
 {
        struct pktcdvd_kobj *p;
+       int error;
+
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
                return NULL;
-       kobject_set_name(&p->kobj, "%s", name);
-       p->kobj.parent = parent;
-       p->kobj.ktype = ktype;
        p->pd = pd;
-       if (kobject_register(&p->kobj) != 0) {
+       error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name);
+       if (error) {
                kobject_put(&p->kobj);
                return NULL;
        }
+       kobject_uevent(&p->kobj, KOBJ_ADD);
        return p;
 }
 /*
@@ -129,7 +130,7 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
 static void pkt_kobj_remove(struct pktcdvd_kobj *p)
 {
        if (p)
-               kobject_unregister(&p->kobj);
+               kobject_put(&p->kobj);
 }
 /*
  * default release function for pktcdvd kernel objects.
@@ -301,18 +302,16 @@ static struct kobj_type kobj_pkt_type_wqueue = {
 static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
 {
        if (class_pktcdvd) {
-               pd->clsdev = class_device_create(class_pktcdvd,
-                                       NULL, pd->pkt_dev,
-                                       NULL, "%s", pd->name);
-               if (IS_ERR(pd->clsdev))
-                       pd->clsdev = NULL;
+               pd->dev = device_create(class_pktcdvd, NULL, pd->pkt_dev, "%s", pd->name);
+               if (IS_ERR(pd->dev))
+                       pd->dev = NULL;
        }
-       if (pd->clsdev) {
+       if (pd->dev) {
                pd->kobj_stat = pkt_kobj_create(pd, "stat",
-                                       &pd->clsdev->kobj,
+                                       &pd->dev->kobj,
                                        &kobj_pkt_type_stat);
                pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
-                                       &pd->clsdev->kobj,
+                                       &pd->dev->kobj,
                                        &kobj_pkt_type_wqueue);
        }
 }
@@ -322,7 +321,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
        pkt_kobj_remove(pd->kobj_stat);
        pkt_kobj_remove(pd->kobj_wqueue);
        if (class_pktcdvd)
-               class_device_destroy(class_pktcdvd, pd->pkt_dev);
+               device_destroy(class_pktcdvd, pd->pkt_dev);
 }
 
 
index 8c3e62a17b4a6f1714d91567bf20c91b569ebff2..b91d45a41b2f6b7e88716626b392a33124b789d8 100644 (file)
@@ -204,6 +204,19 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu)
        spin_lock_irqsave(&ll->hcill_lock, flags);
 
        switch (ll->hcill_state) {
+       case HCILL_ASLEEP_TO_AWAKE:
+               /*
+                * This state means that both the host and the BRF chip
+                * have simultaneously sent a wake-up-indication packet.
+                * Traditionaly, in this case, receiving a wake-up-indication
+                * was enough and an additional wake-up-ack wasn't needed.
+                * This has changed with the BRF6350, which does require an
+                * explicit wake-up-ack. Other BRF versions, which do not
+                * require an explicit ack here, do accept it, thus it is
+                * perfectly safe to always send one.
+                */
+               BT_DBG("dual wake-up-indication");
+               /* deliberate fall-through - do not add break */
        case HCILL_ASLEEP:
                /* acknowledge device wake up */
                if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
@@ -211,16 +224,8 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu)
                        goto out;
                }
                break;
-       case HCILL_ASLEEP_TO_AWAKE:
-               /*
-                * this state means that a wake-up-indication
-                * is already on its way to the device,
-                * and will serve as the required wake-up-ack
-                */
-               BT_DBG("dual wake-up-indication");
-               break;
        default:
-               /* any other state are illegal */
+               /* any other state is illegal */
                BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
                break;
        }
index ef1ed5d701255e17037b9256ad3730a85cb95ef7..466629594776fc4af443dec3ca4dc0fa767d0c4e 100644 (file)
@@ -137,7 +137,7 @@ config CYCLADES
          your Linux box, for instance in order to become a dial-in server.
 
          For information about the Cyclades-Z card, read
-         <file:drivers/char/README.cycladesZ>.
+         <file:Documentation/README.cycladesZ>.
 
          To compile this driver as a module, choose M here: the
          module will be called cyclades.
@@ -373,6 +373,16 @@ config ISTALLION
          To compile this driver as a module, choose M here: the
          module will be called istallion.
 
+config NOZOMI
+       tristate "HSDPA Broadband Wireless Data Card - Globe Trotter"
+       depends on PCI && EXPERIMENTAL
+       help
+         If you have a HSDPA driver Broadband Wireless Data Card -
+         Globe Trotter PCMCIA card, say Y here.
+
+         To compile this driver as a module, choose M here, the module
+         will be called nozomi.
+
 config A2232
        tristate "Commodore A2232 serial support (EXPERIMENTAL)"
        depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
index 07304d50e0cbcbde89e5cb26273bfbad73fdc3fc..96fc01eddefe805553ea1a834ba2f06a7f25c3b0 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_SERIAL167)               += serial167.o
 obj-$(CONFIG_CYCLADES)         += cyclades.o
 obj-$(CONFIG_STALLION)         += stallion.o
 obj-$(CONFIG_ISTALLION)                += istallion.o
+obj-$(CONFIG_NOZOMI)           += nozomi.o
 obj-$(CONFIG_DIGIEPCA)         += epca.o
 obj-$(CONFIG_SPECIALIX)                += specialix.o
 obj-$(CONFIG_MOXA_INTELLIO)    += moxa.o
index d87961993ccf7f0ab5acf76155b12367bd6b37e0..03eac1eb8e0fc863356905611bf344a5828a1554 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+#define PCI_DEVICE_ID_INTEL_E7221_HB   0x2588
+#define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
 #define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
 #define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
 #define PCI_DEVICE_ID_INTEL_82965G_1_HB     0x2980
@@ -526,7 +528,8 @@ static void intel_i830_init_gtt_entries(void)
                        break;
                case I915_GMCH_GMS_STOLEN_48M:
                        /* Check it's really I915G */
-                       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
+                       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
+                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
@@ -538,7 +541,8 @@ static void intel_i830_init_gtt_entries(void)
                        break;
                case I915_GMCH_GMS_STOLEN_64M:
                        /* Check it's really I915G */
-                       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
+                       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
+                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
@@ -1854,6 +1858,8 @@ static const struct intel_driver_description {
        { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865",
                &intel_845_driver, &intel_830_driver },
        { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)",
+               NULL, &intel_915_driver },
        { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G",
                NULL, &intel_915_driver },
        { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM",
@@ -2059,6 +2065,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_82875_HB),
        ID(PCI_DEVICE_ID_INTEL_7505_0),
        ID(PCI_DEVICE_ID_INTEL_7205_0),
+       ID(PCI_DEVICE_ID_INTEL_E7221_HB),
        ID(PCI_DEVICE_ID_INTEL_82915G_HB),
        ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
        ID(PCI_DEVICE_ID_INTEL_82945G_HB),
index f3593974496c443a76152b849724333f74ce7a2e..43d3c42df360552a47e6dc9ecbf3c0c3f1839e3c 100644 (file)
        {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x8086, 0x258a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
index 8252f86685385f341aa6f34797d52581264ed543..480fae29c9b2a508305d67e870684136c8f7581e 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/init.h>
 #include <linux/kbd_kern.h>
 #include <linux/kernel.h>
-#include <linux/kobject.h>
+#include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -89,7 +89,7 @@ struct hvc_struct {
        int irq_requested;
        int irq;
        struct list_head next;
-       struct kobject kobj; /* ref count & hvc_struct lifetime */
+       struct kref kref; /* ref count & hvc_struct lifetime */
 };
 
 /* dynamic list of hvc_struct instances */
@@ -110,7 +110,7 @@ static int last_hvc = -1;
 
 /*
  * Do not call this function with either the hvc_structs_lock or the hvc_struct
- * lock held.  If successful, this function increments the kobject reference
+ * lock held.  If successful, this function increments the kref reference
  * count against the target hvc_struct so it should be released when finished.
  */
 static struct hvc_struct *hvc_get_by_index(int index)
@@ -123,7 +123,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
        list_for_each_entry(hp, &hvc_structs, next) {
                spin_lock_irqsave(&hp->lock, flags);
                if (hp->index == index) {
-                       kobject_get(&hp->kobj);
+                       kref_get(&hp->kref);
                        spin_unlock_irqrestore(&hp->lock, flags);
                        spin_unlock(&hvc_structs_lock);
                        return hp;
@@ -242,6 +242,23 @@ static int __init hvc_console_init(void)
 }
 console_initcall(hvc_console_init);
 
+/* callback when the kboject ref count reaches zero. */
+static void destroy_hvc_struct(struct kref *kref)
+{
+       struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+       unsigned long flags;
+
+       spin_lock(&hvc_structs_lock);
+
+       spin_lock_irqsave(&hp->lock, flags);
+       list_del(&(hp->next));
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       spin_unlock(&hvc_structs_lock);
+
+       kfree(hp);
+}
+
 /*
  * hvc_instantiate() is an early console discovery method which locates
  * consoles * prior to the vio subsystem discovering them.  Hotplugged
@@ -261,7 +278,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
        /* make sure no no tty has been registered in this index */
        hp = hvc_get_by_index(index);
        if (hp) {
-               kobject_put(&hp->kobj);
+               kref_put(&hp->kref, destroy_hvc_struct);
                return -1;
        }
 
@@ -318,9 +335,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
        unsigned long flags;
        int irq = 0;
        int rc = 0;
-       struct kobject *kobjp;
 
-       /* Auto increments kobject reference if found. */
+       /* Auto increments kref reference if found. */
        if (!(hp = hvc_get_by_index(tty->index)))
                return -ENODEV;
 
@@ -341,8 +357,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
        if (irq)
                hp->irq_requested = 1;
 
-       kobjp = &hp->kobj;
-
        spin_unlock_irqrestore(&hp->lock, flags);
        /* check error, fallback to non-irq */
        if (irq)
@@ -352,7 +366,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
         * If the request_irq() fails and we return an error.  The tty layer
         * will call hvc_close() after a failed open but we don't want to clean
         * up there so we'll clean up here and clear out the previously set
-        * tty fields and return the kobject reference.
+        * tty fields and return the kref reference.
         */
        if (rc) {
                spin_lock_irqsave(&hp->lock, flags);
@@ -360,7 +374,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
                hp->irq_requested = 0;
                spin_unlock_irqrestore(&hp->lock, flags);
                tty->driver_data = NULL;
-               kobject_put(kobjp);
+               kref_put(&hp->kref, destroy_hvc_struct);
                printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
        }
        /* Force wakeup of the polling thread */
@@ -372,7 +386,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 static void hvc_close(struct tty_struct *tty, struct file * filp)
 {
        struct hvc_struct *hp;
-       struct kobject *kobjp;
        int irq = 0;
        unsigned long flags;
 
@@ -382,7 +395,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
        /*
         * No driver_data means that this close was issued after a failed
         * hvc_open by the tty layer's release_dev() function and we can just
-        * exit cleanly because the kobject reference wasn't made.
+        * exit cleanly because the kref reference wasn't made.
         */
        if (!tty->driver_data)
                return;
@@ -390,7 +403,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
        hp = tty->driver_data;
        spin_lock_irqsave(&hp->lock, flags);
 
-       kobjp = &hp->kobj;
        if (--hp->count == 0) {
                if (hp->irq_requested)
                        irq = hp->irq;
@@ -417,7 +429,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                spin_unlock_irqrestore(&hp->lock, flags);
        }
 
-       kobject_put(kobjp);
+       kref_put(&hp->kref, destroy_hvc_struct);
 }
 
 static void hvc_hangup(struct tty_struct *tty)
@@ -426,7 +438,6 @@ static void hvc_hangup(struct tty_struct *tty)
        unsigned long flags;
        int irq = 0;
        int temp_open_count;
-       struct kobject *kobjp;
 
        if (!hp)
                return;
@@ -443,7 +454,6 @@ static void hvc_hangup(struct tty_struct *tty)
                return;
        }
 
-       kobjp = &hp->kobj;
        temp_open_count = hp->count;
        hp->count = 0;
        hp->n_outbuf = 0;
@@ -457,7 +467,7 @@ static void hvc_hangup(struct tty_struct *tty)
                free_irq(irq, hp);
        while(temp_open_count) {
                --temp_open_count;
-               kobject_put(kobjp);
+               kref_put(&hp->kref, destroy_hvc_struct);
        }
 }
 
@@ -729,27 +739,6 @@ static const struct tty_operations hvc_ops = {
        .chars_in_buffer = hvc_chars_in_buffer,
 };
 
-/* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kobject *kobj)
-{
-       struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj);
-       unsigned long flags;
-
-       spin_lock(&hvc_structs_lock);
-
-       spin_lock_irqsave(&hp->lock, flags);
-       list_del(&(hp->next));
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       spin_unlock(&hvc_structs_lock);
-
-       kfree(hp);
-}
-
-static struct kobj_type hvc_kobj_type = {
-       .release = destroy_hvc_struct,
-};
-
 struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
                                        struct hv_ops *ops, int outbuf_size)
 {
@@ -776,8 +765,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
        hp->outbuf_size = outbuf_size;
        hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
 
-       kobject_init(&hp->kobj);
-       hp->kobj.ktype = &hvc_kobj_type;
+       kref_init(&hp->kref);
 
        spin_lock_init(&hp->lock);
        spin_lock(&hvc_structs_lock);
@@ -806,12 +794,10 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
 int __devexit hvc_remove(struct hvc_struct *hp)
 {
        unsigned long flags;
-       struct kobject *kobjp;
        struct tty_struct *tty;
 
        spin_lock_irqsave(&hp->lock, flags);
        tty = hp->tty;
-       kobjp = &hp->kobj;
 
        if (hp->index < MAX_NR_HVC_CONSOLES)
                vtermnos[hp->index] = -1;
@@ -821,12 +807,12 @@ int __devexit hvc_remove(struct hvc_struct *hp)
        spin_unlock_irqrestore(&hp->lock, flags);
 
        /*
-        * We 'put' the instance that was grabbed when the kobject instance
-        * was initialized using kobject_init().  Let the last holder of this
-        * kobject cause it to be removed, which will probably be the tty_hangup
+        * We 'put' the instance that was grabbed when the kref instance
+        * was initialized using kref_init().  Let the last holder of this
+        * kref cause it to be removed, which will probably be the tty_hangup
         * below.
         */
-       kobject_put(kobjp);
+       kref_put(&hp->kref, destroy_hvc_struct);
 
        /*
         * This function call will auto chain call hvc_hangup.  The tty should
index 69d8866de783f36a70ff38d63d4b47d9f0688385..fd7559084b8204479c76dc0cbd72da06fe431126 100644 (file)
  * rescanning partner information upon a user's request.
  *
  * Each vty-server, prior to being exposed to this driver is reference counted
- * using the 2.6 Linux kernel kobject construct.  This kobject is also used by
- * the vio bus to provide a vio device sysfs entry that this driver attaches
- * device specific attributes to, including partner information.  The vio bus
- * framework also provides a sysfs entry for each vio driver.  The hvcs driver
- * provides driver attributes in this entry.
+ * using the 2.6 Linux kernel kref construct.
  *
  * For direction on installation and usage of this driver please reference
  * Documentation/powerpc/hvcs.txt.
@@ -71,7 +67,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/kobject.h>
+#include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/major.h>
@@ -293,12 +289,12 @@ struct hvcs_struct {
        int chars_in_buffer;
 
        /*
-        * Any variable below the kobject is valid before a tty is connected and
+        * Any variable below the kref is valid before a tty is connected and
         * stays valid after the tty is disconnected.  These shouldn't be
         * whacked until the koject refcount reaches zero though some entries
         * may be changed via sysfs initiatives.
         */
-       struct kobject kobj; /* ref count & hvcs_struct lifetime */
+       struct kref kref; /* ref count & hvcs_struct lifetime */
        int connected; /* is the vty-server currently connected to a vty? */
        uint32_t p_unit_address; /* partner unit address */
        uint32_t p_partition_ID; /* partner partition ID */
@@ -307,8 +303,8 @@ struct hvcs_struct {
        struct vio_dev *vdev;
 };
 
-/* Required to back map a kobject to its containing object */
-#define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj)
+/* Required to back map a kref to its containing object */
+#define from_kref(k) container_of(k, struct hvcs_struct, kref)
 
 static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
@@ -334,7 +330,6 @@ static void hvcs_partner_free(struct hvcs_struct *hvcsd);
 static int hvcs_enable_device(struct hvcs_struct *hvcsd,
                uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
 
-static void destroy_hvcs_struct(struct kobject *kobj);
 static int hvcs_open(struct tty_struct *tty, struct file *filp);
 static void hvcs_close(struct tty_struct *tty, struct file *filp);
 static void hvcs_hangup(struct tty_struct * tty);
@@ -703,10 +698,10 @@ static void hvcs_return_index(int index)
                hvcs_index_list[index] = -1;
 }
 
-/* callback when the kboject ref count reaches zero */
-static void destroy_hvcs_struct(struct kobject *kobj)
+/* callback when the kref ref count reaches zero */
+static void destroy_hvcs_struct(struct kref *kref)
 {
-       struct hvcs_struct *hvcsd = from_kobj(kobj);
+       struct hvcs_struct *hvcsd = from_kref(kref);
        struct vio_dev *vdev;
        unsigned long flags;
 
@@ -743,10 +738,6 @@ static void destroy_hvcs_struct(struct kobject *kobj)
        kfree(hvcsd);
 }
 
-static struct kobj_type hvcs_kobj_type = {
-       .release = destroy_hvcs_struct,
-};
-
 static int hvcs_get_index(void)
 {
        int i;
@@ -791,9 +782,7 @@ static int __devinit hvcs_probe(
 
        spin_lock_init(&hvcsd->lock);
        /* Automatically incs the refcount the first time */
-       kobject_init(&hvcsd->kobj);
-       /* Set up the callback for terminating the hvcs_struct's life */
-       hvcsd->kobj.ktype = &hvcs_kobj_type;
+       kref_init(&hvcsd->kref);
 
        hvcsd->vdev = dev;
        dev->dev.driver_data = hvcsd;
@@ -844,7 +833,6 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 {
        struct hvcs_struct *hvcsd = dev->dev.driver_data;
        unsigned long flags;
-       struct kobject *kobjp;
        struct tty_struct *tty;
 
        if (!hvcsd)
@@ -856,15 +844,13 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 
        tty = hvcsd->tty;
 
-       kobjp = &hvcsd->kobj;
-
        spin_unlock_irqrestore(&hvcsd->lock, flags);
 
        /*
         * Let the last holder of this object cause it to be removed, which
         * would probably be tty_hangup below.
         */
-       kobject_put (kobjp);
+       kref_put(&hvcsd->kref, destroy_hvcs_struct);
 
        /*
         * The hangup is a scheduled function which will auto chain call
@@ -1086,7 +1072,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
 }
 
 /*
- * This always increments the kobject ref count if the call is successful.
+ * This always increments the kref ref count if the call is successful.
  * Please remember to dec when you are done with the instance.
  *
  * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
@@ -1103,7 +1089,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
                list_for_each_entry(hvcsd, &hvcs_structs, next) {
                        spin_lock_irqsave(&hvcsd->lock, flags);
                        if (hvcsd->index == index) {
-                               kobject_get(&hvcsd->kobj);
+                               kref_get(&hvcsd->kref);
                                spin_unlock_irqrestore(&hvcsd->lock, flags);
                                spin_unlock(&hvcs_structs_lock);
                                return hvcsd;
@@ -1129,14 +1115,13 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
        unsigned int irq;
        struct vio_dev *vdev;
        unsigned long unit_address;
-       struct kobject *kobjp;
 
        if (tty->driver_data)
                goto fast_open;
 
        /*
         * Is there a vty-server that shares the same index?
-        * This function increments the kobject index.
+        * This function increments the kref index.
         */
        if (!(hvcsd = hvcs_get_by_index(tty->index))) {
                printk(KERN_WARNING "HVCS: open failed, no device associated"
@@ -1181,7 +1166,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
         * and will grab the spinlock and free the connection if it fails.
         */
        if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
-               kobject_put(&hvcsd->kobj);
+               kref_put(&hvcsd->kref, destroy_hvcs_struct);
                printk(KERN_WARNING "HVCS: enable device failed.\n");
                return rc;
        }
@@ -1192,17 +1177,11 @@ fast_open:
        hvcsd = tty->driver_data;
 
        spin_lock_irqsave(&hvcsd->lock, flags);
-       if (!kobject_get(&hvcsd->kobj)) {
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-               printk(KERN_ERR "HVCS: Kobject of open"
-                       " hvcs doesn't exist.\n");
-               return -EFAULT; /* Is this the right return value? */
-       }
-
+       kref_get(&hvcsd->kref);
        hvcsd->open_count++;
-
        hvcsd->todo_mask |= HVCS_SCHED_READ;
        spin_unlock_irqrestore(&hvcsd->lock, flags);
+
 open_success:
        hvcs_kick();
 
@@ -1212,9 +1191,8 @@ open_success:
        return 0;
 
 error_release:
-       kobjp = &hvcsd->kobj;
        spin_unlock_irqrestore(&hvcsd->lock, flags);
-       kobject_put(&hvcsd->kobj);
+       kref_put(&hvcsd->kref, destroy_hvcs_struct);
 
        printk(KERN_WARNING "HVCS: partner connect failed.\n");
        return retval;
@@ -1224,7 +1202,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 {
        struct hvcs_struct *hvcsd;
        unsigned long flags;
-       struct kobject *kobjp;
        int irq = NO_IRQ;
 
        /*
@@ -1245,7 +1222,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
        hvcsd = tty->driver_data;
 
        spin_lock_irqsave(&hvcsd->lock, flags);
-       kobjp = &hvcsd->kobj;
        if (--hvcsd->open_count == 0) {
 
                vio_disable_interrupts(hvcsd->vdev);
@@ -1270,7 +1246,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
                tty->driver_data = NULL;
 
                free_irq(irq, hvcsd);
-               kobject_put(kobjp);
+               kref_put(&hvcsd->kref, destroy_hvcs_struct);
                return;
        } else if (hvcsd->open_count < 0) {
                printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1279,7 +1255,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
        }
 
        spin_unlock_irqrestore(&hvcsd->lock, flags);
-       kobject_put(kobjp);
+       kref_put(&hvcsd->kref, destroy_hvcs_struct);
 }
 
 static void hvcs_hangup(struct tty_struct * tty)
@@ -1287,21 +1263,17 @@ static void hvcs_hangup(struct tty_struct * tty)
        struct hvcs_struct *hvcsd = tty->driver_data;
        unsigned long flags;
        int temp_open_count;
-       struct kobject *kobjp;
        int irq = NO_IRQ;
 
        spin_lock_irqsave(&hvcsd->lock, flags);
-       /* Preserve this so that we know how many kobject refs to put */
+       /* Preserve this so that we know how many kref refs to put */
        temp_open_count = hvcsd->open_count;
 
        /*
-        * Don't kobject put inside the spinlock because the destruction
+        * Don't kref put inside the spinlock because the destruction
         * callback may use the spinlock and it may get called before the
-        * spinlock has been released.  Get a pointer to the kobject and
-        * kobject_put on that after releasing the spinlock.
+        * spinlock has been released.
         */
-       kobjp = &hvcsd->kobj;
-
        vio_disable_interrupts(hvcsd->vdev);
 
        hvcsd->todo_mask = 0;
@@ -1324,7 +1296,7 @@ static void hvcs_hangup(struct tty_struct * tty)
        free_irq(irq, hvcsd);
 
        /*
-        * We need to kobject_put() for every open_count we have since the
+        * We need to kref_put() for every open_count we have since the
         * tty_hangup() function doesn't invoke a close per open connection on a
         * non-console device.
         */
@@ -1335,7 +1307,7 @@ static void hvcs_hangup(struct tty_struct * tty)
                 * NOTE:  If this hangup was signaled from user space then the
                 * final put will never happen.
                 */
-               kobject_put(kobjp);
+               kref_put(&hvcsd->kref, destroy_hvcs_struct);
        }
 }
 
index 556fd81fa8155737caacc44039517c93d13bd4be..c422e870dc52705cf779fe7742706bca3eaad86c 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
@@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 static struct pci_dev *amd_pdev;
 
 
-static int amd_rng_data_present(struct hwrng *rng)
+static int amd_rng_data_present(struct hwrng *rng, int wait)
 {
        u32 pmbase = (u32)rng->priv;
+       int data, i;
 
-       return !!(inl(pmbase + 0xF4) & 1);
+       for (i = 0; i < 20; i++) {
+               data = !!(inl(pmbase + 0xF4) & 1);
+               if (data || !wait)
+                       break;
+               udelay(10);
+       }
+       return data;
 }
 
 static int amd_rng_data_read(struct hwrng *rng, u32 *data)
index 26a860adcb3854817f079c526aacde2d2f917b02..0118b9817a95efa7a414033d52418f2d6885f6f1 100644 (file)
@@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng)
                rng->cleanup(rng);
 }
 
-static inline int hwrng_data_present(struct hwrng *rng)
+static inline int hwrng_data_present(struct hwrng *rng, int wait)
 {
        if (!rng->data_present)
                return 1;
-       return rng->data_present(rng);
+       return rng->data_present(rng, wait);
 }
 
 static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
@@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
 {
        u32 data;
        ssize_t ret = 0;
-       int i, err = 0;
-       int data_present;
+       int err = 0;
        int bytes_read;
 
        while (size) {
@@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
                        err = -ENODEV;
                        goto out;
                }
-               if (filp->f_flags & O_NONBLOCK) {
-                       data_present = hwrng_data_present(current_rng);
-               } else {
-                       /* Some RNG require some time between data_reads to gather
-                        * new entropy. Poll it.
-                        */
-                       for (i = 0; i < 20; i++) {
-                               data_present = hwrng_data_present(current_rng);
-                               if (data_present)
-                                       break;
-                               udelay(10);
-                       }
-               }
+
                bytes_read = 0;
-               if (data_present)
+               if (hwrng_data_present(current_rng,
+                                      !(filp->f_flags & O_NONBLOCK)))
                        bytes_read = hwrng_data_read(current_rng, &data);
                mutex_unlock(&rng_mutex);
 
index 8e8658dcd2e3b1bfa87036f33da090928e4b0818..fed4ef5569f5be94e778ee4103f32566ebe8c426 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
@@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data)
        return 4;
 }
 
-static int geode_rng_data_present(struct hwrng *rng)
+static int geode_rng_data_present(struct hwrng *rng, int wait)
 {
        void __iomem *mem = (void __iomem *)rng->priv;
+       int data, i;
 
-       return !!(readl(mem + GEODE_RNG_STATUS_REG));
+       for (i = 0; i < 20; i++) {
+               data = !!(readl(mem + GEODE_RNG_STATUS_REG));
+               if (data || !wait)
+                       break;
+               udelay(10);
+       }
+       return data;
 }
 
 
index 753f46052b874abdaa4f56ee55dd4dd2c542f3f5..5cc651ef75ebd96b61deeb187d46d5ee5f2ecd53 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/stop_machine.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
@@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem,
        return hwstatus_get(mem);
 }
 
-static int intel_rng_data_present(struct hwrng *rng)
+static int intel_rng_data_present(struct hwrng *rng, int wait)
 {
        void __iomem *mem = (void __iomem *)rng->priv;
-
-       return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT);
+       int data, i;
+
+       for (i = 0; i < 20; i++) {
+               data = !!(readb(mem + INTEL_RNG_STATUS) &
+                         INTEL_RNG_DATA_PRESENT);
+               if (data || !wait)
+                       break;
+               udelay(10);
+       }
+       return data;
 }
 
 static int intel_rng_data_read(struct hwrng *rng, u32 *data)
index 3f35a1c562b1a1bb6c1fa211577caa87ac92c015..7e319951fa4111fec37688f052596a29cd27c211 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
@@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val)
 }
 
 /* REVISIT: Does the status bit really work on 16xx? */
-static int omap_rng_data_present(struct hwrng *rng)
+static int omap_rng_data_present(struct hwrng *rng, int wait)
 {
-       return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+       int data, i;
+
+       for (i = 0; i < 20; i++) {
+               data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+               if (data || !wait)
+                       break;
+               udelay(10);
+       }
+       return data;
 }
 
 static int omap_rng_data_read(struct hwrng *rng, u32 *data)
index fa6040b6c8f2a4f0483d830aa97abe48ae2f7f60..e2ea210cfa5f9149d018fa1f64995902d86774bd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/of_platform.h>
 #include <asm/io.h>
 
 
 #define MODULE_NAME "pasemi_rng"
 
-static int pasemi_rng_data_present(struct hwrng *rng)
+static int pasemi_rng_data_present(struct hwrng *rng, int wait)
 {
        void __iomem *rng_regs = (void __iomem *)rng->priv;
-
-       return (in_le32(rng_regs + SDCRNG_CTL_REG)
-               & SDCRNG_CTL_FVLD_M) ? 1 : 0;
+       int data, i;
+
+       for (i = 0; i < 20; i++) {
+               data = (in_le32(rng_regs + SDCRNG_CTL_REG)
+                       & SDCRNG_CTL_FVLD_M) ? 1 : 0;
+               if (data || !wait)
+                       break;
+               udelay(10);
+       }
+       return data;
 }
 
 static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
index ec435cb25c4fd4709f58c47d4f3ce9153b2748ca..868e39fd42e49779e494d8c96d097c700ab2d0b2 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
@@ -77,10 +78,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in)
        return eax_out;
 }
 
-static int via_rng_data_present(struct hwrng *rng)
+static int via_rng_data_present(struct hwrng *rng, int wait)
 {
        u32 bytes_out;
        u32 *via_rng_datum = (u32 *)(&rng->priv);
+       int i;
 
        /* We choose the recommended 1-byte-per-instruction RNG rate,
         * for greater randomness at the expense of speed.  Larger
@@ -95,12 +97,15 @@ static int via_rng_data_present(struct hwrng *rng)
         * completes.
         */
 
-       *via_rng_datum = 0; /* paranoia, not really necessary */
-       bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
-       bytes_out &= VIA_XSTORE_CNT_MASK;
-       if (bytes_out == 0)
-               return 0;
-       return 1;
+       for (i = 0; i < 20; i++) {
+               *via_rng_datum = 0; /* paranoia, not really necessary */
+               bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
+               bytes_out &= VIA_XSTORE_CNT_MASK;
+               if (bytes_out || !wait)
+                       break;
+               udelay(10);
+       }
+       return bytes_out ? 1 : 0;
 }
 
 static int via_rng_data_read(struct hwrng *rng, u32 *data)
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
new file mode 100644 (file)
index 0000000..6076e66
--- /dev/null
@@ -0,0 +1,1993 @@
+/*
+ * nozomi.c  -- HSDPA driver Broadband Wireless Data Card - Globe Trotter
+ *
+ * Written by: Ulf Jakobsson,
+ *             Jan �erfeldt,
+ *             Stefan Thomasson,
+ *
+ * Maintained by: Paul Hardwick (p.hardwick@option.com)
+ *
+ * Patches:
+ *          Locking code changes for Vodafone by Sphere Systems Ltd,
+ *                              Andrew Bird (ajb@spheresystems.co.uk )
+ *                              & Phil Sanderson
+ *
+ * Source has been ported from an implementation made by Filip Aben @ Option
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Copyright (c) 2005,2006 Option Wireless Sweden AB
+ * Copyright (c) 2006 Sphere Systems Ltd
+ * Copyright (c) 2006 Option Wireless n/v
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * --------------------------------------------------------------------------
+ */
+
+/*
+ * CHANGELOG
+ * Version 2.1d
+ * 11-November-2007 Jiri Slaby, Frank Seidel
+ * - Big rework of multicard support by Jiri
+ * - Major cleanups (semaphore to mutex, endianess, no major reservation)
+ * - Optimizations
+ *
+ * Version 2.1c
+ * 30-October-2007 Frank Seidel
+ * - Completed multicard support
+ * - Minor cleanups
+ *
+ * Version 2.1b
+ * 07-August-2007 Frank Seidel
+ * - Minor cleanups
+ * - theoretical multicard support
+ *
+ * Version 2.1
+ * 03-July-2006 Paul Hardwick
+ *
+ * - Stability Improvements. Incorporated spinlock wraps patch.
+ * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room)
+ * - using __devexit macro for tty
+ *
+ *
+ * Version 2.0
+ * 08-feb-2006 15:34:10:Ulf
+ *
+ * -Fixed issue when not waking up line disipine layer, could probably result
+ *  in better uplink performance for 2.4.
+ *
+ * -Fixed issue with big endian during initalization, now proper toggle flags
+ *  are handled between preloader and maincode.
+ *
+ * -Fixed flow control issue.
+ *
+ * -Added support for setting DTR.
+ *
+ * -For 2.4 kernels, removing temporary buffer that's not needed.
+ *
+ * -Reading CTS only for modem port (only port that supports it).
+ *
+ * -Return 0 in write_room instead of netative value, it's not handled in
+ *  upper layer.
+ *
+ * --------------------------------------------------------------------------
+ * Version 1.0
+ *
+ * First version of driver, only tested with card of type F32_2.
+ * Works fine with 2.4 and 2.6 kernels.
+ * Driver also support big endian architecture.
+ */
+
+/* Enable this to have a lot of debug printouts */
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/interrupt.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/kfifo.h>
+#include <linux/uaccess.h>
+#include <asm/byteorder.h>
+
+#include <linux/delay.h>
+
+
+#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \
+                                       __DATE__ " " __TIME__ ")"
+
+/*    Macros definitions */
+
+/* Default debug printout level */
+#define NOZOMI_DEBUG_LEVEL 0x00
+
+#define P_BUF_SIZE 128
+#define NFO(_err_flag_, args...)                               \
+do {                                                           \
+       char tmp[P_BUF_SIZE];                                   \
+       snprintf(tmp, sizeof(tmp), ##args);                     \
+       printk(_err_flag_ "[%d] %s(): %s\n", __LINE__,          \
+               __FUNCTION__, tmp);                             \
+} while (0)
+
+#define DBG1(args...) D_(0x01, ##args)
+#define DBG2(args...) D_(0x02, ##args)
+#define DBG3(args...) D_(0x04, ##args)
+#define DBG4(args...) D_(0x08, ##args)
+#define DBG5(args...) D_(0x10, ##args)
+#define DBG6(args...) D_(0x20, ##args)
+#define DBG7(args...) D_(0x40, ##args)
+#define DBG8(args...) D_(0x80, ##args)
+
+#ifdef DEBUG
+/* Do we need this settable at runtime? */
+static int debug = NOZOMI_DEBUG_LEVEL;
+
+#define D(lvl, args...)  do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
+                               while (0)
+#define D_(lvl, args...) D(lvl, ##args)
+
+/* These printouts are always printed */
+
+#else
+static int debug;
+#define D_(lvl, args...)
+#endif
+
+/* TODO: rewrite to optimize macros... */
+
+#define TMP_BUF_MAX 256
+
+#define DUMP(buf__,len__) \
+  do {  \
+    char tbuf[TMP_BUF_MAX] = {0};\
+    if (len__ > 1) {\
+       snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\
+       if (tbuf[len__-2] == '\r') {\
+               tbuf[len__-2] = 'r';\
+       } \
+       DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\
+    } else {\
+       DBG1("SENDING: '%s' (%d)", tbuf, len__);\
+    } \
+} while (0)
+
+/*    Defines */
+#define NOZOMI_NAME            "nozomi"
+#define NOZOMI_NAME_TTY                "nozomi_tty"
+#define DRIVER_DESC            "Nozomi driver"
+
+#define NTTY_TTY_MAXMINORS     256
+#define NTTY_FIFO_BUFFER_SIZE  8192
+
+/* Must be power of 2 */
+#define FIFO_BUFFER_SIZE_UL    8192
+
+/* Size of tmp send buffer to card */
+#define SEND_BUF_MAX           1024
+#define RECEIVE_BUF_MAX                4
+
+
+/* Define all types of vendors and devices to support */
+#define VENDOR1                0x1931  /* Vendor Option */
+#define DEVICE1                0x000c  /* HSDPA card */
+
+#define R_IIR          0x0000  /* Interrupt Identity Register */
+#define R_FCR          0x0000  /* Flow Control Register */
+#define R_IER          0x0004  /* Interrupt Enable Register */
+
+#define CONFIG_MAGIC   0xEFEFFEFE
+#define TOGGLE_VALID   0x0000
+
+/* Definition of interrupt tokens */
+#define MDM_DL1                0x0001
+#define MDM_UL1                0x0002
+#define MDM_DL2                0x0004
+#define MDM_UL2                0x0008
+#define DIAG_DL1       0x0010
+#define DIAG_DL2       0x0020
+#define DIAG_UL                0x0040
+#define APP1_DL                0x0080
+#define APP1_UL                0x0100
+#define APP2_DL                0x0200
+#define APP2_UL                0x0400
+#define CTRL_DL                0x0800
+#define CTRL_UL                0x1000
+#define RESET          0x8000
+
+#define MDM_DL         (MDM_DL1  | MDM_DL2)
+#define MDM_UL         (MDM_UL1  | MDM_UL2)
+#define DIAG_DL                (DIAG_DL1 | DIAG_DL2)
+
+/* modem signal definition */
+#define CTRL_DSR       0x0001
+#define CTRL_DCD       0x0002
+#define CTRL_RI                0x0004
+#define CTRL_CTS       0x0008
+
+#define CTRL_DTR       0x0001
+#define CTRL_RTS       0x0002
+
+#define MAX_PORT               4
+#define NOZOMI_MAX_PORTS       5
+#define NOZOMI_MAX_CARDS       (NTTY_TTY_MAXMINORS / MAX_PORT)
+
+/*    Type definitions */
+
+/*
+ * There are two types of nozomi cards,
+ * one with 2048 memory and with 8192 memory
+ */
+enum card_type {
+       F32_2 = 2048,   /* 512 bytes downlink + uplink * 2 -> 2048 */
+       F32_8 = 8192,   /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */
+};
+
+/* Two different toggle channels exist */
+enum channel_type {
+       CH_A = 0,
+       CH_B = 1,
+};
+
+/* Port definition for the card regarding flow control */
+enum ctrl_port_type {
+       CTRL_CMD        = 0,
+       CTRL_MDM        = 1,
+       CTRL_DIAG       = 2,
+       CTRL_APP1       = 3,
+       CTRL_APP2       = 4,
+       CTRL_ERROR      = -1,
+};
+
+/* Ports that the nozomi has */
+enum port_type {
+       PORT_MDM        = 0,
+       PORT_DIAG       = 1,
+       PORT_APP1       = 2,
+       PORT_APP2       = 3,
+       PORT_CTRL       = 4,
+       PORT_ERROR      = -1,
+};
+
+#ifdef __BIG_ENDIAN
+/* Big endian */
+
+struct toggles {
+       unsigned enabled:5;     /*
+                                * Toggle fields are valid if enabled is 0,
+                                * else A-channels must always be used.
+                                */
+       unsigned diag_dl:1;
+       unsigned mdm_dl:1;
+       unsigned mdm_ul:1;
+} __attribute__ ((packed));
+
+/* Configuration table to read at startup of card */
+/* Is for now only needed during initialization phase */
+struct config_table {
+       u32 signature;
+       u16 product_information;
+       u16 version;
+       u8 pad3[3];
+       struct toggles toggle;
+       u8 pad1[4];
+       u16 dl_mdm_len1;        /*
+                                * If this is 64, it can hold
+                                * 60 bytes + 4 that is length field
+                                */
+       u16 dl_start;
+
+       u16 dl_diag_len1;
+       u16 dl_mdm_len2;        /*
+                                * If this is 64, it can hold
+                                * 60 bytes + 4 that is length field
+                                */
+       u16 dl_app1_len;
+
+       u16 dl_diag_len2;
+       u16 dl_ctrl_len;
+       u16 dl_app2_len;
+       u8 pad2[16];
+       u16 ul_mdm_len1;
+       u16 ul_start;
+       u16 ul_diag_len;
+       u16 ul_mdm_len2;
+       u16 ul_app1_len;
+       u16 ul_app2_len;
+       u16 ul_ctrl_len;
+} __attribute__ ((packed));
+
+/* This stores all control downlink flags */
+struct ctrl_dl {
+       u8 port;
+       unsigned reserved:4;
+       unsigned CTS:1;
+       unsigned RI:1;
+       unsigned DCD:1;
+       unsigned DSR:1;
+} __attribute__ ((packed));
+
+/* This stores all control uplink flags */
+struct ctrl_ul {
+       u8 port;
+       unsigned reserved:6;
+       unsigned RTS:1;
+       unsigned DTR:1;
+} __attribute__ ((packed));
+
+#else
+/* Little endian */
+
+/* This represents the toggle information */
+struct toggles {
+       unsigned mdm_ul:1;
+       unsigned mdm_dl:1;
+       unsigned diag_dl:1;
+       unsigned enabled:5;     /*
+                                * Toggle fields are valid if enabled is 0,
+                                * else A-channels must always be used.
+                                */
+} __attribute__ ((packed));
+
+/* Configuration table to read at startup of card */
+struct config_table {
+       u32 signature;
+       u16 version;
+       u16 product_information;
+       struct toggles toggle;
+       u8 pad1[7];
+       u16 dl_start;
+       u16 dl_mdm_len1;        /*
+                                * If this is 64, it can hold
+                                * 60 bytes + 4 that is length field
+                                */
+       u16 dl_mdm_len2;
+       u16 dl_diag_len1;
+       u16 dl_diag_len2;
+       u16 dl_app1_len;
+       u16 dl_app2_len;
+       u16 dl_ctrl_len;
+       u8 pad2[16];
+       u16 ul_start;
+       u16 ul_mdm_len2;
+       u16 ul_mdm_len1;
+       u16 ul_diag_len;
+       u16 ul_app1_len;
+       u16 ul_app2_len;
+       u16 ul_ctrl_len;
+} __attribute__ ((packed));
+
+/* This stores all control downlink flags */
+struct ctrl_dl {
+       unsigned DSR:1;
+       unsigned DCD:1;
+       unsigned RI:1;
+       unsigned CTS:1;
+       unsigned reserverd:4;
+       u8 port;
+} __attribute__ ((packed));
+
+/* This stores all control uplink flags */
+struct ctrl_ul {
+       unsigned DTR:1;
+       unsigned RTS:1;
+       unsigned reserved:6;
+       u8 port;
+} __attribute__ ((packed));
+#endif
+
+/* This holds all information that is needed regarding a port */
+struct port {
+       u8 update_flow_control;
+       struct ctrl_ul ctrl_ul;
+       struct ctrl_dl ctrl_dl;
+       struct kfifo *fifo_ul;
+       void __iomem *dl_addr[2];
+       u32 dl_size[2];
+       u8 toggle_dl;
+       void __iomem *ul_addr[2];
+       u32 ul_size[2];
+       u8 toggle_ul;
+       u16 token_dl;
+
+       struct tty_struct *tty;
+       int tty_open_count;
+       /* mutex to ensure one access patch to this port */
+       struct mutex tty_sem;
+       wait_queue_head_t tty_wait;
+       struct async_icount tty_icount;
+};
+
+/* Private data one for each card in the system */
+struct nozomi {
+       void __iomem *base_addr;
+       unsigned long flip;
+
+       /* Pointers to registers */
+       void __iomem *reg_iir;
+       void __iomem *reg_fcr;
+       void __iomem *reg_ier;
+
+       u16 last_ier;
+       enum card_type card_type;
+       struct config_table config_table;       /* Configuration table */
+       struct pci_dev *pdev;
+       struct port port[NOZOMI_MAX_PORTS];
+       u8 *send_buf;
+
+       spinlock_t spin_mutex;  /* secures access to registers and tty */
+
+       unsigned int index_start;
+       u32 open_ttys;
+};
+
+/* This is a data packet that is read or written to/from card */
+struct buffer {
+       u32 size;               /* size is the length of the data buffer */
+       u8 *data;
+} __attribute__ ((packed));
+
+/*    Global variables */
+static struct pci_device_id nozomi_pci_tbl[] = {
+       {PCI_DEVICE(VENDOR1, DEVICE1)},
+       {},
+};
+
+MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl);
+
+static struct nozomi *ndevs[NOZOMI_MAX_CARDS];
+static struct tty_driver *ntty_driver;
+
+/*
+ * find card by tty_index
+ */
+static inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty)
+{
+       return tty ? ndevs[tty->index / MAX_PORT] : NULL;
+}
+
+static inline struct port *get_port_by_tty(const struct tty_struct *tty)
+{
+       struct nozomi *ndev = get_dc_by_tty(tty);
+       return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL;
+}
+
+/*
+ * TODO:
+ * -Optimize
+ * -Rewrite cleaner
+ */
+
+static void read_mem32(u32 *buf, const void __iomem *mem_addr_start,
+                       u32 size_bytes)
+{
+       u32 i = 0;
+       const u32 *ptr = (__force u32 *) mem_addr_start;
+       u16 *buf16;
+
+       if (unlikely(!ptr || !buf))
+               goto out;
+
+       /* shortcut for extremely often used cases */
+       switch (size_bytes) {
+       case 2: /* 2 bytes */
+               buf16 = (u16 *) buf;
+               *buf16 = __le16_to_cpu(readw((void __iomem *)ptr));
+               goto out;
+               break;
+       case 4: /* 4 bytes */
+               *(buf) = __le32_to_cpu(readl((void __iomem *)ptr));
+               goto out;
+               break;
+       }
+
+       while (i < size_bytes) {
+               if (size_bytes - i == 2) {
+                       /* Handle 2 bytes in the end */
+                       buf16 = (u16 *) buf;
+                       *(buf16) = __le16_to_cpu(readw((void __iomem *)ptr));
+                       i += 2;
+               } else {
+                       /* Read 4 bytes */
+                       *(buf) = __le32_to_cpu(readl((void __iomem *)ptr));
+                       i += 4;
+               }
+               buf++;
+               ptr++;
+       }
+out:
+       return;
+}
+
+/*
+ * TODO:
+ * -Optimize
+ * -Rewrite cleaner
+ */
+static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf,
+                       u32 size_bytes)
+{
+       u32 i = 0;
+       u32 *ptr = (__force u32 *) mem_addr_start;
+       u16 *buf16;
+
+       if (unlikely(!ptr || !buf))
+               return 0;
+
+       /* shortcut for extremely often used cases */
+       switch (size_bytes) {
+       case 2: /* 2 bytes */
+               buf16 = (u16 *) buf;
+               writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
+               return 2;
+               break;
+       case 1: /*
+                * also needs to write 4 bytes in this case
+                * so falling through..
+                */
+       case 4: /* 4 bytes */
+               writel(__cpu_to_le32(*buf), (void __iomem *)ptr);
+               return 4;
+               break;
+       }
+
+       while (i < size_bytes) {
+               if (size_bytes - i == 2) {
+                       /* 2 bytes */
+                       buf16 = (u16 *) buf;
+                       writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
+                       i += 2;
+               } else {
+                       /* 4 bytes */
+                       writel(__cpu_to_le32(*buf), (void __iomem *)ptr);
+                       i += 4;
+               }
+               buf++;
+               ptr++;
+       }
+       return i;
+}
+
+/* Setup pointers to different channels and also setup buffer sizes. */
+static void setup_memory(struct nozomi *dc)
+{
+       void __iomem *offset = dc->base_addr + dc->config_table.dl_start;
+       /* The length reported is including the length field of 4 bytes,
+        * hence subtract with 4.
+        */
+       const u16 buff_offset = 4;
+
+       /* Modem port dl configuration */
+       dc->port[PORT_MDM].dl_addr[CH_A] = offset;
+       dc->port[PORT_MDM].dl_addr[CH_B] =
+                               (offset += dc->config_table.dl_mdm_len1);
+       dc->port[PORT_MDM].dl_size[CH_A] =
+                               dc->config_table.dl_mdm_len1 - buff_offset;
+       dc->port[PORT_MDM].dl_size[CH_B] =
+                               dc->config_table.dl_mdm_len2 - buff_offset;
+
+       /* Diag port dl configuration */
+       dc->port[PORT_DIAG].dl_addr[CH_A] =
+                               (offset += dc->config_table.dl_mdm_len2);
+       dc->port[PORT_DIAG].dl_size[CH_A] =
+                               dc->config_table.dl_diag_len1 - buff_offset;
+       dc->port[PORT_DIAG].dl_addr[CH_B] =
+                               (offset += dc->config_table.dl_diag_len1);
+       dc->port[PORT_DIAG].dl_size[CH_B] =
+                               dc->config_table.dl_diag_len2 - buff_offset;
+
+       /* App1 port dl configuration */
+       dc->port[PORT_APP1].dl_addr[CH_A] =
+                               (offset += dc->config_table.dl_diag_len2);
+       dc->port[PORT_APP1].dl_size[CH_A] =
+                               dc->config_table.dl_app1_len - buff_offset;
+
+       /* App2 port dl configuration */
+       dc->port[PORT_APP2].dl_addr[CH_A] =
+                               (offset += dc->config_table.dl_app1_len);
+       dc->port[PORT_APP2].dl_size[CH_A] =
+                               dc->config_table.dl_app2_len - buff_offset;
+
+       /* Ctrl dl configuration */
+       dc->port[PORT_CTRL].dl_addr[CH_A] =
+                               (offset += dc->config_table.dl_app2_len);
+       dc->port[PORT_CTRL].dl_size[CH_A] =
+                               dc->config_table.dl_ctrl_len - buff_offset;
+
+       offset = dc->base_addr + dc->config_table.ul_start;
+
+       /* Modem Port ul configuration */
+       dc->port[PORT_MDM].ul_addr[CH_A] = offset;
+       dc->port[PORT_MDM].ul_size[CH_A] =
+                               dc->config_table.ul_mdm_len1 - buff_offset;
+       dc->port[PORT_MDM].ul_addr[CH_B] =
+                               (offset += dc->config_table.ul_mdm_len1);
+       dc->port[PORT_MDM].ul_size[CH_B] =
+                               dc->config_table.ul_mdm_len2 - buff_offset;
+
+       /* Diag port ul configuration */
+       dc->port[PORT_DIAG].ul_addr[CH_A] =
+                               (offset += dc->config_table.ul_mdm_len2);
+       dc->port[PORT_DIAG].ul_size[CH_A] =
+                               dc->config_table.ul_diag_len - buff_offset;
+
+       /* App1 port ul configuration */
+       dc->port[PORT_APP1].ul_addr[CH_A] =
+                               (offset += dc->config_table.ul_diag_len);
+       dc->port[PORT_APP1].ul_size[CH_A] =
+                               dc->config_table.ul_app1_len - buff_offset;
+
+       /* App2 port ul configuration */
+       dc->port[PORT_APP2].ul_addr[CH_A] =
+                               (offset += dc->config_table.ul_app1_len);
+       dc->port[PORT_APP2].ul_size[CH_A] =
+                               dc->config_table.ul_app2_len - buff_offset;
+
+       /* Ctrl ul configuration */
+       dc->port[PORT_CTRL].ul_addr[CH_A] =
+                               (offset += dc->config_table.ul_app2_len);
+       dc->port[PORT_CTRL].ul_size[CH_A] =
+                               dc->config_table.ul_ctrl_len - buff_offset;
+}
+
+/* Dump config table under initalization phase */
+#ifdef DEBUG
+static void dump_table(const struct nozomi *dc)
+{
+       DBG3("signature: 0x%08X", dc->config_table.signature);
+       DBG3("version: 0x%04X", dc->config_table.version);
+       DBG3("product_information: 0x%04X", \
+                               dc->config_table.product_information);
+       DBG3("toggle enabled: %d", dc->config_table.toggle.enabled);
+       DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul);
+       DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl);
+       DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl);
+
+       DBG3("dl_start: 0x%04X", dc->config_table.dl_start);
+       DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1,
+          dc->config_table.dl_mdm_len1);
+       DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2,
+          dc->config_table.dl_mdm_len2);
+       DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1,
+          dc->config_table.dl_diag_len1);
+       DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2,
+          dc->config_table.dl_diag_len2);
+       DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len,
+          dc->config_table.dl_app1_len);
+       DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len,
+          dc->config_table.dl_app2_len);
+       DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len,
+          dc->config_table.dl_ctrl_len);
+       DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start,
+          dc->config_table.ul_start);
+       DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1,
+          dc->config_table.ul_mdm_len1);
+       DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2,
+          dc->config_table.ul_mdm_len2);
+       DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len,
+          dc->config_table.ul_diag_len);
+       DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len,
+          dc->config_table.ul_app1_len);
+       DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len,
+          dc->config_table.ul_app2_len);
+       DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len,
+          dc->config_table.ul_ctrl_len);
+}
+#else
+static __inline__ void dump_table(const struct nozomi *dc) { }
+#endif
+
+/*
+ * Read configuration table from card under intalization phase
+ * Returns 1 if ok, else 0
+ */
+static int nozomi_read_config_table(struct nozomi *dc)
+{
+       read_mem32((u32 *) &dc->config_table, dc->base_addr + 0,
+                                               sizeof(struct config_table));
+
+       if (dc->config_table.signature != CONFIG_MAGIC) {
+               dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n",
+                       dc->config_table.signature, CONFIG_MAGIC);
+               return 0;
+       }
+
+       if ((dc->config_table.version == 0)
+           || (dc->config_table.toggle.enabled == TOGGLE_VALID)) {
+               int i;
+               DBG1("Second phase, configuring card");
+
+               setup_memory(dc);
+
+               dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul;
+               dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl;
+               dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl;
+               DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d",
+                  dc->port[PORT_MDM].toggle_ul,
+                  dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl);
+
+               dump_table(dc);
+
+               for (i = PORT_MDM; i < MAX_PORT; i++) {
+                       dc->port[i].fifo_ul =
+                           kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL);
+                       memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl));
+                       memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul));
+               }
+
+               /* Enable control channel */
+               dc->last_ier = dc->last_ier | CTRL_DL;
+               writew(dc->last_ier, dc->reg_ier);
+
+               dev_info(&dc->pdev->dev, "Initialization OK!\n");
+               return 1;
+       }
+
+       if ((dc->config_table.version > 0)
+           && (dc->config_table.toggle.enabled != TOGGLE_VALID)) {
+               u32 offset = 0;
+               DBG1("First phase: pushing upload buffers, clearing download");
+
+               dev_info(&dc->pdev->dev, "Version of card: %d\n",
+                        dc->config_table.version);
+
+               /* Here we should disable all I/O over F32. */
+               setup_memory(dc);
+
+               /*
+                * We should send ALL channel pair tokens back along
+                * with reset token
+                */
+
+               /* push upload modem buffers */
+               write_mem32(dc->port[PORT_MDM].ul_addr[CH_A],
+                       (u32 *) &offset, 4);
+               write_mem32(dc->port[PORT_MDM].ul_addr[CH_B],
+                       (u32 *) &offset, 4);
+
+               writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr);
+
+               DBG1("First phase done");
+       }
+
+       return 1;
+}
+
+/* Enable uplink interrupts  */
+static void enable_transmit_ul(enum port_type port, struct nozomi *dc)
+{
+       u16 mask[NOZOMI_MAX_PORTS] = \
+                       {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL};
+
+       if (port < NOZOMI_MAX_PORTS) {
+               dc->last_ier |= mask[port];
+               writew(dc->last_ier, dc->reg_ier);
+       } else {
+               dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+       }
+}
+
+/* Disable uplink interrupts  */
+static void disable_transmit_ul(enum port_type port, struct nozomi *dc)
+{
+       u16 mask[NOZOMI_MAX_PORTS] = \
+                       {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL};
+
+       if (port < NOZOMI_MAX_PORTS) {
+               dc->last_ier &= mask[port];
+               writew(dc->last_ier, dc->reg_ier);
+       } else {
+               dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+       }
+}
+
+/* Enable downlink interrupts */
+static void enable_transmit_dl(enum port_type port, struct nozomi *dc)
+{
+       u16 mask[NOZOMI_MAX_PORTS] = \
+                       {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL};
+
+       if (port < NOZOMI_MAX_PORTS) {
+               dc->last_ier |= mask[port];
+               writew(dc->last_ier, dc->reg_ier);
+       } else {
+               dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+       }
+}
+
+/* Disable downlink interrupts */
+static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
+{
+       u16 mask[NOZOMI_MAX_PORTS] = \
+                       {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL};
+
+       if (port < NOZOMI_MAX_PORTS) {
+               dc->last_ier &= mask[port];
+               writew(dc->last_ier, dc->reg_ier);
+       } else {
+               dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+       }
+}
+
+/*
+ * Return 1 - send buffer to card and ack.
+ * Return 0 - don't ack, don't send buffer to card.
+ */
+static int send_data(enum port_type index, struct nozomi *dc)
+{
+       u32 size = 0;
+       struct port *port = &dc->port[index];
+       u8 toggle = port->toggle_ul;
+       void __iomem *addr = port->ul_addr[toggle];
+       u32 ul_size = port->ul_size[toggle];
+       struct tty_struct *tty = port->tty;
+
+       /* Get data from tty and place in buf for now */
+       size = __kfifo_get(port->fifo_ul, dc->send_buf,
+                          ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX);
+
+       if (size == 0) {
+               DBG4("No more data to send, disable link:");
+               return 0;
+       }
+
+       /* DUMP(buf, size); */
+
+       /* Write length + data */
+       write_mem32(addr, (u32 *) &size, 4);
+       write_mem32(addr + 4, (u32 *) dc->send_buf, size);
+
+       if (tty)
+               tty_wakeup(tty);
+
+       return 1;
+}
+
+/* If all data has been read, return 1, else 0 */
+static int receive_data(enum port_type index, struct nozomi *dc)
+{
+       u8 buf[RECEIVE_BUF_MAX] = { 0 };
+       int size;
+       u32 offset = 4;
+       struct port *port = &dc->port[index];
+       void __iomem *addr = port->dl_addr[port->toggle_dl];
+       struct tty_struct *tty = port->tty;
+       int i;
+
+       if (unlikely(!tty)) {
+               DBG1("tty not open for port: %d?", index);
+               return 1;
+       }
+
+       read_mem32((u32 *) &size, addr, 4);
+       /*  DBG1( "%d bytes port: %d", size, index); */
+
+       if (test_bit(TTY_THROTTLED, &tty->flags)) {
+               DBG1("No room in tty, don't read data, don't ack interrupt, "
+                       "disable interrupt");
+
+               /* disable interrupt in downlink... */
+               disable_transmit_dl(index, dc);
+               return 0;
+       }
+
+       if (unlikely(size == 0)) {
+               dev_err(&dc->pdev->dev, "size == 0?\n");
+               return 1;
+       }
+
+       tty_buffer_request_room(tty, size);
+
+       while (size > 0) {
+               read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX);
+
+               if (size == 1) {
+                       tty_insert_flip_char(tty, buf[0], TTY_NORMAL);
+                       size = 0;
+               } else if (size < RECEIVE_BUF_MAX) {
+                       size -= tty_insert_flip_string(tty, (char *) buf, size);
+               } else {
+                       i = tty_insert_flip_string(tty, \
+                                               (char *) buf, RECEIVE_BUF_MAX);
+                       size -= i;
+                       offset += i;
+               }
+       }
+
+       set_bit(index, &dc->flip);
+
+       return 1;
+}
+
+/* Debug for interrupts */
+#ifdef DEBUG
+static char *interrupt2str(u16 interrupt)
+{
+       static char buf[TMP_BUF_MAX];
+       char *p = buf;
+
+       interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL;
+       interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "MDM_DL2 ") : NULL;
+
+       interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "MDM_UL1 ") : NULL;
+       interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "MDM_UL2 ") : NULL;
+
+       interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "DIAG_DL1 ") : NULL;
+       interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "DIAG_DL2 ") : NULL;
+
+       interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "DIAG_UL ") : NULL;
+
+       interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "APP1_DL ") : NULL;
+       interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "APP2_DL ") : NULL;
+
+       interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "APP1_UL ") : NULL;
+       interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "APP2_UL ") : NULL;
+
+       interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "CTRL_DL ") : NULL;
+       interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "CTRL_UL ") : NULL;
+
+       interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+                                       "RESET ") : NULL;
+
+       return buf;
+}
+#endif
+
+/*
+ * Receive flow control
+ * Return 1 - If ok, else 0
+ */
+static int receive_flow_control(struct nozomi *dc)
+{
+       enum port_type port = PORT_MDM;
+       struct ctrl_dl ctrl_dl;
+       struct ctrl_dl old_ctrl;
+       u16 enable_ier = 0;
+
+       read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2);
+
+       switch (ctrl_dl.port) {
+       case CTRL_CMD:
+               DBG1("The Base Band sends this value as a response to a "
+                       "request for IMSI detach sent over the control "
+                       "channel uplink (see section 7.6.1).");
+               break;
+       case CTRL_MDM:
+               port = PORT_MDM;
+               enable_ier = MDM_DL;
+               break;
+       case CTRL_DIAG:
+               port = PORT_DIAG;
+               enable_ier = DIAG_DL;
+               break;
+       case CTRL_APP1:
+               port = PORT_APP1;
+               enable_ier = APP1_DL;
+               break;
+       case CTRL_APP2:
+               port = PORT_APP2;
+               enable_ier = APP2_DL;
+               break;
+       default:
+               dev_err(&dc->pdev->dev,
+                       "ERROR: flow control received for non-existing port\n");
+               return 0;
+       };
+
+       DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl),
+          *((u16 *)&ctrl_dl));
+
+       old_ctrl = dc->port[port].ctrl_dl;
+       dc->port[port].ctrl_dl = ctrl_dl;
+
+       if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) {
+               DBG1("Disable interrupt (0x%04X) on port: %d",
+                       enable_ier, port);
+               disable_transmit_ul(port, dc);
+
+       } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) {
+
+               if (__kfifo_len(dc->port[port].fifo_ul)) {
+                       DBG1("Enable interrupt (0x%04X) on port: %d",
+                               enable_ier, port);
+                       DBG1("Data in buffer [%d], enable transmit! ",
+                               __kfifo_len(dc->port[port].fifo_ul));
+                       enable_transmit_ul(port, dc);
+               } else {
+                       DBG1("No data in buffer...");
+               }
+       }
+
+       if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) {
+               DBG1(" No change in mctrl");
+               return 1;
+       }
+       /* Update statistics */
+       if (old_ctrl.CTS != ctrl_dl.CTS)
+               dc->port[port].tty_icount.cts++;
+       if (old_ctrl.DSR != ctrl_dl.DSR)
+               dc->port[port].tty_icount.dsr++;
+       if (old_ctrl.RI != ctrl_dl.RI)
+               dc->port[port].tty_icount.rng++;
+       if (old_ctrl.DCD != ctrl_dl.DCD)
+               dc->port[port].tty_icount.dcd++;
+
+       wake_up_interruptible(&dc->port[port].tty_wait);
+
+       DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)",
+          port,
+          dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts,
+          dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr);
+
+       return 1;
+}
+
+static enum ctrl_port_type port2ctrl(enum port_type port,
+                                       const struct nozomi *dc)
+{
+       switch (port) {
+       case PORT_MDM:
+               return CTRL_MDM;
+       case PORT_DIAG:
+               return CTRL_DIAG;
+       case PORT_APP1:
+               return CTRL_APP1;
+       case PORT_APP2:
+               return CTRL_APP2;
+       default:
+               dev_err(&dc->pdev->dev,
+                       "ERROR: send flow control " \
+                       "received for non-existing port\n");
+       };
+       return CTRL_ERROR;
+}
+
+/*
+ * Send flow control, can only update one channel at a time
+ * Return 0 - If we have updated all flow control
+ * Return 1 - If we need to update more flow control, ack current enable more
+ */
+static int send_flow_control(struct nozomi *dc)
+{
+       u32 i, more_flow_control_to_be_updated = 0;
+       u16 *ctrl;
+
+       for (i = PORT_MDM; i < MAX_PORT; i++) {
+               if (dc->port[i].update_flow_control) {
+                       if (more_flow_control_to_be_updated) {
+                               /* We have more flow control to be updated */
+                               return 1;
+                       }
+                       dc->port[i].ctrl_ul.port = port2ctrl(i, dc);
+                       ctrl = (u16 *)&dc->port[i].ctrl_ul;
+                       write_mem32(dc->port[PORT_CTRL].ul_addr[0], \
+                               (u32 *) ctrl, 2);
+                       dc->port[i].update_flow_control = 0;
+                       more_flow_control_to_be_updated = 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Handle donlink data, ports that are handled are modem and diagnostics
+ * Return 1 - ok
+ * Return 0 - toggle fields are out of sync
+ */
+static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle,
+                       u16 read_iir, u16 mask1, u16 mask2)
+{
+       if (*toggle == 0 && read_iir & mask1) {
+               if (receive_data(port, dc)) {
+                       writew(mask1, dc->reg_fcr);
+                       *toggle = !(*toggle);
+               }
+
+               if (read_iir & mask2) {
+                       if (receive_data(port, dc)) {
+                               writew(mask2, dc->reg_fcr);
+                               *toggle = !(*toggle);
+                       }
+               }
+       } else if (*toggle == 1 && read_iir & mask2) {
+               if (receive_data(port, dc)) {
+                       writew(mask2, dc->reg_fcr);
+                       *toggle = !(*toggle);
+               }
+
+               if (read_iir & mask1) {
+                       if (receive_data(port, dc)) {
+                               writew(mask1, dc->reg_fcr);
+                               *toggle = !(*toggle);
+                       }
+               }
+       } else {
+               dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n",
+                       *toggle);
+               return 0;
+       }
+       return 1;
+}
+
+/*
+ * Handle uplink data, this is currently for the modem port
+ * Return 1 - ok
+ * Return 0 - toggle field are out of sync
+ */
+static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir)
+{
+       u8 *toggle = &(dc->port[port].toggle_ul);
+
+       if (*toggle == 0 && read_iir & MDM_UL1) {
+               dc->last_ier &= ~MDM_UL;
+               writew(dc->last_ier, dc->reg_ier);
+               if (send_data(port, dc)) {
+                       writew(MDM_UL1, dc->reg_fcr);
+                       dc->last_ier = dc->last_ier | MDM_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+                       *toggle = !*toggle;
+               }
+
+               if (read_iir & MDM_UL2) {
+                       dc->last_ier &= ~MDM_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+                       if (send_data(port, dc)) {
+                               writew(MDM_UL2, dc->reg_fcr);
+                               dc->last_ier = dc->last_ier | MDM_UL;
+                               writew(dc->last_ier, dc->reg_ier);
+                               *toggle = !*toggle;
+                       }
+               }
+
+       } else if (*toggle == 1 && read_iir & MDM_UL2) {
+               dc->last_ier &= ~MDM_UL;
+               writew(dc->last_ier, dc->reg_ier);
+               if (send_data(port, dc)) {
+                       writew(MDM_UL2, dc->reg_fcr);
+                       dc->last_ier = dc->last_ier | MDM_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+                       *toggle = !*toggle;
+               }
+
+               if (read_iir & MDM_UL1) {
+                       dc->last_ier &= ~MDM_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+                       if (send_data(port, dc)) {
+                               writew(MDM_UL1, dc->reg_fcr);
+                               dc->last_ier = dc->last_ier | MDM_UL;
+                               writew(dc->last_ier, dc->reg_ier);
+                               *toggle = !*toggle;
+                       }
+               }
+       } else {
+               writew(read_iir & MDM_UL, dc->reg_fcr);
+               dev_err(&dc->pdev->dev, "port out of sync!\n");
+               return 0;
+       }
+       return 1;
+}
+
+static irqreturn_t interrupt_handler(int irq, void *dev_id)
+{
+       struct nozomi *dc = dev_id;
+       unsigned int a;
+       u16 read_iir;
+
+       if (!dc)
+               return IRQ_NONE;
+
+       spin_lock(&dc->spin_mutex);
+       read_iir = readw(dc->reg_iir);
+
+       /* Card removed */
+       if (read_iir == (u16)-1)
+               goto none;
+       /*
+        * Just handle interrupt enabled in IER
+        * (by masking with dc->last_ier)
+        */
+       read_iir &= dc->last_ier;
+
+       if (read_iir == 0)
+               goto none;
+
+
+       DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir,
+               dc->last_ier);
+
+       if (read_iir & RESET) {
+               if (unlikely(!nozomi_read_config_table(dc))) {
+                       dc->last_ier = 0x0;
+                       writew(dc->last_ier, dc->reg_ier);
+                       dev_err(&dc->pdev->dev, "Could not read status from "
+                               "card, we should disable interface\n");
+               } else {
+                       writew(RESET, dc->reg_fcr);
+               }
+               /* No more useful info if this was the reset interrupt. */
+               goto exit_handler;
+       }
+       if (read_iir & CTRL_UL) {
+               DBG1("CTRL_UL");
+               dc->last_ier &= ~CTRL_UL;
+               writew(dc->last_ier, dc->reg_ier);
+               if (send_flow_control(dc)) {
+                       writew(CTRL_UL, dc->reg_fcr);
+                       dc->last_ier = dc->last_ier | CTRL_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+               }
+       }
+       if (read_iir & CTRL_DL) {
+               receive_flow_control(dc);
+               writew(CTRL_DL, dc->reg_fcr);
+       }
+       if (read_iir & MDM_DL) {
+               if (!handle_data_dl(dc, PORT_MDM,
+                               &(dc->port[PORT_MDM].toggle_dl), read_iir,
+                               MDM_DL1, MDM_DL2)) {
+                       dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n");
+                       goto exit_handler;
+               }
+       }
+       if (read_iir & MDM_UL) {
+               if (!handle_data_ul(dc, PORT_MDM, read_iir)) {
+                       dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n");
+                       goto exit_handler;
+               }
+       }
+       if (read_iir & DIAG_DL) {
+               if (!handle_data_dl(dc, PORT_DIAG,
+                               &(dc->port[PORT_DIAG].toggle_dl), read_iir,
+                               DIAG_DL1, DIAG_DL2)) {
+                       dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n");
+                       goto exit_handler;
+               }
+       }
+       if (read_iir & DIAG_UL) {
+               dc->last_ier &= ~DIAG_UL;
+               writew(dc->last_ier, dc->reg_ier);
+               if (send_data(PORT_DIAG, dc)) {
+                       writew(DIAG_UL, dc->reg_fcr);
+                       dc->last_ier = dc->last_ier | DIAG_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+               }
+       }
+       if (read_iir & APP1_DL) {
+               if (receive_data(PORT_APP1, dc))
+                       writew(APP1_DL, dc->reg_fcr);
+       }
+       if (read_iir & APP1_UL) {
+               dc->last_ier &= ~APP1_UL;
+               writew(dc->last_ier, dc->reg_ier);
+               if (send_data(PORT_APP1, dc)) {
+                       writew(APP1_UL, dc->reg_fcr);
+                       dc->last_ier = dc->last_ier | APP1_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+               }
+       }
+       if (read_iir & APP2_DL) {
+               if (receive_data(PORT_APP2, dc))
+                       writew(APP2_DL, dc->reg_fcr);
+       }
+       if (read_iir & APP2_UL) {
+               dc->last_ier &= ~APP2_UL;
+               writew(dc->last_ier, dc->reg_ier);
+               if (send_data(PORT_APP2, dc)) {
+                       writew(APP2_UL, dc->reg_fcr);
+                       dc->last_ier = dc->last_ier | APP2_UL;
+                       writew(dc->last_ier, dc->reg_ier);
+               }
+       }
+
+exit_handler:
+       spin_unlock(&dc->spin_mutex);
+       for (a = 0; a < NOZOMI_MAX_PORTS; a++)
+               if (test_and_clear_bit(a, &dc->flip))
+                       tty_flip_buffer_push(dc->port[a].tty);
+       return IRQ_HANDLED;
+none:
+       spin_unlock(&dc->spin_mutex);
+       return IRQ_NONE;
+}
+
+static void nozomi_get_card_type(struct nozomi *dc)
+{
+       int i;
+       u32 size = 0;
+
+       for (i = 0; i < 6; i++)
+               size += pci_resource_len(dc->pdev, i);
+
+       /* Assume card type F32_8 if no match */
+       dc->card_type = size == 2048 ? F32_2 : F32_8;
+
+       dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type);
+}
+
+static void nozomi_setup_private_data(struct nozomi *dc)
+{
+       void __iomem *offset = dc->base_addr + dc->card_type / 2;
+       unsigned int i;
+
+       dc->reg_fcr = (void __iomem *)(offset + R_FCR);
+       dc->reg_iir = (void __iomem *)(offset + R_IIR);
+       dc->reg_ier = (void __iomem *)(offset + R_IER);
+       dc->last_ier = 0;
+       dc->flip = 0;
+
+       dc->port[PORT_MDM].token_dl = MDM_DL;
+       dc->port[PORT_DIAG].token_dl = DIAG_DL;
+       dc->port[PORT_APP1].token_dl = APP1_DL;
+       dc->port[PORT_APP2].token_dl = APP2_DL;
+
+       for (i = 0; i < MAX_PORT; i++)
+               init_waitqueue_head(&dc->port[i].tty_wait);
+}
+
+static ssize_t card_type_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+
+       return sprintf(buf, "%d\n", dc->card_type);
+}
+static DEVICE_ATTR(card_type, 0444, card_type_show, NULL);
+
+static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+
+       return sprintf(buf, "%u\n", dc->open_ttys);
+}
+static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL);
+
+static void make_sysfs_files(struct nozomi *dc)
+{
+       if (device_create_file(&dc->pdev->dev, &dev_attr_card_type))
+               dev_err(&dc->pdev->dev,
+                       "Could not create sysfs file for card_type\n");
+       if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys))
+               dev_err(&dc->pdev->dev,
+                       "Could not create sysfs file for open_ttys\n");
+}
+
+static void remove_sysfs_files(struct nozomi *dc)
+{
+       device_remove_file(&dc->pdev->dev, &dev_attr_card_type);
+       device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys);
+}
+
+/* Allocate memory for one device */
+static int __devinit nozomi_card_init(struct pci_dev *pdev,
+                                     const struct pci_device_id *ent)
+{
+       resource_size_t start;
+       int ret;
+       struct nozomi *dc = NULL;
+       int ndev_idx;
+       int i;
+
+       dev_dbg(&pdev->dev, "Init, new card found\n");
+
+       for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++)
+               if (!ndevs[ndev_idx])
+                       break;
+
+       if (ndev_idx >= ARRAY_SIZE(ndevs)) {
+               dev_err(&pdev->dev, "no free tty range for this card left\n");
+               ret = -EIO;
+               goto err;
+       }
+
+       dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL);
+       if (unlikely(!dc)) {
+               dev_err(&pdev->dev, "Could not allocate memory\n");
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
+       dc->pdev = pdev;
+
+       /* Find out what card type it is */
+       nozomi_get_card_type(dc);
+
+       ret = pci_enable_device(dc->pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to enable PCI Device\n");
+               goto err_free;
+       }
+
+       start = pci_resource_start(dc->pdev, 0);
+       if (start == 0) {
+               dev_err(&pdev->dev, "No I/O address for card detected\n");
+               ret = -ENODEV;
+               goto err_disable_device;
+       }
+
+       ret = pci_request_regions(dc->pdev, NOZOMI_NAME);
+       if (ret) {
+               dev_err(&pdev->dev, "I/O address 0x%04x already in use\n",
+                       (int) /* nozomi_private.io_addr */ 0);
+               goto err_disable_device;
+       }
+
+       dc->base_addr = ioremap(start, dc->card_type);
+       if (!dc->base_addr) {
+               dev_err(&pdev->dev, "Unable to map card MMIO\n");
+               ret = -ENODEV;
+               goto err_rel_regs;
+       }
+
+       dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL);
+       if (!dc->send_buf) {
+               dev_err(&pdev->dev, "Could not allocate send buffer?\n");
+               ret = -ENOMEM;
+               goto err_free_sbuf;
+       }
+
+       spin_lock_init(&dc->spin_mutex);
+
+       nozomi_setup_private_data(dc);
+
+       /* Disable all interrupts */
+       dc->last_ier = 0;
+       writew(dc->last_ier, dc->reg_ier);
+
+       ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED,
+                       NOZOMI_NAME, dc);
+       if (unlikely(ret)) {
+               dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
+               goto err_free_sbuf;
+       }
+
+       DBG1("base_addr: %p", dc->base_addr);
+
+       make_sysfs_files(dc);
+
+       dc->index_start = ndev_idx * MAX_PORT;
+       ndevs[ndev_idx] = dc;
+
+       for (i = 0; i < MAX_PORT; i++) {
+               mutex_init(&dc->port[i].tty_sem);
+               dc->port[i].tty_open_count = 0;
+               dc->port[i].tty = NULL;
+               tty_register_device(ntty_driver, dc->index_start + i,
+                                                       &pdev->dev);
+       }
+
+       /* Enable  RESET interrupt. */
+       dc->last_ier = RESET;
+       writew(dc->last_ier, dc->reg_ier);
+
+       pci_set_drvdata(pdev, dc);
+
+       return 0;
+
+err_free_sbuf:
+       kfree(dc->send_buf);
+       iounmap(dc->base_addr);
+err_rel_regs:
+       pci_release_regions(pdev);
+err_disable_device:
+       pci_disable_device(pdev);
+err_free:
+       kfree(dc);
+err:
+       return ret;
+}
+
+static void __devexit tty_exit(struct nozomi *dc)
+{
+       unsigned int i;
+
+       DBG1(" ");
+
+       flush_scheduled_work();
+
+       for (i = 0; i < MAX_PORT; ++i)
+               if (dc->port[i].tty && \
+                               list_empty(&dc->port[i].tty->hangup_work.entry))
+                       tty_hangup(dc->port[i].tty);
+
+       while (dc->open_ttys)
+               msleep(1);
+
+       for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
+               tty_unregister_device(ntty_driver, i);
+}
+
+/* Deallocate memory for one device */
+static void __devexit nozomi_card_exit(struct pci_dev *pdev)
+{
+       int i;
+       struct ctrl_ul ctrl;
+       struct nozomi *dc = pci_get_drvdata(pdev);
+
+       /* Disable all interrupts */
+       dc->last_ier = 0;
+       writew(dc->last_ier, dc->reg_ier);
+
+       tty_exit(dc);
+
+       /* Send 0x0001, command card to resend the reset token.  */
+       /* This is to get the reset when the module is reloaded. */
+       ctrl.port = 0x00;
+       ctrl.reserved = 0;
+       ctrl.RTS = 0;
+       ctrl.DTR = 1;
+       DBG1("sending flow control 0x%04X", *((u16 *)&ctrl));
+
+       /* Setup dc->reg addresses to we can use defines here */
+       write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2);
+       writew(CTRL_UL, dc->reg_fcr);   /* push the token to the card. */
+
+       remove_sysfs_files(dc);
+
+       free_irq(pdev->irq, dc);
+
+       for (i = 0; i < MAX_PORT; i++)
+               if (dc->port[i].fifo_ul)
+                       kfifo_free(dc->port[i].fifo_ul);
+
+       kfree(dc->send_buf);
+
+       iounmap(dc->base_addr);
+
+       pci_release_regions(pdev);
+
+       pci_disable_device(pdev);
+
+       ndevs[dc->index_start / MAX_PORT] = NULL;
+
+       kfree(dc);
+}
+
+static void set_rts(const struct tty_struct *tty, int rts)
+{
+       struct port *port = get_port_by_tty(tty);
+
+       port->ctrl_ul.RTS = rts;
+       port->update_flow_control = 1;
+       enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty));
+}
+
+static void set_dtr(const struct tty_struct *tty, int dtr)
+{
+       struct port *port = get_port_by_tty(tty);
+
+       DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr);
+
+       port->ctrl_ul.DTR = dtr;
+       port->update_flow_control = 1;
+       enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty));
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * TTY code
+ * ----------------------------------------------------------------------------
+ */
+
+/* Called when the userspace process opens the tty, /dev/noz*.  */
+static int ntty_open(struct tty_struct *tty, struct file *file)
+{
+       struct port *port = get_port_by_tty(tty);
+       struct nozomi *dc = get_dc_by_tty(tty);
+       unsigned long flags;
+
+       if (!port || !dc)
+               return -ENODEV;
+
+       if (mutex_lock_interruptible(&port->tty_sem))
+               return -ERESTARTSYS;
+
+       port->tty_open_count++;
+       dc->open_ttys++;
+
+       /* Enable interrupt downlink for channel */
+       if (port->tty_open_count == 1) {
+               tty->low_latency = 1;
+               tty->driver_data = port;
+               port->tty = tty;
+               DBG1("open: %d", port->token_dl);
+               spin_lock_irqsave(&dc->spin_mutex, flags);
+               dc->last_ier = dc->last_ier | port->token_dl;
+               writew(dc->last_ier, dc->reg_ier);
+               spin_unlock_irqrestore(&dc->spin_mutex, flags);
+       }
+
+       mutex_unlock(&port->tty_sem);
+
+       return 0;
+}
+
+/* Called when the userspace process close the tty, /dev/noz*. */
+static void ntty_close(struct tty_struct *tty, struct file *file)
+{
+       struct nozomi *dc = get_dc_by_tty(tty);
+       struct port *port = tty->driver_data;
+       unsigned long flags;
+
+       if (!dc || !port)
+               return;
+
+       if (mutex_lock_interruptible(&port->tty_sem))
+               return;
+
+       if (!port->tty_open_count)
+               goto exit;
+
+       dc->open_ttys--;
+       port->tty_open_count--;
+
+       if (port->tty_open_count == 0) {
+               DBG1("close: %d", port->token_dl);
+               spin_lock_irqsave(&dc->spin_mutex, flags);
+               dc->last_ier &= ~(port->token_dl);
+               writew(dc->last_ier, dc->reg_ier);
+               spin_unlock_irqrestore(&dc->spin_mutex, flags);
+       }
+
+exit:
+       mutex_unlock(&port->tty_sem);
+}
+
+/*
+ * called when the userspace process writes to the tty (/dev/noz*).
+ * Data is inserted into a fifo, which is then read and transfered to the modem.
+ */
+static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
+                     int count)
+{
+       int rval = -EINVAL;
+       struct nozomi *dc = get_dc_by_tty(tty);
+       struct port *port = tty->driver_data;
+       unsigned long flags;
+
+       /* DBG1( "WRITEx: %d, index = %d", count, index); */
+
+       if (!dc || !port)
+               return -ENODEV;
+
+       if (unlikely(!mutex_trylock(&port->tty_sem))) {
+               /*
+                * must test lock as tty layer wraps calls
+                * to this function with BKL
+                */
+               dev_err(&dc->pdev->dev, "Would have deadlocked - "
+                       "return EAGAIN\n");
+               return -EAGAIN;
+       }
+
+       if (unlikely(!port->tty_open_count)) {
+               DBG1(" ");
+               goto exit;
+       }
+
+       rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count);
+
+       /* notify card */
+       if (unlikely(dc == NULL)) {
+               DBG1("No device context?");
+               goto exit;
+       }
+
+       spin_lock_irqsave(&dc->spin_mutex, flags);
+       /* CTS is only valid on the modem channel */
+       if (port == &(dc->port[PORT_MDM])) {
+               if (port->ctrl_dl.CTS) {
+                       DBG4("Enable interrupt");
+                       enable_transmit_ul(tty->index % MAX_PORT, dc);
+               } else {
+                       dev_err(&dc->pdev->dev,
+                               "CTS not active on modem port?\n");
+               }
+       } else {
+               enable_transmit_ul(tty->index % MAX_PORT, dc);
+       }
+       spin_unlock_irqrestore(&dc->spin_mutex, flags);
+
+exit:
+       mutex_unlock(&port->tty_sem);
+       return rval;
+}
+
+/*
+ * Calculate how much is left in device
+ * This method is called by the upper tty layer.
+ *   #according to sources N_TTY.c it expects a value >= 0 and
+ *    does not check for negative values.
+ */
+static int ntty_write_room(struct tty_struct *tty)
+{
+       struct port *port = tty->driver_data;
+       int room = 0;
+       struct nozomi *dc = get_dc_by_tty(tty);
+
+       if (!dc || !port)
+               return 0;
+       if (!mutex_trylock(&port->tty_sem))
+               return 0;
+
+       if (!port->tty_open_count)
+               goto exit;
+
+       room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
+
+exit:
+       mutex_unlock(&port->tty_sem);
+       return room;
+}
+
+/* Gets io control parameters */
+static int ntty_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct port *port = tty->driver_data;
+       struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
+       struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+
+       return  (ctrl_ul->RTS ? TIOCM_RTS : 0) |
+               (ctrl_ul->DTR ? TIOCM_DTR : 0) |
+               (ctrl_dl->DCD ? TIOCM_CAR : 0) |
+               (ctrl_dl->RI  ? TIOCM_RNG : 0) |
+               (ctrl_dl->DSR ? TIOCM_DSR : 0) |
+               (ctrl_dl->CTS ? TIOCM_CTS : 0);
+}
+
+/* Sets io controls parameters */
+static int ntty_tiocmset(struct tty_struct *tty, struct file *file,
+       unsigned int set, unsigned int clear)
+{
+       if (set & TIOCM_RTS)
+               set_rts(tty, 1);
+       else if (clear & TIOCM_RTS)
+               set_rts(tty, 0);
+
+       if (set & TIOCM_DTR)
+               set_dtr(tty, 1);
+       else if (clear & TIOCM_DTR)
+               set_dtr(tty, 0);
+
+       return 0;
+}
+
+static int ntty_cflags_changed(struct port *port, unsigned long flags,
+               struct async_icount *cprev)
+{
+       struct async_icount cnow = port->tty_icount;
+       int ret;
+
+       ret =   ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+               ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+               ((flags & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
+               ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+       *cprev = cnow;
+
+       return ret;
+}
+
+static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
+{
+       struct async_icount cnow = port->tty_icount;
+       struct serial_icounter_struct icount;
+
+       icount.cts = cnow.cts;
+       icount.dsr = cnow.dsr;
+       icount.rng = cnow.rng;
+       icount.dcd = cnow.dcd;
+       icount.rx = cnow.rx;
+       icount.tx = cnow.tx;
+       icount.frame = cnow.frame;
+       icount.overrun = cnow.overrun;
+       icount.parity = cnow.parity;
+       icount.brk = cnow.brk;
+       icount.buf_overrun = cnow.buf_overrun;
+
+       return copy_to_user(argp, &icount, sizeof(icount));
+}
+
+static int ntty_ioctl(struct tty_struct *tty, struct file *file,
+                     unsigned int cmd, unsigned long arg)
+{
+       struct port *port = tty->driver_data;
+       void __user *argp = (void __user *)arg;
+       int rval = -ENOIOCTLCMD;
+
+       DBG1("******** IOCTL, cmd: %d", cmd);
+
+       switch (cmd) {
+       case TIOCMIWAIT: {
+               struct async_icount cprev = port->tty_icount;
+
+               rval = wait_event_interruptible(port->tty_wait,
+                               ntty_cflags_changed(port, arg, &cprev));
+               break;
+       } case TIOCGICOUNT:
+               rval = ntty_ioctl_tiocgicount(port, argp);
+               break;
+       default:
+               DBG1("ERR: 0x%08X, %d", cmd, cmd);
+               break;
+       };
+
+       return rval;
+}
+
+/*
+ * Called by the upper tty layer when tty buffers are ready
+ * to receive data again after a call to throttle.
+ */
+static void ntty_unthrottle(struct tty_struct *tty)
+{
+       struct nozomi *dc = get_dc_by_tty(tty);
+       unsigned long flags;
+
+       DBG1("UNTHROTTLE");
+       spin_lock_irqsave(&dc->spin_mutex, flags);
+       enable_transmit_dl(tty->index % MAX_PORT, dc);
+       set_rts(tty, 1);
+
+       spin_unlock_irqrestore(&dc->spin_mutex, flags);
+}
+
+/*
+ * Called by the upper tty layer when the tty buffers are almost full.
+ * The driver should stop send more data.
+ */
+static void ntty_throttle(struct tty_struct *tty)
+{
+       struct nozomi *dc = get_dc_by_tty(tty);
+       unsigned long flags;
+
+       DBG1("THROTTLE");
+       spin_lock_irqsave(&dc->spin_mutex, flags);
+       set_rts(tty, 0);
+       spin_unlock_irqrestore(&dc->spin_mutex, flags);
+}
+
+/* just to discard single character writes */
+static void ntty_put_char(struct tty_struct *tty, unsigned char c)
+{
+       /* FIXME !!! */
+       DBG2("PUT CHAR Function: %c", c);
+}
+
+/* Returns number of chars in buffer, called by tty layer */
+static s32 ntty_chars_in_buffer(struct tty_struct *tty)
+{
+       struct port *port = tty->driver_data;
+       struct nozomi *dc = get_dc_by_tty(tty);
+       s32 rval;
+
+       if (unlikely(!dc || !port)) {
+               rval = -ENODEV;
+               goto exit_in_buffer;
+       }
+
+       if (unlikely(!port->tty_open_count)) {
+               dev_err(&dc->pdev->dev, "No tty open?\n");
+               rval = -ENODEV;
+               goto exit_in_buffer;
+       }
+
+       rval = __kfifo_len(port->fifo_ul);
+
+exit_in_buffer:
+       return rval;
+}
+
+static struct tty_operations tty_ops = {
+       .ioctl = ntty_ioctl,
+       .open = ntty_open,
+       .close = ntty_close,
+       .write = ntty_write,
+       .write_room = ntty_write_room,
+       .unthrottle = ntty_unthrottle,
+       .throttle = ntty_throttle,
+       .chars_in_buffer = ntty_chars_in_buffer,
+       .put_char = ntty_put_char,
+       .tiocmget = ntty_tiocmget,
+       .tiocmset = ntty_tiocmset,
+};
+
+/* Module initialization */
+static struct pci_driver nozomi_driver = {
+       .name = NOZOMI_NAME,
+       .id_table = nozomi_pci_tbl,
+       .probe = nozomi_card_init,
+       .remove = __devexit_p(nozomi_card_exit),
+};
+
+static __init int nozomi_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Initializing %s\n", VERSION_STRING);
+
+       ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS);
+       if (!ntty_driver)
+               return -ENOMEM;
+
+       ntty_driver->owner = THIS_MODULE;
+       ntty_driver->driver_name = NOZOMI_NAME_TTY;
+       ntty_driver->name = "noz";
+       ntty_driver->major = 0;
+       ntty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       ntty_driver->subtype = SERIAL_TYPE_NORMAL;
+       ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       ntty_driver->init_termios = tty_std_termios;
+       ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \
+                                               HUPCL | CLOCAL;
+       ntty_driver->init_termios.c_ispeed = 115200;
+       ntty_driver->init_termios.c_ospeed = 115200;
+       tty_set_operations(ntty_driver, &tty_ops);
+
+       ret = tty_register_driver(ntty_driver);
+       if (ret) {
+               printk(KERN_ERR "Nozomi: failed to register ntty driver\n");
+               goto free_tty;
+       }
+
+       ret = pci_register_driver(&nozomi_driver);
+       if (ret) {
+               printk(KERN_ERR "Nozomi: can't register pci driver\n");
+               goto unr_tty;
+       }
+
+       return 0;
+unr_tty:
+       tty_unregister_driver(ntty_driver);
+free_tty:
+       put_tty_driver(ntty_driver);
+       return ret;
+}
+
+static __exit void nozomi_exit(void)
+{
+       printk(KERN_INFO "Unloading %s\n", DRIVER_DESC);
+       pci_unregister_driver(&nozomi_driver);
+       tty_unregister_driver(ntty_driver);
+       put_tty_driver(ntty_driver);
+}
+
+module_init(nozomi_init);
+module_exit(nozomi_exit);
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
index 39564b76d4a36670e501f5f8e24fa1632f625982..c88424a0c89b60d28d3805895e6ee973710b7d8c 100644 (file)
@@ -1046,12 +1046,6 @@ void tpm_remove_hardware(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tpm_remove_hardware);
 
-static u8 savestate[] = {
-       0, 193,                 /* TPM_TAG_RQU_COMMAND */
-       0, 0, 0, 10,            /* blob length (in bytes) */
-       0, 0, 0, 152            /* TPM_ORD_SaveState */
-};
-
 /*
  * We are about to suspend. Save the TPM state
  * so that it can be restored.
@@ -1059,6 +1053,12 @@ static u8 savestate[] = {
 int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
+       u8 savestate[] = {
+               0, 193,         /* TPM_TAG_RQU_COMMAND */
+               0, 0, 0, 10,    /* blob length (in bytes) */
+               0, 0, 0, 152    /* TPM_ORD_SaveState */
+       };
+
        if (chip == NULL)
                return -ENODEV;
 
index e02d59245a17ecf6b1d78ffd66f5d68c8ead261d..d4b6d64e858b5e4ec18255a992ce0e57a0cbd92b 100644 (file)
@@ -364,6 +364,25 @@ void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
 
 EXPORT_SYMBOL(tty_termios_copy_hw);
 
+/**
+ *     tty_termios_hw_change   -       check for setting change
+ *     @a: termios
+ *     @b: termios to compare
+ *
+ *     Check if any of the bits that affect a dumb device have changed
+ *     between the two termios structures, or a speed change is needed.
+ */
+
+int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
+{
+       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
+               return 1;
+       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(tty_termios_hw_change);
+
 /**
  *     change_termios          -       update termios values
  *     @tty: tty to update
index 296f51002b555a4398d0450f92d1c1392d61d70a..12ceed54ab18001f89b2e587106fa8fa7b20de82 100644 (file)
@@ -99,8 +99,8 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id
        spin_unlock_bh(&dev->queue_lock);
 
        if (found) {
-               atomic_dec(&dev->refcnt);
                cn_queue_free_callback(cbq);
+               atomic_dec(&dev->refcnt);
                return -EINVAL;
        }
 
index 6883fcb79ad35d27cd3eb5d65d2f6eaab82ded4c..bf9716b75513d957a79e8836d8a127295d86f4d4 100644 (file)
@@ -145,6 +145,8 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
                                if (queue_work(dev->cbdev->cn_queue,
                                                        &__cbq->work))
                                        err = 0;
+                               else
+                                       err = -EINVAL;
                        } else {
                                struct cn_callback_data *d;
                                
index 79581fab82d69464a77cf6c51363cec85fede91f..5efd5550f4ca7a4afcf1a606d29e293eea5b4c9e 100644 (file)
@@ -828,11 +828,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
 
        /* prepare interface data */
-       policy->kobj.parent = &sys_dev->kobj;
-       policy->kobj.ktype = &ktype_cpufreq;
-       kobject_set_name(&policy->kobj, "cpufreq");
-
-       ret = kobject_register(&policy->kobj);
+       ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
+                                  "cpufreq");
        if (ret) {
                unlock_policy_rwsem_write(cpu);
                goto err_out_driver_exit;
@@ -902,6 +899,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
                goto err_out_unregister;
        }
 
+       kobject_uevent(&policy->kobj, KOBJ_ADD);
        module_put(cpufreq_driver->owner);
        dprintk("initialization complete\n");
        cpufreq_debug_enable_ratelimit();
@@ -915,7 +913,7 @@ err_out_unregister:
                cpufreq_cpu_data[j] = NULL;
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       kobject_unregister(&policy->kobj);
+       kobject_put(&policy->kobj);
        wait_for_completion(&policy->kobj_unregister);
 
 err_out_driver_exit:
@@ -1032,8 +1030,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
 
        unlock_policy_rwsem_write(cpu);
 
-       kobject_unregister(&data->kobj);
-
        kobject_put(&data->kobj);
 
        /* we need to make sure that the underlying kobj is actually
index 1bba99747f5b3da806fea25aa991d3ac151673be..5d3a04ba6ad2c38aaf18d443b508511206bfac0c 100644 (file)
@@ -603,5 +603,9 @@ MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for "
                "optimised for use in a battery environment");
 MODULE_LICENSE ("GPL");
 
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+fs_initcall(cpufreq_gov_dbs_init);
+#else
 module_init(cpufreq_gov_dbs_init);
+#endif
 module_exit(cpufreq_gov_dbs_exit);
index 369f44595150f7e568fff7802d8047ca645f0ffd..d2af20dda3827919d218d9dc592aeb8ca0fd8f03 100644 (file)
@@ -610,6 +610,9 @@ MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
                    "Low Latency Frequency Transition capable processors");
 MODULE_LICENSE("GPL");
 
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+fs_initcall(cpufreq_gov_dbs_init);
+#else
 module_init(cpufreq_gov_dbs_init);
+#endif
 module_exit(cpufreq_gov_dbs_exit);
-
index 51bedab6c808da57dd2b26e896021613d2540655..f8cdde4bf6cd86030a8f829d00fdac862d5847f2 100644 (file)
@@ -231,5 +231,9 @@ MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>, Russell King <rmk@arm.linux.
 MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'");
 MODULE_LICENSE ("GPL");
 
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
 fs_initcall(cpufreq_gov_userspace_init);
+#else
+module_init(cpufreq_gov_userspace_init);
+#endif
 module_exit(cpufreq_gov_userspace_exit);
index 0f3515e77d4b5e9a0632ecbb95369962697eae6a..088ea74edd3480d42d883e7e7705e3a1f17af7fa 100644 (file)
@@ -277,7 +277,7 @@ static struct kobj_type ktype_state_cpuidle = {
 
 static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
 {
-       kobject_unregister(&device->kobjs[i]->kobj);
+       kobject_put(&device->kobjs[i]->kobj);
        wait_for_completion(&device->kobjs[i]->kobj_unregister);
        kfree(device->kobjs[i]);
        device->kobjs[i] = NULL;
@@ -300,14 +300,13 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
                kobj->state = &device->states[i];
                init_completion(&kobj->kobj_unregister);
 
-               kobj->kobj.parent = &device->kobj;
-               kobj->kobj.ktype = &ktype_state_cpuidle;
-               kobject_set_name(&kobj->kobj, "state%d", i);
-               ret = kobject_register(&kobj->kobj);
+               ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
+                                          "state%d", i);
                if (ret) {
                        kfree(kobj);
                        goto error_state;
                }
+               kobject_uevent(&kobj->kobj, KOBJ_ADD);
                device->kobjs[i] = kobj;
        }
 
@@ -339,12 +338,14 @@ int cpuidle_add_sysfs(struct sys_device *sysdev)
 {
        int cpu = sysdev->id;
        struct cpuidle_device *dev;
+       int error;
 
        dev = per_cpu(cpuidle_devices, cpu);
-       dev->kobj.parent = &sysdev->kobj;
-       dev->kobj.ktype = &ktype_cpuidle;
-       kobject_set_name(&dev->kobj, "%s", "cpuidle");
-       return kobject_register(&dev->kobj);
+       error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj,
+                                    "cpuidle");
+       if (!error)
+               kobject_uevent(&dev->kobj, KOBJ_ADD);
+       return error;
 }
 
 /**
@@ -357,5 +358,5 @@ void cpuidle_remove_sysfs(struct sys_device *sysdev)
        struct cpuidle_device *dev;
 
        dev = per_cpu(cpuidle_devices, cpu);
-       kobject_unregister(&dev->kobj);
+       kobject_put(&dev->kobj);
 }
index ddd3a259cea1161061aaf3419e199e8507a7867c..6b658d84d521c4d8aed4e3a86fcd3efb0be057c5 100644 (file)
@@ -48,8 +48,6 @@ config CRYPTO_DEV_PADLOCK_SHA
          If unsure say M. The compiled module will be
          called padlock-sha.ko
 
-source "arch/s390/crypto/Kconfig"
-
 config CRYPTO_DEV_GEODE
        tristate "Support for the Geode LX AES engine"
        depends on X86_32 && PCI
@@ -83,4 +81,82 @@ config ZCRYPT_MONOLITHIC
          that contains all parts of the crypto device driver (ap bus,
          request router and all the card drivers).
 
+config CRYPTO_SHA1_S390
+       tristate "SHA1 digest algorithm"
+       depends on S390
+       select CRYPTO_ALGAPI
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+       tristate "SHA256 digest algorithm"
+       depends on S390
+       select CRYPTO_ALGAPI
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA256 secure hash standard (DFIPS 180-2).
+
+         This version of SHA implements a 256 bit hash with 128 bits of
+         security against collision attacks.
+
+config CRYPTO_DES_S390
+       tristate "DES and Triple DES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
+       help
+         This us the s390 hardware accelerated implementation of the
+         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+       tristate "AES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
+       help
+         This is the s390 hardware accelerated implementation of the
+         AES cipher algorithms (FIPS-197). AES uses the Rijndael
+         algorithm.
+
+         Rijndael appears to be consistently a very good performer in
+         both hardware and software across a wide range of computing
+         environments regardless of its use in feedback or non-feedback
+         modes. Its key setup time is excellent, and its key agility is
+         good. Rijndael's very low memory requirements make it very well
+         suited for restricted-space environments, in which it also
+         demonstrates excellent performance. Rijndael's operations are
+         among the easiest to defend against power and timing attacks.
+
+         On s390 the System z9-109 currently only supports the key size
+         of 128 bit.
+
+config S390_PRNG
+       tristate "Pseudo random number generator device driver"
+       depends on S390
+       default "m"
+       help
+         Select this option if you want to use the s390 pseudo random number
+         generator. The PRNG is part of the cryptographic processor functions
+         and uses triple-DES to generate secure random numbers like the
+         ANSI X9.17 standard. The PRNG is usable via the char device
+         /dev/prandom.
+
+config CRYPTO_DEV_HIFN_795X
+       tristate "Driver HIFN 795x crypto accelerator chips"
+       select CRYPTO_DES
+       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
+       select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG
+       depends on PCI
+       help
+         This option allows you to have support for HIFN 795x crypto adapters.
+
+config CRYPTO_DEV_HIFN_795X_RNG
+       bool "HIFN 795x random number generator"
+       depends on CRYPTO_DEV_HIFN_795X
+       help
+         Select this option if you want to enable the random number generator
+         on the HIFN 795x crypto adapters.
+
 endif # CRYPTO_HW
index d070030f7d7ec9ac83d20ec61126c8483dfd6a79..c0327f0dadc56e878df6679575dba3b10ff60f43 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
index 711e246e1ef021ee66fd297105482328580b0cd8..4801162919d9db389ac9acc9b19b8d56c94cf752 100644 (file)
 #include <linux/crypto.h>
 #include <linux/spinlock.h>
 #include <crypto/algapi.h>
+#include <crypto/aes.h>
 
 #include <asm/io.h>
 #include <asm/delay.h>
 
 #include "geode-aes.h"
 
-/* Register definitions */
-
-#define AES_CTRLA_REG  0x0000
-
-#define AES_CTRL_START     0x01
-#define AES_CTRL_DECRYPT   0x00
-#define AES_CTRL_ENCRYPT   0x02
-#define AES_CTRL_WRKEY     0x04
-#define AES_CTRL_DCA       0x08
-#define AES_CTRL_SCA       0x10
-#define AES_CTRL_CBC       0x20
-
-#define AES_INTR_REG  0x0008
-
-#define AES_INTRA_PENDING (1 << 16)
-#define AES_INTRB_PENDING (1 << 17)
-
-#define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
-#define AES_INTR_MASK     0x07
-
-#define AES_SOURCEA_REG   0x0010
-#define AES_DSTA_REG      0x0014
-#define AES_LENA_REG      0x0018
-#define AES_WRITEKEY0_REG 0x0030
-#define AES_WRITEIV0_REG  0x0040
-
-/*  A very large counter that is used to gracefully bail out of an
- *  operation in case of trouble
- */
-
-#define AES_OP_TIMEOUT    0x50000
-
 /* Static structures */
 
 static void __iomem * _iobase;
@@ -87,9 +56,10 @@ do_crypt(void *src, void *dst, int len, u32 flags)
        /* Start the operation */
        iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG);
 
-       do
+       do {
                status = ioread32(_iobase + AES_INTR_REG);
-       while(!(status & AES_INTRA_PENDING) && --counter);
+               cpu_relax();
+       } while(!(status & AES_INTRA_PENDING) && --counter);
 
        /* Clear the event */
        iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG);
@@ -101,6 +71,7 @@ geode_aes_crypt(struct geode_aes_op *op)
 {
        u32 flags = 0;
        unsigned long iflags;
+       int ret;
 
        if (op->len == 0)
                return 0;
@@ -129,7 +100,8 @@ geode_aes_crypt(struct geode_aes_op *op)
                _writefield(AES_WRITEKEY0_REG, op->key);
        }
 
-       do_crypt(op->src, op->dst, op->len, flags);
+       ret = do_crypt(op->src, op->dst, op->len, flags);
+       BUG_ON(ret);
 
        if (op->mode == AES_MODE_CBC)
                _readfield(AES_WRITEIV0_REG, op->iv);
@@ -141,18 +113,103 @@ geode_aes_crypt(struct geode_aes_op *op)
 
 /* CRYPTO-API Functions */
 
-static int
-geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len)
+static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
+               unsigned int len)
 {
        struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+       unsigned int ret;
 
-       if (len != AES_KEY_LENGTH) {
+       op->keylen = len;
+
+       if (len == AES_KEYSIZE_128) {
+               memcpy(op->key, key, len);
+               return 0;
+       }
+
+       if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+               /* not supported at all */
                tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
                return -EINVAL;
        }
 
-       memcpy(op->key, key, len);
-       return 0;
+       /*
+        * The requested key size is not supported by HW, do a fallback
+        */
+       op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+       op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+
+       ret = crypto_cipher_setkey(op->fallback.cip, key, len);
+       if (ret) {
+               tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+               tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+       }
+       return ret;
+}
+
+static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
+               unsigned int len)
+{
+       struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+       unsigned int ret;
+
+       op->keylen = len;
+
+       if (len == AES_KEYSIZE_128) {
+               memcpy(op->key, key, len);
+               return 0;
+       }
+
+       if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+               /* not supported at all */
+               tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       /*
+        * The requested key size is not supported by HW, do a fallback
+        */
+       op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+       op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+
+       ret = crypto_blkcipher_setkey(op->fallback.blk, key, len);
+       if (ret) {
+               tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+               tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+       }
+       return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+               struct scatterlist *dst, struct scatterlist *src,
+               unsigned int nbytes)
+{
+       unsigned int ret;
+       struct crypto_blkcipher *tfm;
+       struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+       tfm = desc->tfm;
+       desc->tfm = op->fallback.blk;
+
+       ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+       desc->tfm = tfm;
+       return ret;
+}
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+               struct scatterlist *dst, struct scatterlist *src,
+               unsigned int nbytes)
+{
+       unsigned int ret;
+       struct crypto_blkcipher *tfm;
+       struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+       tfm = desc->tfm;
+       desc->tfm = op->fallback.blk;
+
+       ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+       desc->tfm = tfm;
+       return ret;
 }
 
 static void
@@ -160,8 +217,10 @@ geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
-       if ((out == NULL) || (in == NULL))
+       if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+               crypto_cipher_encrypt_one(op->fallback.cip, out, in);
                return;
+       }
 
        op->src = (void *) in;
        op->dst = (void *) out;
@@ -179,8 +238,10 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
-       if ((out == NULL) || (in == NULL))
+       if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+               crypto_cipher_decrypt_one(op->fallback.cip, out, in);
                return;
+       }
 
        op->src = (void *) in;
        op->dst = (void *) out;
@@ -192,24 +253,50 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
        geode_aes_crypt(op);
 }
 
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+       const char *name = tfm->__crt_alg->cra_name;
+       struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+       op->fallback.cip = crypto_alloc_cipher(name, 0,
+                               CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+       if (IS_ERR(op->fallback.cip)) {
+               printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+               return PTR_ERR(op->fallback.blk);
+       }
+
+       return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+       struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+       crypto_free_cipher(op->fallback.cip);
+       op->fallback.cip = NULL;
+}
 
 static struct crypto_alg geode_alg = {
-       .cra_name               =       "aes",
-       .cra_driver_name        =       "geode-aes-128",
-       .cra_priority           =       300,
-       .cra_alignmask          =       15,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_name                       =       "aes",
+       .cra_driver_name        =       "geode-aes",
+       .cra_priority           =       300,
+       .cra_alignmask          =       15,
+       .cra_flags                      =       CRYPTO_ALG_TYPE_CIPHER |
+                                                       CRYPTO_ALG_NEED_FALLBACK,
+       .cra_init                       =       fallback_init_cip,
+       .cra_exit                       =       fallback_exit_cip,
        .cra_blocksize          =       AES_MIN_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct geode_aes_op),
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(geode_alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =  AES_KEY_LENGTH,
-                       .cia_max_keysize        =  AES_KEY_LENGTH,
-                       .cia_setkey             =  geode_setkey,
-                       .cia_encrypt            =  geode_encrypt,
-                       .cia_decrypt            =  geode_decrypt
+       .cra_module                     =       THIS_MODULE,
+       .cra_list                       =       LIST_HEAD_INIT(geode_alg.cra_list),
+       .cra_u                          =       {
+               .cipher =       {
+                       .cia_min_keysize        =       AES_MIN_KEY_SIZE,
+                       .cia_max_keysize        =       AES_MAX_KEY_SIZE,
+                       .cia_setkey                     =       geode_setkey_cip,
+                       .cia_encrypt            =       geode_encrypt,
+                       .cia_decrypt            =       geode_decrypt
                }
        }
 };
@@ -223,8 +310,12 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (unlikely(op->keylen != AES_KEYSIZE_128))
+               return fallback_blk_dec(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       op->iv = walk.iv;
 
        while((nbytes = walk.nbytes)) {
                op->src = walk.src.virt.addr,
@@ -233,13 +324,9 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
                op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
                op->dir = AES_DIR_DECRYPT;
 
-               memcpy(op->iv, walk.iv, AES_IV_LENGTH);
-
                ret = geode_aes_crypt(op);
 
-               memcpy(walk.iv, op->iv, AES_IV_LENGTH);
                nbytes -= ret;
-
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
 
@@ -255,8 +342,12 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (unlikely(op->keylen != AES_KEYSIZE_128))
+               return fallback_blk_enc(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       op->iv = walk.iv;
 
        while((nbytes = walk.nbytes)) {
                op->src = walk.src.virt.addr,
@@ -265,8 +356,6 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
                op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
                op->dir = AES_DIR_ENCRYPT;
 
-               memcpy(op->iv, walk.iv, AES_IV_LENGTH);
-
                ret = geode_aes_crypt(op);
                nbytes -= ret;
                err = blkcipher_walk_done(desc, &walk, nbytes);
@@ -275,22 +364,49 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
        return err;
 }
 
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+       const char *name = tfm->__crt_alg->cra_name;
+       struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+       op->fallback.blk = crypto_alloc_blkcipher(name, 0,
+                       CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+       if (IS_ERR(op->fallback.blk)) {
+               printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+               return PTR_ERR(op->fallback.blk);
+       }
+
+       return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+       struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+       crypto_free_blkcipher(op->fallback.blk);
+       op->fallback.blk = NULL;
+}
+
 static struct crypto_alg geode_cbc_alg = {
        .cra_name               =       "cbc(aes)",
-       .cra_driver_name        =       "cbc-aes-geode-128",
+       .cra_driver_name        =       "cbc-aes-geode",
        .cra_priority           =       400,
-       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_flags                      =       CRYPTO_ALG_TYPE_BLKCIPHER |
+                                                       CRYPTO_ALG_NEED_FALLBACK,
+       .cra_init                       =       fallback_init_blk,
+       .cra_exit                       =       fallback_exit_blk,
        .cra_blocksize          =       AES_MIN_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct geode_aes_op),
        .cra_alignmask          =       15,
-       .cra_type               =       &crypto_blkcipher_type,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(geode_cbc_alg.cra_list),
-       .cra_u                  =       {
-               .blkcipher = {
-                       .min_keysize            =       AES_KEY_LENGTH,
-                       .max_keysize            =       AES_KEY_LENGTH,
-                       .setkey                 =       geode_setkey,
+       .cra_type                       =       &crypto_blkcipher_type,
+       .cra_module                     =       THIS_MODULE,
+       .cra_list                       =       LIST_HEAD_INIT(geode_cbc_alg.cra_list),
+       .cra_u                          =       {
+               .blkcipher      =       {
+                       .min_keysize    =       AES_MIN_KEY_SIZE,
+                       .max_keysize    =       AES_MAX_KEY_SIZE,
+                       .setkey                 =       geode_setkey_blk,
                        .encrypt                =       geode_cbc_encrypt,
                        .decrypt                =       geode_cbc_decrypt,
                        .ivsize                 =       AES_IV_LENGTH,
@@ -307,6 +423,9 @@ geode_ecb_decrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (unlikely(op->keylen != AES_KEYSIZE_128))
+               return fallback_blk_dec(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
 
@@ -334,6 +453,9 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (unlikely(op->keylen != AES_KEYSIZE_128))
+               return fallback_blk_enc(desc, dst, src, nbytes);
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
 
@@ -353,28 +475,31 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
 }
 
 static struct crypto_alg geode_ecb_alg = {
-       .cra_name               =       "ecb(aes)",
-       .cra_driver_name        =       "ecb-aes-geode-128",
+       .cra_name                       =       "ecb(aes)",
+       .cra_driver_name        =       "ecb-aes-geode",
        .cra_priority           =       400,
-       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_flags                      =       CRYPTO_ALG_TYPE_BLKCIPHER |
+                                                       CRYPTO_ALG_NEED_FALLBACK,
+       .cra_init                       =       fallback_init_blk,
+       .cra_exit                       =       fallback_exit_blk,
        .cra_blocksize          =       AES_MIN_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct geode_aes_op),
        .cra_alignmask          =       15,
-       .cra_type               =       &crypto_blkcipher_type,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(geode_ecb_alg.cra_list),
-       .cra_u                  =       {
-               .blkcipher = {
-                       .min_keysize            =       AES_KEY_LENGTH,
-                       .max_keysize            =       AES_KEY_LENGTH,
-                       .setkey                 =       geode_setkey,
+       .cra_type                       =       &crypto_blkcipher_type,
+       .cra_module                     =       THIS_MODULE,
+       .cra_list                       =       LIST_HEAD_INIT(geode_ecb_alg.cra_list),
+       .cra_u                          =       {
+               .blkcipher      =       {
+                       .min_keysize    =       AES_MIN_KEY_SIZE,
+                       .max_keysize    =       AES_MAX_KEY_SIZE,
+                       .setkey                 =       geode_setkey_blk,
                        .encrypt                =       geode_ecb_encrypt,
                        .decrypt                =       geode_ecb_decrypt,
                }
        }
 };
 
-static void
+static void __devexit
 geode_aes_remove(struct pci_dev *dev)
 {
        crypto_unregister_alg(&geode_alg);
@@ -389,7 +514,7 @@ geode_aes_remove(struct pci_dev *dev)
 }
 
 
-static int
+static int __devinit
 geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int ret;
@@ -397,7 +522,7 @@ geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if ((ret = pci_enable_device(dev)))
                return ret;
 
-       if ((ret = pci_request_regions(dev, "geode-aes-128")))
+       if ((ret = pci_request_regions(dev, "geode-aes")))
                goto eenable;
 
        _iobase = pci_iomap(dev, 0, 0);
@@ -472,7 +597,6 @@ geode_aes_exit(void)
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("aes");
 
 module_init(geode_aes_init);
 module_exit(geode_aes_exit);
index f47968671ae7cfede80dacbfbda8c1b236014d75..f1855b50da48d53cbc3e1f2d6d953529e56252d5 100644 (file)
@@ -9,9 +9,9 @@
 #ifndef _GEODE_AES_H_
 #define _GEODE_AES_H_
 
-#define AES_KEY_LENGTH 16
+/* driver logic flags */
 #define AES_IV_LENGTH  16
-
+#define AES_KEY_LENGTH 16
 #define AES_MIN_BLOCK_SIZE 16
 
 #define AES_MODE_ECB 0
 
 #define AES_FLAGS_HIDDENKEY (1 << 0)
 
+/* Register definitions */
+
+#define AES_CTRLA_REG  0x0000
+
+#define AES_CTRL_START     0x01
+#define AES_CTRL_DECRYPT   0x00
+#define AES_CTRL_ENCRYPT   0x02
+#define AES_CTRL_WRKEY     0x04
+#define AES_CTRL_DCA       0x08
+#define AES_CTRL_SCA       0x10
+#define AES_CTRL_CBC       0x20
+
+#define AES_INTR_REG  0x0008
+
+#define AES_INTRA_PENDING (1 << 16)
+#define AES_INTRB_PENDING (1 << 17)
+
+#define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
+#define AES_INTR_MASK     0x07
+
+#define AES_SOURCEA_REG   0x0010
+#define AES_DSTA_REG      0x0014
+#define AES_LENA_REG      0x0018
+#define AES_WRITEKEY0_REG 0x0030
+#define AES_WRITEIV0_REG  0x0040
+
+/*  A very large counter that is used to gracefully bail out of an
+ *  operation in case of trouble
+ */
+
+#define AES_OP_TIMEOUT    0x50000
+
 struct geode_aes_op {
 
        void *src;
@@ -33,7 +65,13 @@ struct geode_aes_op {
        int len;
 
        u8 key[AES_KEY_LENGTH];
-       u8 iv[AES_IV_LENGTH];
+       u8 *iv;
+
+       union {
+               struct crypto_blkcipher *blk;
+               struct crypto_cipher *cip;
+       } fallback;
+       u32 keylen;
 };
 
 #endif
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
new file mode 100644 (file)
index 0000000..dfbf24c
--- /dev/null
@@ -0,0 +1,2838 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mod_devicetable.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <linux/ktime.h>
+
+#include <crypto/algapi.h>
+#include <crypto/des.h>
+
+#include <asm/kmap_types.h>
+
+#undef dprintk
+
+#define HIFN_TEST
+//#define HIFN_DEBUG
+
+#ifdef HIFN_DEBUG
+#define dprintk(f, a...)       printk(f, ##a)
+#else
+#define dprintk(f, a...)       do {} while (0)
+#endif
+
+static char hifn_pll_ref[sizeof("extNNN")] = "ext";
+module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444);
+MODULE_PARM_DESC(hifn_pll_ref,
+                "PLL reference clock (pci[freq] or ext[freq], default ext)");
+
+static atomic_t hifn_dev_number;
+
+#define ACRYPTO_OP_DECRYPT     0
+#define ACRYPTO_OP_ENCRYPT     1
+#define ACRYPTO_OP_HMAC                2
+#define ACRYPTO_OP_RNG         3
+
+#define ACRYPTO_MODE_ECB               0
+#define ACRYPTO_MODE_CBC               1
+#define ACRYPTO_MODE_CFB               2
+#define ACRYPTO_MODE_OFB               3
+
+#define ACRYPTO_TYPE_AES_128   0
+#define ACRYPTO_TYPE_AES_192   1
+#define ACRYPTO_TYPE_AES_256   2
+#define ACRYPTO_TYPE_3DES      3
+#define ACRYPTO_TYPE_DES       4
+
+#define PCI_VENDOR_ID_HIFN             0x13A3
+#define PCI_DEVICE_ID_HIFN_7955                0x0020
+#define        PCI_DEVICE_ID_HIFN_7956         0x001d
+
+/* I/O region sizes */
+
+#define HIFN_BAR0_SIZE                 0x1000
+#define HIFN_BAR1_SIZE                 0x2000
+#define HIFN_BAR2_SIZE                 0x8000
+
+/* DMA registres */
+
+#define HIFN_DMA_CRA                   0x0C    /* DMA Command Ring Address */
+#define HIFN_DMA_SDRA                  0x1C    /* DMA Source Data Ring Address */
+#define HIFN_DMA_RRA                   0x2C    /* DMA Result Ring Address */
+#define HIFN_DMA_DDRA                  0x3C    /* DMA Destination Data Ring Address */
+#define HIFN_DMA_STCTL                 0x40    /* DMA Status and Control */
+#define HIFN_DMA_INTREN                0x44    /* DMA Interrupt Enable */
+#define HIFN_DMA_CFG1                  0x48    /* DMA Configuration #1 */
+#define HIFN_DMA_CFG2                  0x6C    /* DMA Configuration #2 */
+#define HIFN_CHIP_ID                   0x98    /* Chip ID */
+
+/*
+ * Processing Unit Registers (offset from BASEREG0)
+ */
+#define        HIFN_0_PUDATA           0x00    /* Processing Unit Data */
+#define        HIFN_0_PUCTRL           0x04    /* Processing Unit Control */
+#define        HIFN_0_PUISR            0x08    /* Processing Unit Interrupt Status */
+#define        HIFN_0_PUCNFG           0x0c    /* Processing Unit Configuration */
+#define        HIFN_0_PUIER            0x10    /* Processing Unit Interrupt Enable */
+#define        HIFN_0_PUSTAT           0x14    /* Processing Unit Status/Chip ID */
+#define        HIFN_0_FIFOSTAT         0x18    /* FIFO Status */
+#define        HIFN_0_FIFOCNFG         0x1c    /* FIFO Configuration */
+#define        HIFN_0_SPACESIZE        0x20    /* Register space size */
+
+/* Processing Unit Control Register (HIFN_0_PUCTRL) */
+#define        HIFN_PUCTRL_CLRSRCFIFO  0x0010  /* clear source fifo */
+#define        HIFN_PUCTRL_STOP        0x0008  /* stop pu */
+#define        HIFN_PUCTRL_LOCKRAM     0x0004  /* lock ram */
+#define        HIFN_PUCTRL_DMAENA      0x0002  /* enable dma */
+#define        HIFN_PUCTRL_RESET       0x0001  /* Reset processing unit */
+
+/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */
+#define        HIFN_PUISR_CMDINVAL     0x8000  /* Invalid command interrupt */
+#define        HIFN_PUISR_DATAERR      0x4000  /* Data error interrupt */
+#define        HIFN_PUISR_SRCFIFO      0x2000  /* Source FIFO ready interrupt */
+#define        HIFN_PUISR_DSTFIFO      0x1000  /* Destination FIFO ready interrupt */
+#define        HIFN_PUISR_DSTOVER      0x0200  /* Destination overrun interrupt */
+#define        HIFN_PUISR_SRCCMD       0x0080  /* Source command interrupt */
+#define        HIFN_PUISR_SRCCTX       0x0040  /* Source context interrupt */
+#define        HIFN_PUISR_SRCDATA      0x0020  /* Source data interrupt */
+#define        HIFN_PUISR_DSTDATA      0x0010  /* Destination data interrupt */
+#define        HIFN_PUISR_DSTRESULT    0x0004  /* Destination result interrupt */
+
+/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */
+#define        HIFN_PUCNFG_DRAMMASK    0xe000  /* DRAM size mask */
+#define        HIFN_PUCNFG_DSZ_256K    0x0000  /* 256k dram */
+#define        HIFN_PUCNFG_DSZ_512K    0x2000  /* 512k dram */
+#define        HIFN_PUCNFG_DSZ_1M      0x4000  /* 1m dram */
+#define        HIFN_PUCNFG_DSZ_2M      0x6000  /* 2m dram */
+#define        HIFN_PUCNFG_DSZ_4M      0x8000  /* 4m dram */
+#define        HIFN_PUCNFG_DSZ_8M      0xa000  /* 8m dram */
+#define        HIFN_PUNCFG_DSZ_16M     0xc000  /* 16m dram */
+#define        HIFN_PUCNFG_DSZ_32M     0xe000  /* 32m dram */
+#define        HIFN_PUCNFG_DRAMREFRESH 0x1800  /* DRAM refresh rate mask */
+#define        HIFN_PUCNFG_DRFR_512    0x0000  /* 512 divisor of ECLK */
+#define        HIFN_PUCNFG_DRFR_256    0x0800  /* 256 divisor of ECLK */
+#define        HIFN_PUCNFG_DRFR_128    0x1000  /* 128 divisor of ECLK */
+#define        HIFN_PUCNFG_TCALLPHASES 0x0200  /* your guess is as good as mine... */
+#define        HIFN_PUCNFG_TCDRVTOTEM  0x0100  /* your guess is as good as mine... */
+#define        HIFN_PUCNFG_BIGENDIAN   0x0080  /* DMA big endian mode */
+#define        HIFN_PUCNFG_BUS32       0x0040  /* Bus width 32bits */
+#define        HIFN_PUCNFG_BUS16       0x0000  /* Bus width 16 bits */
+#define        HIFN_PUCNFG_CHIPID      0x0020  /* Allow chipid from PUSTAT */
+#define        HIFN_PUCNFG_DRAM        0x0010  /* Context RAM is DRAM */
+#define        HIFN_PUCNFG_SRAM        0x0000  /* Context RAM is SRAM */
+#define        HIFN_PUCNFG_COMPSING    0x0004  /* Enable single compression context */
+#define        HIFN_PUCNFG_ENCCNFG     0x0002  /* Encryption configuration */
+
+/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */
+#define        HIFN_PUIER_CMDINVAL     0x8000  /* Invalid command interrupt */
+#define        HIFN_PUIER_DATAERR      0x4000  /* Data error interrupt */
+#define        HIFN_PUIER_SRCFIFO      0x2000  /* Source FIFO ready interrupt */
+#define        HIFN_PUIER_DSTFIFO      0x1000  /* Destination FIFO ready interrupt */
+#define        HIFN_PUIER_DSTOVER      0x0200  /* Destination overrun interrupt */
+#define        HIFN_PUIER_SRCCMD       0x0080  /* Source command interrupt */
+#define        HIFN_PUIER_SRCCTX       0x0040  /* Source context interrupt */
+#define        HIFN_PUIER_SRCDATA      0x0020  /* Source data interrupt */
+#define        HIFN_PUIER_DSTDATA      0x0010  /* Destination data interrupt */
+#define        HIFN_PUIER_DSTRESULT    0x0004  /* Destination result interrupt */
+
+/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */
+#define        HIFN_PUSTAT_CMDINVAL    0x8000  /* Invalid command interrupt */
+#define        HIFN_PUSTAT_DATAERR     0x4000  /* Data error interrupt */
+#define        HIFN_PUSTAT_SRCFIFO     0x2000  /* Source FIFO ready interrupt */
+#define        HIFN_PUSTAT_DSTFIFO     0x1000  /* Destination FIFO ready interrupt */
+#define        HIFN_PUSTAT_DSTOVER     0x0200  /* Destination overrun interrupt */
+#define        HIFN_PUSTAT_SRCCMD      0x0080  /* Source command interrupt */
+#define        HIFN_PUSTAT_SRCCTX      0x0040  /* Source context interrupt */
+#define        HIFN_PUSTAT_SRCDATA     0x0020  /* Source data interrupt */
+#define        HIFN_PUSTAT_DSTDATA     0x0010  /* Destination data interrupt */
+#define        HIFN_PUSTAT_DSTRESULT   0x0004  /* Destination result interrupt */
+#define        HIFN_PUSTAT_CHIPREV     0x00ff  /* Chip revision mask */
+#define        HIFN_PUSTAT_CHIPENA     0xff00  /* Chip enabled mask */
+#define        HIFN_PUSTAT_ENA_2       0x1100  /* Level 2 enabled */
+#define        HIFN_PUSTAT_ENA_1       0x1000  /* Level 1 enabled */
+#define        HIFN_PUSTAT_ENA_0       0x3000  /* Level 0 enabled */
+#define        HIFN_PUSTAT_REV_2       0x0020  /* 7751 PT6/2 */
+#define        HIFN_PUSTAT_REV_3       0x0030  /* 7751 PT6/3 */
+
+/* FIFO Status Register (HIFN_0_FIFOSTAT) */
+#define        HIFN_FIFOSTAT_SRC       0x7f00  /* Source FIFO available */
+#define        HIFN_FIFOSTAT_DST       0x007f  /* Destination FIFO available */
+
+/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */
+#define        HIFN_FIFOCNFG_THRESHOLD 0x0400  /* must be written as 1 */
+
+/*
+ * DMA Interface Registers (offset from BASEREG1)
+ */
+#define        HIFN_1_DMA_CRAR         0x0c    /* DMA Command Ring Address */
+#define        HIFN_1_DMA_SRAR         0x1c    /* DMA Source Ring Address */
+#define        HIFN_1_DMA_RRAR         0x2c    /* DMA Result Ring Address */
+#define        HIFN_1_DMA_DRAR         0x3c    /* DMA Destination Ring Address */
+#define        HIFN_1_DMA_CSR          0x40    /* DMA Status and Control */
+#define        HIFN_1_DMA_IER          0x44    /* DMA Interrupt Enable */
+#define        HIFN_1_DMA_CNFG         0x48    /* DMA Configuration */
+#define        HIFN_1_PLL              0x4c    /* 795x: PLL config */
+#define        HIFN_1_7811_RNGENA      0x60    /* 7811: rng enable */
+#define        HIFN_1_7811_RNGCFG      0x64    /* 7811: rng config */
+#define        HIFN_1_7811_RNGDAT      0x68    /* 7811: rng data */
+#define        HIFN_1_7811_RNGSTS      0x6c    /* 7811: rng status */
+#define        HIFN_1_7811_MIPSRST     0x94    /* 7811: MIPS reset */
+#define        HIFN_1_REVID            0x98    /* Revision ID */
+#define        HIFN_1_UNLOCK_SECRET1   0xf4
+#define        HIFN_1_UNLOCK_SECRET2   0xfc
+#define        HIFN_1_PUB_RESET        0x204   /* Public/RNG Reset */
+#define        HIFN_1_PUB_BASE         0x300   /* Public Base Address */
+#define        HIFN_1_PUB_OPLEN        0x304   /* Public Operand Length */
+#define        HIFN_1_PUB_OP           0x308   /* Public Operand */
+#define        HIFN_1_PUB_STATUS       0x30c   /* Public Status */
+#define        HIFN_1_PUB_IEN          0x310   /* Public Interrupt enable */
+#define        HIFN_1_RNG_CONFIG       0x314   /* RNG config */
+#define        HIFN_1_RNG_DATA         0x318   /* RNG data */
+#define        HIFN_1_PUB_MEM          0x400   /* start of Public key memory */
+#define        HIFN_1_PUB_MEMEND       0xbff   /* end of Public key memory */
+
+/* DMA Status and Control Register (HIFN_1_DMA_CSR) */
+#define        HIFN_DMACSR_D_CTRLMASK  0xc0000000      /* Destinition Ring Control */
+#define        HIFN_DMACSR_D_CTRL_NOP  0x00000000      /* Dest. Control: no-op */
+#define        HIFN_DMACSR_D_CTRL_DIS  0x40000000      /* Dest. Control: disable */
+#define        HIFN_DMACSR_D_CTRL_ENA  0x80000000      /* Dest. Control: enable */
+#define        HIFN_DMACSR_D_ABORT     0x20000000      /* Destinition Ring PCIAbort */
+#define        HIFN_DMACSR_D_DONE      0x10000000      /* Destinition Ring Done */
+#define        HIFN_DMACSR_D_LAST      0x08000000      /* Destinition Ring Last */
+#define        HIFN_DMACSR_D_WAIT      0x04000000      /* Destinition Ring Waiting */
+#define        HIFN_DMACSR_D_OVER      0x02000000      /* Destinition Ring Overflow */
+#define        HIFN_DMACSR_R_CTRL      0x00c00000      /* Result Ring Control */
+#define        HIFN_DMACSR_R_CTRL_NOP  0x00000000      /* Result Control: no-op */
+#define        HIFN_DMACSR_R_CTRL_DIS  0x00400000      /* Result Control: disable */
+#define        HIFN_DMACSR_R_CTRL_ENA  0x00800000      /* Result Control: enable */
+#define        HIFN_DMACSR_R_ABORT     0x00200000      /* Result Ring PCI Abort */
+#define        HIFN_DMACSR_R_DONE      0x00100000      /* Result Ring Done */
+#define        HIFN_DMACSR_R_LAST      0x00080000      /* Result Ring Last */
+#define        HIFN_DMACSR_R_WAIT      0x00040000      /* Result Ring Waiting */
+#define        HIFN_DMACSR_R_OVER      0x00020000      /* Result Ring Overflow */
+#define        HIFN_DMACSR_S_CTRL      0x0000c000      /* Source Ring Control */
+#define        HIFN_DMACSR_S_CTRL_NOP  0x00000000      /* Source Control: no-op */
+#define        HIFN_DMACSR_S_CTRL_DIS  0x00004000      /* Source Control: disable */
+#define        HIFN_DMACSR_S_CTRL_ENA  0x00008000      /* Source Control: enable */
+#define        HIFN_DMACSR_S_ABORT     0x00002000      /* Source Ring PCI Abort */
+#define        HIFN_DMACSR_S_DONE      0x00001000      /* Source Ring Done */
+#define        HIFN_DMACSR_S_LAST      0x00000800      /* Source Ring Last */
+#define        HIFN_DMACSR_S_WAIT      0x00000400      /* Source Ring Waiting */
+#define        HIFN_DMACSR_ILLW        0x00000200      /* Illegal write (7811 only) */
+#define        HIFN_DMACSR_ILLR        0x00000100      /* Illegal read (7811 only) */
+#define        HIFN_DMACSR_C_CTRL      0x000000c0      /* Command Ring Control */
+#define        HIFN_DMACSR_C_CTRL_NOP  0x00000000      /* Command Control: no-op */
+#define        HIFN_DMACSR_C_CTRL_DIS  0x00000040      /* Command Control: disable */
+#define        HIFN_DMACSR_C_CTRL_ENA  0x00000080      /* Command Control: enable */
+#define        HIFN_DMACSR_C_ABORT     0x00000020      /* Command Ring PCI Abort */
+#define        HIFN_DMACSR_C_DONE      0x00000010      /* Command Ring Done */
+#define        HIFN_DMACSR_C_LAST      0x00000008      /* Command Ring Last */
+#define        HIFN_DMACSR_C_WAIT      0x00000004      /* Command Ring Waiting */
+#define        HIFN_DMACSR_PUBDONE     0x00000002      /* Public op done (7951 only) */
+#define        HIFN_DMACSR_ENGINE      0x00000001      /* Command Ring Engine IRQ */
+
+/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */
+#define        HIFN_DMAIER_D_ABORT     0x20000000      /* Destination Ring PCIAbort */
+#define        HIFN_DMAIER_D_DONE      0x10000000      /* Destination Ring Done */
+#define        HIFN_DMAIER_D_LAST      0x08000000      /* Destination Ring Last */
+#define        HIFN_DMAIER_D_WAIT      0x04000000      /* Destination Ring Waiting */
+#define        HIFN_DMAIER_D_OVER      0x02000000      /* Destination Ring Overflow */
+#define        HIFN_DMAIER_R_ABORT     0x00200000      /* Result Ring PCI Abort */
+#define        HIFN_DMAIER_R_DONE      0x00100000      /* Result Ring Done */
+#define        HIFN_DMAIER_R_LAST      0x00080000      /* Result Ring Last */
+#define        HIFN_DMAIER_R_WAIT      0x00040000      /* Result Ring Waiting */
+#define        HIFN_DMAIER_R_OVER      0x00020000      /* Result Ring Overflow */
+#define        HIFN_DMAIER_S_ABORT     0x00002000      /* Source Ring PCI Abort */
+#define        HIFN_DMAIER_S_DONE      0x00001000      /* Source Ring Done */
+#define        HIFN_DMAIER_S_LAST      0x00000800      /* Source Ring Last */
+#define        HIFN_DMAIER_S_WAIT      0x00000400      /* Source Ring Waiting */
+#define        HIFN_DMAIER_ILLW        0x00000200      /* Illegal write (7811 only) */
+#define        HIFN_DMAIER_ILLR        0x00000100      /* Illegal read (7811 only) */
+#define        HIFN_DMAIER_C_ABORT     0x00000020      /* Command Ring PCI Abort */
+#define        HIFN_DMAIER_C_DONE      0x00000010      /* Command Ring Done */
+#define        HIFN_DMAIER_C_LAST      0x00000008      /* Command Ring Last */
+#define        HIFN_DMAIER_C_WAIT      0x00000004      /* Command Ring Waiting */
+#define        HIFN_DMAIER_PUBDONE     0x00000002      /* public op done (7951 only) */
+#define        HIFN_DMAIER_ENGINE      0x00000001      /* Engine IRQ */
+
+/* DMA Configuration Register (HIFN_1_DMA_CNFG) */
+#define        HIFN_DMACNFG_BIGENDIAN  0x10000000      /* big endian mode */
+#define        HIFN_DMACNFG_POLLFREQ   0x00ff0000      /* Poll frequency mask */
+#define        HIFN_DMACNFG_UNLOCK     0x00000800
+#define        HIFN_DMACNFG_POLLINVAL  0x00000700      /* Invalid Poll Scalar */
+#define        HIFN_DMACNFG_LAST       0x00000010      /* Host control LAST bit */
+#define        HIFN_DMACNFG_MODE       0x00000004      /* DMA mode */
+#define        HIFN_DMACNFG_DMARESET   0x00000002      /* DMA Reset # */
+#define        HIFN_DMACNFG_MSTRESET   0x00000001      /* Master Reset # */
+
+/* PLL configuration register */
+#define HIFN_PLL_REF_CLK_HBI   0x00000000      /* HBI reference clock */
+#define HIFN_PLL_REF_CLK_PLL   0x00000001      /* PLL reference clock */
+#define HIFN_PLL_BP            0x00000002      /* Reference clock bypass */
+#define HIFN_PLL_PK_CLK_HBI    0x00000000      /* PK engine HBI clock */
+#define HIFN_PLL_PK_CLK_PLL    0x00000008      /* PK engine PLL clock */
+#define HIFN_PLL_PE_CLK_HBI    0x00000000      /* PE engine HBI clock */
+#define HIFN_PLL_PE_CLK_PLL    0x00000010      /* PE engine PLL clock */
+#define HIFN_PLL_RESERVED_1    0x00000400      /* Reserved bit, must be 1 */
+#define HIFN_PLL_ND_SHIFT      11              /* Clock multiplier shift */
+#define HIFN_PLL_ND_MULT_2     0x00000000      /* PLL clock multiplier 2 */
+#define HIFN_PLL_ND_MULT_4     0x00000800      /* PLL clock multiplier 4 */
+#define HIFN_PLL_ND_MULT_6     0x00001000      /* PLL clock multiplier 6 */
+#define HIFN_PLL_ND_MULT_8     0x00001800      /* PLL clock multiplier 8 */
+#define HIFN_PLL_ND_MULT_10    0x00002000      /* PLL clock multiplier 10 */
+#define HIFN_PLL_ND_MULT_12    0x00002800      /* PLL clock multiplier 12 */
+#define HIFN_PLL_IS_1_8                0x00000000      /* charge pump (mult. 1-8) */
+#define HIFN_PLL_IS_9_12       0x00010000      /* charge pump (mult. 9-12) */
+
+#define HIFN_PLL_FCK_MAX       266             /* Maximum PLL frequency */
+
+/* Public key reset register (HIFN_1_PUB_RESET) */
+#define        HIFN_PUBRST_RESET       0x00000001      /* reset public/rng unit */
+
+/* Public base address register (HIFN_1_PUB_BASE) */
+#define        HIFN_PUBBASE_ADDR       0x00003fff      /* base address */
+
+/* Public operand length register (HIFN_1_PUB_OPLEN) */
+#define        HIFN_PUBOPLEN_MOD_M     0x0000007f      /* modulus length mask */
+#define        HIFN_PUBOPLEN_MOD_S     0               /* modulus length shift */
+#define        HIFN_PUBOPLEN_EXP_M     0x0003ff80      /* exponent length mask */
+#define        HIFN_PUBOPLEN_EXP_S     7               /* exponent lenght shift */
+#define        HIFN_PUBOPLEN_RED_M     0x003c0000      /* reducend length mask */
+#define        HIFN_PUBOPLEN_RED_S     18              /* reducend length shift */
+
+/* Public operation register (HIFN_1_PUB_OP) */
+#define        HIFN_PUBOP_AOFFSET_M    0x0000007f      /* A offset mask */
+#define        HIFN_PUBOP_AOFFSET_S    0               /* A offset shift */
+#define        HIFN_PUBOP_BOFFSET_M    0x00000f80      /* B offset mask */
+#define        HIFN_PUBOP_BOFFSET_S    7               /* B offset shift */
+#define        HIFN_PUBOP_MOFFSET_M    0x0003f000      /* M offset mask */
+#define        HIFN_PUBOP_MOFFSET_S    12              /* M offset shift */
+#define        HIFN_PUBOP_OP_MASK      0x003c0000      /* Opcode: */
+#define        HIFN_PUBOP_OP_NOP       0x00000000      /*  NOP */
+#define        HIFN_PUBOP_OP_ADD       0x00040000      /*  ADD */
+#define        HIFN_PUBOP_OP_ADDC      0x00080000      /*  ADD w/carry */
+#define        HIFN_PUBOP_OP_SUB       0x000c0000      /*  SUB */
+#define        HIFN_PUBOP_OP_SUBC      0x00100000      /*  SUB w/carry */
+#define        HIFN_PUBOP_OP_MODADD    0x00140000      /*  Modular ADD */
+#define        HIFN_PUBOP_OP_MODSUB    0x00180000      /*  Modular SUB */
+#define        HIFN_PUBOP_OP_INCA      0x001c0000      /*  INC A */
+#define        HIFN_PUBOP_OP_DECA      0x00200000      /*  DEC A */
+#define        HIFN_PUBOP_OP_MULT      0x00240000      /*  MULT */
+#define        HIFN_PUBOP_OP_MODMULT   0x00280000      /*  Modular MULT */
+#define        HIFN_PUBOP_OP_MODRED    0x002c0000      /*  Modular RED */
+#define        HIFN_PUBOP_OP_MODEXP    0x00300000      /*  Modular EXP */
+
+/* Public status register (HIFN_1_PUB_STATUS) */
+#define        HIFN_PUBSTS_DONE        0x00000001      /* operation done */
+#define        HIFN_PUBSTS_CARRY       0x00000002      /* carry */
+
+/* Public interrupt enable register (HIFN_1_PUB_IEN) */
+#define        HIFN_PUBIEN_DONE        0x00000001      /* operation done interrupt */
+
+/* Random number generator config register (HIFN_1_RNG_CONFIG) */
+#define        HIFN_RNGCFG_ENA         0x00000001      /* enable rng */
+
+#define HIFN_NAMESIZE                  32
+#define HIFN_MAX_RESULT_ORDER          5
+
+#define        HIFN_D_CMD_RSIZE                24*4
+#define        HIFN_D_SRC_RSIZE                80*4
+#define        HIFN_D_DST_RSIZE                80*4
+#define        HIFN_D_RES_RSIZE                24*4
+
+#define HIFN_QUEUE_LENGTH              HIFN_D_CMD_RSIZE-5
+
+#define AES_MIN_KEY_SIZE               16
+#define AES_MAX_KEY_SIZE               32
+
+#define HIFN_DES_KEY_LENGTH            8
+#define HIFN_3DES_KEY_LENGTH           24
+#define HIFN_MAX_CRYPT_KEY_LENGTH      AES_MAX_KEY_SIZE
+#define HIFN_IV_LENGTH                 8
+#define HIFN_AES_IV_LENGTH             16
+#define        HIFN_MAX_IV_LENGTH              HIFN_AES_IV_LENGTH
+
+#define HIFN_MAC_KEY_LENGTH            64
+#define HIFN_MD5_LENGTH                        16
+#define HIFN_SHA1_LENGTH               20
+#define HIFN_MAC_TRUNC_LENGTH          12
+
+#define        HIFN_MAX_COMMAND                (8 + 8 + 8 + 64 + 260)
+#define        HIFN_MAX_RESULT                 (8 + 4 + 4 + 20 + 4)
+#define HIFN_USED_RESULT               12
+
+struct hifn_desc
+{
+       volatile u32            l;
+       volatile u32            p;
+};
+
+struct hifn_dma {
+       struct hifn_desc        cmdr[HIFN_D_CMD_RSIZE+1];
+       struct hifn_desc        srcr[HIFN_D_SRC_RSIZE+1];
+       struct hifn_desc        dstr[HIFN_D_DST_RSIZE+1];
+       struct hifn_desc        resr[HIFN_D_RES_RSIZE+1];
+
+       u8                      command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND];
+       u8                      result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT];
+
+       u64                     test_src, test_dst;
+
+       /*
+        *  Our current positions for insertion and removal from the descriptor
+        *  rings.
+        */
+       volatile int            cmdi, srci, dsti, resi;
+       volatile int            cmdu, srcu, dstu, resu;
+       int                     cmdk, srck, dstk, resk;
+};
+
+#define HIFN_FLAG_CMD_BUSY     (1<<0)
+#define HIFN_FLAG_SRC_BUSY     (1<<1)
+#define HIFN_FLAG_DST_BUSY     (1<<2)
+#define HIFN_FLAG_RES_BUSY     (1<<3)
+#define HIFN_FLAG_OLD_KEY      (1<<4)
+
+#define HIFN_DEFAULT_ACTIVE_NUM        5
+
+struct hifn_device
+{
+       char                    name[HIFN_NAMESIZE];
+
+       int                     irq;
+
+       struct pci_dev          *pdev;
+       void __iomem            *bar[3];
+
+       unsigned long           result_mem;
+       dma_addr_t              dst;
+
+       void                    *desc_virt;
+       dma_addr_t              desc_dma;
+
+       u32                     dmareg;
+
+       void                    *sa[HIFN_D_RES_RSIZE];
+
+       spinlock_t              lock;
+
+       void                    *priv;
+
+       u32                     flags;
+       int                     active, started;
+       struct delayed_work     work;
+       unsigned long           reset;
+       unsigned long           success;
+       unsigned long           prev_success;
+
+       u8                      snum;
+
+       struct tasklet_struct   tasklet;
+
+       struct crypto_queue     queue;
+       struct list_head        alg_list;
+
+       unsigned int            pk_clk_freq;
+
+#ifdef CRYPTO_DEV_HIFN_795X_RNG
+       unsigned int            rng_wait_time;
+       ktime_t                 rngtime;
+       struct hwrng            rng;
+#endif
+};
+
+#define        HIFN_D_LENGTH                   0x0000ffff
+#define        HIFN_D_NOINVALID                0x01000000
+#define        HIFN_D_MASKDONEIRQ              0x02000000
+#define        HIFN_D_DESTOVER                 0x04000000
+#define        HIFN_D_OVER                     0x08000000
+#define        HIFN_D_LAST                     0x20000000
+#define        HIFN_D_JUMP                     0x40000000
+#define        HIFN_D_VALID                    0x80000000
+
+struct hifn_base_command
+{
+       volatile u16            masks;
+       volatile u16            session_num;
+       volatile u16            total_source_count;
+       volatile u16            total_dest_count;
+};
+
+#define        HIFN_BASE_CMD_COMP              0x0100  /* enable compression engine */
+#define        HIFN_BASE_CMD_PAD               0x0200  /* enable padding engine */
+#define        HIFN_BASE_CMD_MAC               0x0400  /* enable MAC engine */
+#define        HIFN_BASE_CMD_CRYPT             0x0800  /* enable crypt engine */
+#define        HIFN_BASE_CMD_DECODE            0x2000
+#define        HIFN_BASE_CMD_SRCLEN_M          0xc000
+#define        HIFN_BASE_CMD_SRCLEN_S          14
+#define        HIFN_BASE_CMD_DSTLEN_M          0x3000
+#define        HIFN_BASE_CMD_DSTLEN_S          12
+#define        HIFN_BASE_CMD_LENMASK_HI        0x30000
+#define        HIFN_BASE_CMD_LENMASK_LO        0x0ffff
+
+/*
+ * Structure to help build up the command data structure.
+ */
+struct hifn_crypt_command
+{
+       volatile u16            masks;
+       volatile u16            header_skip;
+       volatile u16            source_count;
+       volatile u16            reserved;
+};
+
+#define        HIFN_CRYPT_CMD_ALG_MASK         0x0003          /* algorithm: */
+#define        HIFN_CRYPT_CMD_ALG_DES          0x0000          /*   DES */
+#define        HIFN_CRYPT_CMD_ALG_3DES         0x0001          /*   3DES */
+#define        HIFN_CRYPT_CMD_ALG_RC4          0x0002          /*   RC4 */
+#define        HIFN_CRYPT_CMD_ALG_AES          0x0003          /*   AES */
+#define        HIFN_CRYPT_CMD_MODE_MASK        0x0018          /* Encrypt mode: */
+#define        HIFN_CRYPT_CMD_MODE_ECB         0x0000          /*   ECB */
+#define        HIFN_CRYPT_CMD_MODE_CBC         0x0008          /*   CBC */
+#define        HIFN_CRYPT_CMD_MODE_CFB         0x0010          /*   CFB */
+#define        HIFN_CRYPT_CMD_MODE_OFB         0x0018          /*   OFB */
+#define        HIFN_CRYPT_CMD_CLR_CTX          0x0040          /* clear context */
+#define        HIFN_CRYPT_CMD_KSZ_MASK         0x0600          /* AES key size: */
+#define        HIFN_CRYPT_CMD_KSZ_128          0x0000          /*  128 bit */
+#define        HIFN_CRYPT_CMD_KSZ_192          0x0200          /*  192 bit */
+#define        HIFN_CRYPT_CMD_KSZ_256          0x0400          /*  256 bit */
+#define        HIFN_CRYPT_CMD_NEW_KEY          0x0800          /* expect new key */
+#define        HIFN_CRYPT_CMD_NEW_IV           0x1000          /* expect new iv */
+#define        HIFN_CRYPT_CMD_SRCLEN_M         0xc000
+#define        HIFN_CRYPT_CMD_SRCLEN_S         14
+
+/*
+ * Structure to help build up the command data structure.
+ */
+struct hifn_mac_command
+{
+       volatile u16            masks;
+       volatile u16            header_skip;
+       volatile u16            source_count;
+       volatile u16            reserved;
+};
+
+#define        HIFN_MAC_CMD_ALG_MASK           0x0001
+#define        HIFN_MAC_CMD_ALG_SHA1           0x0000
+#define        HIFN_MAC_CMD_ALG_MD5            0x0001
+#define        HIFN_MAC_CMD_MODE_MASK          0x000c
+#define        HIFN_MAC_CMD_MODE_HMAC          0x0000
+#define        HIFN_MAC_CMD_MODE_SSL_MAC       0x0004
+#define        HIFN_MAC_CMD_MODE_HASH          0x0008
+#define        HIFN_MAC_CMD_MODE_FULL          0x0004
+#define        HIFN_MAC_CMD_TRUNC              0x0010
+#define        HIFN_MAC_CMD_RESULT             0x0020
+#define        HIFN_MAC_CMD_APPEND             0x0040
+#define        HIFN_MAC_CMD_SRCLEN_M           0xc000
+#define        HIFN_MAC_CMD_SRCLEN_S           14
+
+/*
+ * MAC POS IPsec initiates authentication after encryption on encodes
+ * and before decryption on decodes.
+ */
+#define        HIFN_MAC_CMD_POS_IPSEC          0x0200
+#define        HIFN_MAC_CMD_NEW_KEY            0x0800
+
+struct hifn_comp_command
+{
+       volatile u16            masks;
+       volatile u16            header_skip;
+       volatile u16            source_count;
+       volatile u16            reserved;
+};
+
+#define        HIFN_COMP_CMD_SRCLEN_M          0xc000
+#define        HIFN_COMP_CMD_SRCLEN_S          14
+#define        HIFN_COMP_CMD_ONE               0x0100  /* must be one */
+#define        HIFN_COMP_CMD_CLEARHIST         0x0010  /* clear history */
+#define        HIFN_COMP_CMD_UPDATEHIST        0x0008  /* update history */
+#define        HIFN_COMP_CMD_LZS_STRIP0        0x0004  /* LZS: strip zero */
+#define        HIFN_COMP_CMD_MPPC_RESTART      0x0004  /* MPPC: restart */
+#define        HIFN_COMP_CMD_ALG_MASK          0x0001  /* compression mode: */
+#define        HIFN_COMP_CMD_ALG_MPPC          0x0001  /*   MPPC */
+#define        HIFN_COMP_CMD_ALG_LZS           0x0000  /*   LZS */
+
+struct hifn_base_result
+{
+       volatile u16            flags;
+       volatile u16            session;
+       volatile u16            src_cnt;                /* 15:0 of source count */
+       volatile u16            dst_cnt;                /* 15:0 of dest count */
+};
+
+#define        HIFN_BASE_RES_DSTOVERRUN        0x0200  /* destination overrun */
+#define        HIFN_BASE_RES_SRCLEN_M          0xc000  /* 17:16 of source count */
+#define        HIFN_BASE_RES_SRCLEN_S          14
+#define        HIFN_BASE_RES_DSTLEN_M          0x3000  /* 17:16 of dest count */
+#define        HIFN_BASE_RES_DSTLEN_S          12
+
+struct hifn_comp_result
+{
+       volatile u16            flags;
+       volatile u16            crc;
+};
+
+#define        HIFN_COMP_RES_LCB_M             0xff00  /* longitudinal check byte */
+#define        HIFN_COMP_RES_LCB_S             8
+#define        HIFN_COMP_RES_RESTART           0x0004  /* MPPC: restart */
+#define        HIFN_COMP_RES_ENDMARKER         0x0002  /* LZS: end marker seen */
+#define        HIFN_COMP_RES_SRC_NOTZERO       0x0001  /* source expired */
+
+struct hifn_mac_result
+{
+       volatile u16            flags;
+       volatile u16            reserved;
+       /* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */
+};
+
+#define        HIFN_MAC_RES_MISCOMPARE         0x0002  /* compare failed */
+#define        HIFN_MAC_RES_SRC_NOTZERO        0x0001  /* source expired */
+
+struct hifn_crypt_result
+{
+       volatile u16            flags;
+       volatile u16            reserved;
+};
+
+#define        HIFN_CRYPT_RES_SRC_NOTZERO      0x0001  /* source expired */
+
+#ifndef HIFN_POLL_FREQUENCY
+#define        HIFN_POLL_FREQUENCY     0x1
+#endif
+
+#ifndef HIFN_POLL_SCALAR
+#define        HIFN_POLL_SCALAR        0x0
+#endif
+
+#define        HIFN_MAX_SEGLEN         0xffff          /* maximum dma segment len */
+#define        HIFN_MAX_DMALEN         0x3ffff         /* maximum dma length */
+
+struct hifn_crypto_alg
+{
+       struct list_head        entry;
+       struct crypto_alg       alg;
+       struct hifn_device      *dev;
+};
+
+#define ASYNC_SCATTERLIST_CACHE        16
+
+#define ASYNC_FLAGS_MISALIGNED (1<<0)
+
+struct ablkcipher_walk
+{
+       struct scatterlist      cache[ASYNC_SCATTERLIST_CACHE];
+       u32                     flags;
+       int                     num;
+};
+
+struct hifn_context
+{
+       u8                      key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv;
+       struct hifn_device      *dev;
+       unsigned int            keysize, ivsize;
+       u8                      op, type, mode, unused;
+       struct ablkcipher_walk  walk;
+       atomic_t                sg_num;
+};
+
+#define crypto_alg_to_hifn(a)  container_of(a, struct hifn_crypto_alg, alg)
+
+static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg)
+{
+       u32 ret;
+
+       ret = readl((char *)(dev->bar[0]) + reg);
+
+       return ret;
+}
+
+static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg)
+{
+       u32 ret;
+
+       ret = readl((char *)(dev->bar[1]) + reg);
+
+       return ret;
+}
+
+static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
+{
+       writel(val, (char *)(dev->bar[0]) + reg);
+}
+
+static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
+{
+       writel(val, (char *)(dev->bar[1]) + reg);
+}
+
+static void hifn_wait_puc(struct hifn_device *dev)
+{
+       int i;
+       u32 ret;
+
+       for (i=10000; i > 0; --i) {
+               ret = hifn_read_0(dev, HIFN_0_PUCTRL);
+               if (!(ret & HIFN_PUCTRL_RESET))
+                       break;
+
+               udelay(1);
+       }
+
+       if (!i)
+               dprintk("%s: Failed to reset PUC unit.\n", dev->name);
+}
+
+static void hifn_reset_puc(struct hifn_device *dev)
+{
+       hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
+       hifn_wait_puc(dev);
+}
+
+static void hifn_stop_device(struct hifn_device *dev)
+{
+       hifn_write_1(dev, HIFN_1_DMA_CSR,
+               HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
+               HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS);
+       hifn_write_0(dev, HIFN_0_PUIER, 0);
+       hifn_write_1(dev, HIFN_1_DMA_IER, 0);
+}
+
+static void hifn_reset_dma(struct hifn_device *dev, int full)
+{
+       hifn_stop_device(dev);
+
+       /*
+        * Setting poll frequency and others to 0.
+        */
+       hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+                       HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+       mdelay(1);
+
+       /*
+        * Reset DMA.
+        */
+       if (full) {
+               hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
+               mdelay(1);
+       } else {
+               hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE |
+                               HIFN_DMACNFG_MSTRESET);
+               hifn_reset_puc(dev);
+       }
+
+       hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+                       HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+
+       hifn_reset_puc(dev);
+}
+
+static u32 hifn_next_signature(u_int32_t a, u_int cnt)
+{
+       int i;
+       u32 v;
+
+       for (i = 0; i < cnt; i++) {
+
+               /* get the parity */
+               v = a & 0x80080125;
+               v ^= v >> 16;
+               v ^= v >> 8;
+               v ^= v >> 4;
+               v ^= v >> 2;
+               v ^= v >> 1;
+
+               a = (v & 1) ^ (a << 1);
+       }
+
+       return a;
+}
+
+static struct pci2id {
+       u_short         pci_vendor;
+       u_short         pci_prod;
+       char            card_id[13];
+} pci2id[] = {
+       {
+               PCI_VENDOR_ID_HIFN,
+               PCI_DEVICE_ID_HIFN_7955,
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x00, 0x00, 0x00, 0x00, 0x00 }
+       },
+       {
+               PCI_VENDOR_ID_HIFN,
+               PCI_DEVICE_ID_HIFN_7956,
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x00, 0x00, 0x00, 0x00, 0x00 }
+       }
+};
+
+#ifdef CRYPTO_DEV_HIFN_795X_RNG
+static int hifn_rng_data_present(struct hwrng *rng, int wait)
+{
+       struct hifn_device *dev = (struct hifn_device *)rng->priv;
+       s64 nsec;
+
+       nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime));
+       nsec -= dev->rng_wait_time;
+       if (nsec <= 0)
+               return 1;
+       if (!wait)
+               return 0;
+       ndelay(nsec);
+       return 1;
+}
+
+static int hifn_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       struct hifn_device *dev = (struct hifn_device *)rng->priv;
+
+       *data = hifn_read_1(dev, HIFN_1_RNG_DATA);
+       dev->rngtime = ktime_get();
+       return 4;
+}
+
+static int hifn_register_rng(struct hifn_device *dev)
+{
+       /*
+        * We must wait at least 256 Pk_clk cycles between two reads of the rng.
+        */
+       dev->rng_wait_time      = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) *
+                                 256;
+
+       dev->rng.name           = dev->name;
+       dev->rng.data_present   = hifn_rng_data_present,
+       dev->rng.data_read      = hifn_rng_data_read,
+       dev->rng.priv           = (unsigned long)dev;
+
+       return hwrng_register(&dev->rng);
+}
+
+static void hifn_unregister_rng(struct hifn_device *dev)
+{
+       hwrng_unregister(&dev->rng);
+}
+#else
+#define hifn_register_rng(dev)         0
+#define hifn_unregister_rng(dev)
+#endif
+
+static int hifn_init_pubrng(struct hifn_device *dev)
+{
+       int i;
+
+       hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) |
+                       HIFN_PUBRST_RESET);
+
+       for (i=100; i > 0; --i) {
+               mdelay(1);
+
+               if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0)
+                       break;
+       }
+
+       if (!i)
+               dprintk("Chip %s: Failed to initialise public key engine.\n",
+                               dev->name);
+       else {
+               hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE);
+               dev->dmareg |= HIFN_DMAIER_PUBDONE;
+               hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+
+               dprintk("Chip %s: Public key engine has been sucessfully "
+                               "initialised.\n", dev->name);
+       }
+
+       /*
+        * Enable RNG engine.
+        */
+
+       hifn_write_1(dev, HIFN_1_RNG_CONFIG,
+                       hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA);
+       dprintk("Chip %s: RNG engine has been successfully initialised.\n",
+                       dev->name);
+
+#ifdef CRYPTO_DEV_HIFN_795X_RNG
+       /* First value must be discarded */
+       hifn_read_1(dev, HIFN_1_RNG_DATA);
+       dev->rngtime = ktime_get();
+#endif
+       return 0;
+}
+
+static int hifn_enable_crypto(struct hifn_device *dev)
+{
+       u32 dmacfg, addr;
+       char *offtbl = NULL;
+       int i;
+
+       for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) {
+               if (pci2id[i].pci_vendor == dev->pdev->vendor &&
+                               pci2id[i].pci_prod == dev->pdev->device) {
+                       offtbl = pci2id[i].card_id;
+                       break;
+               }
+       }
+
+       if (offtbl == NULL) {
+               dprintk("Chip %s: Unknown card!\n", dev->name);
+               return -ENODEV;
+       }
+
+       dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG);
+
+       hifn_write_1(dev, HIFN_1_DMA_CNFG,
+                       HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET |
+                       HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+       mdelay(1);
+       addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1);
+       mdelay(1);
+       hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0);
+       mdelay(1);
+
+       for (i=0; i<12; ++i) {
+               addr = hifn_next_signature(addr, offtbl[i] + 0x101);
+               hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr);
+
+               mdelay(1);
+       }
+       hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg);
+
+       dprintk("Chip %s: %s.\n", dev->name, pci_name(dev->pdev));
+
+       return 0;
+}
+
+static void hifn_init_dma(struct hifn_device *dev)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       u32 dptr = dev->desc_dma;
+       int i;
+
+       for (i=0; i<HIFN_D_CMD_RSIZE; ++i)
+               dma->cmdr[i].p = __cpu_to_le32(dptr +
+                               offsetof(struct hifn_dma, command_bufs[i][0]));
+       for (i=0; i<HIFN_D_RES_RSIZE; ++i)
+               dma->resr[i].p = __cpu_to_le32(dptr +
+                               offsetof(struct hifn_dma, result_bufs[i][0]));
+
+       /*
+        * Setup LAST descriptors.
+        */
+       dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr +
+                       offsetof(struct hifn_dma, cmdr[0]));
+       dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr +
+                       offsetof(struct hifn_dma, srcr[0]));
+       dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr +
+                       offsetof(struct hifn_dma, dstr[0]));
+       dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr +
+                       offsetof(struct hifn_dma, resr[0]));
+
+       dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0;
+       dma->cmdi = dma->srci = dma->dsti = dma->resi = 0;
+       dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
+}
+
+/*
+ * Initialize the PLL. We need to know the frequency of the reference clock
+ * to calculate the optimal multiplier. For PCI we assume 66MHz, since that
+ * allows us to operate without the risk of overclocking the chip. If it
+ * actually uses 33MHz, the chip will operate at half the speed, this can be
+ * overriden by specifying the frequency as module parameter (pci33).
+ *
+ * Unfortunately the PCI clock is not very suitable since the HIFN needs a
+ * stable clock and the PCI clock frequency may vary, so the default is the
+ * external clock. There is no way to find out its frequency, we default to
+ * 66MHz since according to Mike Ham of HiFn, almost every board in existence
+ * has an external crystal populated at 66MHz.
+ */
+static void hifn_init_pll(struct hifn_device *dev)
+{
+       unsigned int freq, m;
+       u32 pllcfg;
+
+       pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1;
+
+       if (strncmp(hifn_pll_ref, "ext", 3) == 0)
+               pllcfg |= HIFN_PLL_REF_CLK_PLL;
+       else
+               pllcfg |= HIFN_PLL_REF_CLK_HBI;
+
+       if (hifn_pll_ref[3] != '\0')
+               freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
+       else {
+               freq = 66;
+               printk(KERN_INFO "hifn795x: assuming %uMHz clock speed, "
+                                "override with hifn_pll_ref=%.3s<frequency>\n",
+                      freq, hifn_pll_ref);
+       }
+
+       m = HIFN_PLL_FCK_MAX / freq;
+
+       pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT;
+       if (m <= 8)
+               pllcfg |= HIFN_PLL_IS_1_8;
+       else
+               pllcfg |= HIFN_PLL_IS_9_12;
+
+       /* Select clock source and enable clock bypass */
+       hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+                    HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP);
+
+       /* Let the chip lock to the input clock */
+       mdelay(10);
+
+       /* Disable clock bypass */
+       hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+                    HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI);
+
+       /* Switch the engines to the PLL */
+       hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+                    HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL);
+
+       /*
+        * The Fpk_clk runs at half the total speed. Its frequency is needed to
+        * calculate the minimum time between two reads of the rng. Since 33MHz
+        * is actually 33.333... we overestimate the frequency here, resulting
+        * in slightly larger intervals.
+        */
+       dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2;
+}
+
+static void hifn_init_registers(struct hifn_device *dev)
+{
+       u32 dptr = dev->desc_dma;
+
+       /* Initialization magic... */
+       hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
+       hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD);
+       hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
+
+       /* write all 4 ring address registers */
+       hifn_write_1(dev, HIFN_1_DMA_CRAR, __cpu_to_le32(dptr +
+                               offsetof(struct hifn_dma, cmdr[0])));
+       hifn_write_1(dev, HIFN_1_DMA_SRAR, __cpu_to_le32(dptr +
+                               offsetof(struct hifn_dma, srcr[0])));
+       hifn_write_1(dev, HIFN_1_DMA_DRAR, __cpu_to_le32(dptr +
+                               offsetof(struct hifn_dma, dstr[0])));
+       hifn_write_1(dev, HIFN_1_DMA_RRAR, __cpu_to_le32(dptr +
+                               offsetof(struct hifn_dma, resr[0])));
+
+       mdelay(2);
+#if 0
+       hifn_write_1(dev, HIFN_1_DMA_CSR,
+           HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
+           HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS |
+           HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
+           HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
+           HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
+           HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
+           HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
+           HIFN_DMACSR_S_WAIT |
+           HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
+           HIFN_DMACSR_C_WAIT |
+           HIFN_DMACSR_ENGINE |
+           HIFN_DMACSR_PUBDONE);
+#else
+       hifn_write_1(dev, HIFN_1_DMA_CSR,
+           HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
+           HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA |
+           HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
+           HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
+           HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
+           HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
+           HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
+           HIFN_DMACSR_S_WAIT |
+           HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
+           HIFN_DMACSR_C_WAIT |
+           HIFN_DMACSR_ENGINE |
+           HIFN_DMACSR_PUBDONE);
+#endif
+       hifn_read_1(dev, HIFN_1_DMA_CSR);
+
+       dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT |
+           HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER |
+           HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT |
+           HIFN_DMAIER_ENGINE;
+       dev->dmareg &= ~HIFN_DMAIER_C_WAIT;
+
+       hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+       hifn_read_1(dev, HIFN_1_DMA_IER);
+#if 0
+       hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG |
+                   HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES |
+                   HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 |
+                   HIFN_PUCNFG_DRAM);
+#else
+       hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342);
+#endif
+       hifn_init_pll(dev);
+
+       hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
+       hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+           HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST |
+           ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) |
+           ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL));
+}
+
+static int hifn_setup_base_command(struct hifn_device *dev, u8 *buf,
+               unsigned dlen, unsigned slen, u16 mask, u8 snum)
+{
+       struct hifn_base_command *base_cmd;
+       u8 *buf_pos = buf;
+
+       base_cmd = (struct hifn_base_command *)buf_pos;
+       base_cmd->masks = __cpu_to_le16(mask);
+       base_cmd->total_source_count =
+               __cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO);
+       base_cmd->total_dest_count =
+               __cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO);
+
+       dlen >>= 16;
+       slen >>= 16;
+       base_cmd->session_num = __cpu_to_le16(snum |
+           ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) |
+           ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M));
+
+       return sizeof(struct hifn_base_command);
+}
+
+static int hifn_setup_crypto_command(struct hifn_device *dev,
+               u8 *buf, unsigned dlen, unsigned slen,
+               u8 *key, int keylen, u8 *iv, int ivsize, u16 mode)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       struct hifn_crypt_command *cry_cmd;
+       u8 *buf_pos = buf;
+       u16 cmd_len;
+
+       cry_cmd = (struct hifn_crypt_command *)buf_pos;
+
+       cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff);
+       dlen >>= 16;
+       cry_cmd->masks = __cpu_to_le16(mode |
+                       ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) &
+                        HIFN_CRYPT_CMD_SRCLEN_M));
+       cry_cmd->header_skip = 0;
+       cry_cmd->reserved = 0;
+
+       buf_pos += sizeof(struct hifn_crypt_command);
+
+       dma->cmdu++;
+       if (dma->cmdu > 1) {
+               dev->dmareg |= HIFN_DMAIER_C_WAIT;
+               hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+       }
+
+       if (keylen) {
+               memcpy(buf_pos, key, keylen);
+               buf_pos += keylen;
+       }
+       if (ivsize) {
+               memcpy(buf_pos, iv, ivsize);
+               buf_pos += ivsize;
+       }
+
+       cmd_len = buf_pos - buf;
+
+       return cmd_len;
+}
+
+static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
+               unsigned int offset, unsigned int size)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int idx;
+       dma_addr_t addr;
+
+       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE);
+
+       idx = dma->srci;
+
+       dma->srcr[idx].p = __cpu_to_le32(addr);
+       dma->srcr[idx].l = __cpu_to_le32(size) | HIFN_D_VALID |
+                       HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST;
+
+       if (++idx == HIFN_D_SRC_RSIZE) {
+               dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+                               HIFN_D_JUMP |
+                               HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+               idx = 0;
+       }
+
+       dma->srci = idx;
+       dma->srcu++;
+
+       if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_SRC_BUSY;
+       }
+
+       return size;
+}
+
+static void hifn_setup_res_desc(struct hifn_device *dev)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+       dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT |
+                       HIFN_D_VALID | HIFN_D_LAST);
+       /*
+        * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID |
+        *                                      HIFN_D_LAST | HIFN_D_NOINVALID);
+        */
+
+       if (++dma->resi == HIFN_D_RES_RSIZE) {
+               dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID |
+                               HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+               dma->resi = 0;
+       }
+
+       dma->resu++;
+
+       if (!(dev->flags & HIFN_FLAG_RES_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_RES_BUSY;
+       }
+}
+
+static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
+               unsigned offset, unsigned size)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int idx;
+       dma_addr_t addr;
+
+       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE);
+
+       idx = dma->dsti;
+       dma->dstr[idx].p = __cpu_to_le32(addr);
+       dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID |
+                       HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST);
+
+       if (++idx == HIFN_D_DST_RSIZE) {
+               dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+                               HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
+                               HIFN_D_LAST | HIFN_D_NOINVALID);
+               idx = 0;
+       }
+       dma->dsti = idx;
+       dma->dstu++;
+
+       if (!(dev->flags & HIFN_FLAG_DST_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_DST_BUSY;
+       }
+}
+
+static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff,
+               struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv,
+               struct hifn_context *ctx)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int cmd_len, sa_idx;
+       u8 *buf, *buf_pos;
+       u16 mask;
+
+       dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n",
+                       dev->name, spage, soff, dpage, doff, nbytes, priv, ctx);
+
+       sa_idx = dma->resi;
+
+       hifn_setup_src_desc(dev, spage, soff, nbytes);
+
+       buf_pos = buf = dma->command_bufs[dma->cmdi];
+
+       mask = 0;
+       switch (ctx->op) {
+               case ACRYPTO_OP_DECRYPT:
+                       mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE;
+                       break;
+               case ACRYPTO_OP_ENCRYPT:
+                       mask = HIFN_BASE_CMD_CRYPT;
+                       break;
+               case ACRYPTO_OP_HMAC:
+                       mask = HIFN_BASE_CMD_MAC;
+                       break;
+               default:
+                       goto err_out;
+       }
+
+       buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes,
+                       nbytes, mask, dev->snum);
+
+       if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) {
+               u16 md = 0;
+
+               if (ctx->keysize)
+                       md |= HIFN_CRYPT_CMD_NEW_KEY;
+               if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB)
+                       md |= HIFN_CRYPT_CMD_NEW_IV;
+
+               switch (ctx->mode) {
+                       case ACRYPTO_MODE_ECB:
+                               md |= HIFN_CRYPT_CMD_MODE_ECB;
+                               break;
+                       case ACRYPTO_MODE_CBC:
+                               md |= HIFN_CRYPT_CMD_MODE_CBC;
+                               break;
+                       case ACRYPTO_MODE_CFB:
+                               md |= HIFN_CRYPT_CMD_MODE_CFB;
+                               break;
+                       case ACRYPTO_MODE_OFB:
+                               md |= HIFN_CRYPT_CMD_MODE_OFB;
+                               break;
+                       default:
+                               goto err_out;
+               }
+
+               switch (ctx->type) {
+                       case ACRYPTO_TYPE_AES_128:
+                               if (ctx->keysize != 16)
+                                       goto err_out;
+                               md |= HIFN_CRYPT_CMD_KSZ_128 |
+                                       HIFN_CRYPT_CMD_ALG_AES;
+                               break;
+                       case ACRYPTO_TYPE_AES_192:
+                               if (ctx->keysize != 24)
+                                       goto err_out;
+                               md |= HIFN_CRYPT_CMD_KSZ_192 |
+                                       HIFN_CRYPT_CMD_ALG_AES;
+                               break;
+                       case ACRYPTO_TYPE_AES_256:
+                               if (ctx->keysize != 32)
+                                       goto err_out;
+                               md |= HIFN_CRYPT_CMD_KSZ_256 |
+                                       HIFN_CRYPT_CMD_ALG_AES;
+                               break;
+                       case ACRYPTO_TYPE_3DES:
+                               if (ctx->keysize != 24)
+                                       goto err_out;
+                               md |= HIFN_CRYPT_CMD_ALG_3DES;
+                               break;
+                       case ACRYPTO_TYPE_DES:
+                               if (ctx->keysize != 8)
+                                       goto err_out;
+                               md |= HIFN_CRYPT_CMD_ALG_DES;
+                               break;
+                       default:
+                               goto err_out;
+               }
+
+               buf_pos += hifn_setup_crypto_command(dev, buf_pos,
+                               nbytes, nbytes, ctx->key, ctx->keysize,
+                               ctx->iv, ctx->ivsize, md);
+       }
+
+       dev->sa[sa_idx] = priv;
+
+       cmd_len = buf_pos - buf;
+       dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID |
+                       HIFN_D_LAST | HIFN_D_MASKDONEIRQ);
+
+       if (++dma->cmdi == HIFN_D_CMD_RSIZE) {
+               dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND |
+                       HIFN_D_VALID | HIFN_D_LAST |
+                       HIFN_D_MASKDONEIRQ | HIFN_D_JUMP);
+               dma->cmdi = 0;
+       } else
+               dma->cmdr[dma->cmdi-1].l |= __cpu_to_le32(HIFN_D_VALID);
+
+       if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_CMD_BUSY;
+       }
+
+       hifn_setup_dst_desc(dev, dpage, doff, nbytes);
+       hifn_setup_res_desc(dev);
+
+       return 0;
+
+err_out:
+       return -EINVAL;
+}
+
+static int ablkcipher_walk_init(struct ablkcipher_walk *w,
+               int num, gfp_t gfp_flags)
+{
+       int i;
+
+       num = min(ASYNC_SCATTERLIST_CACHE, num);
+       sg_init_table(w->cache, num);
+
+       w->num = 0;
+       for (i=0; i<num; ++i) {
+               struct page *page = alloc_page(gfp_flags);
+               struct scatterlist *s;
+
+               if (!page)
+                       break;
+
+               s = &w->cache[i];
+
+               sg_set_page(s, page, PAGE_SIZE, 0);
+               w->num++;
+       }
+
+       return i;
+}
+
+static void ablkcipher_walk_exit(struct ablkcipher_walk *w)
+{
+       int i;
+
+       for (i=0; i<w->num; ++i) {
+               struct scatterlist *s = &w->cache[i];
+
+               __free_page(sg_page(s));
+
+               s->length = 0;
+       }
+
+       w->num = 0;
+}
+
+static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src,
+               unsigned int size, unsigned int *nbytesp)
+{
+       unsigned int copy, drest = *drestp, nbytes = *nbytesp;
+       int idx = 0;
+       void *saddr;
+
+       if (drest < size || size > nbytes)
+               return -EINVAL;
+
+       while (size) {
+               copy = min(drest, src->length);
+
+               saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1);
+               memcpy(daddr, saddr + src->offset, copy);
+               kunmap_atomic(saddr, KM_SOFTIRQ1);
+
+               size -= copy;
+               drest -= copy;
+               nbytes -= copy;
+               daddr += copy;
+
+               dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n",
+                               __func__, copy, size, drest, nbytes);
+
+               src++;
+               idx++;
+       }
+
+       *nbytesp = nbytes;
+       *drestp = drest;
+
+       return idx;
+}
+
+static int ablkcipher_walk(struct ablkcipher_request *req,
+               struct ablkcipher_walk *w)
+{
+       unsigned blocksize =
+               crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
+       unsigned alignmask =
+               crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
+       struct scatterlist *src, *dst, *t;
+       void *daddr;
+       unsigned int nbytes = req->nbytes, offset, copy, diff;
+       int idx, tidx, err;
+
+       tidx = idx = 0;
+       offset = 0;
+       while (nbytes) {
+               if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED))
+                       return -EINVAL;
+
+               src = &req->src[idx];
+               dst = &req->dst[idx];
+
+               dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, "
+                               "blocksize: %u, nbytes: %u.\n",
+                               __func__, src->length, dst->length, src->offset,
+                               dst->offset, offset, blocksize, nbytes);
+
+               if (src->length & (blocksize - 1) ||
+                               src->offset & (alignmask - 1) ||
+                               dst->length & (blocksize - 1) ||
+                               dst->offset & (alignmask - 1) ||
+                               offset) {
+                       unsigned slen = src->length - offset;
+                       unsigned dlen = PAGE_SIZE;
+
+                       t = &w->cache[idx];
+
+                       daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0);
+                       err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes);
+                       if (err < 0)
+                               goto err_out_unmap;
+
+                       idx += err;
+
+                       copy = slen & ~(blocksize - 1);
+                       diff = slen & (blocksize - 1);
+
+                       if (dlen < nbytes) {
+                               /*
+                                * Destination page does not have enough space
+                                * to put there additional blocksized chunk,
+                                * so we mark that page as containing only
+                                * blocksize aligned chunks:
+                                *      t->length = (slen & ~(blocksize - 1));
+                                * and increase number of bytes to be processed
+                                * in next chunk:
+                                *      nbytes += diff;
+                                */
+                               nbytes += diff;
+
+                               /*
+                                * Temporary of course...
+                                * Kick author if you will catch this one.
+                                */
+                               printk(KERN_ERR "%s: dlen: %u, nbytes: %u,"
+                                       "slen: %u, offset: %u.\n",
+                                       __func__, dlen, nbytes, slen, offset);
+                               printk(KERN_ERR "%s: please contact author to fix this "
+                                       "issue, generally you should not catch "
+                                       "this path under any condition but who "
+                                       "knows how did you use crypto code.\n"
+                                       "Thank you.\n", __func__);
+                               BUG();
+                       } else {
+                               copy += diff + nbytes;
+
+                               src = &req->src[idx];
+
+                               err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes);
+                               if (err < 0)
+                                       goto err_out_unmap;
+
+                               idx += err;
+                       }
+
+                       t->length = copy;
+                       t->offset = offset;
+
+                       kunmap_atomic(daddr, KM_SOFTIRQ0);
+               } else {
+                       nbytes -= src->length;
+                       idx++;
+               }
+
+               tidx++;
+       }
+
+       return tidx;
+
+err_out_unmap:
+       kunmap_atomic(daddr, KM_SOFTIRQ0);
+       return err;
+}
+
+static int hifn_setup_session(struct ablkcipher_request *req)
+{
+       struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+       struct hifn_device *dev = ctx->dev;
+       struct page *spage, *dpage;
+       unsigned long soff, doff, flags;
+       unsigned int nbytes = req->nbytes, idx = 0, len;
+       int err = -EINVAL, sg_num;
+       struct scatterlist *src, *dst, *t;
+       unsigned blocksize =
+               crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
+       unsigned alignmask =
+               crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
+
+       if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB)
+               goto err_out_exit;
+
+       ctx->walk.flags = 0;
+
+       while (nbytes) {
+               src = &req->src[idx];
+               dst = &req->dst[idx];
+
+               if (src->length & (blocksize - 1) ||
+                               src->offset & (alignmask - 1) ||
+                               dst->length & (blocksize - 1) ||
+                               dst->offset & (alignmask - 1)) {
+                       ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED;
+               }
+
+               nbytes -= src->length;
+               idx++;
+       }
+
+       if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+               err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC);
+               if (err < 0)
+                       return err;
+       }
+
+       nbytes = req->nbytes;
+       idx = 0;
+
+       sg_num = ablkcipher_walk(req, &ctx->walk);
+
+       atomic_set(&ctx->sg_num, sg_num);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->started + sg_num > HIFN_QUEUE_LENGTH) {
+               err = -EAGAIN;
+               goto err_out;
+       }
+
+       dev->snum++;
+       dev->started += sg_num;
+
+       while (nbytes) {
+               src = &req->src[idx];
+               dst = &req->dst[idx];
+               t = &ctx->walk.cache[idx];
+
+               if (t->length) {
+                       spage = dpage = sg_page(t);
+                       soff = doff = 0;
+                       len = t->length;
+               } else {
+                       spage = sg_page(src);
+                       soff = src->offset;
+
+                       dpage = sg_page(dst);
+                       doff = dst->offset;
+
+                       len = dst->length;
+               }
+
+               idx++;
+
+               err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes,
+                               req, ctx);
+               if (err)
+                       goto err_out;
+
+               nbytes -= len;
+       }
+
+       dev->active = HIFN_DEFAULT_ACTIVE_NUM;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+
+err_out:
+       spin_unlock_irqrestore(&dev->lock, flags);
+err_out_exit:
+       if (err && printk_ratelimit())
+               dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
+                               "type: %u, err: %d.\n",
+                       dev->name, ctx->iv, ctx->ivsize,
+                       ctx->key, ctx->keysize,
+                       ctx->mode, ctx->op, ctx->type, err);
+
+       return err;
+}
+
+static int hifn_test(struct hifn_device *dev, int encdec, u8 snum)
+{
+       int n, err;
+       u8 src[16];
+       struct hifn_context ctx;
+       u8 fips_aes_ecb_from_zero[16] = {
+               0x66, 0xE9, 0x4B, 0xD4,
+               0xEF, 0x8A, 0x2C, 0x3B,
+               0x88, 0x4C, 0xFA, 0x59,
+               0xCA, 0x34, 0x2B, 0x2E};
+
+       memset(src, 0, sizeof(src));
+       memset(ctx.key, 0, sizeof(ctx.key));
+
+       ctx.dev = dev;
+       ctx.keysize = 16;
+       ctx.ivsize = 0;
+       ctx.iv = NULL;
+       ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT;
+       ctx.mode = ACRYPTO_MODE_ECB;
+       ctx.type = ACRYPTO_TYPE_AES_128;
+       atomic_set(&ctx.sg_num, 1);
+
+       err = hifn_setup_dma(dev,
+                       virt_to_page(src), offset_in_page(src),
+                       virt_to_page(src), offset_in_page(src),
+                       sizeof(src), NULL, &ctx);
+       if (err)
+               goto err_out;
+
+       msleep(200);
+
+       dprintk("%s: decoded: ", dev->name);
+       for (n=0; n<sizeof(src); ++n)
+               dprintk("%02x ", src[n]);
+       dprintk("\n");
+       dprintk("%s: FIPS   : ", dev->name);
+       for (n=0; n<sizeof(fips_aes_ecb_from_zero); ++n)
+               dprintk("%02x ", fips_aes_ecb_from_zero[n]);
+       dprintk("\n");
+
+       if (!memcmp(src, fips_aes_ecb_from_zero, sizeof(fips_aes_ecb_from_zero))) {
+               printk(KERN_INFO "%s: AES 128 ECB test has been successfully "
+                               "passed.\n", dev->name);
+               return 0;
+       }
+
+err_out:
+       printk(KERN_INFO "%s: AES 128 ECB test has been failed.\n", dev->name);
+       return -1;
+}
+
+static int hifn_start_device(struct hifn_device *dev)
+{
+       int err;
+
+       hifn_reset_dma(dev, 1);
+
+       err = hifn_enable_crypto(dev);
+       if (err)
+               return err;
+
+       hifn_reset_puc(dev);
+
+       hifn_init_dma(dev);
+
+       hifn_init_registers(dev);
+
+       hifn_init_pubrng(dev);
+
+       return 0;
+}
+
+static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset,
+               struct scatterlist *dst, unsigned int size, unsigned int *nbytesp)
+{
+       unsigned int srest = *srestp, nbytes = *nbytesp, copy;
+       void *daddr;
+       int idx = 0;
+
+       if (srest < size || size > nbytes)
+               return -EINVAL;
+
+       while (size) {
+
+               copy = min(dst->length, srest);
+
+               daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
+               memcpy(daddr + dst->offset + offset, saddr, copy);
+               kunmap_atomic(daddr, KM_IRQ0);
+
+               nbytes -= copy;
+               size -= copy;
+               srest -= copy;
+               saddr += copy;
+               offset = 0;
+
+               dprintk("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n",
+                               __func__, copy, size, srest, nbytes);
+
+               dst++;
+               idx++;
+       }
+
+       *nbytesp = nbytes;
+       *srestp = srest;
+
+       return idx;
+}
+
+static void hifn_process_ready(struct ablkcipher_request *req, int error)
+{
+       struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+       struct hifn_device *dev;
+
+       dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx);
+
+       dev = ctx->dev;
+       dprintk("%s: req: %p, started: %d, sg_num: %d.\n",
+               __func__, req, dev->started, atomic_read(&ctx->sg_num));
+
+       if (--dev->started < 0)
+               BUG();
+
+       if (atomic_dec_and_test(&ctx->sg_num)) {
+               unsigned int nbytes = req->nbytes;
+               int idx = 0, err;
+               struct scatterlist *dst, *t;
+               void *saddr;
+
+               if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+                       while (nbytes) {
+                               t = &ctx->walk.cache[idx];
+                               dst = &req->dst[idx];
+
+                               dprintk("\n%s: sg_page(t): %p, t->length: %u, "
+                                       "sg_page(dst): %p, dst->length: %u, "
+                                       "nbytes: %u.\n",
+                                       __func__, sg_page(t), t->length,
+                                       sg_page(dst), dst->length, nbytes);
+
+                               if (!t->length) {
+                                       nbytes -= dst->length;
+                                       idx++;
+                                       continue;
+                               }
+
+                               saddr = kmap_atomic(sg_page(t), KM_IRQ1);
+
+                               err = ablkcipher_get(saddr, &t->length, t->offset,
+                                               dst, nbytes, &nbytes);
+                               if (err < 0) {
+                                       kunmap_atomic(saddr, KM_IRQ1);
+                                       break;
+                               }
+
+                               idx += err;
+                               kunmap_atomic(saddr, KM_IRQ1);
+                       }
+
+                       ablkcipher_walk_exit(&ctx->walk);
+               }
+
+               req->base.complete(&req->base, error);
+       }
+}
+
+static void hifn_check_for_completion(struct hifn_device *dev, int error)
+{
+       int i;
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+       for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+               struct hifn_desc *d = &dma->resr[i];
+
+               if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) {
+                       dev->success++;
+                       dev->reset = 0;
+                       hifn_process_ready(dev->sa[i], error);
+                       dev->sa[i] = NULL;
+               }
+
+               if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER))
+                       if (printk_ratelimit())
+                               printk("%s: overflow detected [d: %u, o: %u] "
+                                               "at %d resr: l: %08x, p: %08x.\n",
+                                       dev->name,
+                                       !!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)),
+                                       !!(d->l & __cpu_to_le32(HIFN_D_OVER)),
+                                       i, d->l, d->p);
+       }
+}
+
+static void hifn_clear_rings(struct hifn_device *dev)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int i, u;
+
+       dprintk("%s: ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, "
+                       "k: %d.%d.%d.%d.\n",
+                       dev->name,
+                       dma->cmdi, dma->srci, dma->dsti, dma->resi,
+                       dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+                       dma->cmdk, dma->srck, dma->dstk, dma->resk);
+
+       i = dma->resk; u = dma->resu;
+       while (u != 0) {
+               if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID))
+                       break;
+
+               if (i != HIFN_D_RES_RSIZE)
+                       u--;
+
+               if (++i == (HIFN_D_RES_RSIZE + 1))
+                       i = 0;
+       }
+       dma->resk = i; dma->resu = u;
+
+       i = dma->srck; u = dma->srcu;
+       while (u != 0) {
+               if (i == HIFN_D_SRC_RSIZE)
+                       i = 0;
+               if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID))
+                       break;
+               i++, u--;
+       }
+       dma->srck = i; dma->srcu = u;
+
+       i = dma->cmdk; u = dma->cmdu;
+       while (u != 0) {
+               if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID))
+                       break;
+               if (i != HIFN_D_CMD_RSIZE)
+                       u--;
+               if (++i == (HIFN_D_CMD_RSIZE + 1))
+                       i = 0;
+       }
+       dma->cmdk = i; dma->cmdu = u;
+
+       i = dma->dstk; u = dma->dstu;
+       while (u != 0) {
+               if (i == HIFN_D_DST_RSIZE)
+                       i = 0;
+               if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID))
+                       break;
+               i++, u--;
+       }
+       dma->dstk = i; dma->dstu = u;
+
+       dprintk("%s: ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, "
+                       "k: %d.%d.%d.%d.\n",
+                       dev->name,
+                       dma->cmdi, dma->srci, dma->dsti, dma->resi,
+                       dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+                       dma->cmdk, dma->srck, dma->dstk, dma->resk);
+}
+
+static void hifn_work(struct work_struct *work)
+{
+       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct hifn_device *dev = container_of(dw, struct hifn_device, work);
+       unsigned long flags;
+       int reset = 0;
+       u32 r = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->active == 0) {
+               struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+               if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) {
+                       dev->flags &= ~HIFN_FLAG_CMD_BUSY;
+                       r |= HIFN_DMACSR_C_CTRL_DIS;
+               }
+               if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) {
+                       dev->flags &= ~HIFN_FLAG_SRC_BUSY;
+                       r |= HIFN_DMACSR_S_CTRL_DIS;
+               }
+               if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) {
+                       dev->flags &= ~HIFN_FLAG_DST_BUSY;
+                       r |= HIFN_DMACSR_D_CTRL_DIS;
+               }
+               if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) {
+                       dev->flags &= ~HIFN_FLAG_RES_BUSY;
+                       r |= HIFN_DMACSR_R_CTRL_DIS;
+               }
+               if (r)
+                       hifn_write_1(dev, HIFN_1_DMA_CSR, r);
+       } else
+               dev->active--;
+
+       if (dev->prev_success == dev->success && dev->started)
+               reset = 1;
+       dev->prev_success = dev->success;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (reset) {
+               dprintk("%s: r: %08x, active: %d, started: %d, "
+                               "success: %lu: reset: %d.\n",
+                       dev->name, r, dev->active, dev->started,
+                       dev->success, reset);
+
+               if (++dev->reset >= 5) {
+                       dprintk("%s: really hard reset.\n", dev->name);
+                       hifn_reset_dma(dev, 1);
+                       hifn_stop_device(dev);
+                       hifn_start_device(dev);
+                       dev->reset = 0;
+               }
+
+               spin_lock_irqsave(&dev->lock, flags);
+               hifn_check_for_completion(dev, -EBUSY);
+               hifn_clear_rings(dev);
+               dev->started = 0;
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+
+       schedule_delayed_work(&dev->work, HZ);
+}
+
+static irqreturn_t hifn_interrupt(int irq, void *data)
+{
+       struct hifn_device *dev = (struct hifn_device *)data;
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       u32 dmacsr, restart;
+
+       dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR);
+
+       dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], "
+                       "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n",
+               dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi,
+               dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+               dma->cmdi, dma->srci, dma->dsti, dma->resi);
+
+       if ((dmacsr & dev->dmareg) == 0)
+               return IRQ_NONE;
+
+       hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg);
+
+       if (dmacsr & HIFN_DMACSR_ENGINE)
+               hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR));
+       if (dmacsr & HIFN_DMACSR_PUBDONE)
+               hifn_write_1(dev, HIFN_1_PUB_STATUS,
+                       hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE);
+
+       restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER);
+       if (restart) {
+               u32 puisr = hifn_read_0(dev, HIFN_0_PUISR);
+
+               if (printk_ratelimit())
+                       printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
+                               dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER),
+                               !!(dmacsr & HIFN_DMACSR_D_OVER),
+                               puisr, !!(puisr & HIFN_PUISR_DSTOVER));
+               if (!!(puisr & HIFN_PUISR_DSTOVER))
+                       hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
+               hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER |
+                                       HIFN_DMACSR_D_OVER));
+       }
+
+       restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
+                       HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
+       if (restart) {
+               if (printk_ratelimit())
+                       printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
+                               dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT),
+                               !!(dmacsr & HIFN_DMACSR_S_ABORT),
+                               !!(dmacsr & HIFN_DMACSR_D_ABORT),
+                               !!(dmacsr & HIFN_DMACSR_R_ABORT));
+               hifn_reset_dma(dev, 1);
+               hifn_init_dma(dev);
+               hifn_init_registers(dev);
+       }
+
+       if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) {
+               dprintk("%s: wait on command.\n", dev->name);
+               dev->dmareg &= ~(HIFN_DMAIER_C_WAIT);
+               hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+       }
+
+       tasklet_schedule(&dev->tasklet);
+       hifn_clear_rings(dev);
+
+       return IRQ_HANDLED;
+}
+
+static void hifn_flush(struct hifn_device *dev)
+{
+       unsigned long flags;
+       struct crypto_async_request *async_req;
+       struct hifn_context *ctx;
+       struct ablkcipher_request *req;
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int i;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+               struct hifn_desc *d = &dma->resr[i];
+
+               if (dev->sa[i]) {
+                       hifn_process_ready(dev->sa[i],
+                               (d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0);
+               }
+       }
+
+       while ((async_req = crypto_dequeue_request(&dev->queue))) {
+               ctx = crypto_tfm_ctx(async_req->tfm);
+               req = container_of(async_req, struct ablkcipher_request, base);
+
+               hifn_process_ready(req, -ENODEV);
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static int hifn_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
+               unsigned int len)
+{
+       struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+       struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+       struct hifn_device *dev = ctx->dev;
+
+       if (len > HIFN_MAX_CRYPT_KEY_LENGTH) {
+               crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -1;
+       }
+
+       if (len == HIFN_DES_KEY_LENGTH) {
+               u32 tmp[DES_EXPKEY_WORDS];
+               int ret = des_ekey(tmp, key);
+               
+               if (unlikely(ret == 0) && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+                       tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
+                       return -EINVAL;
+               }
+       }
+
+       dev->flags &= ~HIFN_FLAG_OLD_KEY;
+
+       memcpy(ctx->key, key, len);
+       ctx->keysize = len;
+
+       return 0;
+}
+
+static int hifn_handle_req(struct ablkcipher_request *req)
+{
+       struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+       struct hifn_device *dev = ctx->dev;
+       int err = -EAGAIN;
+
+       if (dev->started + DIV_ROUND_UP(req->nbytes, PAGE_SIZE) <= HIFN_QUEUE_LENGTH)
+               err = hifn_setup_session(req);
+
+       if (err == -EAGAIN) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&dev->lock, flags);
+               err = ablkcipher_enqueue_request(&dev->queue, req);
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+
+       return err;
+}
+
+static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op,
+               u8 type, u8 mode)
+{
+       struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+       unsigned ivsize;
+
+       ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req));
+
+       if (req->info && mode != ACRYPTO_MODE_ECB) {
+               if (type == ACRYPTO_TYPE_AES_128)
+                       ivsize = HIFN_AES_IV_LENGTH;
+               else if (type == ACRYPTO_TYPE_DES)
+                       ivsize = HIFN_DES_KEY_LENGTH;
+               else if (type == ACRYPTO_TYPE_3DES)
+                       ivsize = HIFN_3DES_KEY_LENGTH;
+       }
+
+       if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) {
+               if (ctx->keysize == 24)
+                       type = ACRYPTO_TYPE_AES_192;
+               else if (ctx->keysize == 32)
+                       type = ACRYPTO_TYPE_AES_256;
+       }
+
+       ctx->op = op;
+       ctx->mode = mode;
+       ctx->type = type;
+       ctx->iv = req->info;
+       ctx->ivsize = ivsize;
+
+       /*
+        * HEAVY TODO: needs to kick Herbert XU to write documentation.
+        * HEAVY TODO: needs to kick Herbert XU to write documentation.
+        * HEAVY TODO: needs to kick Herbert XU to write documentation.
+        */
+
+       return hifn_handle_req(req);
+}
+
+static int hifn_process_queue(struct hifn_device *dev)
+{
+       struct crypto_async_request *async_req;
+       struct hifn_context *ctx;
+       struct ablkcipher_request *req;
+       unsigned long flags;
+       int err = 0;
+
+       while (dev->started < HIFN_QUEUE_LENGTH) {
+               spin_lock_irqsave(&dev->lock, flags);
+               async_req = crypto_dequeue_request(&dev->queue);
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               if (!async_req)
+                       break;
+
+               ctx = crypto_tfm_ctx(async_req->tfm);
+               req = container_of(async_req, struct ablkcipher_request, base);
+
+               err = hifn_handle_req(req);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op,
+               u8 type, u8 mode)
+{
+       int err;
+       struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+       struct hifn_device *dev = ctx->dev;
+
+       err = hifn_setup_crypto_req(req, op, type, mode);
+       if (err)
+               return err;
+
+       if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen)
+               err = hifn_process_queue(dev);
+
+       return err;
+}
+
+/*
+ * AES ecryption functions.
+ */
+static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * AES decryption functions.
+ */
+static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * DES ecryption functions.
+ */
+static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * DES decryption functions.
+ */
+static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * 3DES ecryption functions.
+ */
+static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * 3DES decryption functions.
+ */
+static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req)
+{
+       return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+                       ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
+}
+
+struct hifn_alg_template
+{
+       char name[CRYPTO_MAX_ALG_NAME];
+       char drv_name[CRYPTO_MAX_ALG_NAME];
+       unsigned int bsize;
+       struct ablkcipher_alg ablkcipher;
+};
+
+static struct hifn_alg_template hifn_alg_templates[] = {
+       /*
+        * 3DES ECB, CBC, CFB and OFB modes.
+        */
+       {
+               .name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_3des_cfb,
+                       .decrypt        =       hifn_decrypt_3des_cfb,
+               },
+       },
+       {
+               .name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_3des_ofb,
+                       .decrypt        =       hifn_decrypt_3des_ofb,
+               },
+       },
+       {
+               .name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_3des_cbc,
+                       .decrypt        =       hifn_decrypt_3des_cbc,
+               },
+       },
+       {
+               .name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_3DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_3des_ecb,
+                       .decrypt        =       hifn_decrypt_3des_ecb,
+               },
+       },
+
+       /*
+        * DES ECB, CBC, CFB and OFB modes.
+        */
+       {
+               .name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_des_cfb,
+                       .decrypt        =       hifn_decrypt_des_cfb,
+               },
+       },
+       {
+               .name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_des_ofb,
+                       .decrypt        =       hifn_decrypt_des_ofb,
+               },
+       },
+       {
+               .name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_des_cbc,
+                       .decrypt        =       hifn_decrypt_des_cbc,
+               },
+       },
+       {
+               .name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8,
+               .ablkcipher = {
+                       .min_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .max_keysize    =       HIFN_DES_KEY_LENGTH,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_des_ecb,
+                       .decrypt        =       hifn_decrypt_des_ecb,
+               },
+       },
+
+       /*
+        * AES ECB, CBC, CFB and OFB modes.
+        */
+       {
+               .name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .ablkcipher = {
+                       .min_keysize    =       AES_MIN_KEY_SIZE,
+                       .max_keysize    =       AES_MAX_KEY_SIZE,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_aes_ecb,
+                       .decrypt        =       hifn_decrypt_aes_ecb,
+               },
+       },
+       {
+               .name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .ablkcipher = {
+                       .min_keysize    =       AES_MIN_KEY_SIZE,
+                       .max_keysize    =       AES_MAX_KEY_SIZE,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_aes_cbc,
+                       .decrypt        =       hifn_decrypt_aes_cbc,
+               },
+       },
+       {
+               .name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .ablkcipher = {
+                       .min_keysize    =       AES_MIN_KEY_SIZE,
+                       .max_keysize    =       AES_MAX_KEY_SIZE,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_aes_cfb,
+                       .decrypt        =       hifn_decrypt_aes_cfb,
+               },
+       },
+       {
+               .name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .ablkcipher = {
+                       .min_keysize    =       AES_MIN_KEY_SIZE,
+                       .max_keysize    =       AES_MAX_KEY_SIZE,
+                       .setkey         =       hifn_setkey,
+                       .encrypt        =       hifn_encrypt_aes_ofb,
+                       .decrypt        =       hifn_decrypt_aes_ofb,
+               },
+       },
+};
+
+static int hifn_cra_init(struct crypto_tfm *tfm)
+{
+       struct crypto_alg *alg = tfm->__crt_alg;
+       struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg);
+       struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->dev = ha->dev;
+
+       return 0;
+}
+
+static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
+{
+       struct hifn_crypto_alg *alg;
+       int err;
+
+       alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL);
+       if (!alg)
+               return -ENOMEM;
+
+       snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name);
+       snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name);
+
+       alg->alg.cra_priority = 300;
+       alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+       alg->alg.cra_blocksize = t->bsize;
+       alg->alg.cra_ctxsize = sizeof(struct hifn_context);
+       alg->alg.cra_alignmask = 15;
+       if (t->bsize == 8)
+               alg->alg.cra_alignmask = 3;
+       alg->alg.cra_type = &crypto_ablkcipher_type;
+       alg->alg.cra_module = THIS_MODULE;
+       alg->alg.cra_u.ablkcipher = t->ablkcipher;
+       alg->alg.cra_init = hifn_cra_init;
+
+       alg->dev = dev;
+
+       list_add_tail(&alg->entry, &dev->alg_list);
+
+       err = crypto_register_alg(&alg->alg);
+       if (err) {
+               list_del(&alg->entry);
+               kfree(alg);
+       }
+
+       return err;
+}
+
+static void hifn_unregister_alg(struct hifn_device *dev)
+{
+       struct hifn_crypto_alg *a, *n;
+
+       list_for_each_entry_safe(a, n, &dev->alg_list, entry) {
+               list_del(&a->entry);
+               crypto_unregister_alg(&a->alg);
+               kfree(a);
+       }
+}
+
+static int hifn_register_alg(struct hifn_device *dev)
+{
+       int i, err;
+
+       for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) {
+               err = hifn_alg_alloc(dev, &hifn_alg_templates[i]);
+               if (err)
+                       goto err_out_exit;
+       }
+
+       return 0;
+
+err_out_exit:
+       hifn_unregister_alg(dev);
+       return err;
+}
+
+static void hifn_tasklet_callback(unsigned long data)
+{
+       struct hifn_device *dev = (struct hifn_device *)data;
+
+       /*
+        * This is ok to call this without lock being held,
+        * althogh it modifies some parameters used in parallel,
+        * (like dev->success), but they are used in process
+        * context or update is atomic (like setting dev->sa[i] to NULL).
+        */
+       hifn_check_for_completion(dev, 0);
+}
+
+static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       int err, i;
+       struct hifn_device *dev;
+       char name[8];
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+       pci_set_master(pdev);
+
+       err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (err)
+               goto err_out_disable_pci_device;
+
+       snprintf(name, sizeof(name), "hifn%d",
+                       atomic_inc_return(&hifn_dev_number)-1);
+
+       err = pci_request_regions(pdev, name);
+       if (err)
+               goto err_out_disable_pci_device;
+
+       if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE ||
+           pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE ||
+           pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) {
+               dprintk("%s: Broken hardware - I/O regions are too small.\n",
+                               pci_name(pdev));
+               err = -ENODEV;
+               goto err_out_free_regions;
+       }
+
+       dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg),
+                       GFP_KERNEL);
+       if (!dev) {
+               err = -ENOMEM;
+               goto err_out_free_regions;
+       }
+
+       INIT_LIST_HEAD(&dev->alg_list);
+
+       snprintf(dev->name, sizeof(dev->name), "%s", name);
+       spin_lock_init(&dev->lock);
+
+       for (i=0; i<3; ++i) {
+               unsigned long addr, size;
+
+               addr = pci_resource_start(pdev, i);
+               size = pci_resource_len(pdev, i);
+
+               dev->bar[i] = ioremap_nocache(addr, size);
+               if (!dev->bar[i])
+                       goto err_out_unmap_bars;
+       }
+
+       dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER);
+       if (!dev->result_mem) {
+               dprintk("Failed to allocate %d pages for result_mem.\n",
+                               HIFN_MAX_RESULT_ORDER);
+               goto err_out_unmap_bars;
+       }
+       memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER));
+
+       dev->dst = pci_map_single(pdev, (void *)dev->result_mem,
+                       PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE);
+
+       dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma),
+                       &dev->desc_dma);
+       if (!dev->desc_virt) {
+               dprintk("Failed to allocate descriptor rings.\n");
+               goto err_out_free_result_pages;
+       }
+       memset(dev->desc_virt, 0, sizeof(struct hifn_dma));
+
+       dev->pdev = pdev;
+       dev->irq = pdev->irq;
+
+       for (i=0; i<HIFN_D_RES_RSIZE; ++i)
+               dev->sa[i] = NULL;
+
+       pci_set_drvdata(pdev, dev);
+
+       tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
+
+       crypto_init_queue(&dev->queue, 1);
+
+       err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
+       if (err) {
+               dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err);
+               dev->irq = 0;
+               goto err_out_free_desc;
+       }
+
+       err = hifn_start_device(dev);
+       if (err)
+               goto err_out_free_irq;
+
+       err = hifn_test(dev, 1, 0);
+       if (err)
+               goto err_out_stop_device;
+
+       err = hifn_register_rng(dev);
+       if (err)
+               goto err_out_stop_device;
+
+       err = hifn_register_alg(dev);
+       if (err)
+               goto err_out_unregister_rng;
+
+       INIT_DELAYED_WORK(&dev->work, hifn_work);
+       schedule_delayed_work(&dev->work, HZ);
+
+       dprintk("HIFN crypto accelerator card at %s has been "
+                       "successfully registered as %s.\n",
+                       pci_name(pdev), dev->name);
+
+       return 0;
+
+err_out_unregister_rng:
+       hifn_unregister_rng(dev);
+err_out_stop_device:
+       hifn_reset_dma(dev, 1);
+       hifn_stop_device(dev);
+err_out_free_irq:
+       free_irq(dev->irq, dev->name);
+       tasklet_kill(&dev->tasklet);
+err_out_free_desc:
+       pci_free_consistent(pdev, sizeof(struct hifn_dma),
+                       dev->desc_virt, dev->desc_dma);
+
+err_out_free_result_pages:
+       pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
+                       PCI_DMA_FROMDEVICE);
+       free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+
+err_out_unmap_bars:
+       for (i=0; i<3; ++i)
+               if (dev->bar[i])
+                       iounmap(dev->bar[i]);
+
+err_out_free_regions:
+       pci_release_regions(pdev);
+
+err_out_disable_pci_device:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void hifn_remove(struct pci_dev *pdev)
+{
+       int i;
+       struct hifn_device *dev;
+
+       dev = pci_get_drvdata(pdev);
+
+       if (dev) {
+               cancel_delayed_work(&dev->work);
+               flush_scheduled_work();
+
+               hifn_unregister_rng(dev);
+               hifn_unregister_alg(dev);
+               hifn_reset_dma(dev, 1);
+               hifn_stop_device(dev);
+
+               free_irq(dev->irq, dev->name);
+               tasklet_kill(&dev->tasklet);
+
+               hifn_flush(dev);
+
+               pci_free_consistent(pdev, sizeof(struct hifn_dma),
+                               dev->desc_virt, dev->desc_dma);
+               pci_unmap_single(pdev, dev->dst,
+                               PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
+                               PCI_DMA_FROMDEVICE);
+               free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+               for (i=0; i<3; ++i)
+                       if (dev->bar[i])
+                               iounmap(dev->bar[i]);
+
+               kfree(dev);
+       }
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id hifn_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) },
+       { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
+
+static struct pci_driver hifn_pci_driver = {
+       .name     = "hifn795x",
+       .id_table = hifn_pci_tbl,
+       .probe    = hifn_probe,
+       .remove   = __devexit_p(hifn_remove),
+};
+
+static int __devinit hifn_init(void)
+{
+       unsigned int freq;
+       int err;
+
+       if (strncmp(hifn_pll_ref, "ext", 3) &&
+           strncmp(hifn_pll_ref, "pci", 3)) {
+               printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
+                               "must be pci or ext");
+               return -EINVAL;
+       }
+
+       /*
+        * For the 7955/7956 the reference clock frequency must be in the
+        * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz,
+        * but this chip is currently not supported.
+        */
+       if (hifn_pll_ref[3] != '\0') {
+               freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
+               if (freq < 20 || freq > 100) {
+                       printk(KERN_ERR "hifn795x: invalid hifn_pll_ref "
+                                       "frequency, must be in the range "
+                                       "of 20-100");
+                       return -EINVAL;
+               }
+       }
+
+       err = pci_register_driver(&hifn_pci_driver);
+       if (err < 0) {
+               dprintk("Failed to register PCI driver for %s device.\n",
+                               hifn_pci_driver.name);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
+                       "has been successfully registered.\n");
+
+       return 0;
+}
+
+static void __devexit hifn_fini(void)
+{
+       pci_unregister_driver(&hifn_pci_driver);
+
+       printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
+                       "has been successfully unregistered.\n");
+}
+
+module_init(hifn_init);
+module_exit(hifn_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip.");
index a337b693b6c911d8a5e3604df96f0956b00fe696..2f3ad3f7dfea2229893864b7b31e9a3dfb5f61c6 100644 (file)
@@ -44,6 +44,7 @@
  */
 
 #include <crypto/algapi.h>
+#include <crypto/aes.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -53,9 +54,6 @@
 #include <asm/byteorder.h>
 #include "padlock.h"
 
-#define AES_MIN_KEY_SIZE       16      /* in uint8_t units */
-#define AES_MAX_KEY_SIZE       32      /* ditto */
-#define AES_BLOCK_SIZE         16      /* ditto */
 #define AES_EXTENDED_KEY_SIZE  64      /* in uint32_t units */
 #define AES_EXTENDED_KEY_SIZE_B        (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
 
@@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 /* ====== Encryption/decryption routines ====== */
 
 /* These are the real call to PadLock. */
+static inline void padlock_reset_key(void)
+{
+       asm volatile ("pushfl; popfl");
+}
+
 static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
                                  void *control_word)
 {
@@ -429,8 +432,8 @@ static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
 
 static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
 {
-       u8 tmp[AES_BLOCK_SIZE * 2]
-               __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
+       u8 buf[AES_BLOCK_SIZE * 2 + PADLOCK_ALIGNMENT - 1];
+       u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
 
        memcpy(tmp, in, AES_BLOCK_SIZE);
        padlock_xcrypt(tmp, out, key, cword);
@@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
 static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
                             struct cword *cword)
 {
-       asm volatile ("pushfl; popfl");
-
        /* padlock_xcrypt requires at least two blocks of data. */
        if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
                       (PAGE_SIZE - 1)))) {
@@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
                return;
        }
 
-       asm volatile ("pushfl; popfl");         /* enforce key reload. */
        asm volatile ("test $1, %%cl;"
                      "je 1f;"
                      "lea -1(%%ecx), %%eax;"
@@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
 static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
                                     u8 *iv, void *control_word, u32 count)
 {
-       /* Enforce key reload. */
-       asm volatile ("pushfl; popfl");
        /* rep xcryptcbc */
        asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
                      : "+S" (input), "+D" (output), "+a" (iv)
@@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        struct aes_ctx *ctx = aes_ctx(tfm);
+       padlock_reset_key();
        aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
 }
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
        struct aes_ctx *ctx = aes_ctx(tfm);
+       padlock_reset_key();
        aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
 }
 
@@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err;
 
+       padlock_reset_key();
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
 
@@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err;
 
+       padlock_reset_key();
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
 
@@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err;
 
+       padlock_reset_key();
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
 
@@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err;
 
+       padlock_reset_key();
+
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
 
index d59b2f417306f91af453962991c5c681aa20381b..bcf52df303390dbf775ea91cd9ab9e714f3f8178 100644 (file)
  * the definition of dma_event_callback in dmaengine.h.
  *
  * Each device has a kref, which is initialized to 1 when the device is
- * registered. A kref_get is done for each class_device registered.  When the
- * class_device is released, the coresponding kref_put is done in the release
+ * registered. A kref_get is done for each device registered.  When the
+ * device is released, the coresponding kref_put is done in the release
  * method. Every time one of the device's channels is allocated to a client,
  * a kref_get occurs.  When the channel is freed, the coresponding kref_put
  * happens. The device's release function does a completion, so
- * unregister_device does a remove event, class_device_unregister, a kref_put
+ * unregister_device does a remove event, device_unregister, a kref_put
  * for the first reference, then waits on the completion for all other
  * references to finish.
  *
@@ -77,9 +77,9 @@ static LIST_HEAD(dma_client_list);
 
 /* --- sysfs implementation --- */
 
-static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
+static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+       struct dma_chan *chan = to_dma_chan(dev);
        unsigned long count = 0;
        int i;
 
@@ -89,9 +89,10 @@ static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
        return sprintf(buf, "%lu\n", count);
 }
 
-static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
+static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
+                                     char *buf)
 {
-       struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+       struct dma_chan *chan = to_dma_chan(dev);
        unsigned long count = 0;
        int i;
 
@@ -101,9 +102,9 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
        return sprintf(buf, "%lu\n", count);
 }
 
-static ssize_t show_in_use(struct class_device *cd, char *buf)
+static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+       struct dma_chan *chan = to_dma_chan(dev);
        int in_use = 0;
 
        if (unlikely(chan->slow_ref) &&
@@ -119,7 +120,7 @@ static ssize_t show_in_use(struct class_device *cd, char *buf)
        return sprintf(buf, "%d\n", in_use);
 }
 
-static struct class_device_attribute dma_class_attrs[] = {
+static struct device_attribute dma_attrs[] = {
        __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
        __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
        __ATTR(in_use, S_IRUGO, show_in_use, NULL),
@@ -128,16 +129,16 @@ static struct class_device_attribute dma_class_attrs[] = {
 
 static void dma_async_device_cleanup(struct kref *kref);
 
-static void dma_class_dev_release(struct class_device *cd)
+static void dma_dev_release(struct device *dev)
 {
-       struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+       struct dma_chan *chan = to_dma_chan(dev);
        kref_put(&chan->device->refcount, dma_async_device_cleanup);
 }
 
 static struct class dma_devclass = {
-       .name            = "dma",
-       .class_dev_attrs = dma_class_attrs,
-       .release = dma_class_dev_release,
+       .name           = "dma",
+       .dev_attrs      = dma_attrs,
+       .dev_release    = dma_dev_release,
 };
 
 /* --- client and device registration --- */
@@ -377,12 +378,12 @@ int dma_async_device_register(struct dma_device *device)
                        continue;
 
                chan->chan_id = chancnt++;
-               chan->class_dev.class = &dma_devclass;
-               chan->class_dev.dev = NULL;
-               snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d",
+               chan->dev.class = &dma_devclass;
+               chan->dev.parent = NULL;
+               snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d",
                         device->dev_id, chan->chan_id);
 
-               rc = class_device_register(&chan->class_dev);
+               rc = device_register(&chan->dev);
                if (rc) {
                        chancnt--;
                        free_percpu(chan->local);
@@ -411,7 +412,7 @@ err_out:
                if (chan->local == NULL)
                        continue;
                kref_put(&device->refcount, dma_async_device_cleanup);
-               class_device_unregister(&chan->class_dev);
+               device_unregister(&chan->dev);
                chancnt--;
                free_percpu(chan->local);
        }
@@ -445,7 +446,7 @@ void dma_async_device_unregister(struct dma_device *device)
 
        list_for_each_entry(chan, &device->channels, device_node) {
                dma_clients_notify_removed(chan);
-               class_device_unregister(&chan->class_dev);
+               device_unregister(&chan->dev);
                dma_chan_release(chan);
        }
 
index 70b837f23c436f88d1c5d8be5d97bbf2745e3c6d..53764577035f3f23d0e073991d368f99b8225479 100644 (file)
@@ -246,16 +246,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 
        /* Init the devices's kobject */
        memset(&edac_dev->kobj, 0, sizeof(struct kobject));
-       edac_dev->kobj.ktype = &ktype_device_ctrl;
-
-       /* set this new device under the edac_class kobject */
-       edac_dev->kobj.parent = &edac_class->kset.kobj;
-
-       /* generate sysfs "..../edac/<name>"   */
-       debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
-       err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
-       if (err)
-               goto err_out;
 
        /* Record which module 'owns' this control structure
         * and bump the ref count of the module
@@ -268,12 +258,15 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
        }
 
        /* register */
-       err = kobject_register(&edac_dev->kobj);
+       err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
+                                  &edac_class->kset.kobj,
+                                  "%s", edac_dev->name);
        if (err) {
                debugf1("%s()Failed to register '.../edac/%s'\n",
                        __func__, edac_dev->name);
                goto err_kobj_reg;
        }
+       kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
 
        /* At this point, to 'free' the control struct,
         * edac_device_unregister_sysfs_main_kobj() must be used
@@ -310,7 +303,7 @@ void edac_device_unregister_sysfs_main_kobj(
         *   a) module_put() this module
         *   b) 'kfree' the memory
         */
-       kobject_unregister(&edac_dev->kobj);
+       kobject_put(&edac_dev->kobj);
 }
 
 /* edac_dev -> instance information */
@@ -533,12 +526,6 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 
        /* init this block's kobject */
        memset(&block->kobj, 0, sizeof(struct kobject));
-       block->kobj.parent = &instance->kobj;
-       block->kobj.ktype = &ktype_block_ctrl;
-
-       err = kobject_set_name(&block->kobj, "%s", block->name);
-       if (err)
-               return err;
 
        /* bump the main kobject's reference count for this controller
         * and this instance is dependant on the main
@@ -550,7 +537,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
        }
 
        /* Add this block's kobject */
-       err = kobject_register(&block->kobj);
+       err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl,
+                                  &instance->kobj,
+                                  "%s", block->name);
        if (err) {
                debugf1("%s() Failed to register instance '%s'\n",
                        __func__, block->name);
@@ -579,12 +568,13 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
                                goto err_on_attrib;
                }
        }
+       kobject_uevent(&block->kobj, KOBJ_ADD);
 
        return 0;
 
        /* Error unwind stack */
 err_on_attrib:
-       kobject_unregister(&block->kobj);
+       kobject_put(&block->kobj);
 
 err_out:
        return err;
@@ -615,7 +605,7 @@ static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
        /* unregister this block's kobject, SEE:
         *      edac_device_ctrl_block_release() callback operation
         */
-       kobject_unregister(&block->kobj);
+       kobject_put(&block->kobj);
 }
 
 /* instance ctor/dtor code */
@@ -637,15 +627,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
        /* Init the instance's kobject */
        memset(&instance->kobj, 0, sizeof(struct kobject));
 
-       /* set this new device under the edac_device main kobject */
-       instance->kobj.parent = &edac_dev->kobj;
-       instance->kobj.ktype = &ktype_instance_ctrl;
        instance->ctl = edac_dev;
 
-       err = kobject_set_name(&instance->kobj, "%s", instance->name);
-       if (err)
-               goto err_out;
-
        /* bump the main kobject's reference count for this controller
         * and this instance is dependant on the main
         */
@@ -655,8 +638,9 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
                goto err_out;
        }
 
-       /* Formally register this instance's kobject */
-       err = kobject_register(&instance->kobj);
+       /* Formally register this instance's kobject under the edac_device */
+       err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
+                                  &edac_dev->kobj, "%s", instance->name);
        if (err != 0) {
                debugf2("%s() Failed to register instance '%s'\n",
                        __func__, instance->name);
@@ -679,6 +663,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
                        goto err_release_instance_kobj;
                }
        }
+       kobject_uevent(&instance->kobj, KOBJ_ADD);
 
        debugf4("%s() Registered instance %d '%s' kobject\n",
                __func__, idx, instance->name);
@@ -687,7 +672,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 
        /* error unwind stack */
 err_release_instance_kobj:
-       kobject_unregister(&instance->kobj);
+       kobject_put(&instance->kobj);
 
 err_out:
        return err;
@@ -712,7 +697,7 @@ static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
        /* unregister this instance's kobject, SEE:
         *      edac_device_ctrl_instance_release() for callback operation
         */
-       kobject_unregister(&instance->kobj);
+       kobject_put(&instance->kobj);
 }
 
 /*
index 3706b2bc0987f8a5a22cc5784054dce95bf17973..9aac88027fb31f8a7398fa33173c396983fd7ad2 100644 (file)
@@ -380,13 +380,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
        /* generate ..../edac/mc/mc<id>/csrow<index>   */
        memset(&csrow->kobj, 0, sizeof(csrow->kobj));
        csrow->mci = mci;       /* include container up link */
-       csrow->kobj.parent = kobj_mci;
-       csrow->kobj.ktype = &ktype_csrow;
-
-       /* name this instance of csrow<id> */
-       err = kobject_set_name(&csrow->kobj, "csrow%d", index);
-       if (err)
-               goto err_out;
 
        /* bump the mci instance's kobject's ref count */
        kobj = kobject_get(&mci->edac_mci_kobj);
@@ -396,12 +389,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
        }
 
        /* Instanstiate the csrow object */
-       err = kobject_register(&csrow->kobj);
+       err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
+                                  "csrow%d", index);
        if (err)
                goto err_release_top_kobj;
 
        /* At this point, to release a csrow kobj, one must
-        * call the kobject_unregister and allow that tear down
+        * call the kobject_put and allow that tear down
         * to work the releasing
         */
 
@@ -412,11 +406,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
                err = edac_create_channel_files(&csrow->kobj, chan);
                if (err) {
                        /* special case the unregister here */
-                       kobject_unregister(&csrow->kobj);
+                       kobject_put(&csrow->kobj);
                        goto err_out;
                }
        }
-
+       kobject_uevent(&csrow->kobj, KOBJ_ADD);
        return 0;
 
        /* error unwind stack */
@@ -744,7 +738,6 @@ static struct kobj_type ktype_mc_set_attribs = {
  */
 static struct kset mc_kset = {
        .kobj = {.ktype = &ktype_mc_set_attribs },
-       .ktype = &ktype_mci,
 };
 
 
@@ -765,14 +758,6 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
        /* Init the mci's kobject */
        memset(kobj_mci, 0, sizeof(*kobj_mci));
 
-       /* this instance become part of the mc_kset */
-       kobj_mci->kset = &mc_kset;
-
-       /* set the name of the mc<id> object */
-       err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
-       if (err)
-               goto fail_out;
-
        /* Record which module 'owns' this control structure
         * and bump the ref count of the module
         */
@@ -784,13 +769,18 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
                goto fail_out;
        }
 
+       /* this instance become part of the mc_kset */
+       kobj_mci->kset = &mc_kset;
+
        /* register the mc<id> kobject to the mc_kset */
-       err = kobject_register(kobj_mci);
+       err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
+                                  "mc%d", mci->mc_idx);
        if (err) {
                debugf1("%s()Failed to register '.../edac/mc%d'\n",
                        __func__, mci->mc_idx);
                goto kobj_reg_fail;
        }
+       kobject_uevent(kobj_mci, KOBJ_ADD);
 
        /* At this point, to 'free' the control struct,
         * edac_mc_unregister_sysfs_main_kobj() must be used
@@ -818,7 +808,7 @@ fail_out:
 void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
 {
        /* delete the kobj from the mc_kset */
-       kobject_unregister(&mci->edac_mci_kobj);
+       kobject_put(&mci->edac_mci_kobj);
 }
 
 #define EDAC_DEVICE_SYMLINK    "device"
@@ -933,7 +923,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 fail1:
        for (i--; i >= 0; i--) {
                if (csrow->nr_pages > 0) {
-                       kobject_unregister(&mci->csrows[i].kobj);
+                       kobject_put(&mci->csrows[i].kobj);
                }
        }
 
@@ -960,7 +950,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
        for (i = 0; i < mci->nr_csrows; i++) {
                if (mci->csrows[i].nr_pages > 0) {
                        debugf0("%s()  unreg csrow-%d\n", __func__, i);
-                       kobject_unregister(&mci->csrows[i].kobj);
+                       kobject_put(&mci->csrows[i].kobj);
                }
        }
 
@@ -977,7 +967,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
        debugf0("%s()  unregister this mci kobj\n", __func__);
 
        /* unregister this instance's kobject */
-       kobject_unregister(&mci->edac_mci_kobj);
+       kobject_put(&mci->edac_mci_kobj);
 }
 
 
index e0c4a4086055ad6f2c00bcaabbc77bd91f531d3a..7e1374afd967256054be17b687954151576d60ae 100644 (file)
@@ -31,7 +31,7 @@ struct workqueue_struct *edac_workqueue;
  *     need to export to other files in this modules
  */
 static struct sysdev_class edac_class = {
-       set_kset_name("edac"),
+       .name = "edac",
 };
 static int edac_class_valid;
 
index 69f5dddabddfcfcb0294e374c42bf70c3104c89f..5b075da9914511ffebcb3f2de1362988957a9c3c 100644 (file)
@@ -162,14 +162,6 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 
        debugf0("%s()\n", __func__);
 
-       /* Set the parent and the instance's ktype */
-       pci->kobj.parent = &edac_pci_top_main_kobj;
-       pci->kobj.ktype = &ktype_pci_instance;
-
-       err = kobject_set_name(&pci->kobj, "pci%d", idx);
-       if (err)
-               return err;
-
        /* First bump the ref count on the top main kobj, which will
         * track the number of PCI instances we have, and thus nest
         * properly on keeping the module loaded
@@ -181,7 +173,8 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
        }
 
        /* And now register this new kobject under the main kobj */
-       err = kobject_register(&pci->kobj);
+       err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
+                                  &edac_pci_top_main_kobj, "pci%d", idx);
        if (err != 0) {
                debugf2("%s() failed to register instance pci%d\n",
                        __func__, idx);
@@ -189,6 +182,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
                goto error_out;
        }
 
+       kobject_uevent(&pci->kobj, KOBJ_ADD);
        debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
 
        return 0;
@@ -211,7 +205,7 @@ void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
         * function release the main reference count and then
         * kfree the memory
         */
-       kobject_unregister(&pci->kobj);
+       kobject_put(&pci->kobj);
 }
 
 /***************************** EDAC PCI sysfs root **********************/
@@ -364,14 +358,6 @@ int edac_pci_main_kobj_setup(void)
                goto decrement_count_fail;
        }
 
-       /* Need the kobject hook ups, and name setting */
-       edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
-       edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
-
-       err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
-       if (err)
-               goto decrement_count_fail;
-
        /* Bump the reference count on this module to ensure the
         * modules isn't unloaded until we deconstruct the top
         * level main kobj for EDAC PCI
@@ -383,23 +369,24 @@ int edac_pci_main_kobj_setup(void)
        }
 
        /* Instanstiate the pci object */
-       /* FIXME: maybe new sysdev_create_subdir() */
-       err = kobject_register(&edac_pci_top_main_kobj);
+       err = kobject_init_and_add(&edac_pci_top_main_kobj, &ktype_edac_pci_main_kobj,
+                                  &edac_class->kset.kobj, "pci");
        if (err) {
                debugf1("Failed to register '.../edac/pci'\n");
-               goto kobject_register_fail;
+               goto kobject_init_and_add_fail;
        }
 
        /* At this point, to 'release' the top level kobject
         * for EDAC PCI, then edac_pci_main_kobj_teardown()
         * must be used, for resources to be cleaned up properly
         */
+       kobject_uevent(&edac_pci_top_main_kobj, KOBJ_ADD);
        debugf1("Registered '.../edac/pci' kobject\n");
 
        return 0;
 
        /* Error unwind statck */
-kobject_register_fail:
+kobject_init_and_add_fail:
        module_put(THIS_MODULE);
 
 decrement_count_fail:
@@ -424,9 +411,9 @@ static void edac_pci_main_kobj_teardown(void)
         * main kobj
         */
        if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
-               debugf0("%s() called kobject_unregister on main kobj\n",
+               debugf0("%s() called kobject_put on main kobj\n",
                        __func__);
-               kobject_unregister(&edac_pci_top_main_kobj);
+               kobject_put(&edac_pci_top_main_kobj);
        }
 }
 
index 624ff3e082f68116f4efe158c80fcdd0c7f27a74..c2169d215bf7473d3fa2a983bd3852b8ab329a24 100644 (file)
@@ -1238,6 +1238,12 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
 
        sdev->allow_restart = 1;
 
+       /*
+        * Update the dma alignment (minimum alignment requirements for
+        * start and end of DMA transfers) to be a sector
+        */
+       blk_queue_update_dma_alignment(sdev->request_queue, 511);
+
        if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
                sdev->inquiry_len = 36;
 
index b6e1eb77d14847c0f7d25f836c76bcfe6e76c554..313c99cbdc62363632217d3061b7709b972b2127 100644 (file)
@@ -173,14 +173,11 @@ static struct device *dmi_dev;
        if (dmi_get_system_info(_field)) \
                sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
 
-extern int dmi_available;
-
-static int __init dmi_id_init(void)
+/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
+   dmi_id_init! */
+static void __init dmi_id_init_attr_table(void)
 {
-       int ret, i;
-
-       if (!dmi_available)
-               return -ENODEV;
+       int i;
 
        /* Not necessarily all DMI fields are available on all
         * systems, hence let's built an attribute table of just
@@ -205,6 +202,16 @@ static int __init dmi_id_init(void)
        ADD_DMI_ATTR(chassis_serial,    DMI_CHASSIS_SERIAL);
        ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
        sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
+}
+
+static int __init dmi_id_init(void)
+{
+       int ret;
+
+       if (!dmi_available)
+               return -ENODEV;
+
+       dmi_id_init_attr_table();
 
        ret = class_register(&dmi_class);
        if (ret)
index 0cdadea7a40e9f58cd027697611bf0d18eafd1bd..5e596a7e36013dc2d24082726a0eab5b792fc354 100644 (file)
@@ -470,3 +470,11 @@ int dmi_get_year(int field)
        return year;
 }
 
+/**
+ *     dmi_get_slot - return dmi_ident[slot]
+ *     @slot:  index into dmi_ident[]
+ */
+char *dmi_get_slot(int slot)
+{
+       return(dmi_ident[slot]);
+}
index 6942e065e6095d2fe55188843f0f7d4dce36dd2a..d168223db1594b7d351956f14903448548c08e1e 100644 (file)
@@ -631,7 +631,7 @@ static struct kobj_type edd_ktype = {
        .default_attrs  = def_attrs,
 };
 
-static decl_subsys(edd, &edd_ktype, NULL);
+static struct kset *edd_kset;
 
 
 /**
@@ -693,7 +693,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev)
 static inline void
 edd_device_unregister(struct edd_device *edev)
 {
-       kobject_unregister(&edev->kobj);
+       kobject_put(&edev->kobj);
 }
 
 static void edd_populate_dir(struct edd_device * edev)
@@ -721,12 +721,13 @@ edd_device_register(struct edd_device *edev, int i)
        if (!edev)
                return 1;
        edd_dev_set_info(edev, i);
-       kobject_set_name(&edev->kobj, "int13_dev%02x",
-                        0x80 + i);
-       kobj_set_kset_s(edev,edd_subsys);
-       error = kobject_register(&edev->kobj);
-       if (!error)
+       edev->kobj.kset = edd_kset;
+       error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL,
+                                    "int13_dev%02x", 0x80 + i);
+       if (!error) {
                edd_populate_dir(edev);
+               kobject_uevent(&edev->kobj, KOBJ_ADD);
+       }
        return error;
 }
 
@@ -755,9 +756,9 @@ edd_init(void)
                return 1;
        }
 
-       rc = firmware_register(&edd_subsys);
-       if (rc)
-               return rc;
+       edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
+       if (!edd_kset)
+               return -ENOMEM;
 
        for (i = 0; i < edd_num_devices() && !rc; i++) {
                edev = kzalloc(sizeof (*edev), GFP_KERNEL);
@@ -773,7 +774,7 @@ edd_init(void)
        }
 
        if (rc)
-               firmware_unregister(&edd_subsys);
+               kset_unregister(edd_kset);
        return rc;
 }
 
@@ -787,7 +788,7 @@ edd_exit(void)
                if ((edev = edd_devices[i]))
                        edd_device_unregister(edev);
        }
-       firmware_unregister(&edd_subsys);
+       kset_unregister(edd_kset);
 }
 
 late_initcall(edd_init);
index 858a7b95933bf21993ddd81d178b17ed3d2cc62d..f4f709d1370bf4b2c0ed0d5517530e8136ce4490 100644 (file)
@@ -129,13 +129,6 @@ struct efivar_attribute {
 };
 
 
-#define EFI_ATTR(_name, _mode, _show, _store) \
-struct subsys_attribute efi_attr_##_name = { \
-       .attr = {.name = __stringify(_name), .mode = _mode}, \
-       .show = _show, \
-       .store = _store, \
-};
-
 #define EFIVAR_ATTR(_name, _mode, _show, _store) \
 struct efivar_attribute efivar_attr_##_name = { \
        .attr = {.name = __stringify(_name), .mode = _mode}, \
@@ -143,13 +136,6 @@ struct efivar_attribute efivar_attr_##_name = { \
        .store = _store, \
 };
 
-#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
-struct subsys_attribute var_subsys_attr_##_name = { \
-       .attr = {.name = __stringify(_name), .mode = _mode}, \
-       .show = _show, \
-       .store = _store, \
-};
-
 #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
 #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
 
@@ -408,21 +394,16 @@ static struct kobj_type efivar_ktype = {
        .default_attrs = def_attrs,
 };
 
-static ssize_t
-dummy(struct kset *kset, char *buf)
-{
-       return -ENODEV;
-}
-
 static inline void
 efivar_unregister(struct efivar_entry *var)
 {
-       kobject_unregister(&var->kobj);
+       kobject_put(&var->kobj);
 }
 
 
-static ssize_t
-efivar_create(struct kset *kset, const char *buf, size_t count)
+static ssize_t efivar_create(struct kobject *kobj,
+                            struct bin_attribute *bin_attr,
+                            char *buf, loff_t pos, size_t count)
 {
        struct efi_variable *new_var = (struct efi_variable *)buf;
        struct efivar_entry *search_efivar, *n;
@@ -479,8 +460,9 @@ efivar_create(struct kset *kset, const char *buf, size_t count)
        return count;
 }
 
-static ssize_t
-efivar_delete(struct kset *kset, const char *buf, size_t count)
+static ssize_t efivar_delete(struct kobject *kobj,
+                            struct bin_attribute *bin_attr,
+                            char *buf, loff_t pos, size_t count)
 {
        struct efi_variable *del_var = (struct efi_variable *)buf;
        struct efivar_entry *search_efivar, *n;
@@ -537,25 +519,26 @@ efivar_delete(struct kset *kset, const char *buf, size_t count)
        return count;
 }
 
-static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);
-static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);
+static struct bin_attribute var_subsys_attr_new_var = {
+       .attr = {.name = "new_var", .mode = 0200},
+       .write = efivar_create,
+};
 
-static struct subsys_attribute *var_subsys_attrs[] = {
-       &var_subsys_attr_new_var,
-       &var_subsys_attr_del_var,
-       NULL,
+static struct bin_attribute var_subsys_attr_del_var = {
+       .attr = {.name = "del_var", .mode = 0200},
+       .write = efivar_delete,
 };
 
 /*
  * Let's not leave out systab information that snuck into
  * the efivars driver
  */
-static ssize_t
-systab_read(struct kset *kset, char *buf)
+static ssize_t systab_show(struct kobject *kobj,
+                          struct kobj_attribute *attr, char *buf)
 {
        char *str = buf;
 
-       if (!kset || !buf)
+       if (!kobj || !buf)
                return -EINVAL;
 
        if (efi.mps != EFI_INVALID_TABLE_ADDR)
@@ -576,15 +559,21 @@ systab_read(struct kset *kset, char *buf)
        return str - buf;
 }
 
-static EFI_ATTR(systab, 0400, systab_read, NULL);
+static struct kobj_attribute efi_attr_systab =
+                       __ATTR(systab, 0400, systab_show, NULL);
 
-static struct subsys_attribute *efi_subsys_attrs[] = {
-       &efi_attr_systab,
+static struct attribute *efi_subsys_attrs[] = {
+       &efi_attr_systab.attr,
        NULL,   /* maybe more in the future? */
 };
 
-static decl_subsys(vars, &efivar_ktype, NULL);
-static decl_subsys(efi, NULL, NULL);
+static struct attribute_group efi_subsys_attr_group = {
+       .attrs = efi_subsys_attrs,
+};
+
+
+static struct kset *vars_kset;
+static struct kobject *efi_kobj;
 
 /*
  * efivar_create_sysfs_entry()
@@ -628,15 +617,16 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
        *(short_name + strlen(short_name)) = '-';
        efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
 
-       kobject_set_name(&new_efivar->kobj, "%s", short_name);
-       kobj_set_kset_s(new_efivar, vars_subsys);
-       i = kobject_register(&new_efivar->kobj);
+       new_efivar->kobj.kset = vars_kset;
+       i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL,
+                                "%s", short_name);
        if (i) {
                kfree(short_name);
                kfree(new_efivar);
                return 1;
        }
 
+       kobject_uevent(&new_efivar->kobj, KOBJ_ADD);
        kfree(short_name);
        short_name = NULL;
 
@@ -660,9 +650,8 @@ efivars_init(void)
        efi_status_t status = EFI_NOT_FOUND;
        efi_guid_t vendor_guid;
        efi_char16_t *variable_name;
-       struct subsys_attribute *attr;
        unsigned long variable_name_size = 1024;
-       int i, error = 0;
+       int error = 0;
 
        if (!efi_enabled)
                return -ENODEV;
@@ -676,23 +665,18 @@ efivars_init(void)
        printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
               EFIVARS_DATE);
 
-       /*
-        * For now we'll register the efi subsys within this driver
-        */
-
-       error = firmware_register(&efi_subsys);
-
-       if (error) {
-               printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error);
+       /* For now we'll register the efi directory at /sys/firmware/efi */
+       efi_kobj = kobject_create_and_add("efi", firmware_kobj);
+       if (!efi_kobj) {
+               printk(KERN_ERR "efivars: Firmware registration failed.\n");
+               error = -ENOMEM;
                goto out_free;
        }
 
-       kobj_set_kset_s(&vars_subsys, efi_subsys);
-
-       error = subsystem_register(&vars_subsys);
-
-       if (error) {
-               printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error);
+       vars_kset = kset_create_and_add("vars", NULL, efi_kobj);
+       if (!vars_kset) {
+               printk(KERN_ERR "efivars: Subsystem registration failed.\n");
+               error = -ENOMEM;
                goto out_firmware_unregister;
        }
 
@@ -727,28 +711,28 @@ efivars_init(void)
         * Now add attributes to allow creation of new vars
         * and deletion of existing ones...
         */
-
-       for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {
-               if (attr->show && attr->store)
-                       error = subsys_create_file(&vars_subsys, attr);
-       }
+       error = sysfs_create_bin_file(&vars_kset->kobj,
+                                     &var_subsys_attr_new_var);
+       if (error)
+               printk(KERN_ERR "efivars: unable to create new_var sysfs file"
+                       " due to error %d\n", error);
+       error = sysfs_create_bin_file(&vars_kset->kobj,
+                                     &var_subsys_attr_del_var);
+       if (error)
+               printk(KERN_ERR "efivars: unable to create del_var sysfs file"
+                       " due to error %d\n", error);
 
        /* Don't forget the systab entry */
-
-       for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {
-               if (attr->show)
-                       error = subsys_create_file(&efi_subsys, attr);
-       }
-
+       error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
        if (error)
                printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error);
        else
                goto out_free;
 
-       subsystem_unregister(&vars_subsys);
+       kset_unregister(vars_kset);
 
 out_firmware_unregister:
-       firmware_unregister(&efi_subsys);
+       kobject_put(efi_kobj);
 
 out_free:
        kfree(variable_name);
@@ -768,8 +752,8 @@ efivars_exit(void)
                efivar_unregister(entry);
        }
 
-       subsystem_unregister(&vars_subsys);
-       firmware_unregister(&efi_subsys);
+       kset_unregister(vars_kset);
+       kobject_put(efi_kobj);
 }
 
 module_init(efivars_init);
index 6a182e14cf589d59f7a5d8e244b8aa9c34c0409d..ad6c8a319903eeb8bf9fcd08950b0b58ddeba605 100644 (file)
@@ -2,6 +2,14 @@
     it87.c - Part of lm_sensors, Linux kernel modules for hardware
              monitoring.
 
+    The IT8705F is an LPC-based Super I/O part that contains UARTs, a
+    parallel port, an IR port, a MIDI port, a floppy controller, etc., in
+    addition to an Environment Controller (Enhanced Hardware Monitor and
+    Fan Controller)
+
+    This driver supports only the Environment Controller in the IT8705F and
+    similar parts.  The other devices are supported by different drivers.
+
     Supports: IT8705F  Super I/O chip w/LPC interface
               IT8712F  Super I/O chip w/LPC interface
               IT8716F  Super I/O chip w/LPC interface
@@ -118,9 +126,15 @@ static int fix_pwm_polarity;
 /* Length of ISA address segment */
 #define IT87_EXTENT 8
 
-/* Where are the ISA address/data registers relative to the base address */
-#define IT87_ADDR_REG_OFFSET 5
-#define IT87_DATA_REG_OFFSET 6
+/* Length of ISA address segment for Environmental Controller */
+#define IT87_EC_EXTENT 2
+
+/* Offset of EC registers from ISA base address */
+#define IT87_EC_OFFSET 5
+
+/* Where are the ISA address/data registers relative to the EC base address */
+#define IT87_ADDR_REG_OFFSET 0
+#define IT87_DATA_REG_OFFSET 1
 
 /*----- The IT87 registers -----*/
 
@@ -968,10 +982,10 @@ static int __devinit it87_probe(struct platform_device *pdev)
        };
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       if (!request_region(res->start, IT87_EXTENT, DRVNAME)) {
+       if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) {
                dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
                        (unsigned long)res->start,
-                       (unsigned long)(res->start + IT87_EXTENT - 1));
+                       (unsigned long)(res->start + IT87_EC_EXTENT - 1));
                err = -EBUSY;
                goto ERROR0;
        }
@@ -1124,7 +1138,7 @@ ERROR2:
        platform_set_drvdata(pdev, NULL);
        kfree(data);
 ERROR1:
-       release_region(res->start, IT87_EXTENT);
+       release_region(res->start, IT87_EC_EXTENT);
 ERROR0:
        return err;
 }
@@ -1137,7 +1151,7 @@ static int __devexit it87_remove(struct platform_device *pdev)
        sysfs_remove_group(&pdev->dev.kobj, &it87_group);
        sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
 
-       release_region(data->addr, IT87_EXTENT);
+       release_region(data->addr, IT87_EC_EXTENT);
        platform_set_drvdata(pdev, NULL);
        kfree(data);
 
@@ -1402,8 +1416,8 @@ static int __init it87_device_add(unsigned short address,
                                  const struct it87_sio_data *sio_data)
 {
        struct resource res = {
-               .start  = address ,
-               .end    = address + IT87_EXTENT - 1,
+               .start  = address + IT87_EC_OFFSET,
+               .end    = address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1,
                .name   = DRVNAME,
                .flags  = IORESOURCE_IO,
        };
index b15c6a998b7271aeb0f45ce21fa21be75be2cf2f..d5aa25ce5dbdc8251d05d384391c418070f80d9b 100644 (file)
@@ -1276,23 +1276,31 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 
        data->vrm = vid_which_vrm();
        superio_enter(sio_data->sioreg);
-       /* Set VID input sensibility if needed. In theory the BIOS should
-          have set it, but in practice it's not always the case. */
-       en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10);
-       if ((en_vrm10 & 0x08) && data->vrm != 100) {
-               dev_warn(dev, "Setting VID input voltage to TTL\n");
-               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
-                            en_vrm10 & ~0x08);
-       } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
-               dev_warn(dev, "Setting VID input voltage to VRM10\n");
-               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
-                            en_vrm10 | 0x08);
-       }
        /* Read VID value */
        superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
-       if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80)
+       if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
+               /* Set VID input sensibility if needed. In theory the BIOS
+                  should have set it, but in practice it's not always the
+                  case. We only do it for the W83627EHF/EHG because the
+                  W83627DHG is more complex in this respect. */
+               if (sio_data->kind == w83627ehf) {
+                       en_vrm10 = superio_inb(sio_data->sioreg,
+                                              SIO_REG_EN_VRM10);
+                       if ((en_vrm10 & 0x08) && data->vrm == 90) {
+                               dev_warn(dev, "Setting VID input voltage to "
+                                        "TTL\n");
+                               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+                                            en_vrm10 & ~0x08);
+                       } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
+                               dev_warn(dev, "Setting VID input voltage to "
+                                        "VRM10\n");
+                               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+                                            en_vrm10 | 0x08);
+                       }
+               }
+
                data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;
-       else {
+       else {
                dev_info(dev, "VID pins in output mode, CPU VID not "
                         "available\n");
                data->vid = 0x3f;
index 9c8b6d5eaec9ef301fe1491d6bf8ce714bfc3c8c..c09b036913bd9588f9789f982b884b319cff5890 100644 (file)
@@ -135,7 +135,7 @@ static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
  * Generic i2c master transfer entrypoint.
  *
  * Note: We do not use Atmel's feature of storing the "internal device address".
- * Instead the "internal device address" has to be written using a seperate
+ * Instead the "internal device address" has to be written using a separate
  * i2c message.
  * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
  */
index cb55cf2ba1e91a4279f3406f34216b4a59f4094e..f2552b19ea607d741082ca54aec28c4984b614f8 100644 (file)
@@ -619,13 +619,13 @@ omap_i2c_probe(struct platform_device *pdev)
 err_free_irq:
        free_irq(dev->irq, dev);
 err_unuse_clocks:
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        omap_i2c_disable_clocks(dev);
        omap_i2c_put_clocks(dev);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 err_release_region:
-       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        release_mem_region(mem->start, (mem->end - mem->start) + 1);
 
        return r;
index 0ab4f2627c26c58c3eb53fb593da0fffe7f03bff..7813127649a101e2977fa42544d7b2d6e50503e9 100644 (file)
@@ -94,7 +94,7 @@ static s32 i2c_powermac_smbus_xfer(   struct i2c_adapter*     adap,
                break;
 
        /* Note that these are broken vs. the expected smbus API where
-        * on reads, the lenght is actually returned from the function,
+        * on reads, the length is actually returned from the function,
         * but I think the current API makes no sense and I don't want
         * any driver that I haven't verified for correctness to go
         * anywhere near a pmac i2c bus anyway ...
index 0ca599d3b4029851ddf022bab424759824060ec2..503a134ec803c13edd0cd43dd71432179216f60a 100644 (file)
@@ -200,11 +200,14 @@ static struct i2c_adapter sibyte_board_adapter[2] = {
 
 static int __init i2c_sibyte_init(void)
 {
-       printk("i2c-swarm.o: i2c SMBus adapter module for SiByte board\n");
+       pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n");
        if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0)
                return -ENODEV;
-       if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], K_SMB_FREQ_400KHZ) < 0)
+       if (i2c_sibyte_add_bus(&sibyte_board_adapter[1],
+                              K_SMB_FREQ_400KHZ) < 0) {
+               i2c_del_adapter(&sibyte_board_adapter[0]);
                return -ENODEV;
+       }
        return 0;
 }
 
index b767603a07ba38d41c08269e727823c89b910c47..ebfbb2947ae6f18ab604360d79c998db852a4485 100644 (file)
@@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp)
        return state_string(isp->otg.state);
 }
 
-#ifdef VERBOSE
-#define        dev_vdbg                        dev_dbg
-#else
-#define        dev_vdbg(dev, fmt, arg...)      do{}while(0)
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 /* NOTE:  some of this ISP1301 setup is specific to H2 boards;
index c21ae20ae362b059a2c347238f0e063616e0411e..df540d5dfaf42db7f249c30491c59679265353da 100644 (file)
@@ -184,7 +184,7 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
 
 /* This address checking function differs from the one in i2c-core
    in that it considers an address with a registered device, but no
-   bounded driver, as NOT busy. */
+   bound driver, as NOT busy. */
 static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
        struct list_head *item;
index fb06555708a8d431734a99e0a1a85cf3f7178139..64df55e20ab53fb90673fa507b42289ccabbb3d4 100644 (file)
@@ -325,7 +325,7 @@ config BLK_DEV_PLATFORM
          If unsure, say N.
 
 config BLK_DEV_CMD640
-       bool "CMD640 chipset bugfix/support"
+       tristate "CMD640 chipset bugfix/support"
        depends on X86
        ---help---
          The CMD-Technologies CMD640 IDE chip is used on many common 486 and
@@ -359,9 +359,8 @@ config BLK_DEV_CMD640_ENHANCED
          Otherwise say N.
 
 config BLK_DEV_IDEPNP
-       bool "PNP EIDE support"
+       tristate "PNP EIDE support"
        depends on PNP
-       select IDE_GENERIC
        help
          If you have a PnP (Plug and Play) compatible EIDE card and
          would like the kernel to automatically detect and activate
@@ -374,19 +373,20 @@ comment "PCI IDE chipsets support"
 config BLK_DEV_IDEPCI
        bool
 
-config IDEPCI_SHARE_IRQ
-       bool "Sharing PCI IDE interrupts support"
-       depends on BLK_DEV_IDEPCI
+config IDEPCI_PCIBUS_ORDER
+       bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
+       depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+       default y
        help
-         Some ATA/IDE chipsets have hardware support which allows for
-         sharing a single IRQ with other cards. To enable support for
-         this in the ATA/IDE driver, say Y here.
+         Probe IDE PCI devices in the order in which they appear on the
+         PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
+         instead of the order in which IDE PCI host drivers are loaded.
 
-         It is safe to say Y to this question, in most cases.
-         If unsure, say N.
+         Please note that this method of assuring stable naming of
+         IDE devices is unreliable and use other means for achieving
+         it (i.e. udev).
 
-config IDEPCI_PCIBUS_ORDER
-       def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+         If in doubt, say N.
 
 # TODO: split it on per host driver config options (or module parameters)
 config BLK_DEV_OFFBOARD
@@ -707,7 +707,6 @@ config BLK_DEV_SVWKS
 config BLK_DEV_SGIIOC4
        tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
        depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
-       select IDEPCI_SHARE_IRQ
        select BLK_DEV_IDEDMA_PCI
        help
          This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
@@ -801,7 +800,7 @@ config BLK_DEV_CELLEB
 endif
 
 config BLK_DEV_IDE_PMAC
-       bool "Builtin PowerMac IDE support"
+       tristate "Builtin PowerMac IDE support"
        depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
        help
          This driver provides support for the built-in IDE controller on
@@ -855,8 +854,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
        depends on BLK_DEV_IDE_AU1XXX
 
 config IDE_ARM
-       def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
-       select IDE_GENERIC
+       tristate "ARM IDE support"
+       depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+       default y
 
 config BLK_DEV_IDE_ICSIDE
        tristate "ICS IDE interface support"
@@ -888,10 +888,9 @@ config BLK_DEV_IDE_BAST
          Simtec BAST or the Thorcom VR1000
 
 config ETRAX_IDE
-       bool "ETRAX IDE support"
+       tristate "ETRAX IDE support"
        depends on CRIS && BROKEN
        select BLK_DEV_IDEDMA
-       select IDE_GENERIC
        help
          Enables the ETRAX IDE driver.
 
@@ -923,17 +922,15 @@ config ETRAX_IDE_G27_RESET
 endchoice
 
 config IDE_H8300
-       bool "H8300 IDE support"
+       tristate "H8300 IDE support"
        depends on H8300
-       select IDE_GENERIC
        default y
        help
          Enables the H8300 IDE driver.
 
 config BLK_DEV_GAYLE
-       bool "Amiga Gayle IDE interface support"
+       tristate "Amiga Gayle IDE interface support"
        depends on AMIGA
-       select IDE_GENERIC
        help
          This is the IDE driver for the Amiga Gayle IDE interface. It supports
          both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
@@ -963,9 +960,8 @@ config BLK_DEV_IDEDOUBLER
          runtime using the "ide=doubler" kernel boot parameter.
 
 config BLK_DEV_BUDDHA
-       bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
+       tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
        depends on ZORRO && EXPERIMENTAL
-       select IDE_GENERIC
        help
          This is the IDE driver for the IDE interfaces on the Buddha, 
          Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
@@ -976,9 +972,8 @@ config BLK_DEV_BUDDHA
          to one of its IDE interfaces.
 
 config BLK_DEV_FALCON_IDE
-       bool "Falcon IDE interface support"
+       tristate "Falcon IDE interface support"
        depends on ATARI
-       select IDE_GENERIC
        help
          This is the IDE driver for the builtin IDE interface on the Atari
          Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
@@ -986,9 +981,8 @@ config BLK_DEV_FALCON_IDE
          interface.
 
 config BLK_DEV_MAC_IDE
-       bool "Macintosh Quadra/Powerbook IDE interface support"
+       tristate "Macintosh Quadra/Powerbook IDE interface support"
        depends on MAC
-       select IDE_GENERIC
        help
          This is the IDE driver for the builtin IDE interface on some m68k
          Macintosh models. It supports both the `Quadra style' (used in
@@ -1000,18 +994,16 @@ config BLK_DEV_MAC_IDE
          builtin IDE interface.
 
 config BLK_DEV_Q40IDE
-       bool "Q40/Q60 IDE interface support"
+       tristate "Q40/Q60 IDE interface support"
        depends on Q40
-       select IDE_GENERIC
        help
          Enable the on-board IDE controller in the Q40/Q60.  This should
          normally be on; disable it only if you are running a custom hard
          drive subsystem through an expansion card.
 
 config BLK_DEV_MPC8xx_IDE
-       bool "MPC8xx IDE support"
+       tristate "MPC8xx IDE support"
        depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
-       select IDE_GENERIC
        help
          This option provides support for IDE on Motorola MPC8xx Systems.
          Please see 'Type of MPC8xx IDE interface' for details.
index b181fc672057b7d157c9a1375f148ea8d06c06d1..0d2da89d15cff8f989f4436f5b9f1e8618e9b05a 100644 (file)
@@ -7,41 +7,37 @@
 # Note : at this point, these files are compiled on all systems.
 # In the future, some of these should be built conditionally.
 #
-# First come modules that register themselves with the core
+# link order is important here
 
 EXTRA_CFLAGS                           += -Idrivers/ide
 
-obj-$(CONFIG_BLK_DEV_IDE)              += pci/
-
 ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
 
-ide-core-$(CONFIG_BLK_DEV_CMD640)      += pci/cmd640.o
-
-# Core IDE code - must come before legacy
+# core IDE code
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)      += setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)      += ide-dma.o
 ide-core-$(CONFIG_IDE_PROC_FS)         += ide-proc.o
-ide-core-$(CONFIG_BLK_DEV_IDEPNP)      += ide-pnp.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)     += ide-acpi.o
 
-# built-in only drivers from arm/
-ide-core-$(CONFIG_IDE_ARM)             += arm/ide_arm.o
+obj-$(CONFIG_BLK_DEV_IDE)              += ide-core.o
 
-# built-in only drivers from legacy/
-ide-core-$(CONFIG_BLK_DEV_BUDDHA)      += legacy/buddha.o
-ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)  += legacy/falconide.o
-ide-core-$(CONFIG_BLK_DEV_GAYLE)       += legacy/gayle.o
-ide-core-$(CONFIG_BLK_DEV_MAC_IDE)     += legacy/macide.o
-ide-core-$(CONFIG_BLK_DEV_Q40IDE)      += legacy/q40ide.o
+ifeq ($(CONFIG_IDE_ARM), y)
+       ide-arm-core-y += arm/ide_arm.o
+       obj-y += ide-arm-core.o
+endif
 
-# built-in only drivers from ppc/
-ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE)  += ppc/mpc8xx.o
-ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)    += ppc/pmac.o
+obj-$(CONFIG_BLK_DEV_IDE)              += legacy/ pci/
 
-# built-in only drivers from h8300/
-ide-core-$(CONFIG_IDE_H8300)           += h8300/ide-h8300.o
+obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)      += ide-scan-pci.o
 
-obj-$(CONFIG_BLK_DEV_IDE)              += ide-core.o
+ifeq ($(CONFIG_BLK_DEV_CMD640), y)
+       cmd640-core-y += pci/cmd640.o
+       obj-y += cmd640-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)              += cris/ ppc/
+obj-$(CONFIG_BLK_DEV_IDEPNP)           += ide-pnp.o
+obj-$(CONFIG_IDE_H8300)                        += h8300/
 obj-$(CONFIG_IDE_GENERIC)              += ide-generic.o
 
 obj-$(CONFIG_BLK_DEV_IDEDISK)          += ide-disk.o
@@ -49,6 +45,20 @@ obj-$(CONFIG_BLK_DEV_IDECD)          += ide-cd.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)          += ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY)                += ide-floppy.o
 
-obj-$(CONFIG_BLK_DEV_IDE)              += legacy/ arm/ mips/
-obj-$(CONFIG_BLK_DEV_HD)               += legacy/
-obj-$(CONFIG_ETRAX_IDE)                += cris/
+ifeq ($(CONFIG_BLK_DEV_IDECS), y)
+       ide-cs-core-y += legacy/ide-cs.o
+       obj-y += ide-cs-core.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
+       ide-platform-core-y += legacy/ide_platform.o
+       obj-y += ide-platform-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)              += arm/ mips/
+
+# old hd driver must be last
+ifeq ($(CONFIG_BLK_DEV_HD), y)
+       hd-core-y += legacy/hd.o
+       obj-y += hd-core.o
+endif
index 6a78f0755f262802b0e5835e4141b0aabb5c05cb..5f63ad216862e50fd1d583384cc61a83d2dd182f 100644 (file)
@@ -3,4 +3,8 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)        += icside.o
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)       += rapide.o
 obj-$(CONFIG_BLK_DEV_IDE_BAST)         += bast-ide.o
 
+ifeq ($(CONFIG_IDE_ARM), m)
+       obj-m += ide_arm.o
+endif
+
 EXTRA_CFLAGS   := -Idrivers/ide
index 48db6167bb90f6005927590431ba56a231061cd3..45bf9c825f2b11c7afd2fd4d65d45c49a0dfaa45 100644 (file)
@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
        hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
        hw.irq = irq;
 
-       ide_register_hw(&hw, NULL, 0, hwif);
+       ide_register_hw(&hw, NULL, hwif);
 
        return 0;
 }
index 93f71fcfc04df46a571aa72e14726d36a3d81f58..8a5c7205b77c7a4176406449c90272fc4fd9f256 100644 (file)
@@ -272,8 +272,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
        case XFER_SW_DMA_0:
                cycle_time = 480;
                break;
-       default:
-               return;
        }
 
        /*
@@ -289,26 +287,10 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
                ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 }
 
-static void icside_dma_host_off(ide_drive_t *drive)
+static void icside_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void icside_dma_off_quietly(ide_drive_t *drive)
-{
-       drive->using_dma = 0;
-}
-
-static void icside_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static int icside_dma_on(ide_drive_t *drive)
-{
-       drive->using_dma = 1;
-
-       return 0;
-}
-
 static int icside_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
@@ -424,10 +406,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
        hwif->dmatable_dma      = 0;
        hwif->set_dma_mode      = icside_set_dma_mode;
 
-       hwif->dma_host_off      = icside_dma_host_off;
-       hwif->dma_off_quietly   = icside_dma_off_quietly;
-       hwif->dma_host_on       = icside_dma_host_on;
-       hwif->ide_dma_on        = icside_dma_on;
+       hwif->dma_host_set      = icside_dma_host_set;
        hwif->dma_setup         = icside_dma_setup;
        hwif->dma_exec_cmd      = icside_dma_exec_cmd;
        hwif->dma_start         = icside_dma_start;
index 8957cbadf5c2a8c5870800a54ebd1d4b6eebae70..60f2497542c05048d9a3f9b5e1a780d8717426f3 100644 (file)
 # define IDE_ARM_IRQ   IRQ_HARDDISK
 #endif
 
-void __init ide_arm_init(void)
+static int __init ide_arm_init(void)
 {
+       ide_hwif_t *hwif;
        hw_regs_t hw;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        memset(&hw, 0, sizeof(hw));
        ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
        hw.irq = IDE_ARM_IRQ;
-       ide_register_hw(&hw, NULL, 1, NULL);
+
+       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif) {
+               ide_init_port_hw(hwif, &hw);
+               idx[0] = hwif->index;
+
+               ide_device_add(idx);
+       }
+
+       return 0;
 }
+
+module_init(ide_arm_init);
index 0775a3afef4862d5e5b2b5646443cbcfdec1448c..e6b56d1d48f4902ce9f1b0f518c1a5fa4103b563 100644 (file)
 
 #include <asm/ecard.h>
 
-static ide_hwif_t *
-rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
+static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
+                              void __iomem *ctrl, unsigned int sz, int irq)
 {
        unsigned long port = (unsigned long)base;
-       ide_hwif_t *hwif = ide_find_port(port);
        int i;
 
-       if (hwif == NULL)
-               goto out;
-
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-               hwif->io_ports[i] = port;
+               hw->io_ports[i] = port;
                port += sz;
        }
-       hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
-       hwif->irq = irq;
-       hwif->mmio = 1;
-       default_hwif_mmiops(hwif);
-out:
-       return hwif;
+       hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+       hw->irq = irq;
 }
 
 static int __devinit
@@ -42,6 +34,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
        void __iomem *base;
        int ret;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+       hw_regs_t hw;
 
        ret = ecard_request_resources(ec);
        if (ret)
@@ -53,11 +46,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
                goto release;
        }
 
-       hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
+       hwif = ide_find_port((unsigned long)base);
        if (hwif) {
-               hwif->hwif_data = base;
-               hwif->gendev.parent = &ec->dev;
-               hwif->noprobe = 0;
+               memset(&hw, 0, sizeof(hw));
+               rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
+               hw.chipset = ide_generic;
+               hw.dev = &ec->dev;
+
+               ide_init_port_hw(hwif, &hw);
+
+               hwif->mmio = 1;
+               default_hwif_mmiops(hwif);
 
                idx[0] = hwif->index;
 
index 6176e8d6b2e669e76233bcfaad3df3f2bf1c0b6c..20b95960531f76ec68838887b8c75ea37da25031 100644 (file)
@@ -1,3 +1,3 @@
 EXTRA_CFLAGS                           += -Idrivers/ide
 
-obj-y                                  += ide-cris.o
+obj-$(CONFIG_IDE_ETRAX)                        += ide-cris.o
index 476e0d65ed438f34375b155f0b80169f39a2b6fa..8c3294c4d23e2fd390dd6653aff30a6cb5d618ca 100644 (file)
@@ -673,9 +673,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
 static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
-static int cris_dma_on (ide_drive_t *drive);
 
-static void cris_dma_off(ide_drive_t *drive)
+static void cris_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -747,8 +746,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
                        strobe = ATA_DMA2_STROBE;
                        hold = ATA_DMA2_HOLD;
                        break;
-               default:
-                       return;
        }
 
        if (speed >= XFER_UDMA_0)
@@ -757,13 +754,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
                cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
 }
 
-void __init
-init_e100_ide (void)
+static int __init init_e100_ide(void)
 {
        hw_regs_t hw;
-       int ide_offsets[IDE_NR_PORTS];
-       int h;
-       int i;
+       int ide_offsets[IDE_NR_PORTS], h, i;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        printk("ide: ETRAX FS built-in ATA DMA controller\n");
 
@@ -780,9 +775,11 @@ init_e100_ide (void)
                                ide_offsets,
                                0, 0, cris_ide_ack_intr,
                                ide_default_irq(0));
-               ide_register_hw(&hw, NULL, 1, &hwif);
+               hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
                if (hwif == NULL)
                        continue;
+               ide_init_port_data(hwif, hwif->index);
+               ide_init_port_hw(hwif, &hw);
                hwif->mmio = 1;
                hwif->chipset = ide_etrax100;
                hwif->set_pio_mode = &cris_set_pio_mode;
@@ -791,6 +788,7 @@ init_e100_ide (void)
                hwif->ata_output_data = &cris_ide_output_data;
                hwif->atapi_input_bytes = &cris_atapi_input_bytes;
                hwif->atapi_output_bytes = &cris_atapi_output_bytes;
+               hwif->dma_host_set = &cris_dma_host_set;
                hwif->ide_dma_end = &cris_dma_end;
                hwif->dma_setup = &cris_dma_setup;
                hwif->dma_exec_cmd = &cris_dma_exec_cmd;
@@ -801,9 +799,6 @@ init_e100_ide (void)
                hwif->OUTBSYNC = &cris_ide_outbsync;
                hwif->INB = &cris_ide_inb;
                hwif->INW = &cris_ide_inw;
-               hwif->dma_host_off = &cris_dma_off;
-               hwif->dma_host_on = &cris_dma_on;
-               hwif->dma_off_quietly = &cris_dma_off;
                hwif->cbl = ATA_CBL_PATA40;
                hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
                hwif->pio_mask = ATA_PIO4,
@@ -811,6 +806,8 @@ init_e100_ide (void)
                hwif->drives[1].autotune = 1;
                hwif->ultra_mask = cris_ultra_mask;
                hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
+
+               idx[h] = hwif->index;
        }
 
        /* Reset pulse */
@@ -823,14 +820,12 @@ init_e100_ide (void)
        cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
        cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
        cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
-}
 
-static int cris_dma_on (ide_drive_t *drive)
-{
+       ide_device_add(idx);
+
        return 0;
 }
 
-
 static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
 
 /*
@@ -1062,3 +1057,5 @@ static void cris_dma_start(ide_drive_t *drive)
                LED_DISK_READ(1);
        }
 }
+
+module_init(init_e100_ide);
diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile
new file mode 100644 (file)
index 0000000..5eba16f
--- /dev/null
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_IDE_H8300)                        += ide-h8300.o
index 4a49b5c59acb3949fa87656814678956b7855e17..4f6d0191cf6c31c74c9bec652c11e08861a23918 100644 (file)
@@ -84,11 +84,12 @@ static inline void hwif_setup(ide_hwif_t *hwif)
        hwif->INSL  = NULL;
 }
 
-void __init h8300_ide_init(void)
+static int __init h8300_ide_init(void)
 {
        hw_regs_t hw;
        ide_hwif_t *hwif;
-       int idx;
+       int index;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
                goto out_busy;
@@ -100,16 +101,28 @@ void __init h8300_ide_init(void)
        hw_setup(&hw);
 
        /* register if */
-       idx = ide_register_hw(&hw, NULL, 1, &hwif);
-       if (idx == -1) {
+       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif == NULL) {
                printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
-               return;
+               return -ENOENT;
        }
 
+       index = hwif->index;
+       ide_init_port_data(hwif, index);
+       ide_init_port_hw(hwif, &hw);
        hwif_setup(hwif);
-       printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx);
-       return;
+       printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", index);
+
+       idx[0] = index;
+
+       ide_device_add(idx);
+
+       return 0;
 
 out_busy:
        printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
+
+       return -EBUSY;
 }
+
+module_init(h8300_ide_init);
index 89df48fdc69d7b6109098153813524862fe4bff1..e888fc35b27ce55401827d7255d064a7670ff02f 100644 (file)
@@ -16,6 +16,7 @@
 #include <acpi/acpi.h>
 #include <linux/ide.h>
 #include <linux/pci.h>
+#include <linux/dmi.h>
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acnames.h>
@@ -65,6 +66,39 @@ extern int ide_noacpi;
 extern int ide_noacpitfs;
 extern int ide_noacpionboot;
 
+static bool ide_noacpi_psx;
+static int no_acpi_psx(const struct dmi_system_id *id)
+{
+       ide_noacpi_psx = true;
+       printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);
+       return 0;
+}
+
+static const struct dmi_system_id ide_acpi_dmi_table[] = {
+       /* Bug 9673. */
+       /* We should check if this is because ACPI NVS isn't save/restored. */
+       {
+               .callback = no_acpi_psx,
+               .ident    = "HP nx9005",
+               .matches  = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),
+                       DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")
+               },
+       },
+
+       { }     /* terminate list */
+};
+
+static int ide_acpi_blacklist(void)
+{
+       static int done;
+       if (done)
+               return 0;
+       done = 1;
+       dmi_check_system(ide_acpi_dmi_table);
+       return 0;
+}
+
 /**
  * ide_get_dev_handle - finds acpi_handle and PCI device.function
  * @dev: device to locate
@@ -349,27 +383,19 @@ static int taskfile_load_raw(ide_drive_t *drive,
               gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
 
        memset(&args, 0, sizeof(ide_task_t));
-       args.command_type = IDE_DRIVE_TASK_NO_DATA;
-       args.data_phase   = TASKFILE_NO_DATA;
-       args.handler      = &task_no_data_intr;
 
        /* convert gtf to IDE Taskfile */
-       args.tfRegister[1] = gtf->tfa[0];       /* 0x1f1 */
-       args.tfRegister[2] = gtf->tfa[1];       /* 0x1f2 */
-       args.tfRegister[3] = gtf->tfa[2];       /* 0x1f3 */
-       args.tfRegister[4] = gtf->tfa[3];       /* 0x1f4 */
-       args.tfRegister[5] = gtf->tfa[4];       /* 0x1f5 */
-       args.tfRegister[6] = gtf->tfa[5];       /* 0x1f6 */
-       args.tfRegister[7] = gtf->tfa[6];       /* 0x1f7 */
+       memcpy(&args.tf_array[7], &gtf->tfa, 7);
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
        if (ide_noacpitfs) {
                DEBPRINT("_GTF execution disabled\n");
                return err;
        }
 
-       err = ide_raw_taskfile(drive, &args, NULL);
+       err = ide_no_data_taskfile(drive, &args);
        if (err)
-               printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+               printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
                       __FUNCTION__, err);
 
        return err;
@@ -623,7 +649,7 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
 {
        int unit;
 
-       if (ide_noacpi)
+       if (ide_noacpi || ide_noacpi_psx)
                return;
 
        DEBPRINT("ENTER:\n");
@@ -668,6 +694,8 @@ void ide_acpi_init(ide_hwif_t *hwif)
        struct ide_acpi_drive_link      *master;
        struct ide_acpi_drive_link      *slave;
 
+       ide_acpi_blacklist();
+
        hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
        if (!hwif->acpidata)
                return;
index c7d77f0ad892d5ae82a1968e64d13b3374164dbd..44b033ec0ab03f893f8edfdca7f6c9d2e6d432a7 100644 (file)
@@ -917,19 +917,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
        if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
                return startstop;
 
+       /* FIXME: for Virtual DMA we must check harder */
        if (info->dma)
                info->dma = !hwif->dma_setup(drive);
 
        /* Set up the controller registers. */
-       /* FIXME: for Virtual DMA we must check harder */
-       HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
-       HWIF(drive)->OUTB(0, IDE_IREASON_REG);
-       HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
-
-       HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
-       HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
-       if (IDE_CONTROL_REG)
-               HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+       ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
+                          IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
  
        if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
                /* waiting for CDB interrupt, not DMA yet. */
index b1781908e1f2caffd4598a35c3037e1a60e59a85..717e114ced524d96bbd89a91ac8b3042ab9a4e8f 100644 (file)
@@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
        return 0;       /* lba_capacity value may be bad */
 }
 
+static const u8 ide_rw_cmds[] = {
+       WIN_MULTREAD,
+       WIN_MULTWRITE,
+       WIN_MULTREAD_EXT,
+       WIN_MULTWRITE_EXT,
+       WIN_READ,
+       WIN_WRITE,
+       WIN_READ_EXT,
+       WIN_WRITE_EXT,
+       WIN_READDMA,
+       WIN_WRITEDMA,
+       WIN_READDMA_EXT,
+       WIN_WRITEDMA_EXT,
+};
+
+static const u8 ide_data_phases[] = {
+       TASKFILE_MULTI_IN,
+       TASKFILE_MULTI_OUT,
+       TASKFILE_IN,
+       TASKFILE_OUT,
+       TASKFILE_IN_DMA,
+       TASKFILE_OUT_DMA,
+};
+
+static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
+{
+       u8 index, lba48, write;
+
+       lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
+       write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
+
+       if (dma)
+               index = drive->vdma ? 4 : 8;
+       else
+               index = drive->mult_count ? 0 : 4;
+
+       task->tf.command = ide_rw_cmds[index + lba48 + write];
+
+       if (dma)
+               index = 8; /* fixup index */
+
+       task->data_phase = ide_data_phases[index / 2 + write];
+}
+
 /*
  * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
  * using LBA if supported, or CHS otherwise, to address sectors.
@@ -137,11 +181,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 {
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned int dma        = drive->using_dma;
+       u16 nsectors            = (u16)rq->nr_sectors;
        u8 lba48                = (drive->addressing == 1) ? 1 : 0;
-       task_ioreg_t command    = WIN_NOP;
-       ata_nsector_t           nsectors;
-
-       nsectors.all            = (u16) rq->nr_sectors;
+       ide_task_t              task;
+       struct ide_taskfile     *tf = &task.tf;
+       ide_startstop_t         rc;
 
        if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
                if (block + rq->nr_sectors > 1ULL << 28)
@@ -155,121 +199,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                ide_map_sg(drive, rq);
        }
 
-       if (IDE_CONTROL_REG)
-               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-
-       /* FIXME: SELECT_MASK(drive, 0) ? */
+       memset(&task, 0, sizeof(task));
+       task.tf_flags = IDE_TFLAG_NO_SELECT_MASK;  /* FIXME? */
+       task.tf_flags |= (IDE_TFLAG_TF | IDE_TFLAG_DEVICE);
 
        if (drive->select.b.lba) {
                if (lba48) {
-                       task_ioreg_t tasklets[10];
-
                        pr_debug("%s: LBA=0x%012llx\n", drive->name,
                                        (unsigned long long)block);
 
-                       tasklets[0] = 0;
-                       tasklets[1] = 0;
-                       tasklets[2] = nsectors.b.low;
-                       tasklets[3] = nsectors.b.high;
-                       tasklets[4] = (task_ioreg_t) block;
-                       tasklets[5] = (task_ioreg_t) (block>>8);
-                       tasklets[6] = (task_ioreg_t) (block>>16);
-                       tasklets[7] = (task_ioreg_t) (block>>24);
-                       if (sizeof(block) == 4) {
-                               tasklets[8] = (task_ioreg_t) 0;
-                               tasklets[9] = (task_ioreg_t) 0;
-                       } else {
-                               tasklets[8] = (task_ioreg_t)((u64)block >> 32);
-                               tasklets[9] = (task_ioreg_t)((u64)block >> 40);
+                       tf->hob_nsect = (nsectors >> 8) & 0xff;
+                       tf->hob_lbal  = (u8)(block >> 24);
+                       if (sizeof(block) != 4) {
+                               tf->hob_lbam = (u8)((u64)block >> 32);
+                               tf->hob_lbah = (u8)((u64)block >> 40);
                        }
-#ifdef DEBUG
-                       printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
-                               drive->name, tasklets[3], tasklets[2],
-                               tasklets[9], tasklets[8], tasklets[7],
-                               tasklets[6], tasklets[5], tasklets[4]);
-#endif
-                       hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
-                       hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
-                       hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
-                       hwif->OUTB(tasklets[8], IDE_LCYL_REG);
-                       hwif->OUTB(tasklets[9], IDE_HCYL_REG);
-
-                       hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
-                       hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
-                       hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
-                       hwif->OUTB(tasklets[5], IDE_LCYL_REG);
-                       hwif->OUTB(tasklets[6], IDE_HCYL_REG);
-                       hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
+
+                       tf->nsect  = nsectors & 0xff;
+                       tf->lbal   = (u8) block;
+                       tf->lbam   = (u8)(block >>  8);
+                       tf->lbah   = (u8)(block >> 16);
+
+                       task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
                } else {
-                       hwif->OUTB(0x00, IDE_FEATURE_REG);
-                       hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
-                       hwif->OUTB(block, IDE_SECTOR_REG);
-                       hwif->OUTB(block>>=8, IDE_LCYL_REG);
-                       hwif->OUTB(block>>=8, IDE_HCYL_REG);
-                       hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+                       tf->nsect  = nsectors & 0xff;
+                       tf->lbal   = block;
+                       tf->lbam   = block >>= 8;
+                       tf->lbah   = block >>= 8;
+                       tf->device = (block >> 8) & 0xf;
                }
        } else {
                unsigned int sect,head,cyl,track;
                track = (int)block / drive->sect;
                sect  = (int)block % drive->sect + 1;
-               hwif->OUTB(sect, IDE_SECTOR_REG);
                head  = track % drive->head;
                cyl   = track / drive->head;
 
                pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
 
-               hwif->OUTB(0x00, IDE_FEATURE_REG);
-               hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
-               hwif->OUTB(cyl, IDE_LCYL_REG);
-               hwif->OUTB(cyl>>8, IDE_HCYL_REG);
-               hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
+               tf->nsect  = nsectors & 0xff;
+               tf->lbal   = sect;
+               tf->lbam   = cyl;
+               tf->lbah   = cyl >> 8;
+               tf->device = head;
        }
 
-       if (dma) {
-               if (!hwif->dma_setup(drive)) {
-                       if (rq_data_dir(rq)) {
-                               command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-                               if (drive->vdma)
-                                       command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
-                       } else {
-                               command = lba48 ? WIN_READDMA_EXT : WIN_READDMA;
-                               if (drive->vdma)
-                                       command = lba48 ? WIN_READ_EXT: WIN_READ;
-                       }
-                       hwif->dma_exec_cmd(drive, command);
-                       hwif->dma_start(drive);
-                       return ide_started;
-               }
-               /* fallback to PIO */
-               ide_init_sg_cmd(drive, rq);
-       }
-
-       if (rq_data_dir(rq) == READ) {
-
-               if (drive->mult_count) {
-                       hwif->data_phase = TASKFILE_MULTI_IN;
-                       command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-               } else {
-                       hwif->data_phase = TASKFILE_IN;
-                       command = lba48 ? WIN_READ_EXT : WIN_READ;
-               }
+       if (rq_data_dir(rq))
+               task.tf_flags |= IDE_TFLAG_WRITE;
 
-               ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);
-               return ide_started;
-       } else {
-               if (drive->mult_count) {
-                       hwif->data_phase = TASKFILE_MULTI_OUT;
-                       command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-               } else {
-                       hwif->data_phase = TASKFILE_OUT;
-                       command = lba48 ? WIN_WRITE_EXT : WIN_WRITE;
-               }
+       ide_tf_set_cmd(drive, &task, dma);
+       if (!dma)
+               hwif->data_phase = task.data_phase;
+       task.rq = rq;
 
-               /* FIXME: ->OUTBSYNC ? */
-               hwif->OUTB(command, IDE_COMMAND_REG);
+       rc = do_rw_taskfile(drive, &task);
 
-               return pre_task_out_intr(drive, rq);
+       if (rc == ide_stopped && dma) {
+               /* fallback to PIO */
+               task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
+               ide_tf_set_cmd(drive, &task, 0);
+               hwif->data_phase = task.data_phase;
+               ide_init_sg_cmd(drive, rq);
+               rc = do_rw_taskfile(drive, &task);
        }
+
+       return rc;
 }
 
 /*
@@ -307,57 +301,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
  */
-static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
 {
        ide_task_t args;
-       unsigned long addr = 0;
+       struct ide_taskfile *tf = &args.tf;
+       u64 addr = 0;
 
        /* Create IDE/ATA command request structure */
        memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_READ_NATIVE_MAX;
-       args.command_type                       = IDE_DRIVE_TASK_NO_DATA;
-       args.handler                            = &task_no_data_intr;
+       if (lba48)
+               tf->command = WIN_READ_NATIVE_MAX_EXT;
+       else
+               tf->command = WIN_READ_NATIVE_MAX;
+       tf->device  = ATA_LBA;
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       if (lba48)
+               args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
        /* submit command request */
-       ide_raw_taskfile(drive, &args, NULL);
+       ide_no_data_taskfile(drive, &args);
 
        /* if OK, compute maximum address value */
-       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-               addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
-                    | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
-                    | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
-                    | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
-               addr++; /* since the return value is (maxlba - 1), we add 1 */
-       }
-       return addr;
-}
+       if ((tf->status & 0x01) == 0)
+               addr = ide_get_lba_addr(tf, lba48) + 1;
 
-static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
-{
-       ide_task_t args;
-       unsigned long long addr = 0;
-
-       /* Create IDE/ATA command request structure */
-       memset(&args, 0, sizeof(ide_task_t));
-
-       args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_READ_NATIVE_MAX_EXT;
-       args.command_type                       = IDE_DRIVE_TASK_NO_DATA;
-       args.handler                            = &task_no_data_intr;
-        /* submit command request */
-        ide_raw_taskfile(drive, &args, NULL);
-
-       /* if OK, compute maximum address value */
-       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-               u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
-                          (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
-                           args.hobRegister[IDE_SECTOR_OFFSET];
-               u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
-                          ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
-                           (args.tfRegister[IDE_SECTOR_OFFSET]);
-               addr = ((__u64)high << 24) | low;
-               addr++; /* since the return value is (maxlba - 1), we add 1 */
-       }
        return addr;
 }
 
@@ -365,67 +331,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
  * Sets maximum virtual LBA address of the drive.
  * Returns new maximum virtual LBA address (> 0) or 0 on failure.
  */
-static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
-{
-       ide_task_t args;
-       unsigned long addr_set = 0;
-       
-       addr_req--;
-       /* Create IDE/ATA command request structure */
-       memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_SECTOR_OFFSET]      = ((addr_req >>  0) & 0xff);
-       args.tfRegister[IDE_LCYL_OFFSET]        = ((addr_req >>  8) & 0xff);
-       args.tfRegister[IDE_HCYL_OFFSET]        = ((addr_req >> 16) & 0xff);
-       args.tfRegister[IDE_SELECT_OFFSET]      = ((addr_req >> 24) & 0x0f) | 0x40;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SET_MAX;
-       args.command_type                       = IDE_DRIVE_TASK_NO_DATA;
-       args.handler                            = &task_no_data_intr;
-       /* submit command request */
-       ide_raw_taskfile(drive, &args, NULL);
-       /* if OK, read new maximum address value */
-       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-               addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
-                        | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
-                        | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
-                        | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
-               addr_set++;
-       }
-       return addr_set;
-}
-
-static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
 {
        ide_task_t args;
-       unsigned long long addr_set = 0;
+       struct ide_taskfile *tf = &args.tf;
+       u64 addr_set = 0;
 
        addr_req--;
        /* Create IDE/ATA command request structure */
        memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_SECTOR_OFFSET]      = ((addr_req >>  0) & 0xff);
-       args.tfRegister[IDE_LCYL_OFFSET]        = ((addr_req >>= 8) & 0xff);
-       args.tfRegister[IDE_HCYL_OFFSET]        = ((addr_req >>= 8) & 0xff);
-       args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SET_MAX_EXT;
-       args.hobRegister[IDE_SECTOR_OFFSET]     = (addr_req >>= 8) & 0xff;
-       args.hobRegister[IDE_LCYL_OFFSET]       = (addr_req >>= 8) & 0xff;
-       args.hobRegister[IDE_HCYL_OFFSET]       = (addr_req >>= 8) & 0xff;
-       args.hobRegister[IDE_SELECT_OFFSET]     = 0x40;
-       args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-       args.command_type                       = IDE_DRIVE_TASK_NO_DATA;
-       args.handler                            = &task_no_data_intr;
+       tf->lbal     = (addr_req >>  0) & 0xff;
+       tf->lbam     = (addr_req >>= 8) & 0xff;
+       tf->lbah     = (addr_req >>= 8) & 0xff;
+       if (lba48) {
+               tf->hob_lbal = (addr_req >>= 8) & 0xff;
+               tf->hob_lbam = (addr_req >>= 8) & 0xff;
+               tf->hob_lbah = (addr_req >>= 8) & 0xff;
+               tf->command  = WIN_SET_MAX_EXT;
+       } else {
+               tf->device   = (addr_req >>= 8) & 0x0f;
+               tf->command  = WIN_SET_MAX;
+       }
+       tf->device |= ATA_LBA;
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       if (lba48)
+               args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
        /* submit command request */
-       ide_raw_taskfile(drive, &args, NULL);
+       ide_no_data_taskfile(drive, &args);
        /* if OK, compute maximum address value */
-       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-               u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
-                          (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
-                           args.hobRegister[IDE_SECTOR_OFFSET];
-               u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
-                          ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
-                           (args.tfRegister[IDE_SECTOR_OFFSET]);
-               addr_set = ((__u64)high << 24) | low;
-               addr_set++;
-       }
+       if ((tf->status & 0x01) == 0)
+               addr_set = ide_get_lba_addr(tf, lba48) + 1;
+
        return addr_set;
 }
 
@@ -471,10 +407,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
        int lba48 = idedisk_supports_lba48(drive->id);
 
        capacity = drive->capacity64;
-       if (lba48)
-               set_max = idedisk_read_native_max_address_ext(drive);
-       else
-               set_max = idedisk_read_native_max_address(drive);
+
+       set_max = idedisk_read_native_max_address(drive, lba48);
 
        if (ide_in_drive_list(drive->id, hpa_list)) {
                /*
@@ -495,10 +429,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
                         capacity, sectors_to_MB(capacity),
                         set_max, sectors_to_MB(set_max));
 
-       if (lba48)
-               set_max = idedisk_set_max_address_ext(drive, set_max);
-       else
-               set_max = idedisk_set_max_address(drive, set_max);
+       set_max = idedisk_set_max_address(drive, set_max, lba48);
+
        if (set_max) {
                drive->capacity64 = set_max;
                printk(KERN_INFO "%s: Host Protected Area disabled.\n",
@@ -556,32 +488,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
 static int smart_enable(ide_drive_t *drive)
 {
        ide_task_t args;
+       struct ide_taskfile *tf = &args.tf;
 
        memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_FEATURE_OFFSET]     = SMART_ENABLE;
-       args.tfRegister[IDE_LCYL_OFFSET]        = SMART_LCYL_PASS;
-       args.tfRegister[IDE_HCYL_OFFSET]        = SMART_HCYL_PASS;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SMART;
-       args.command_type                       = IDE_DRIVE_TASK_NO_DATA;
-       args.handler                            = &task_no_data_intr;
-       return ide_raw_taskfile(drive, &args, NULL);
+       tf->feature = SMART_ENABLE;
+       tf->lbam    = SMART_LCYL_PASS;
+       tf->lbah    = SMART_HCYL_PASS;
+       tf->command = WIN_SMART;
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       return ide_no_data_taskfile(drive, &args);
 }
 
 static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
 {
        ide_task_t args;
+       struct ide_taskfile *tf = &args.tf;
 
        memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_FEATURE_OFFSET]     = sub_cmd;
-       args.tfRegister[IDE_NSECTOR_OFFSET]     = 0x01;
-       args.tfRegister[IDE_LCYL_OFFSET]        = SMART_LCYL_PASS;
-       args.tfRegister[IDE_HCYL_OFFSET]        = SMART_HCYL_PASS;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SMART;
-       args.command_type                       = IDE_DRIVE_TASK_IN;
-       args.data_phase                         = TASKFILE_IN;
-       args.handler                            = &task_in_intr;
+       tf->feature = sub_cmd;
+       tf->nsect   = 0x01;
+       tf->lbam    = SMART_LCYL_PASS;
+       tf->lbah    = SMART_HCYL_PASS;
+       tf->command = WIN_SMART;
+       args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       args.data_phase = TASKFILE_IN;
        (void) smart_enable(drive);
-       return ide_raw_taskfile(drive, &args, buf);
+       return ide_raw_taskfile(drive, &args, buf, 1);
 }
 
 static int proc_idedisk_read_cache
@@ -659,19 +591,20 @@ static ide_proc_entry_t idedisk_proc[] = {
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
        ide_drive_t *drive = q->queuedata;
+       ide_task_t task;
 
-       memset(rq->cmd, 0, sizeof(rq->cmd));
-
+       memset(&task, 0, sizeof(task));
        if (ide_id_has_flush_cache_ext(drive->id) &&
            (drive->capacity64 >= (1UL << 28)))
-               rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
+               task.tf.command = WIN_FLUSH_CACHE_EXT;
        else
-               rq->cmd[0] = WIN_FLUSH_CACHE;
+               task.tf.command = WIN_FLUSH_CACHE;
+       task.tf_flags   = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+       task.data_phase = TASKFILE_NO_DATA;
 
-
-       rq->cmd_type = REQ_TYPE_ATA_TASK;
+       rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
        rq->cmd_flags |= REQ_SOFTBARRIER;
-       rq->buffer = rq->cmd;
+       rq->special = &task;
 }
 
 /*
@@ -687,8 +620,10 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
        if (drive->special.b.set_multmode)
                return -EBUSY;
+
        ide_init_drive_cmd (&rq);
-       rq.cmd_type = REQ_TYPE_ATA_CMD;
+       rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
        drive->mult_req = arg;
        drive->special.b.set_multmode = 1;
        (void) ide_do_drive_cmd (drive, &rq, ide_wait);
@@ -753,12 +688,11 @@ static int write_cache(ide_drive_t *drive, int arg)
 
        if (ide_id_has_flush_cache(drive->id)) {
                memset(&args, 0, sizeof(ide_task_t));
-               args.tfRegister[IDE_FEATURE_OFFSET]     = (arg) ?
+               args.tf.feature = arg ?
                        SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-               args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SETFEATURES;
-               args.command_type               = IDE_DRIVE_TASK_NO_DATA;
-               args.handler                    = &task_no_data_intr;
-               err = ide_raw_taskfile(drive, &args, NULL);
+               args.tf.command = WIN_SETFEATURES;
+               args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+               err = ide_no_data_taskfile(drive, &args);
                if (err == 0)
                        drive->wcache = arg;
        }
@@ -774,12 +708,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
 
        memset(&args, 0, sizeof(ide_task_t));
        if (ide_id_has_flush_cache_ext(drive->id))
-               args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_FLUSH_CACHE_EXT;
+               args.tf.command = WIN_FLUSH_CACHE_EXT;
        else
-               args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_FLUSH_CACHE;
-       args.command_type                       = IDE_DRIVE_TASK_NO_DATA;
-       args.handler                            = &task_no_data_intr;
-       return ide_raw_taskfile(drive, &args, NULL);
+               args.tf.command = WIN_FLUSH_CACHE;
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       return ide_no_data_taskfile(drive, &args);
 }
 
 static int set_acoustic (ide_drive_t *drive, int arg)
@@ -790,13 +723,11 @@ static int set_acoustic (ide_drive_t *drive, int arg)
                return -EINVAL;
 
        memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_FEATURE_OFFSET]     = (arg) ? SETFEATURES_EN_AAM :
-                                                         SETFEATURES_DIS_AAM;
-       args.tfRegister[IDE_NSECTOR_OFFSET]     = arg;
-       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SETFEATURES;
-       args.command_type = IDE_DRIVE_TASK_NO_DATA;
-       args.handler      = &task_no_data_intr;
-       ide_raw_taskfile(drive, &args, NULL);
+       args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM;
+       args.tf.nsect   = arg;
+       args.tf.command = WIN_SETFEATURES;
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       ide_no_data_taskfile(drive, &args);
        drive->acoustic = arg;
        return 0;
 }
@@ -832,7 +763,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
        ide_add_setting(drive,  "bios_head",    SETTING_RW,     TYPE_BYTE,      0,      255,                    1,      1,      &drive->bios_head,      NULL);
        ide_add_setting(drive,  "bios_sect",    SETTING_RW,     TYPE_BYTE,      0,      63,                     1,      1,      &drive->bios_sect,      NULL);
        ide_add_setting(drive,  "address",      SETTING_RW,     TYPE_BYTE,      0,      2,                      1,      1,      &drive->addressing,     set_lba_addressing);
-       ide_add_setting(drive,  "bswap",        SETTING_READ,   TYPE_BYTE,      0,      1,                      1,      1,      &drive->bswap,          NULL);
        ide_add_setting(drive,  "multcount",    SETTING_RW,     TYPE_BYTE,      0,      id->max_multsect,       1,      1,      &drive->mult_count,     set_multcount);
        ide_add_setting(drive,  "nowerr",       SETTING_RW,     TYPE_BYTE,      0,      1,                      1,      1,      &drive->nowerr,         set_nowerr);
        ide_add_setting(drive,  "lun",          SETTING_RW,     TYPE_INT,       0,      7,                      1,      1,      &drive->lun,            NULL);
@@ -1041,6 +971,17 @@ static ide_driver_t idedisk_driver = {
 #endif
 };
 
+static int idedisk_set_doorlock(ide_drive_t *drive, int on)
+{
+       ide_task_t task;
+
+       memset(&task, 0, sizeof(task));
+       task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       return ide_no_data_taskfile(drive, &task);
+}
+
 static int idedisk_open(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
@@ -1055,18 +996,13 @@ static int idedisk_open(struct inode *inode, struct file *filp)
        idkp->openers++;
 
        if (drive->removable && idkp->openers == 1) {
-               ide_task_t args;
-               memset(&args, 0, sizeof(ide_task_t));
-               args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
-               args.command_type = IDE_DRIVE_TASK_NO_DATA;
-               args.handler      = &task_no_data_intr;
                check_disk_change(inode->i_bdev);
                /*
                 * Ignore the return code from door_lock,
                 * since the open() has already succeeded,
                 * and the door_lock is irrelevant at this point.
                 */
-               if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+               if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
                        drive->doorlocking = 0;
        }
        return 0;
@@ -1082,12 +1018,7 @@ static int idedisk_release(struct inode *inode, struct file *filp)
                ide_cacheflush_p(drive);
 
        if (drive->removable && idkp->openers == 1) {
-               ide_task_t args;
-               memset(&args, 0, sizeof(ide_task_t));
-               args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
-               args.command_type = IDE_DRIVE_TASK_NO_DATA;
-               args.handler      = &task_no_data_intr;
-               if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+               if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
                        drive->doorlocking = 0;
        }
 
index 4703837bf1fcdab9b6523c2fa4d5ff70bccd50a3..5bf32038dc435ed029644d425045efbdde610397 100644 (file)
@@ -153,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
                if (!dma_stat) {
                        struct request *rq = HWGROUP(drive)->rq;
 
-                       if (rq->rq_disk) {
-                               ide_driver_t *drv;
-
-                               drv = *(ide_driver_t **)rq->rq_disk->private_data;
-                               drv->end_request(drive, 1, rq->nr_sectors);
-                       } else
-                               ide_end_request(drive, 1, rq->nr_sectors);
+                       task_end_request(drive, rq, stat);
                        return ide_stopped;
                }
                printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
@@ -408,23 +402,29 @@ static int dma_timer_expiry (ide_drive_t *drive)
 }
 
 /**
- *     ide_dma_host_off        -       Generic DMA kill
+ *     ide_dma_host_set        -       Enable/disable DMA on a host
  *     @drive: drive to control
  *
- *     Perform the generic IDE controller DMA off operation. This
- *     works for most IDE bus mastering controllers
+ *     Enable/disable DMA on an IDE controller following generic
+ *     bus-mastering IDE controller behaviour.
  */
 
-void ide_dma_host_off(ide_drive_t *drive)
+void ide_dma_host_set(ide_drive_t *drive, int on)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        u8 unit                 = (drive->select.b.unit & 0x01);
        u8 dma_stat             = hwif->INB(hwif->dma_status);
 
-       hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+       if (on)
+               dma_stat |= (1 << (5 + unit));
+       else
+               dma_stat &= ~(1 << (5 + unit));
+
+       hwif->OUTB(dma_stat, hwif->dma_status);
 }
 
-EXPORT_SYMBOL(ide_dma_host_off);
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *     ide_dma_off_quietly     -       Generic DMA kill
@@ -438,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
        drive->using_dma = 0;
        ide_toggle_bounce(drive, 0);
 
-       drive->hwif->dma_host_off(drive);
+       drive->hwif->dma_host_set(drive, 0);
 }
 
 EXPORT_SYMBOL(ide_dma_off_quietly);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *     ide_dma_off     -       disable DMA on a device
@@ -455,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
 void ide_dma_off(ide_drive_t *drive)
 {
        printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-       drive->hwif->dma_off_quietly(drive);
+       ide_dma_off_quietly(drive);
 }
 
 EXPORT_SYMBOL(ide_dma_off);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
- *     ide_dma_host_on -       Enable DMA on a host
- *     @drive: drive to enable for DMA
- *
- *     Enable DMA on an IDE controller following generic bus mastering
- *     IDE controller behaviour
- */
-
-void ide_dma_host_on(ide_drive_t *drive)
-{
-       if (drive->using_dma) {
-               ide_hwif_t *hwif        = HWIF(drive);
-               u8 unit                 = (drive->select.b.unit & 0x01);
-               u8 dma_stat             = hwif->INB(hwif->dma_status);
-
-               hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
-       }
-}
-
-EXPORT_SYMBOL(ide_dma_host_on);
-
-/**
- *     __ide_dma_on            -       Enable DMA on a device
+ *     ide_dma_on              -       Enable DMA on a device
  *     @drive: drive to enable DMA on
  *
  *     Enable IDE DMA for a device on this IDE controller.
  */
-int __ide_dma_on (ide_drive_t *drive)
-{
-       /* consult the list of known "bad" drives */
-       if (__ide_dma_bad_drive(drive))
-               return 1;
 
+void ide_dma_on(ide_drive_t *drive)
+{
        drive->using_dma = 1;
        ide_toggle_bounce(drive, 1);
 
-       drive->hwif->dma_host_on(drive);
-
-       return 0;
+       drive->hwif->dma_host_set(drive, 1);
 }
 
-EXPORT_SYMBOL(__ide_dma_on);
+EXPORT_SYMBOL(ide_dma_on);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_dma_setup   -       begin a DMA phase
  *     @drive: target device
@@ -759,6 +731,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 static int ide_tune_dma(ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = drive->hwif;
        u8 speed;
 
        if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
@@ -771,15 +744,21 @@ static int ide_tune_dma(ide_drive_t *drive)
        if (ide_id_dma_bug(drive))
                return 0;
 
-       if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+       if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
                return config_drive_for_dma(drive);
 
        speed = ide_max_dma_mode(drive);
 
-       if (!speed)
-               return 0;
+       if (!speed) {
+                /* is this really correct/needed? */
+               if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
+                   ide_dma_good_drive(drive))
+                       return 1;
+               else
+                       return 0;
+       }
 
-       if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
                return 0;
 
        if (ide_set_dma_mode(drive, speed))
@@ -824,25 +803,23 @@ err_out:
 
 int ide_set_dma(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = drive->hwif;
        int rc;
 
+       /*
+        * Force DMAing for the beginning of the check.
+        * Some chipsets appear to do interesting
+        * things, if not checked and cleared.
+        *   PARANOIA!!!
+        */
+       ide_dma_off_quietly(drive);
+
        rc = ide_dma_check(drive);
+       if (rc)
+               return rc;
 
-       switch(rc) {
-       case -1: /* DMA needs to be disabled */
-               hwif->dma_off_quietly(drive);
-               return -1;
-       case  0: /* DMA needs to be enabled */
-               return hwif->ide_dma_on(drive);
-       case  1: /* DMA setting cannot be changed */
-               break;
-       default:
-               BUG();
-               break;
-       }
+       ide_dma_on(drive);
 
-       return rc;
+       return 0;
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -968,11 +945,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
 
        hwif->dma_base = base;
 
-       if (hwif->mate)
-               hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base;
-       else
-               hwif->dma_master = base;
-
        if (!(hwif->dma_command))
                hwif->dma_command       = hwif->dma_base;
        if (!(hwif->dma_vendor1))
@@ -984,14 +956,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
        if (!(hwif->dma_prdtable))
                hwif->dma_prdtable      = (hwif->dma_base + 4);
 
-       if (!hwif->dma_off_quietly)
-               hwif->dma_off_quietly = &ide_dma_off_quietly;
-       if (!hwif->dma_host_off)
-               hwif->dma_host_off = &ide_dma_host_off;
-       if (!hwif->ide_dma_on)
-               hwif->ide_dma_on = &__ide_dma_on;
-       if (!hwif->dma_host_on)
-               hwif->dma_host_on = &ide_dma_host_on;
+       if (!hwif->dma_host_set)
+               hwif->dma_host_set = &ide_dma_host_set;
        if (!hwif->dma_setup)
                hwif->dma_setup = &ide_dma_setup;
        if (!hwif->dma_exec_cmd)
@@ -1014,8 +980,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
                       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
        }
        printk("\n");
-
-       BUG_ON(!hwif->dma_master);
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_dma);
index 04a357808f2e82a883770292bf00c5bd3e4f48cb..ff8232ef96598ae784001a0a61dd2da69a91c69a 100644 (file)
@@ -369,27 +369,6 @@ typedef struct ide_floppy_obj {
 #define        IDEFLOPPY_IOCTL_FORMAT_START            0x4602
 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS    0x4603
 
-#if 0
-/*
- *     Special requests for our block device strategy routine.
- */
-#define        IDEFLOPPY_FIRST_RQ      90
-
-/*
- *     IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
- */
-#define        IDEFLOPPY_PC_RQ         90
-
-#define IDEFLOPPY_LAST_RQ      90
-
-/*
- *     A macro which can be used to check if a given request command
- *     originated in the driver or in the buffer cache layer.
- */
-#define IDEFLOPPY_RQ_CMD(cmd)  ((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
-
-#endif
-
 /*
  *     Error codes which are returned in rq->errors to the higher part
  *     of the driver.
@@ -793,9 +772,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
 {
        idefloppy_pc_t *pc;
        struct request *rq;
-       atapi_error_t error;
 
-       error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+       (void)drive->hwif->INB(IDE_ERROR_REG);
        pc = idefloppy_next_pc_storage(drive);
        rq = idefloppy_next_rq_storage(drive);
        idefloppy_create_request_sense_cmd(pc);
@@ -809,12 +787,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
-       atapi_status_t status;
-       atapi_bcount_t bcount;
-       atapi_ireason_t ireason;
+       ide_hwif_t *hwif = drive->hwif;
        idefloppy_pc_t *pc = floppy->pc;
        struct request *rq = pc->rq;
        unsigned int temp;
+       u16 bcount;
+       u8 stat, ireason;
 
        debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
                __FUNCTION__);
@@ -830,16 +808,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
        }
 
        /* Clear the interrupt */
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = drive->hwif->INB(IDE_STATUS_REG);
 
-       if (!status.b.drq) {                    /* No more interrupts */
+       if ((stat & DRQ_STAT) == 0) {           /* No more interrupts */
                debug_log(KERN_INFO "Packet command completed, %d bytes "
                        "transferred\n", pc->actually_transferred);
                clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
                local_irq_enable_in_hardirq();
 
-               if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+               if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
                        /* Error detected */
                        debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
                                drive->name);
@@ -870,32 +848,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
        }
 
        /* Get the number of bytes to transfer */
-       bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-       bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+       bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+                 hwif->INB(IDE_BCOUNTL_REG);
        /* on this interrupt */
-       ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+       ireason = hwif->INB(IDE_IREASON_REG);
 
-       if (ireason.b.cod) {
+       if (ireason & CD) {
                printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
                return ide_do_reset(drive);
        }
-       if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+       if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "ide-floppy: We wanted to %s, ",
-                       ireason.b.io ? "Write":"Read");
+                               (ireason & IO) ? "Write" : "Read");
                printk(KERN_ERR "but the floppy wants us to %s !\n",
-                       ireason.b.io ? "Read":"Write");
+                               (ireason & IO) ? "Read" : "Write");
                return ide_do_reset(drive);
        }
        if (!test_bit(PC_WRITING, &pc->flags)) {
                /* Reading - Check that we have enough space */
-               temp = pc->actually_transferred + bcount.all;
+               temp = pc->actually_transferred + bcount;
                if (temp > pc->request_transfer) {
                        if (temp > pc->buffer_size) {
                                printk(KERN_ERR "ide-floppy: The floppy wants "
                                        "to send us more data than expected "
                                        "- discarding data\n");
-                               idefloppy_discard_data(drive,bcount.all);
+                               idefloppy_discard_data(drive, bcount);
                                BUG_ON(HWGROUP(drive)->handler != NULL);
                                ide_set_handler(drive,
                                                &idefloppy_pc_intr,
@@ -911,23 +889,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
        if (test_bit(PC_WRITING, &pc->flags)) {
                if (pc->buffer != NULL)
                        /* Write the current buffer */
-                       HWIF(drive)->atapi_output_bytes(drive,
-                                               pc->current_position,
-                                               bcount.all);
+                       hwif->atapi_output_bytes(drive, pc->current_position,
+                                                bcount);
                else
-                       idefloppy_output_buffers(drive, pc, bcount.all);
+                       idefloppy_output_buffers(drive, pc, bcount);
        } else {
                if (pc->buffer != NULL)
                        /* Read the current buffer */
-                       HWIF(drive)->atapi_input_bytes(drive,
-                                               pc->current_position,
-                                               bcount.all);
+                       hwif->atapi_input_bytes(drive, pc->current_position,
+                                               bcount);
                else
-                       idefloppy_input_buffers(drive, pc, bcount.all);
+                       idefloppy_input_buffers(drive, pc, bcount);
        }
        /* Update the current position */
-       pc->actually_transferred += bcount.all;
-       pc->current_position += bcount.all;
+       pc->actually_transferred += bcount;
+       pc->current_position += bcount;
 
        BUG_ON(HWGROUP(drive)->handler != NULL);
        ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);           /* And set the interrupt handler again */
@@ -943,15 +919,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
        ide_startstop_t startstop;
        idefloppy_floppy_t *floppy = drive->driver_data;
-       atapi_ireason_t ireason;
+       u8 ireason;
 
        if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
                printk(KERN_ERR "ide-floppy: Strange, packet command "
                                "initiated yet DRQ isn't asserted\n");
                return startstop;
        }
-       ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
-       if (!ireason.b.cod || ireason.b.io) {
+       ireason = drive->hwif->INB(IDE_IREASON_REG);
+       if ((ireason & CD) == 0 || (ireason & IO)) {
                printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
                                "issuing a packet command\n");
                return ide_do_reset(drive);
@@ -991,15 +967,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        ide_startstop_t startstop;
-       atapi_ireason_t ireason;
+       u8 ireason;
 
        if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
                printk(KERN_ERR "ide-floppy: Strange, packet command "
                                "initiated yet DRQ isn't asserted\n");
                return startstop;
        }
-       ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
-       if (!ireason.b.cod || ireason.b.io) {
+       ireason = drive->hwif->INB(IDE_IREASON_REG);
+       if ((ireason & CD) == 0 || (ireason & IO)) {
                printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
                                "while issuing a packet command\n");
                return ide_do_reset(drive);
@@ -1041,21 +1017,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        ide_hwif_t *hwif = drive->hwif;
-       atapi_feature_t feature;
-       atapi_bcount_t bcount;
        ide_handler_t *pkt_xfer_routine;
-
-#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone
-         and have lived on another thread's stack; that stack may have become
-         unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */
-#if IDEFLOPPY_DEBUG_BUGS
-       if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
-           pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-               printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
-                       "Two request sense in serial were issued\n");
-       }
-#endif /* IDEFLOPPY_DEBUG_BUGS */
-#endif
+       u16 bcount;
+       u8 dma;
 
        if (floppy->failed_pc == NULL &&
            pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
@@ -1093,25 +1057,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
        /* We haven't transferred any data yet */
        pc->actually_transferred = 0;
        pc->current_position = pc->buffer;
-       bcount.all = min(pc->request_transfer, 63 * 1024);
+       bcount = min(pc->request_transfer, 63 * 1024);
 
        if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
                ide_dma_off(drive);
 
-       feature.all = 0;
+       dma = 0;
 
        if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-               feature.b.dma = !hwif->dma_setup(drive);
+               dma = !hwif->dma_setup(drive);
 
-       if (IDE_CONTROL_REG)
-               HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
-       /* Use PIO/DMA */
-       HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
-       HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-       HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
-       HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+       ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
+                          IDE_TFLAG_OUT_DEVICE, bcount, dma);
 
-       if (feature.b.dma) {    /* Begin DMA, if necessary */
+       if (dma) {      /* Begin DMA, if necessary */
                set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
                hwif->dma_start(drive);
        }
@@ -1665,14 +1624,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
                /* Else assume format_unit has finished, and we're
                ** at 0x10000 */
        } else {
-               atapi_status_t status;
                unsigned long flags;
+               u8 stat;
 
                local_irq_save(flags);
-               status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+               stat = drive->hwif->INB(IDE_STATUS_REG);
                local_irq_restore(flags);
 
-               progress_indication = !status.b.dsc ? 0 : 0x10000;
+               progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
        }
        if (put_user(progress_indication, arg))
                return (-EFAULT);
index 0f72b98d727f43ba72f4d68b2a53871ec9806bcd..bb30c29f6ec04599d7d55d86ffc5cdc351c3b9c4 100644 (file)
 
 static int __init ide_generic_init(void)
 {
+       u8 idx[MAX_HWIFS];
+       int i;
+
        if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
                ide_get_lock(NULL, NULL); /* for atari only */
 
-       (void)ideprobe_init();
+       for (i = 0; i < MAX_HWIFS; i++)
+               idx[i] = ide_hwifs[i].present ? 0xff : i;
+
+       ide_device_add_all(idx);
 
        if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
                ide_release_lock();     /* for atari only */
index bef781fec5006d694069c614e2bda90ebec2b277..6f8f544392a82a5e4fdd90af36539694fd2d1037 100644 (file)
@@ -75,7 +75,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
         */
        if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
                drive->state = 0;
-               HWGROUP(drive)->hwif->ide_dma_on(drive);
+               ide_dma_on(drive);
        }
 
        if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
@@ -189,18 +189,14 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
                        return ide_stopped;
                }
                if (ide_id_has_flush_cache_ext(drive->id))
-                       args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
+                       args->tf.command = WIN_FLUSH_CACHE_EXT;
                else
-                       args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
-               args->command_type = IDE_DRIVE_TASK_NO_DATA;
-               args->handler      = &task_no_data_intr;
-               return do_rw_taskfile(drive, args);
+                       args->tf.command = WIN_FLUSH_CACHE;
+               goto out_do_tf;
 
        case idedisk_pm_standby:        /* Suspend step 2 (standby) */
-               args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
-               args->command_type = IDE_DRIVE_TASK_NO_DATA;
-               args->handler      = &task_no_data_intr;
-               return do_rw_taskfile(drive, args);
+               args->tf.command = WIN_STANDBYNOW1;
+               goto out_do_tf;
 
        case idedisk_pm_restore_pio:    /* Resume step 1 (restore PIO) */
                ide_set_max_pio(drive);
@@ -214,10 +210,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
                return ide_stopped;
 
        case idedisk_pm_idle:           /* Resume step 2 (idle) */
-               args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
-               args->command_type = IDE_DRIVE_TASK_NO_DATA;
-               args->handler = task_no_data_intr;
-               return do_rw_taskfile(drive, args);
+               args->tf.command = WIN_IDLEIMMEDIATE;
+               goto out_do_tf;
 
        case ide_pm_restore_dma:        /* Resume step 3 (restore DMA) */
                /*
@@ -225,9 +219,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
                 * we could be smarter and check for current xfer_speed
                 * in struct drive etc...
                 */
-               if (drive->hwif->ide_dma_on == NULL)
+               if (drive->hwif->dma_host_set == NULL)
                        break;
-               drive->hwif->dma_off_quietly(drive);
                /*
                 * TODO: respect ->using_dma setting
                 */
@@ -236,6 +229,11 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
        }
        pm->pm_step = ide_pm_state_completed;
        return ide_stopped;
+
+out_do_tf:
+       args->tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       args->data_phase = TASKFILE_NO_DATA;
+       return do_rw_taskfile(drive, args);
 }
 
 /**
@@ -298,6 +296,48 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
        spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_taskfile *tf = &task->tf;
+
+       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+               u16 data = hwif->INW(IDE_DATA_REG);
+
+               tf->data = data & 0xff;
+               tf->hob_data = (data >> 8) & 0xff;
+       }
+
+       /* be sure we're looking at the low order bits */
+       hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
+
+       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+               tf->nsect  = hwif->INB(IDE_NSECTOR_REG);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+               tf->lbal   = hwif->INB(IDE_SECTOR_REG);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+               tf->lbam   = hwif->INB(IDE_LCYL_REG);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+               tf->lbah   = hwif->INB(IDE_HCYL_REG);
+       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+               tf->device = hwif->INB(IDE_SELECT_REG);
+
+       if (task->tf_flags & IDE_TFLAG_LBA48) {
+               hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG);
+
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+                       tf->hob_feature = hwif->INB(IDE_FEATURE_REG);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect   = hwif->INB(IDE_NSECTOR_REG);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal    = hwif->INB(IDE_SECTOR_REG);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam    = hwif->INB(IDE_LCYL_REG);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah    = hwif->INB(IDE_HCYL_REG);
+       }
+}
+
 /**
  *     ide_end_drive_cmd       -       end an explicit drive command
  *     @drive: command 
@@ -314,7 +354,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
  
 void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 {
-       ide_hwif_t *hwif = HWIF(drive);
        unsigned long flags;
        struct request *rq;
 
@@ -322,61 +361,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
        rq = HWGROUP(drive)->rq;
        spin_unlock_irqrestore(&ide_lock, flags);
 
-       if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-               u8 *args = (u8 *) rq->buffer;
-               if (rq->errors == 0)
-                       rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-
-               if (args) {
-                       args[0] = stat;
-                       args[1] = err;
-                       args[2] = hwif->INB(IDE_NSECTOR_REG);
-               }
-       } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
-               u8 *args = (u8 *) rq->buffer;
-               if (rq->errors == 0)
-                       rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-
-               if (args) {
-                       args[0] = stat;
-                       args[1] = err;
-                       /* be sure we're looking at the low order bits */
-                       hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
-                       args[2] = hwif->INB(IDE_NSECTOR_REG);
-                       args[3] = hwif->INB(IDE_SECTOR_REG);
-                       args[4] = hwif->INB(IDE_LCYL_REG);
-                       args[5] = hwif->INB(IDE_HCYL_REG);
-                       args[6] = hwif->INB(IDE_SELECT_REG);
-               }
-       } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
                ide_task_t *args = (ide_task_t *) rq->special;
                if (rq->errors == 0)
                        rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
                        
                if (args) {
-                       if (args->tf_in_flags.b.data) {
-                               u16 data                                = hwif->INW(IDE_DATA_REG);
-                               args->tfRegister[IDE_DATA_OFFSET]       = (data) & 0xFF;
-                               args->hobRegister[IDE_DATA_OFFSET]      = (data >> 8) & 0xFF;
-                       }
-                       args->tfRegister[IDE_ERROR_OFFSET]   = err;
-                       /* be sure we're looking at the low order bits */
-                       hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
-                       args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
-                       args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
-                       args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
-                       args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
-                       args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
-                       args->tfRegister[IDE_STATUS_OFFSET]  = stat;
-
-                       if (drive->addressing == 1) {
-                               hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
-                               args->hobRegister[IDE_FEATURE_OFFSET]   = hwif->INB(IDE_FEATURE_REG);
-                               args->hobRegister[IDE_NSECTOR_OFFSET]   = hwif->INB(IDE_NSECTOR_REG);
-                               args->hobRegister[IDE_SECTOR_OFFSET]    = hwif->INB(IDE_SECTOR_REG);
-                               args->hobRegister[IDE_LCYL_OFFSET]      = hwif->INB(IDE_LCYL_REG);
-                               args->hobRegister[IDE_HCYL_OFFSET]      = hwif->INB(IDE_HCYL_REG);
-                       }
+                       struct ide_taskfile *tf = &args->tf;
+
+                       tf->error = err;
+                       tf->status = stat;
+
+                       ide_tf_read(drive, args);
                }
        } else if (blk_pm_request(rq)) {
                struct request_pm_state *pm = rq->data;
@@ -615,90 +611,26 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
                return __ide_abort(drive, rq);
 }
 
-/**
- *     ide_cmd         -       issue a simple drive command
- *     @drive: drive the command is for
- *     @cmd: command byte
- *     @nsect: sector byte
- *     @handler: handler for the command completion
- *
- *     Issue a simple drive command with interrupts.
- *     The drive must be selected beforehand.
- */
-
-static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect,
-               ide_handler_t *handler)
+static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       if (IDE_CONTROL_REG)
-               hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
-       SELECT_MASK(drive,0);
-       hwif->OUTB(nsect,IDE_NSECTOR_REG);
-       ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);
+       tf->nsect   = drive->sect;
+       tf->lbal    = drive->sect;
+       tf->lbam    = drive->cyl;
+       tf->lbah    = drive->cyl >> 8;
+       tf->device  = ((drive->head - 1) | drive->select.all) & ~ATA_LBA;
+       tf->command = WIN_SPECIFY;
 }
 
-/**
- *     drive_cmd_intr          -       drive command completion interrupt
- *     @drive: drive the completion interrupt occurred on
- *
- *     drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
- *     We do any necessary data reading and then wait for the drive to
- *     go non busy. At that point we may read the error data and complete
- *     the request
- */
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
-       struct request *rq = HWGROUP(drive)->rq;
-       ide_hwif_t *hwif = HWIF(drive);
-       u8 *args = (u8 *) rq->buffer;
-       u8 stat = hwif->INB(IDE_STATUS_REG);
-       int retries = 10;
-
-       local_irq_enable_in_hardirq();
-       if (rq->cmd_type == REQ_TYPE_ATA_CMD &&
-           (stat & DRQ_STAT) && args && args[3]) {
-               u8 io_32bit = drive->io_32bit;
-               drive->io_32bit = 0;
-               hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
-               drive->io_32bit = io_32bit;
-               while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
-                       udelay(100);
-       }
-
-       if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-               return ide_error(drive, "drive_cmd", stat);
-               /* calls ide_end_drive_cmd */
-       ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
-       return ide_stopped;
+       tf->nsect   = drive->sect;
+       tf->command = WIN_RESTORE;
 }
 
-static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
+static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
-       task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
-       task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
-       task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
-       task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
-       task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
-       task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
-
-       task->handler = &set_geometry_intr;
-}
-
-static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
-{
-       task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
-       task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
-
-       task->handler = &recal_intr;
-}
-
-static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
-{
-       task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
-       task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
-
-       task->handler = &set_multmode_intr;
+       tf->nsect   = drive->mult_req;
+       tf->command = WIN_SETMULT;
 }
 
 static ide_startstop_t ide_disk_special(ide_drive_t *drive)
@@ -707,19 +639,19 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
        ide_task_t args;
 
        memset(&args, 0, sizeof(ide_task_t));
-       args.command_type = IDE_DRIVE_TASK_NO_DATA;
+       args.data_phase = TASKFILE_NO_DATA;
 
        if (s->b.set_geometry) {
                s->b.set_geometry = 0;
-               ide_init_specify_cmd(drive, &args);
+               ide_tf_set_specify_cmd(drive, &args.tf);
        } else if (s->b.recalibrate) {
                s->b.recalibrate = 0;
-               ide_init_restore_cmd(drive, &args);
+               ide_tf_set_restore_cmd(drive, &args.tf);
        } else if (s->b.set_multmode) {
                s->b.set_multmode = 0;
                if (drive->mult_req > drive->id->max_multsect)
                        drive->mult_req = drive->id->max_multsect;
-               ide_init_setmult_cmd(drive, &args);
+               ide_tf_set_setmult_cmd(drive, &args.tf);
        } else if (s->all) {
                int special = s->all;
                s->all = 0;
@@ -727,6 +659,9 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
                return ide_stopped;
        }
 
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
+                       IDE_TFLAG_CUSTOM_HANDLER;
+
        do_rw_taskfile(drive, &args);
 
        return ide_started;
@@ -801,7 +736,7 @@ static ide_startstop_t do_special (ide_drive_t *drive)
 
                        if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
                                if (keep_dma)
-                                       hwif->ide_dma_on(drive);
+                                       ide_dma_on(drive);
                        }
                }
 
@@ -861,13 +796,10 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
                struct request *rq)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               ide_task_t *args = rq->special;
-               if (!args)
-                       goto done;
+       ide_task_t *task = rq->special;
 
-               hwif->data_phase = args->data_phase;
+       if (task) {
+               hwif->data_phase = task->data_phase;
 
                switch (hwif->data_phase) {
                case TASKFILE_MULTI_OUT:
@@ -880,57 +812,9 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
                        break;
                }
 
-               if (args->tf_out_flags.all != 0) 
-                       return flagged_taskfile(drive, args);
-               return do_rw_taskfile(drive, args);
-       } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
-               u8 *args = rq->buffer;
-               if (!args)
-                       goto done;
-#ifdef DEBUG
-               printk("%s: DRIVE_TASK_CMD ", drive->name);
-               printk("cmd=0x%02x ", args[0]);
-               printk("fr=0x%02x ", args[1]);
-               printk("ns=0x%02x ", args[2]);
-               printk("sc=0x%02x ", args[3]);
-               printk("lcyl=0x%02x ", args[4]);
-               printk("hcyl=0x%02x ", args[5]);
-               printk("sel=0x%02x\n", args[6]);
-#endif
-               hwif->OUTB(args[1], IDE_FEATURE_REG);
-               hwif->OUTB(args[3], IDE_SECTOR_REG);
-               hwif->OUTB(args[4], IDE_LCYL_REG);
-               hwif->OUTB(args[5], IDE_HCYL_REG);
-               hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG);
-               ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
-               return ide_started;
-       } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-               u8 *args = rq->buffer;
-
-               if (!args)
-                       goto done;
-#ifdef DEBUG
-               printk("%s: DRIVE_CMD ", drive->name);
-               printk("cmd=0x%02x ", args[0]);
-               printk("sc=0x%02x ", args[1]);
-               printk("fr=0x%02x ", args[2]);
-               printk("xx=0x%02x\n", args[3]);
-#endif
-               if (args[0] == WIN_SMART) {
-                       hwif->OUTB(0x4f, IDE_LCYL_REG);
-                       hwif->OUTB(0xc2, IDE_HCYL_REG);
-                       hwif->OUTB(args[2],IDE_FEATURE_REG);
-                       hwif->OUTB(args[1],IDE_SECTOR_REG);
-                       ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
-                       return ide_started;
-               }
-               hwif->OUTB(args[2],IDE_FEATURE_REG);
-               ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
-               return ide_started;
-       }
-
-done:
+               return do_rw_taskfile(drive, task);
+       }
+
        /*
         * NULL is actually a valid way of waiting for
         * all current requests to be flushed from the queue.
@@ -970,8 +854,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
                if (rc)
                        printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
                SELECT_DRIVE(drive);
-               if (IDE_CONTROL_REG)
-                       HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+               ide_set_irq(drive, 1);
                rc = ide_wait_not_busy(HWIF(drive), 100000);
                if (rc)
                        printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
@@ -1003,6 +886,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 
        /* bail early if we've exceeded max_failures */
        if (drive->max_failures && (drive->failures > drive->max_failures)) {
+               rq->cmd_flags |= REQ_FAILED;
                goto kill_rq;
        }
 
@@ -1034,9 +918,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                if (drive->current_speed == 0xff)
                        ide_config_drive_speed(drive, drive->desired_speed);
 
-               if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
-                   rq->cmd_type == REQ_TYPE_ATA_TASK ||
-                   rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+               if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
                        return execute_drive_cmd(drive, rq);
                else if (blk_pm_request(rq)) {
                        struct request_pm_state *pm = rq->data;
@@ -1244,11 +1126,13 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                }
        again:
                hwif = HWIF(drive);
-               if (hwgroup->hwif->sharing_irq &&
-                   hwif != hwgroup->hwif &&
-                   hwif->io_ports[IDE_CONTROL_OFFSET]) {
-                       /* set nIEN for previous hwif */
-                       SELECT_INTERRUPT(drive);
+               if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
+                       /*
+                        * set nIEN for previous hwif, drives in the
+                        * quirk_list may not like intr setups/cleanups
+                        */
+                       if (drive->quirk_list != 1)
+                               ide_set_irq(drive, 0);
                }
                hwgroup->hwif = hwif;
                hwgroup->drive = drive;
@@ -1361,7 +1245,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
         */
        drive->retry_pio++;
        drive->state = DMA_PIO_RETRY;
-       hwif->dma_off_quietly(drive);
+       ide_dma_off_quietly(drive);
 
        /*
         * un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1454,12 +1338,8 @@ void ide_timer_expiry (unsigned long data)
                         */
                        spin_unlock(&ide_lock);
                        hwif  = HWIF(drive);
-#if DISABLE_IRQ_NOSYNC
-                       disable_irq_nosync(hwif->irq);
-#else
                        /* disable_irq_nosync ?? */
                        disable_irq(hwif->irq);
-#endif /* DISABLE_IRQ_NOSYNC */
                        /* local CPU only,
                         * as if we were handling an interrupt */
                        local_irq_disable();
@@ -1710,7 +1590,6 @@ irqreturn_t ide_intr (int irq, void *dev_id)
 void ide_init_drive_cmd (struct request *rq)
 {
        memset(rq, 0, sizeof(*rq));
-       rq->cmd_type = REQ_TYPE_ATA_CMD;
        rq->ref_count = 1;
 }
 
@@ -1785,3 +1664,19 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
 }
 
 EXPORT_SYMBOL(ide_do_drive_cmd);
+
+void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
+{
+       ide_task_t task;
+
+       memset(&task, 0, sizeof(task));
+       task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
+                       IDE_TFLAG_OUT_FEATURE | tf_flags;
+       task.tf.feature = dma;          /* Use PIO/DMA */
+       task.tf.lbam    = bcount & 0xff;
+       task.tf.lbah    = (bcount >> 8) & 0xff;
+
+       ide_tf_load(drive, &task);
+}
+
+EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
index cef405ddaf0e3191a2d0eadd3f63681284d9d31f..e2a7e95e1636ccfc326748f5fa32a27132f2341d 100644 (file)
@@ -158,14 +158,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
 
 EXPORT_SYMBOL(default_hwif_mmiops);
 
-u32 ide_read_24 (ide_drive_t *drive)
-{
-       u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
-       u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
-       u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
-       return (hcyl<<16)|(lcyl<<8)|sect;
-}
-
 void SELECT_DRIVE (ide_drive_t *drive)
 {
        if (HWIF(drive)->selectproc)
@@ -175,26 +167,12 @@ void SELECT_DRIVE (ide_drive_t *drive)
 
 EXPORT_SYMBOL(SELECT_DRIVE);
 
-void SELECT_INTERRUPT (ide_drive_t *drive)
-{
-       if (HWIF(drive)->intrproc)
-               HWIF(drive)->intrproc(drive);
-       else
-               HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
-}
-
 void SELECT_MASK (ide_drive_t *drive, int mask)
 {
        if (HWIF(drive)->maskproc)
                HWIF(drive)->maskproc(drive, mask);
 }
 
-void QUIRK_LIST (ide_drive_t *drive)
-{
-       if (HWIF(drive)->quirkproc)
-               drive->quirk_list = HWIF(drive)->quirkproc(drive);
-}
-
 /*
  * Some localbus EIDE interfaces require a special access sequence
  * when using 32-bit I/O instructions to transfer data.  We call this
@@ -449,7 +427,6 @@ int drive_is_ready (ide_drive_t *drive)
        udelay(1);
 #endif
 
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
        /*
         * We do a passive status test under shared PCI interrupts on
         * cards that truly share the ATA side interrupt, but may also share
@@ -459,7 +436,6 @@ int drive_is_ready (ide_drive_t *drive)
        if (IDE_CONTROL_REG)
                stat = hwif->INB(IDE_ALTSTATUS_REG);
        else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
                /* Note: this may clear a pending IRQ!! */
                stat = hwif->INB(IDE_STATUS_REG);
 
@@ -612,12 +588,12 @@ u8 eighty_ninty_three (ide_drive_t *drive)
                printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
                                  drive->name);
 
+       if (ide_dev_is_sata(id) && !ivb)
+               return 1;
+
        if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
                goto no_80w;
 
-       if (ide_dev_is_sata(id))
-               return 1;
-
        /*
         * FIXME:
         * - force bit13 (80c cable present) check also for !ivb devices
@@ -642,9 +618,9 @@ no_80w:
 
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
-       if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-           (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
-           (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+       if (args->tf.command == WIN_SETFEATURES &&
+           args->tf.nsect > XFER_UDMA_2 &&
+           args->tf.feature == SETFEATURES_XFER) {
                if (eighty_ninty_three(drive) == 0) {
                        printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
                                            "be set\n", drive->name);
@@ -662,9 +638,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
  */
 int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
-       if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-           (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
-           (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+       if (args->tf.command == WIN_SETFEATURES &&
+           args->tf.nsect >= XFER_SW_DMA_0 &&
+           args->tf.feature == SETFEATURES_XFER &&
            (drive->id->dma_ultra ||
             drive->id->dma_mword ||
             drive->id->dma_1word))
@@ -712,8 +688,7 @@ int ide_driveid_update(ide_drive_t *drive)
         */
 
        SELECT_MASK(drive, 1);
-       if (IDE_CONTROL_REG)
-               hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+       ide_set_irq(drive, 1);
        msleep(50);
        hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
        timeout = jiffies + WAIT_WORSTCASE;
@@ -766,8 +741,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 //             msleep(50);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-       if (hwif->ide_dma_on)   /* check if host supports DMA */
-               hwif->dma_host_off(drive);
+       if (hwif->dma_host_set) /* check if host supports DMA */
+               hwif->dma_host_set(drive, 0);
 #endif
 
        /* Skip setting PIO flow-control modes on pre-EIDE drives */
@@ -796,13 +771,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
        SELECT_DRIVE(drive);
        SELECT_MASK(drive, 0);
        udelay(1);
-       if (IDE_CONTROL_REG)
-               hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+       ide_set_irq(drive, 0);
        hwif->OUTB(speed, IDE_NSECTOR_REG);
        hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
        hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
-       if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+       if (drive->quirk_list == 2)
+               ide_set_irq(drive, 1);
 
        error = __ide_wait_stat(drive, drive->ready_stat,
                                BUSY_STAT|DRQ_STAT|ERR_STAT,
@@ -823,10 +797,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-       if (speed >= XFER_SW_DMA_0)
-               hwif->dma_host_on(drive);
-       else if (hwif->ide_dma_on)      /* check if host supports DMA */
-               hwif->dma_off_quietly(drive);
+       if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) &&
+           drive->using_dma)
+               hwif->dma_host_set(drive, 1);
+       else if (hwif->dma_host_set)    /* check if host supports DMA */
+               ide_dma_off_quietly(drive);
 #endif
 
        switch(speed) {
@@ -902,8 +877,9 @@ EXPORT_SYMBOL(ide_set_handler);
  *     handler and IRQ setup do not race. All IDE command kick off
  *     should go via this function or do equivalent locking.
  */
-void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
+
+void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
+                        unsigned timeout, ide_expiry_t *expiry)
 {
        unsigned long flags;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -1035,10 +1011,10 @@ static void check_dma_crc(ide_drive_t *drive)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (drive->crc_count) {
-               drive->hwif->dma_off_quietly(drive);
+               ide_dma_off_quietly(drive);
                ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
                if (drive->current_speed >= XFER_SW_DMA_0)
-                       (void) HWIF(drive)->ide_dma_on(drive);
+                       ide_dma_on(drive);
        } else
                ide_dma_off(drive);
 #endif
@@ -1051,8 +1027,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
        drive->special.all = 0;
        drive->special.b.set_geometry = legacy;
        drive->special.b.recalibrate  = legacy;
-       if (OK_TO_RESET_CONTROLLER)
-               drive->mult_count = 0;
+       drive->mult_count = 0;
        if (!drive->keep_settings && !drive->using_dma)
                drive->mult_req = 0;
        if (drive->mult_req != drive->mult_count)
@@ -1137,7 +1112,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
        for (unit = 0; unit < MAX_DRIVES; ++unit)
                pre_reset(&hwif->drives[unit]);
 
-#if OK_TO_RESET_CONTROLLER
        if (!IDE_CONTROL_REG) {
                spin_unlock_irqrestore(&ide_lock, flags);
                return ide_stopped;
@@ -1174,11 +1148,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
         * state when the disks are reset this way. At least, the Winbond
         * 553 documentation says that
         */
-       if (hwif->resetproc != NULL) {
+       if (hwif->resetproc)
                hwif->resetproc(drive);
-       }
-       
-#endif /* OK_TO_RESET_CONTROLLER */
 
        spin_unlock_irqrestore(&ide_lock, flags);
        return ide_started;
index 062d3bcb2471c4a3cd4a9a9c2ed17a5557a9ea39..9b44fbdfe41fc503d085b6a0f08c1d3a9775d8fe 100644 (file)
@@ -441,6 +441,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
         * case could happen iff the transfer mode has already been set on
         * the device by ide-proc.c::set_xfer_rate()).
         */
+       if (rate < XFER_PIO_0) {
+               if (hwif->host_flags & IDE_HFLAG_ABUSE_SET_DMA_MODE)
+                       return ide_set_dma_mode(drive, rate);
+               else
+                       return ide_config_drive_speed(drive, rate);
+       }
 
        return ide_set_dma_mode(drive, rate);
 }
@@ -448,8 +454,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 static void ide_dump_opcode(ide_drive_t *drive)
 {
        struct request *rq;
-       u8 opcode = 0;
-       int found = 0;
+       ide_task_t *task = NULL;
 
        spin_lock(&ide_lock);
        rq = NULL;
@@ -458,164 +463,129 @@ static void ide_dump_opcode(ide_drive_t *drive)
        spin_unlock(&ide_lock);
        if (!rq)
                return;
-       if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
-           rq->cmd_type == REQ_TYPE_ATA_TASK) {
-               char *args = rq->buffer;
-               if (args) {
-                       opcode = args[0];
-                       found = 1;
-               }
-       } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               ide_task_t *args = rq->special;
-               if (args) {
-                       task_struct_t *tf = (task_struct_t *) args->tfRegister;
-                       opcode = tf->command;
-                       found = 1;
-               }
-       }
+
+       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+               task = rq->special;
 
        printk("ide: failed opcode was: ");
-       if (!found)
-               printk("unknown\n");
+       if (task == NULL)
+               printk(KERN_CONT "unknown\n");
        else
-               printk("0x%02x\n", opcode);
+               printk(KERN_CONT "0x%02x\n", task->tf.command);
 }
 
-static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
+u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       unsigned long flags;
-       u8 err = 0;
+       u32 high, low;
 
-       local_irq_save(flags);
-       printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-       if (stat & BUSY_STAT)
-               printk("Busy ");
-       else {
-               if (stat & READY_STAT)  printk("DriveReady ");
-               if (stat & WRERR_STAT)  printk("DeviceFault ");
-               if (stat & SEEK_STAT)   printk("SeekComplete ");
-               if (stat & DRQ_STAT)    printk("DataRequest ");
-               if (stat & ECC_STAT)    printk("CorrectedError ");
-               if (stat & INDEX_STAT)  printk("Index ");
-               if (stat & ERR_STAT)    printk("Error ");
+       if (lba48)
+               high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) |
+                       tf->hob_lbal;
+       else
+               high = tf->device & 0xf;
+       low  = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
+
+       return ((u64)high << 24) | low;
+}
+EXPORT_SYMBOL_GPL(ide_get_lba_addr);
+
+static void ide_dump_sector(ide_drive_t *drive)
+{
+       ide_task_t task;
+       struct ide_taskfile *tf = &task.tf;
+       int lba48 = (drive->addressing == 1) ? 1 : 0;
+
+       memset(&task, 0, sizeof(task));
+       if (lba48)
+               task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
+                               IDE_TFLAG_LBA48;
+       else
+               task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
+
+       ide_tf_read(drive, &task);
+
+       if (lba48 || (tf->device & ATA_LBA))
+               printk(", LBAsect=%llu",
+                       (unsigned long long)ide_get_lba_addr(tf, lba48));
+       else
+               printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
+                                        tf->device & 0xf, tf->lbal);
+}
+
+static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
+{
+       printk("{ ");
+       if (err & ABRT_ERR)     printk("DriveStatusError ");
+       if (err & ICRC_ERR)
+               printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+       if (err & ECC_ERR)      printk("UncorrectableError ");
+       if (err & ID_ERR)       printk("SectorIdNotFound ");
+       if (err & TRK0_ERR)     printk("TrackZeroNotFound ");
+       if (err & MARK_ERR)     printk("AddrMarkNotFound ");
+       printk("}");
+       if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+           (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+               ide_dump_sector(drive);
+               if (HWGROUP(drive) && HWGROUP(drive)->rq)
+                       printk(", sector=%llu",
+                              (unsigned long long)HWGROUP(drive)->rq->sector);
        }
+       printk("\n");
+}
+
+static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
+{
+       printk("{ ");
+       if (err & ILI_ERR)      printk("IllegalLengthIndication ");
+       if (err & EOM_ERR)      printk("EndOfMedia ");
+       if (err & ABRT_ERR)     printk("AbortedCommand ");
+       if (err & MCR_ERR)      printk("MediaChangeRequested ");
+       if (err & LFS_ERR)      printk("LastFailedSense=0x%02x ",
+                                      (err & LFS_ERR) >> 4);
        printk("}\n");
-       if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-               err = hwif->INB(IDE_ERROR_REG);
-               printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
-               if (err & ABRT_ERR)     printk("DriveStatusError ");
-               if (err & ICRC_ERR)
-                       printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-               if (err & ECC_ERR)      printk("UncorrectableError ");
-               if (err & ID_ERR)       printk("SectorIdNotFound ");
-               if (err & TRK0_ERR)     printk("TrackZeroNotFound ");
-               if (err & MARK_ERR)     printk("AddrMarkNotFound ");
-               printk("}");
-               if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
-                   (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-                       if (drive->addressing == 1) {
-                               __u64 sectors = 0;
-                               u32 low = 0, high = 0;
-                               hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG);
-                               low = ide_read_24(drive);
-                               hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
-                               high = ide_read_24(drive);
-                               sectors = ((__u64)high << 24) | low;
-                               printk(", LBAsect=%llu, high=%d, low=%d",
-                                      (unsigned long long) sectors,
-                                      high, low);
-                       } else {
-                               u8 cur = hwif->INB(IDE_SELECT_REG);
-                               if (cur & 0x40) {       /* using LBA? */
-                                       printk(", LBAsect=%ld", (unsigned long)
-                                        ((cur&0xf)<<24)
-                                        |(hwif->INB(IDE_HCYL_REG)<<16)
-                                        |(hwif->INB(IDE_LCYL_REG)<<8)
-                                        | hwif->INB(IDE_SECTOR_REG));
-                               } else {
-                                       printk(", CHS=%d/%d/%d",
-                                        (hwif->INB(IDE_HCYL_REG)<<8) +
-                                         hwif->INB(IDE_LCYL_REG),
-                                         cur & 0xf,
-                                         hwif->INB(IDE_SECTOR_REG));
-                               }
-                       }
-                       if (HWGROUP(drive) && HWGROUP(drive)->rq)
-                               printk(", sector=%llu",
-                                       (unsigned long long)HWGROUP(drive)->rq->sector);
-               }
-               printk("\n");
-       }
-       ide_dump_opcode(drive);
-       local_irq_restore(flags);
-       return err;
 }
 
 /**
- *     ide_dump_atapi_status       -       print human readable atapi status
+ *     ide_dump_status         -       translate ATA/ATAPI error
  *     @drive: drive that status applies to
  *     @msg: text message to print
  *     @stat: status byte to decode
  *
  *     Error reporting, in human readable form (luxurious, but a memory hog).
+ *     Combines the drive name, message and status byte to provide a
+ *     user understandable explanation of the device error.
  */
 
-static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
+u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
 {
        unsigned long flags;
+       u8 err = 0;
 
-       atapi_status_t status;
-       atapi_error_t error;
-
-       status.all = stat;
-       error.all = 0;
        local_irq_save(flags);
        printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-       if (status.b.bsy)
+       if (stat & BUSY_STAT)
                printk("Busy ");
        else {
-               if (status.b.drdy)      printk("DriveReady ");
-               if (status.b.df)        printk("DeviceFault ");
-               if (status.b.dsc)       printk("SeekComplete ");
-               if (status.b.drq)       printk("DataRequest ");
-               if (status.b.corr)      printk("CorrectedError ");
-               if (status.b.idx)       printk("Index ");
-               if (status.b.check)     printk("Error ");
+               if (stat & READY_STAT)  printk("DriveReady ");
+               if (stat & WRERR_STAT)  printk("DeviceFault ");
+               if (stat & SEEK_STAT)   printk("SeekComplete ");
+               if (stat & DRQ_STAT)    printk("DataRequest ");
+               if (stat & ECC_STAT)    printk("CorrectedError ");
+               if (stat & INDEX_STAT)  printk("Index ");
+               if (stat & ERR_STAT)    printk("Error ");
        }
        printk("}\n");
-       if (status.b.check && !status.b.bsy) {
-               error.all = HWIF(drive)->INB(IDE_ERROR_REG);
-               printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
-               if (error.b.ili)        printk("IllegalLengthIndication ");
-               if (error.b.eom)        printk("EndOfMedia ");
-               if (error.b.abrt)       printk("AbortedCommand ");
-               if (error.b.mcr)        printk("MediaChangeRequested ");
-               if (error.b.sense_key)  printk("LastFailedSense=0x%02x ",
-                                               error.b.sense_key);
-               printk("}\n");
+       if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+               err = drive->hwif->INB(IDE_ERROR_REG);
+               printk("%s: %s: error=0x%02x ", drive->name, msg, err);
+               if (drive->media == ide_disk)
+                       ide_dump_ata_error(drive, err);
+               else
+                       ide_dump_atapi_error(drive, err);
        }
        ide_dump_opcode(drive);
        local_irq_restore(flags);
-       return error.all;
-}
-
-/**
- *     ide_dump_status         -       translate ATA/ATAPI error
- *     @drive: drive the error occured on
- *     @msg: information string
- *     @stat: status byte
- *
- *     Error reporting, in human readable form (luxurious, but a memory hog).
- *     Combines the drive name, message and status byte to provide a
- *     user understandable explanation of the device error.
- */
-
-u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
-{
-       if (drive->media == ide_disk)
-               return ide_dump_ata_status(drive, msg, stat);
-       return ide_dump_atapi_status(drive, msg, stat);
+       return err;
 }
 
 EXPORT_SYMBOL(ide_dump_status);
index e245521af7b55d3aa9ae97c381c2234213183179..cbbb0f75be92ea218d2ccf9ae4e452bfeb3adb1d 100644 (file)
@@ -31,7 +31,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
 {
        hw_regs_t hw;
        ide_hwif_t *hwif;
-       int index;
 
        if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
                return -1;
@@ -41,11 +40,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
                                pnp_port_start(dev, 1));
        hw.irq = pnp_irq(dev, 0);
 
-       index = ide_register_hw(&hw, NULL, 1, &hwif);
+       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif) {
+               u8 index = hwif->index;
+               u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+               ide_init_port_data(hwif, index);
+               ide_init_port_hw(hwif, &hw);
 
-       if (index != -1) {
-               printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
+               printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
                pnp_set_drvdata(dev,hwif);
+
+               ide_device_add(idx);
+
                return 0;
        }
 
@@ -68,12 +75,15 @@ static struct pnp_driver idepnp_driver = {
        .remove         = idepnp_remove,
 };
 
-void __init pnpide_init(void)
+static int __init pnpide_init(void)
 {
-       pnp_register_driver(&idepnp_driver);
+       return pnp_register_driver(&idepnp_driver);
 }
 
-void __exit pnpide_exit(void)
+static void __exit pnpide_exit(void)
 {
        pnp_unregister_driver(&idepnp_driver);
 }
+
+module_init(pnpide_init);
+module_exit(pnpide_exit);
index 2994523be7bf8ed508160bb3ab60c71467081da1..edf650b20c67b87782b12a09488e612de03250f9 100644 (file)
@@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
 #ifdef CONFIG_IDEDISK_MULTI_MODE
                id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
                id->multsect_valid = id->multsect ? 1 : 0;
-               drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+               drive->mult_req = id->multsect_valid ? id->max_multsect : 0;
                drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
 #else  /* original, pre IDE-NFG, per request of AC */
-               drive->mult_req = INITIAL_MULT_COUNT;
+               drive->mult_req = 0;
                if (drive->mult_req > id->max_multsect)
                        drive->mult_req = id->max_multsect;
                if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
@@ -234,7 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
 
        drive->media = ide_disk;
        printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
-       QUIRK_LIST(drive);
+
        return;
 
 err_misc:
@@ -350,22 +350,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
         * the irq handler isn't expecting.
         */
        if (IDE_CONTROL_REG) {
-               u8 ctl = drive->ctl | 2;
                if (!hwif->irq) {
                        autoprobe = 1;
                        cookie = probe_irq_on();
-                       /* enable device irq */
-                       ctl &= ~2;
                }
-               hwif->OUTB(ctl, IDE_CONTROL_REG);
+               ide_set_irq(drive, autoprobe);
        }
 
        retval = actual_try_to_identify(drive, cmd);
 
        if (autoprobe) {
                int irq;
-               /* mask device irq */
-               hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+
+               ide_set_irq(drive, 0);
                /* clear drive IRQ */
                (void) hwif->INB(IDE_STATUS_REG);
                udelay(5);
@@ -385,6 +382,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
        return retval;
 }
 
+static int ide_busy_sleep(ide_hwif_t *hwif)
+{
+       unsigned long timeout = jiffies + WAIT_WORSTCASE;
+       u8 stat;
+
+       do {
+               msleep(50);
+               stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+               if ((stat & BUSY_STAT) == 0)
+                       return 0;
+       } while (time_before(jiffies, timeout));
+
+       return 1;
+}
 
 /**
  *     do_probe                -       probe an IDE device
@@ -453,7 +464,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
                        ((drive->autotune == IDE_TUNE_DEFAULT) ||
                        (drive->autotune == IDE_TUNE_AUTO))) {
-                       unsigned long timeout;
                        printk("%s: no response (status = 0x%02x), "
                                "resetting drive\n", drive->name,
                                hwif->INB(IDE_STATUS_REG));
@@ -461,10 +471,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        hwif->OUTB(drive->select.all, IDE_SELECT_REG);
                        msleep(50);
                        hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
-                       timeout = jiffies;
-                       while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
-                              time_before(jiffies, timeout + WAIT_WORSTCASE))
-                               msleep(50);
+                       (void)ide_busy_sleep(hwif);
                        rc = try_to_identify(drive, cmd);
                }
                if (rc == 1)
@@ -492,20 +499,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 static void enable_nest (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       unsigned long timeout;
 
        printk("%s: enabling %s -- ", hwif->name, drive->id->model);
        SELECT_DRIVE(drive);
        msleep(50);
        hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
-       timeout = jiffies + WAIT_WORSTCASE;
-       do {
-               if (time_after(jiffies, timeout)) {
-                       printk("failed (timeout)\n");
-                       return;
-               }
-               msleep(50);
-       } while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
+       if (ide_busy_sleep(hwif)) {
+               printk(KERN_CONT "failed (timeout)\n");
+               return;
+       }
 
        msleep(50);
 
@@ -653,8 +656,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
                /* Ignore disks that we will not probe for later. */
                if (!drive->noprobe || drive->present) {
                        SELECT_DRIVE(drive);
-                       if (IDE_CONTROL_REG)
-                               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+                       ide_set_irq(drive, 1);
                        mdelay(2);
                        rc = ide_wait_not_busy(hwif, 35000);
                        if (rc)
@@ -673,19 +675,18 @@ out:
 
 /**
  *     ide_undecoded_slave     -       look for bad CF adapters
- *     @hwif: interface
+ *     @drive1: drive
  *
  *     Analyse the drives on the interface and attempt to decide if we
  *     have the same drive viewed twice. This occurs with crap CF adapters
  *     and PCMCIA sometimes.
  */
 
-void ide_undecoded_slave(ide_hwif_t *hwif)
+void ide_undecoded_slave(ide_drive_t *drive1)
 {
-       ide_drive_t *drive0 = &hwif->drives[0];
-       ide_drive_t *drive1 = &hwif->drives[1];
+       ide_drive_t *drive0 = &drive1->hwif->drives[0];
 
-       if (drive0->present == 0 || drive1->present == 0)
+       if ((drive1->dn & 1) == 0 || drive0->present == 0)
                return;
 
        /* If the models don't match they are not the same product */
@@ -788,18 +789,11 @@ static void probe_hwif(ide_hwif_t *hwif)
                }
        }
        if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
-               unsigned long timeout = jiffies + WAIT_WORSTCASE;
-               u8 stat;
-
                printk(KERN_WARNING "%s: reset\n", hwif->name);
                hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
                udelay(10);
                hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-               do {
-                       msleep(50);
-                       stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
-               } while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
-
+               (void)ide_busy_sleep(hwif);
        }
        local_irq_restore(flags);
        /*
@@ -814,8 +808,12 @@ static void probe_hwif(ide_hwif_t *hwif)
                return;
        }
 
-       if (hwif->fixup)
-               hwif->fixup(hwif);
+       for (unit = 0; unit < MAX_DRIVES; unit++) {
+               ide_drive_t *drive = &hwif->drives[unit];
+
+               if (drive->present && hwif->quirkproc)
+                       hwif->quirkproc(drive);
+       }
 
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
@@ -830,16 +828,8 @@ static void probe_hwif(ide_hwif_t *hwif)
 
                        drive->nice1 = 1;
 
-                       if (hwif->ide_dma_on) {
-                               /*
-                                * Force DMAing for the beginning of the check.
-                                * Some chipsets appear to do interesting
-                                * things, if not checked and cleared.
-                                *   PARANOIA!!!
-                                */
-                               hwif->dma_off_quietly(drive);
+                       if (hwif->dma_host_set)
                                ide_set_dma(drive);
-                       }
                }
        }
 
@@ -853,25 +843,6 @@ static void probe_hwif(ide_hwif_t *hwif)
        }
 }
 
-static int hwif_init(ide_hwif_t *hwif);
-static void hwif_register_devices(ide_hwif_t *hwif);
-
-static int probe_hwif_init(ide_hwif_t *hwif)
-{
-       probe_hwif(hwif);
-
-       if (!hwif_init(hwif)) {
-               printk(KERN_INFO "%s: failed to initialize IDE interface\n",
-                                hwif->name);
-               return -1;
-       }
-
-       if (hwif->present)
-               hwif_register_devices(hwif);
-
-       return 0;
-}
-
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -968,11 +939,6 @@ static int ide_init_queue(ide_drive_t *drive)
  * Much of the code is for correctly detecting/handling irq sharing
  * and irq serialization situations.  This is somewhat complex because
  * it handles static as well as dynamic (PCMCIA) IDE interfaces.
- *
- * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with
- * interrupts completely disabled.  This can be bad for interrupt latency,
- * but anything else has led to problems on some machines.  We re-enable
- * interrupts as much as we can safely do in most places.
  */
 static int init_irq (ide_hwif_t *hwif)
 {
@@ -1055,17 +1021,13 @@ static int init_irq (ide_hwif_t *hwif)
         * Allocate the irq, if not already obtained for another hwif
         */
        if (!match || match->irq != hwif->irq) {
-               int sa = IRQF_DISABLED;
+               int sa = 0;
 #if defined(__mc68000__) || defined(CONFIG_APUS)
                sa = IRQF_SHARED;
 #endif /* __mc68000__ || CONFIG_APUS */
 
-               if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+               if (IDE_CHIPSET_IS_PCI(hwif->chipset))
                        sa = IRQF_SHARED;
-#ifndef CONFIG_IDEPCI_SHARE_IRQ
-                       sa |= IRQF_DISABLED;
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-               }
 
                if (hwif->io_ports[IDE_CONTROL_OFFSET])
                        /* clear nIEN */
@@ -1173,7 +1135,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
 {
        struct gendisk *p = data;
        *part &= (1 << PARTN_BITS) - 1;
-       return &p->kobj;
+       return &p->dev.kobj;
 }
 
 static int exact_lock(dev_t dev, void *data)
@@ -1373,54 +1335,63 @@ static void hwif_register_devices(ide_hwif_t *hwif)
        }
 }
 
-int ideprobe_init (void)
+int ide_device_add_all(u8 *idx)
 {
-       unsigned int index;
-       int probe[MAX_HWIFS];
-
-       memset(probe, 0, MAX_HWIFS * sizeof(int));
-       for (index = 0; index < MAX_HWIFS; ++index)
-               probe[index] = !ide_hwifs[index].present;
-
-       for (index = 0; index < MAX_HWIFS; ++index)
-               if (probe[index])
-                       probe_hwif(&ide_hwifs[index]);
-       for (index = 0; index < MAX_HWIFS; ++index)
-               if (probe[index])
-                       hwif_init(&ide_hwifs[index]);
-       for (index = 0; index < MAX_HWIFS; ++index) {
-               if (probe[index]) {
-                       ide_hwif_t *hwif = &ide_hwifs[index];
-                       if (!hwif->present)
-                               continue;
-                       if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
-                               hwif->chipset = ide_generic;
-                       hwif_register_devices(hwif);
+       ide_hwif_t *hwif;
+       int i, rc = 0;
+
+       for (i = 0; i < MAX_HWIFS; i++) {
+               if (idx[i] == 0xff)
+                       continue;
+
+               probe_hwif(&ide_hwifs[idx[i]]);
+       }
+
+       for (i = 0; i < MAX_HWIFS; i++) {
+               if (idx[i] == 0xff)
+                       continue;
+
+               hwif = &ide_hwifs[idx[i]];
+
+               if (hwif_init(hwif) == 0) {
+                       printk(KERN_INFO "%s: failed to initialize IDE "
+                                        "interface\n", hwif->name);
+                       rc = -1;
+                       continue;
                }
        }
-       for (index = 0; index < MAX_HWIFS; ++index)
-               if (probe[index])
-                       ide_proc_register_port(&ide_hwifs[index]);
-       return 0;
-}
 
-EXPORT_SYMBOL_GPL(ideprobe_init);
+       for (i = 0; i < MAX_HWIFS; i++) {
+               if (idx[i] == 0xff)
+                       continue;
 
-int ide_device_add(u8 idx[4])
-{
-       int i, rc = 0;
+               hwif = &ide_hwifs[idx[i]];
 
-       for (i = 0; i < 4; i++) {
-               if (idx[i] != 0xff)
-                       rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
+               if (hwif->present) {
+                       if (hwif->chipset == ide_unknown ||
+                           hwif->chipset == ide_forced)
+                               hwif->chipset = ide_generic;
+                       hwif_register_devices(hwif);
+               }
        }
 
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < MAX_HWIFS; i++) {
                if (idx[i] != 0xff)
                        ide_proc_register_port(&ide_hwifs[idx[i]]);
        }
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(ide_device_add_all);
+
+int ide_device_add(u8 idx[4])
+{
+       u8 idx_all[MAX_HWIFS];
+       int i;
 
+       for (i = 0; i < MAX_HWIFS; i++)
+               idx_all[i] = (i < 4) ? idx[i] : 0xff;
+
+       return ide_device_add_all(idx_all);
+}
 EXPORT_SYMBOL_GPL(ide_device_add);
index a4007d30da520c091491f4ca6e9923b9cc83d232..aa663e7f46f2f4b29ebc3fad6fe612a6166ffc3e 100644 (file)
@@ -346,14 +346,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
 
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
+       ide_task_t task;
        int err;
 
        if (arg < 0 || arg > 70)
                return -EINVAL;
 
-       err = ide_wait_cmd(drive,
-                       WIN_SETFEATURES, (u8) arg,
-                       SETFEATURES_XFER, 0, NULL);
+       memset(&task, 0, sizeof(task));
+       task.tf.command = WIN_SETFEATURES;
+       task.tf.feature = SETFEATURES_XFER;
+       task.tf.nsect   = (u8)arg;
+       task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
+                       IDE_TFLAG_IN_NSECT;
+
+       err = ide_no_data_taskfile(drive, &task);
 
        if (!err && arg) {
                ide_set_xfer_rate(drive, (u8) arg);
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
new file mode 100644 (file)
index 0000000..7ffa332
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * support for probing IDE PCI devices in the PCI bus order
+ *
+ * Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ * Copyright (c) 1995-1998  Mark Lord
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+
+/*
+ *     Module interfaces
+ */
+
+static int pre_init = 1;               /* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *     __ide_pci_register_driver       -       attach IDE driver
+ *     @driver: pci driver
+ *     @module: owner module of the driver
+ *
+ *     Registers a driver with the IDE layer. The IDE layer arranges that
+ *     boot time setup is done in the expected device order and then
+ *     hands the controllers off to the core PCI code to do the rest of
+ *     the work.
+ *
+ *     Returns are the same as for pci_register_driver
+ */
+
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+                             const char *mod_name)
+{
+       if (!pre_init)
+               return __pci_register_driver(driver, module, mod_name);
+       driver->driver.owner = module;
+       list_add_tail(&driver->node, &ide_pci_drivers);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
+
+/**
+ *     ide_scan_pcidev         -       find an IDE driver for a device
+ *     @dev: PCI device to check
+ *
+ *     Look for an IDE driver to handle the device we are considering.
+ *     This is only used during boot up to get the ordering correct. After
+ *     boot up the pci layer takes over the job.
+ */
+
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+       struct list_head *l;
+       struct pci_driver *d;
+
+       list_for_each(l, &ide_pci_drivers) {
+               d = list_entry(l, struct pci_driver, node);
+               if (d->id_table) {
+                       const struct pci_device_id *id =
+                               pci_match_id(d->id_table, dev);
+
+                       if (id != NULL && d->probe(dev, id) >= 0) {
+                               dev->driver = d;
+                               pci_dev_get(dev);
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+/**
+ *     ide_scan_pcibus         -       perform the initial IDE driver scan
+ *
+ *     Perform the initial bus rather than driver ordered scan of the
+ *     PCI drivers. After this all IDE pci handling becomes standard
+ *     module ordering not traditionally ordered.
+ */
+
+int __init ide_scan_pcibus(void)
+{
+       struct pci_dev *dev = NULL;
+       struct pci_driver *d;
+       struct list_head *l, *n;
+
+       pre_init = 0;
+       if (!ide_scan_direction)
+               while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
+                       ide_scan_pcidev(dev);
+       else
+               while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
+                                                    dev)))
+                       ide_scan_pcidev(dev);
+
+       /*
+        *      Hand the drivers over to the PCI layer now we
+        *      are post init.
+        */
+
+       list_for_each_safe(l, n, &ide_pci_drivers) {
+               list_del(l);
+               d = list_entry(l, struct pci_driver, node);
+               if (__pci_register_driver(d, d->driver.owner,
+                                         d->driver.mod_name))
+                       printk(KERN_ERR "%s: failed to register %s driver\n",
+                                       __FUNCTION__, d->driver.mod_name);
+       }
+
+       return 0;
+}
+
+static int __init ide_scan_pci(void)
+{
+       return ide_scan_pcibus();
+}
+
+module_init(ide_scan_pci);
index 7b9181b5469d3be9d3e8e0929c5a0c2d4122c8d5..d71a584f076547661674cc6876fe7e37cc9391ca 100644 (file)
@@ -614,16 +614,6 @@ typedef struct os_dat_s {
 
 /*************************** End of tunable parameters ***********************/
 
-/*
- *     Debugging/Performance analysis
- *
- *     I/O trace support
- */
-#define USE_IOTRACE    0
-#if USE_IOTRACE
-#define IO_IDETAPE_FIFO        500
-#endif
-
 /*
  *     Read/Write error simulation
  */
@@ -1700,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
        if (error)
                tape->failed_pc = NULL;
 
+       if (!blk_special_request(rq)) {
+               ide_end_request(drive, uptodate, nr_sects);
+               return 0;
+       }
+
        spin_lock_irqsave(&tape->spinlock, flags);
 
        /* The request was a pipelined data transfer request */
@@ -1818,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc;
        struct request *rq;
-       atapi_error_t error;
 
-       error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+       (void)drive->hwif->INB(IDE_ERROR_REG);
        pc = idetape_next_pc_storage(drive);
        rq = idetape_next_rq_storage(drive);
        idetape_create_request_sense_cmd(pc);
@@ -1858,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
-       atapi_status_t status;
-       atapi_bcount_t bcount;
-       atapi_ireason_t ireason;
        idetape_pc_t *pc = tape->pc;
-
        unsigned int temp;
 #if SIMULATE_ERRORS
        static int error_sim_count = 0;
 #endif
+       u16 bcount;
+       u8 stat, ireason;
 
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 4)
@@ -1875,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 #endif /* IDETAPE_DEBUG_LOG */ 
 
        /* Clear the interrupt */
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = hwif->INB(IDE_STATUS_REG);
 
        if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-               if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
+               if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
                        /*
                         * A DMA error is sometimes expected. For example,
                         * if the tape is crossing a filemark during a
@@ -1912,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
        }
 
        /* No more interrupts */
-       if (!status.b.drq) {
+       if ((stat & DRQ_STAT) == 0) {
 #if IDETAPE_DEBUG_LOG
                if (tape->debug_level >= 2)
                        printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
@@ -1927,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                    (++error_sim_count % 100) == 0) {
                        printk(KERN_INFO "ide-tape: %s: simulating error\n",
                                tape->name);
-                       status.b.check = 1;
+                       stat |= ERR_STAT;
                }
 #endif
-               if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
-                       status.b.check = 0;
-               if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {     /* Error detected */
+               if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+                       stat &= ~ERR_STAT;
+               if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
+                       /* Error detected */
 #if IDETAPE_DEBUG_LOG
                        if (tape->debug_level >= 1)
                                printk(KERN_INFO "ide-tape: %s: I/O error\n",
@@ -1951,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                }
                pc->error = 0;
                if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
-                   !status.b.dsc) {
+                   (stat & SEEK_STAT) == 0) {
                        /* Media access command */
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
@@ -1973,30 +1966,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                return ide_do_reset(drive);
        }
        /* Get the number of bytes to transfer on this interrupt. */
-       bcount.b.high = hwif->INB(IDE_BCOUNTH_REG);
-       bcount.b.low = hwif->INB(IDE_BCOUNTL_REG);
+       bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+                 hwif->INB(IDE_BCOUNTL_REG);
 
-       ireason.all = hwif->INB(IDE_IREASON_REG);
+       ireason = hwif->INB(IDE_IREASON_REG);
 
-       if (ireason.b.cod) {
+       if (ireason & CD) {
                printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
                return ide_do_reset(drive);
        }
-       if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+       if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "ide-tape: We wanted to %s, ",
-                       ireason.b.io ? "Write":"Read");
+                               (ireason & IO) ? "Write" : "Read");
                printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
-                       ireason.b.io ? "Read":"Write");
+                               (ireason & IO) ? "Read" : "Write");
                return ide_do_reset(drive);
        }
        if (!test_bit(PC_WRITING, &pc->flags)) {
                /* Reading - Check that we have enough space */
-               temp = pc->actually_transferred + bcount.all;
+               temp = pc->actually_transferred + bcount;
                if (temp > pc->request_transfer) {
                        if (temp > pc->buffer_size) {
                                printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-                               idetape_discard_data(drive, bcount.all);
+                               idetape_discard_data(drive, bcount);
                                ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
                                return ide_started;
                        }
@@ -2008,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
        }
        if (test_bit(PC_WRITING, &pc->flags)) {
                if (pc->bh != NULL)
-                       idetape_output_buffers(drive, pc, bcount.all);
+                       idetape_output_buffers(drive, pc, bcount);
                else
                        /* Write the current buffer */
-                       HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+                       hwif->atapi_output_bytes(drive, pc->current_position,
+                                                bcount);
        } else {
                if (pc->bh != NULL)
-                       idetape_input_buffers(drive, pc, bcount.all);
+                       idetape_input_buffers(drive, pc, bcount);
                else
                        /* Read the current buffer */
-                       HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+                       hwif->atapi_input_bytes(drive, pc->current_position,
+                                               bcount);
        }
        /* Update the current position */
-       pc->actually_transferred += bcount.all;
-       pc->current_position += bcount.all;
+       pc->actually_transferred += bcount;
+       pc->current_position += bcount;
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+               printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
+                                "on that interrupt\n", pc->c[0], bcount);
 #endif
        /* And set the interrupt handler again */
        ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
@@ -2078,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
-       atapi_ireason_t ireason;
        int retries = 100;
        ide_startstop_t startstop;
+       u8 ireason;
 
        if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
                printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
                return startstop;
        }
-       ireason.all = hwif->INB(IDE_IREASON_REG);
-       while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+       ireason = hwif->INB(IDE_IREASON_REG);
+       while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
                printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
                                "a packet command, retrying\n");
                udelay(100);
-               ireason.all = hwif->INB(IDE_IREASON_REG);
+               ireason = hwif->INB(IDE_IREASON_REG);
                if (retries == 0) {
                        printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
                                        "issuing a packet command, ignoring\n");
-                       ireason.b.cod = 1;
-                       ireason.b.io = 0;
+                       ireason |= CD;
+                       ireason &= ~IO;
                }
        }
-       if (!ireason.b.cod || ireason.b.io) {
+       if ((ireason & CD) == 0 || (ireason & IO)) {
                printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
                                "a packet command\n");
                return ide_do_reset(drive);
@@ -2120,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
-       atapi_bcount_t bcount;
        int dma_ok = 0;
+       u16 bcount;
 
 #if IDETAPE_DEBUG_BUGS
        if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
@@ -2170,7 +2166,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
        pc->actually_transferred = 0;
        pc->current_position = pc->buffer;
        /* Request to transfer the entire buffer at once */
-       bcount.all = pc->request_transfer;
+       bcount = pc->request_transfer;
 
        if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
                printk(KERN_WARNING "ide-tape: DMA disabled, "
@@ -2180,12 +2176,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
        if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
                dma_ok = !hwif->dma_setup(drive);
 
-       if (IDE_CONTROL_REG)
-               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-       hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG);    /* Use PIO/DMA */
-       hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-       hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
-       hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+       ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
+                          IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
+
        if (dma_ok)                     /* Will begin DMA later */
                set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
        if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
@@ -2295,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
-       atapi_status_t status;
+       u8 stat;
 
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-       if (status.b.dsc) {
-               if (status.b.check) {
+       stat = drive->hwif->INB(IDE_STATUS_REG);
+       if (stat & SEEK_STAT) {
+               if (stat & ERR_STAT) {
                        /* Error detected */
                        if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
                                printk(KERN_ERR "ide-tape: %s: I/O error, ",
@@ -2417,7 +2410,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = NULL;
        struct request *postponed_rq = tape->postponed_rq;
-       atapi_status_t status;
+       u8 stat;
 
 #if IDETAPE_DEBUG_LOG
 #if 0
@@ -2465,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
         * If the tape is still busy, postpone our request and service
         * the other device meanwhile.
         */
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = drive->hwif->INB(IDE_STATUS_REG);
 
        if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
                set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
@@ -2481,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
        calculate_speeds(drive);
        if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
-           !status.b.dsc) {
+           (stat & SEEK_STAT) == 0) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2502,9 +2495,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        }
        if (rq->cmd[0] & REQ_IDETAPE_READ) {
                tape->buffer_head++;
-#if USE_IOTRACE
-               IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
                idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
@@ -2512,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        }
        if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
                tape->buffer_head++;
-#if USE_IOTRACE
-               IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
                idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
@@ -3241,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
        idetape_switch_buffers(tape, new_stage);
        idetape_add_stage_tail(drive, new_stage);
        tape->pipeline_head++;
-#if USE_IOTRACE
-       IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
        calculate_speeds(drive);
 
        /*
@@ -3493,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
                idetape_remove_stage_head(drive);
                spin_unlock_irqrestore(&tape->spinlock, flags);
                tape->pipeline_head++;
-#if USE_IOTRACE
-               IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
                calculate_speeds(drive);
        }
 #if IDETAPE_DEBUG_BUGS
@@ -4724,10 +4705,8 @@ static void ide_tape_release(struct kref *kref)
 
        drive->dsc_overlap = 0;
        drive->driver_data = NULL;
-       class_device_destroy(idetape_sysfs_class,
-                       MKDEV(IDETAPE_MAJOR, tape->minor));
-       class_device_destroy(idetape_sysfs_class,
-                       MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+       device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
+       device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
        idetape_devs[tape->minor] = NULL;
        g->private_data = NULL;
        put_disk(g);
@@ -4884,10 +4863,10 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        idetape_setup(drive, tape, minor);
 
-       class_device_create(idetape_sysfs_class, NULL,
-                       MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
-       class_device_create(idetape_sysfs_class, NULL,
-                       MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
+       device_create(idetape_sysfs_class, &drive->gendev,
+                     MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name);
+       device_create(idetape_sysfs_class, &drive->gendev,
+                       MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name);
 
        g->fops = &idetape_block_ops;
        ide_register_region(g);
index 2b60f1b0437e9aa790d446369ac285243bd6719f..5eb6fa15dc4df6d65c5408869b6e22027d049085 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static void ata_bswap_data (void *buffer, int wcount)
+void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
 {
-       u16 *p = buffer;
-
-       while (wcount--) {
-               *p = *p << 8 | *p >> 8; p++;
-               *p = *p << 8 | *p >> 8; p++;
-       }
-}
-
-static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
-{
-       HWIF(drive)->ata_input_data(drive, buffer, wcount);
-       if (drive->bswap)
-               ata_bswap_data(buffer, wcount);
-}
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_taskfile *tf = &task->tf;
+       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+               HIHI = 0xFF;
+
+#ifdef DEBUG
+       printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
+               "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
+               drive->name, tf->feature, tf->nsect, tf->lbal,
+               tf->lbam, tf->lbah, tf->device, tf->command);
+       printk("%s: hob: nsect 0x%02x lbal 0x%02x "
+               "lbam 0x%02x lbah 0x%02x\n",
+               drive->name, tf->hob_nsect, tf->hob_lbal,
+               tf->hob_lbam, tf->hob_lbah);
+#endif
 
-static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
-{
-       if (drive->bswap) {
-               ata_bswap_data(buffer, wcount);
-               HWIF(drive)->ata_output_data(drive, buffer, wcount);
-               ata_bswap_data(buffer, wcount);
-       } else {
-               HWIF(drive)->ata_output_data(drive, buffer, wcount);
-       }
+       ide_set_irq(drive, 1);
+
+       if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
+               SELECT_MASK(drive, 0);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_DATA)
+               hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+               hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+               hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+               hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+               hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+               hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+               hwif->OUTB(tf->feature, IDE_FEATURE_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+               hwif->OUTB(tf->nsect, IDE_NSECTOR_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+               hwif->OUTB(tf->lbal, IDE_SECTOR_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+               hwif->OUTB(tf->lbam, IDE_LCYL_REG);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+               hwif->OUTB(tf->lbah, IDE_HCYL_REG);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+               hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG);
 }
 
 int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
        ide_task_t args;
+
        memset(&args, 0, sizeof(ide_task_t));
-       args.tfRegister[IDE_NSECTOR_OFFSET]     = 0x01;
+       args.tf.nsect = 0x01;
        if (drive->media == ide_disk)
-               args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_IDENTIFY;
+               args.tf.command = WIN_IDENTIFY;
        else
-               args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_PIDENTIFY;
-       args.command_type = IDE_DRIVE_TASK_IN;
-       args.data_phase   = TASKFILE_IN;
-       args.handler      = &task_in_intr;
-       return ide_raw_taskfile(drive, &args, buf);
+               args.tf.command = WIN_PIDENTIFY;
+       args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       args.data_phase = TASKFILE_IN;
+       return ide_raw_taskfile(drive, &args, buf, 1);
 }
 
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+static int inline task_dma_ok(ide_task_t *task)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-       hob_struct_t *hobfile   = (hob_struct_t *) task->hobRegister;
-       u8 HIHI                 = (drive->addressing == 1) ? 0xE0 : 0xEF;
-
-       /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
-       if (IDE_CONTROL_REG) {
-               /* clear nIEN */
-               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-       }
-       SELECT_MASK(drive, 0);
-
-       if (drive->addressing == 1) {
-               hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
-               hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
-               hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
-               hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
-               hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
-       }
-
-       hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
-       hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
-       hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
-       hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
-       hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
-
-       hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-
-       if (task->handler != NULL) {
-               if (task->prehandler != NULL) {
-                       hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
-                       ndelay(400);    /* FIXME */
-                       return task->prehandler(drive, task->rq);
-               }
-               ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
-               return ide_started;
-       }
+       if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED))
+               return 1;
 
-       if (!drive->using_dma)
-               return ide_stopped;
-
-       switch (taskfile->command) {
+       switch (task->tf.command) {
                case WIN_WRITEDMA_ONCE:
                case WIN_WRITEDMA:
                case WIN_WRITEDMA_EXT:
@@ -129,24 +117,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
                case WIN_READDMA:
                case WIN_READDMA_EXT:
                case WIN_IDENTIFY_DMA:
-                       if (!hwif->dma_setup(drive)) {
-                               hwif->dma_exec_cmd(drive, taskfile->command);
-                               hwif->dma_start(drive);
-                               return ide_started;
-                       }
-                       break;
-               default:
-                       if (task->handler == NULL)
-                               return ide_stopped;
+                       return 1;
        }
 
-       return ide_stopped;
+       return 0;
 }
 
+static ide_startstop_t task_no_data_intr(ide_drive_t *);
+static ide_startstop_t set_geometry_intr(ide_drive_t *);
+static ide_startstop_t recal_intr(ide_drive_t *);
+static ide_startstop_t set_multmode_intr(ide_drive_t *);
+static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+static ide_startstop_t task_in_intr(ide_drive_t *);
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct ide_taskfile *tf = &task->tf;
+       ide_handler_t *handler = NULL;
+
+       if (task->data_phase == TASKFILE_MULTI_IN ||
+           task->data_phase == TASKFILE_MULTI_OUT) {
+               if (!drive->mult_count) {
+                       printk(KERN_ERR "%s: multimode not set!\n",
+                                       drive->name);
+                       return ide_stopped;
+               }
+       }
+
+       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+               task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
+
+       if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0)
+               ide_tf_load(drive, task);
+
+       switch (task->data_phase) {
+       case TASKFILE_MULTI_OUT:
+       case TASKFILE_OUT:
+               hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG);
+               ndelay(400);    /* FIXME */
+               return pre_task_out_intr(drive, task->rq);
+       case TASKFILE_MULTI_IN:
+       case TASKFILE_IN:
+               handler = task_in_intr;
+               /* fall-through */
+       case TASKFILE_NO_DATA:
+               if (handler == NULL)
+                       handler = task_no_data_intr;
+               /* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */
+               if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
+                       switch (tf->command) {
+                       case WIN_SPECIFY: handler = set_geometry_intr;  break;
+                       case WIN_RESTORE: handler = recal_intr;         break;
+                       case WIN_SETMULT: handler = set_multmode_intr;  break;
+                       }
+               }
+               ide_execute_command(drive, tf->command, handler,
+                                   WAIT_WORSTCASE, NULL);
+               return ide_started;
+       default:
+               if (task_dma_ok(task) == 0 || drive->using_dma == 0 ||
+                   hwif->dma_setup(drive))
+                       return ide_stopped;
+               hwif->dma_exec_cmd(drive, tf->command);
+               hwif->dma_start(drive);
+               return ide_started;
+       }
+}
+EXPORT_SYMBOL_GPL(do_rw_taskfile);
+
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
-ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
        u8 stat;
@@ -164,7 +207,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
-ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
        int retries = 5;
@@ -187,7 +230,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
-ide_startstop_t recal_intr (ide_drive_t *drive)
+static ide_startstop_t recal_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
        u8 stat;
@@ -200,7 +243,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive)
 /*
  * Handler for commands without a data phase
  */
-ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
 {
        ide_task_t *args        = HWGROUP(drive)->rq->special;
        ide_hwif_t *hwif        = HWIF(drive);
@@ -217,9 +260,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
        return ide_stopped;
 }
 
-EXPORT_SYMBOL(task_no_data_intr);
-
-static u8 wait_drive_not_busy(ide_drive_t *drive)
+u8 wait_drive_not_busy(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
        int retries;
@@ -227,8 +268,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
 
        /*
         * Last sector was transfered, wait until drive is ready.
-        * This can take up to 10 usec, but we will wait max 1 ms
-        * (drive_cmd_intr() waits that long).
+        * This can take up to 10 usec, but we will wait max 1 ms.
         */
        for (retries = 0; retries < 100; retries++) {
                if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
@@ -283,9 +323,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
 
        /* do the actual data transfer */
        if (write)
-               taskfile_output_data(drive, buf, SECTOR_WORDS);
+               hwif->ata_output_data(drive, buf, SECTOR_WORDS);
        else
-               taskfile_input_data(drive, buf, SECTOR_WORDS);
+               hwif->ata_input_data(drive, buf, SECTOR_WORDS);
 
        kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 #ifdef CONFIG_HIGHMEM
@@ -305,9 +345,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
 static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
                                     unsigned int write)
 {
+       u8 saved_io_32bit = drive->io_32bit;
+
        if (rq->bio)    /* fs request */
                rq->errors = 0;
 
+       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+               ide_task_t *task = rq->special;
+
+               if (task->tf_flags & IDE_TFLAG_IO_16BIT)
+                       drive->io_32bit = 0;
+       }
+
        touch_softlockup_watchdog();
 
        switch (drive->hwif->data_phase) {
@@ -319,6 +368,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
                ide_pio_sector(drive, write);
                break;
        }
+
+       drive->io_32bit = saved_io_32bit;
 }
 
 static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
@@ -356,40 +407,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
        return ide_error(drive, s, stat);
 }
 
-static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 {
-       HWIF(drive)->cursg = NULL;
-
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               ide_task_t *task = rq->special;
+               u8 err = drive->hwif->INB(IDE_ERROR_REG);
 
-               if (task->tf_out_flags.all) {
-                       u8 err = drive->hwif->INB(IDE_ERROR_REG);
-                       ide_end_drive_cmd(drive, stat, err);
-                       return;
-               }
+               ide_end_drive_cmd(drive, stat, err);
+               return;
        }
 
        if (rq->rq_disk) {
                ide_driver_t *drv;
 
                drv = *(ide_driver_t **)rq->rq_disk->private_data;;
-               drv->end_request(drive, 1, rq->hard_nr_sectors);
+               drv->end_request(drive, 1, rq->nr_sectors);
        } else
-               ide_end_request(drive, 1, rq->hard_nr_sectors);
+               ide_end_request(drive, 1, rq->nr_sectors);
 }
 
 /*
  * Handler for command with PIO data-in phase (Read/Read Multiple).
  */
-ide_startstop_t task_in_intr (ide_drive_t *drive)
+static ide_startstop_t task_in_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = HWGROUP(drive)->rq;
        u8 stat = hwif->INB(IDE_STATUS_REG);
 
        /* new way for dealing with premature shared PCI interrupts */
-       if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+       if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
                if (stat & (ERR_STAT | DRQ_STAT))
                        return task_error(drive, rq, __FUNCTION__, stat);
                /* No data yet, so wait for another IRQ. */
@@ -402,7 +448,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
        /* If it was the last datablock check status and finish transfer. */
        if (!hwif->nleft) {
                stat = wait_drive_not_busy(drive);
-               if (!OK_STAT(stat, 0, BAD_R_STAT))
+               if (!OK_STAT(stat, 0, BAD_STAT))
                        return task_error(drive, rq, __FUNCTION__, stat);
                task_end_request(drive, rq, stat);
                return ide_stopped;
@@ -413,7 +459,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
 
        return ide_started;
 }
-EXPORT_SYMBOL(task_in_intr);
 
 /*
  * Handler for command with PIO data-out phase (Write/Write Multiple).
@@ -443,11 +488,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
        return ide_started;
 }
 
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
 {
        ide_startstop_t startstop;
 
-       if (ide_wait_stat(&startstop, drive, DATA_READY,
+       if (ide_wait_stat(&startstop, drive, DRQ_STAT,
                          drive->bad_wstat, WAIT_DRQ)) {
                printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
                                drive->name,
@@ -464,9 +509,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 
        return ide_started;
 }
-EXPORT_SYMBOL(pre_task_out_intr);
 
-static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
 {
        struct request rq;
 
@@ -481,36 +525,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
         * if we would find a solution to transfer any size.
         * To support special commands like READ LONG.
         */
-       if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
-               if (data_size == 0)
-                       rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
-               else
-                       rq.nr_sectors = data_size / SECTOR_SIZE;
-
-               if (!rq.nr_sectors) {
-                       printk(KERN_ERR "%s: in/out command without data\n",
-                                       drive->name);
-                       return -EFAULT;
-               }
+       rq.hard_nr_sectors = rq.nr_sectors = nsect;
+       rq.hard_cur_sectors = rq.current_nr_sectors = nsect;
 
-               rq.hard_nr_sectors = rq.nr_sectors;
-               rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
+       if (task->tf_flags & IDE_TFLAG_WRITE)
+               rq.cmd_flags |= REQ_RW;
 
-               if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-                       rq.cmd_flags |= REQ_RW;
-       }
+       rq.special = task;
+       task->rq = &rq;
 
-       rq.special = args;
-       args->rq = &rq;
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
+EXPORT_SYMBOL(ide_raw_taskfile);
+
+int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
 {
-       return ide_diag_taskfile(drive, args, 0, buf);
-}
+       task->data_phase = TASKFILE_NO_DATA;
 
-EXPORT_SYMBOL(ide_raw_taskfile);
+       return ide_raw_taskfile(drive, task, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
 
 #ifdef CONFIG_IDE_TASK_IOCTL
 int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
@@ -519,13 +554,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        ide_task_t              args;
        u8 *outbuf              = NULL;
        u8 *inbuf               = NULL;
-       task_ioreg_t *argsptr   = args.tfRegister;
-       task_ioreg_t *hobsptr   = args.hobRegister;
+       u8 *data_buf            = NULL;
        int err                 = 0;
        int tasksize            = sizeof(struct ide_task_request_s);
        unsigned int taskin     = 0;
        unsigned int taskout    = 0;
-       u8 io_32bit             = drive->io_32bit;
+       u16 nsect               = 0;
        char __user *buf = (char __user *)arg;
 
 //     printk("IDE Taskfile ...\n");
@@ -572,24 +606,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        }
 
        memset(&args, 0, sizeof(ide_task_t));
-       memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
-       memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 
-       args.tf_in_flags  = req_task->in_flags;
-       args.tf_out_flags = req_task->out_flags;
-       args.data_phase   = req_task->data_phase;
-       args.command_type = req_task->req_cmd;
+       memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
+       memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+
+       args.data_phase = req_task->data_phase;
+
+       args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
+                       IDE_TFLAG_IN_TF;
+       if (drive->addressing == 1)
+               args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
+
+       if (req_task->out_flags.all) {
+               args.tf_flags |= IDE_TFLAG_FLAGGED;
+
+               if (req_task->out_flags.b.data)
+                       args.tf_flags |= IDE_TFLAG_OUT_DATA;
+
+               if (req_task->out_flags.b.nsector_hob)
+                       args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
+               if (req_task->out_flags.b.sector_hob)
+                       args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
+               if (req_task->out_flags.b.lcyl_hob)
+                       args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
+               if (req_task->out_flags.b.hcyl_hob)
+                       args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
+
+               if (req_task->out_flags.b.error_feature)
+                       args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
+               if (req_task->out_flags.b.nsector)
+                       args.tf_flags |= IDE_TFLAG_OUT_NSECT;
+               if (req_task->out_flags.b.sector)
+                       args.tf_flags |= IDE_TFLAG_OUT_LBAL;
+               if (req_task->out_flags.b.lcyl)
+                       args.tf_flags |= IDE_TFLAG_OUT_LBAM;
+               if (req_task->out_flags.b.hcyl)
+                       args.tf_flags |= IDE_TFLAG_OUT_LBAH;
+       } else {
+               args.tf_flags |= IDE_TFLAG_OUT_TF;
+               if (args.tf_flags & IDE_TFLAG_LBA48)
+                       args.tf_flags |= IDE_TFLAG_OUT_HOB;
+       }
+
+       if (req_task->in_flags.b.data)
+               args.tf_flags |= IDE_TFLAG_IN_DATA;
 
-       drive->io_32bit = 0;
        switch(req_task->data_phase) {
-               case TASKFILE_OUT_DMAQ:
-               case TASKFILE_OUT_DMA:
-                       err = ide_diag_taskfile(drive, &args, taskout, outbuf);
-                       break;
-               case TASKFILE_IN_DMAQ:
-               case TASKFILE_IN_DMA:
-                       err = ide_diag_taskfile(drive, &args, taskin, inbuf);
-                       break;
                case TASKFILE_MULTI_OUT:
                        if (!drive->mult_count) {
                                /* (hs): give up if multcount is not set */
@@ -601,9 +663,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                        }
                        /* fall through */
                case TASKFILE_OUT:
-                       args.prehandler = &pre_task_out_intr;
-                       args.handler = &task_out_intr;
-                       err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+                       /* fall through */
+               case TASKFILE_OUT_DMAQ:
+               case TASKFILE_OUT_DMA:
+                       nsect = taskout / SECTOR_SIZE;
+                       data_buf = outbuf;
                        break;
                case TASKFILE_MULTI_IN:
                        if (!drive->mult_count) {
@@ -616,22 +680,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                        }
                        /* fall through */
                case TASKFILE_IN:
-                       args.handler = &task_in_intr;
-                       err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+                       /* fall through */
+               case TASKFILE_IN_DMAQ:
+               case TASKFILE_IN_DMA:
+                       nsect = taskin / SECTOR_SIZE;
+                       data_buf = inbuf;
                        break;
                case TASKFILE_NO_DATA:
-                       args.handler = &task_no_data_intr;
-                       err = ide_diag_taskfile(drive, &args, 0, NULL);
                        break;
                default:
                        err = -EFAULT;
                        goto abort;
        }
 
-       memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
-       memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
-       req_task->in_flags  = args.tf_in_flags;
-       req_task->out_flags = args.tf_out_flags;
+       if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
+               nsect = 0;
+       else if (!nsect) {
+               nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
+
+               if (!nsect) {
+                       printk(KERN_ERR "%s: in/out command without data\n",
+                                       drive->name);
+                       err = -EFAULT;
+                       goto abort;
+               }
+       }
+
+       if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
+               args.tf_flags |= IDE_TFLAG_WRITE;
+
+       err = ide_raw_taskfile(drive, &args, data_buf, nsect);
+
+       memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
+       memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
+
+       if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
+           req_task->in_flags.all == 0) {
+               req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+               if (drive->addressing == 1)
+                       req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
+       }
 
        if (copy_to_user(buf, req_task, tasksize)) {
                err = -EFAULT;
@@ -658,40 +746,24 @@ abort:
 
 //     printk("IDE Taskfile ioctl ended. rc = %i\n", err);
 
-       drive->io_32bit = io_32bit;
-
        return err;
 }
 #endif
 
-int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
-{
-       struct request rq;
-       u8 buffer[4];
-
-       if (!buf)
-               buf = buffer;
-       memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-       ide_init_drive_cmd(&rq);
-       rq.buffer = buf;
-       *buf++ = cmd;
-       *buf++ = nsect;
-       *buf++ = feature;
-       *buf++ = sectors;
-       return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 {
-       int err = 0;
-       u8 args[4], *argbuf = args;
-       u8 xfer_rate = 0;
-       int argsize = 4;
+       u8 *buf = NULL;
+       int bufsize = 0, err = 0;
+       u8 args[4], xfer_rate = 0;
        ide_task_t tfargs;
+       struct ide_taskfile *tf = &tfargs.tf;
 
        if (NULL == (void *) arg) {
                struct request rq;
+
                ide_init_drive_cmd(&rq);
+               rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
                return ide_do_drive_cmd(drive, &rq, ide_wait);
        }
 
@@ -699,27 +771,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                return -EFAULT;
 
        memset(&tfargs, 0, sizeof(ide_task_t));
-       tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
-       tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
-       tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
-       tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
-       tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
-       tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
-       tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+       tf->feature = args[2];
+       if (args[0] == WIN_SMART) {
+               tf->nsect = args[3];
+               tf->lbal  = args[1];
+               tf->lbam  = 0x4f;
+               tf->lbah  = 0xc2;
+               tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+       } else {
+               tf->nsect = args[1];
+               tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+                                 IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+       }
+       tf->command = args[0];
+       tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
 
        if (args[3]) {
-               argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-               argbuf = kzalloc(argsize, GFP_KERNEL);
-               if (argbuf == NULL)
+               tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+               bufsize = SECTOR_WORDS * 4 * args[3];
+               buf = kzalloc(bufsize, GFP_KERNEL);
+               if (buf == NULL)
                        return -ENOMEM;
        }
+
        if (set_transfer(drive, &tfargs)) {
                xfer_rate = args[1];
                if (ide_ata66_check(drive, &tfargs))
                        goto abort;
        }
 
-       err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+       err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+       args[0] = tf->status;
+       args[1] = tf->error;
+       args[2] = tf->nsect;
 
        if (!err && xfer_rate) {
                /* active-retuning-calls future */
@@ -727,142 +812,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                ide_driveid_update(drive);
        }
 abort:
-       if (copy_to_user((void __user *)arg, argbuf, argsize))
+       if (copy_to_user((void __user *)arg, &args, 4))
                err = -EFAULT;
-       if (argsize > 4)
-               kfree(argbuf);
+       if (buf) {
+               if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+                       err = -EFAULT;
+               kfree(buf);
+       }
        return err;
 }
 
-static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
-{
-       struct request rq;
-
-       ide_init_drive_cmd(&rq);
-       rq.cmd_type = REQ_TYPE_ATA_TASK;
-       rq.buffer = buf;
-       return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 {
        void __user *p = (void __user *)arg;
        int err = 0;
-       u8 args[7], *argbuf = args;
-       int argsize = 7;
+       u8 args[7];
+       ide_task_t task;
 
        if (copy_from_user(args, p, 7))
                return -EFAULT;
-       err = ide_wait_cmd_task(drive, argbuf);
-       if (copy_to_user(p, argbuf, argsize))
-               err = -EFAULT;
-       return err;
-}
-
-/*
- * NOTICE: This is additions from IBM to provide a discrete interface,
- * for selective taskregister access operations.  Nice JOB Klaus!!!
- * Glad to be able to work and co-develop this with you and IBM.
- */
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-       hob_struct_t *hobfile   = (hob_struct_t *) task->hobRegister;
-
-       if (task->data_phase == TASKFILE_MULTI_IN ||
-           task->data_phase == TASKFILE_MULTI_OUT) {
-               if (!drive->mult_count) {
-                       printk(KERN_ERR "%s: multimode not set!\n", drive->name);
-                       return ide_stopped;
-               }
-       }
 
-       /*
-        * (ks) Check taskfile in flags.
-        * If set, then execute as it is defined.
-        * If not set, then define default settings.
-        * The default values are:
-        *      read all taskfile registers (except data)
-        *      read the hob registers (sector, nsector, lcyl, hcyl)
-        */
-       if (task->tf_in_flags.all == 0) {
-               task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-               if (drive->addressing == 1)
-                       task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
-        }
-
-       /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
-       if (IDE_CONTROL_REG)
-               /* clear nIEN */
-               hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-       SELECT_MASK(drive, 0);
-
-       if (task->tf_out_flags.b.data) {
-               u16 data =  taskfile->data + (hobfile->data << 8);
-               hwif->OUTW(data, IDE_DATA_REG);
-       }
-
-       /* (ks) send hob registers first */
-       if (task->tf_out_flags.b.nsector_hob)
-               hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
-       if (task->tf_out_flags.b.sector_hob)
-               hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
-       if (task->tf_out_flags.b.lcyl_hob)
-               hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
-       if (task->tf_out_flags.b.hcyl_hob)
-               hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
-
-       /* (ks) Send now the standard registers */
-       if (task->tf_out_flags.b.error_feature)
-               hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
-       /* refers to number of sectors to transfer */
-       if (task->tf_out_flags.b.nsector)
-               hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
-       /* refers to sector offset or start sector */
-       if (task->tf_out_flags.b.sector)
-               hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
-       if (task->tf_out_flags.b.lcyl)
-               hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
-       if (task->tf_out_flags.b.hcyl)
-               hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
-
-        /*
-        * (ks) In the flagged taskfile approch, we will use all specified
-        * registers and the register value will not be changed, except the
-        * select bit (master/slave) in the drive_head register. We must make
-        * sure that the desired drive is selected.
-        */
-       hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
-       switch(task->data_phase) {
+       memset(&task, 0, sizeof(task));
+       memcpy(&task.tf_array[7], &args[1], 6);
+       task.tf.command = args[0];
+       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-               case TASKFILE_OUT_DMAQ:
-               case TASKFILE_OUT_DMA:
-               case TASKFILE_IN_DMAQ:
-               case TASKFILE_IN_DMA:
-                       if (!drive->using_dma)
-                               break;
+       err = ide_no_data_taskfile(drive, &task);
 
-                       if (!hwif->dma_setup(drive)) {
-                               hwif->dma_exec_cmd(drive, taskfile->command);
-                               hwif->dma_start(drive);
-                               return ide_started;
-                       }
-                       break;
+       args[0] = task.tf.command;
+       memcpy(&args[1], &task.tf_array[7], 6);
 
-               default:
-                       if (task->handler == NULL)
-                               return ide_stopped;
-
-                       /* Issue the command */
-                       if (task->prehandler) {
-                               hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
-                               ndelay(400);    /* FIXME */
-                               return task->prehandler(drive, task->rq);
-                       }
-                       ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
-                       return ide_started;
-       }
+       if (copy_to_user(p, args, 7))
+               err = -EFAULT;
 
-       return ide_stopped;
+       return err;
 }
index 54943da6e4e5cfa45c80ac73a86f6c9de3a10769..97894abd9ebca93da51af65b7268a953e7969a47 100644 (file)
@@ -95,7 +95,7 @@ DEFINE_MUTEX(ide_cfg_mtx);
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
+int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 #endif
 
 int noautodma = 0;
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(ide_hwifs);
 /*
  * Do not even *think* about calling this!
  */
-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
 {
        unsigned int unit;
 
@@ -159,6 +159,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
                init_completion(&drive->gendev_rel_comp);
        }
 }
+EXPORT_SYMBOL_GPL(ide_init_port_data);
 
 static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
 {
@@ -177,8 +178,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
 #endif
 }
 
-extern void ide_arm_init(void);
-
 /*
  * init_ide_data() sets reasonable default values into all fields
  * of all instances of the hwifs and drives, but only on the first call.
@@ -210,16 +209,13 @@ static void __init init_ide_data (void)
        /* Initialise all interface structures */
        for (index = 0; index < MAX_HWIFS; ++index) {
                hwif = &ide_hwifs[index];
-               init_hwif_data(hwif, index);
+               ide_init_port_data(hwif, index);
                init_hwif_default(hwif, index);
 #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
                hwif->irq =
                        ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
 #endif
        }
-#ifdef CONFIG_IDE_ARM
-       ide_arm_init();
-#endif
 }
 
 /**
@@ -414,8 +410,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->cds                       = tmp_hwif->cds;
 #endif
 
-       hwif->fixup                     = tmp_hwif->fixup;
-
        hwif->set_pio_mode              = tmp_hwif->set_pio_mode;
        hwif->set_dma_mode              = tmp_hwif->set_dma_mode;
        hwif->mdma_filter               = tmp_hwif->mdma_filter;
@@ -424,7 +418,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->reset_poll                = tmp_hwif->reset_poll;
        hwif->pre_reset                 = tmp_hwif->pre_reset;
        hwif->resetproc                 = tmp_hwif->resetproc;
-       hwif->intrproc                  = tmp_hwif->intrproc;
        hwif->maskproc                  = tmp_hwif->maskproc;
        hwif->quirkproc                 = tmp_hwif->quirkproc;
        hwif->busproc                   = tmp_hwif->busproc;
@@ -434,16 +427,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->atapi_input_bytes         = tmp_hwif->atapi_input_bytes;
        hwif->atapi_output_bytes        = tmp_hwif->atapi_output_bytes;
 
+       hwif->dma_host_set              = tmp_hwif->dma_host_set;
        hwif->dma_setup                 = tmp_hwif->dma_setup;
        hwif->dma_exec_cmd              = tmp_hwif->dma_exec_cmd;
        hwif->dma_start                 = tmp_hwif->dma_start;
        hwif->ide_dma_end               = tmp_hwif->ide_dma_end;
-       hwif->ide_dma_on                = tmp_hwif->ide_dma_on;
-       hwif->dma_off_quietly           = tmp_hwif->dma_off_quietly;
        hwif->ide_dma_test_irq          = tmp_hwif->ide_dma_test_irq;
        hwif->ide_dma_clear_irq         = tmp_hwif->ide_dma_clear_irq;
-       hwif->dma_host_on               = tmp_hwif->dma_host_on;
-       hwif->dma_host_off              = tmp_hwif->dma_host_off;
        hwif->dma_lost_irq              = tmp_hwif->dma_lost_irq;
        hwif->dma_timeout               = tmp_hwif->dma_timeout;
 
@@ -468,7 +458,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 #endif
 
        hwif->dma_base                  = tmp_hwif->dma_base;
-       hwif->dma_master                = tmp_hwif->dma_master;
        hwif->dma_command               = tmp_hwif->dma_command;
        hwif->dma_vendor1               = tmp_hwif->dma_vendor1;
        hwif->dma_status                = tmp_hwif->dma_status;
@@ -602,7 +591,6 @@ void ide_unregister(unsigned int index)
                (void) ide_release_dma(hwif);
 
                hwif->dma_base = 0;
-               hwif->dma_master = 0;
                hwif->dma_command = 0;
                hwif->dma_vendor1 = 0;
                hwif->dma_status = 0;
@@ -617,7 +605,7 @@ void ide_unregister(unsigned int index)
        tmp_hwif = *hwif;
 
        /* restore hwif data to pristine status */
-       init_hwif_data(hwif, index);
+       ide_init_port_data(hwif, index);
        init_hwif_default(hwif, index);
 
        ide_hwif_restore(hwif, &tmp_hwif);
@@ -683,24 +671,34 @@ void ide_setup_ports (    hw_regs_t *hw,
  */
 }
 
+void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
+{
+       memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
+       hwif->irq = hw->irq;
+       hwif->noprobe = 0;
+       hwif->chipset = hw->chipset;
+       hwif->gendev.parent = hw->dev;
+       hwif->ack_intr = hw->ack_intr;
+}
+EXPORT_SYMBOL_GPL(ide_init_port_hw);
+
 /**
  *     ide_register_hw         -       register IDE interface
  *     @hw: hardware registers
- *     @fixup: fixup function
- *     @initializing: set while initializing built-in drivers
+ *     @quirkproc: quirkproc function
  *     @hwifp: pointer to returned hwif
  *
  *     Register an IDE interface, specifying exactly the registers etc.
- *     Set init=1 iff calling before probes have taken place.
  *
  *     Returns -1 on error.
  */
 
-int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
-                   int initializing, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *),
+                   ide_hwif_t **hwifp)
 {
        int index, retry = 1;
        ide_hwif_t *hwif;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        do {
                for (index = 0; index < MAX_HWIFS; ++index) {
@@ -712,8 +710,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
                        hwif = &ide_hwifs[index];
                        if (hwif->hold)
                                continue;
-                       if ((!hwif->present && !hwif->mate && !initializing) ||
-                           (!hwif->io_ports[IDE_DATA_OFFSET] && initializing))
+                       if (!hwif->present && hwif->mate == NULL)
                                goto found;
                }
                for (index = 0; index < MAX_HWIFS; index++)
@@ -724,29 +721,23 @@ found:
        if (hwif->present)
                ide_unregister(index);
        else if (!hwif->hold) {
-               init_hwif_data(hwif, index);
+               ide_init_port_data(hwif, index);
                init_hwif_default(hwif, index);
        }
        if (hwif->present)
                return -1;
-       memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
-       hwif->irq = hw->irq;
-       hwif->noprobe = 0;
-       hwif->fixup = fixup;
-       hwif->chipset = hw->chipset;
-       hwif->gendev.parent = hw->dev;
-       hwif->ack_intr = hw->ack_intr;
 
-       if (initializing == 0) {
-               u8 idx[4] = { index, 0xff, 0xff, 0xff };
+       ide_init_port_hw(hwif, hw);
+       hwif->quirkproc = quirkproc;
 
-               ide_device_add(idx);
-       }
+       idx[0] = index;
+
+       ide_device_add(idx);
 
        if (hwifp)
                *hwifp = hwif;
 
-       return (initializing || hwif->present) ? index : -1;
+       return hwif->present ? index : -1;
 }
 
 EXPORT_SYMBOL(ide_register_hw);
@@ -839,7 +830,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
        if (!drive->id || !(drive->id->capability & 1))
                goto out;
 
-       if (hwif->ide_dma_on == NULL)
+       if (hwif->dma_host_set == NULL)
                goto out;
 
        err = -EBUSY;
@@ -854,8 +845,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
        err = 0;
 
        if (arg) {
-               hwif->dma_off_quietly(drive);
-               if (ide_set_dma(drive) || hwif->ide_dma_on(drive))
+               if (ide_set_dma(drive))
                        err = -EIO;
        } else
                ide_dma_off(drive);
@@ -888,7 +878,10 @@ int set_pio_mode(ide_drive_t *drive, int arg)
 
        if (drive->special.b.set_tune)
                return -EBUSY;
+
        ide_init_drive_cmd(&rq);
+       rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
        drive->tune_req = (u8) arg;
        drive->special.b.set_tune = 1;
        (void) ide_do_drive_cmd(drive, &rq, ide_wait);
@@ -1070,7 +1063,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        ide_init_hwif_ports(&hw, (unsigned long) args[0],
                                            (unsigned long) args[1], NULL);
                        hw.irq = args[2];
-                       if (ide_register_hw(&hw, NULL, 0, NULL) == -1)
+                       if (ide_register_hw(&hw, NULL, NULL) == -1)
                                return -EIO;
                        return 0;
                }
@@ -1231,26 +1224,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
        return 0;       /* zero = nothing matched */
 }
 
-#ifdef CONFIG_BLK_DEV_ALI14XX
 extern int probe_ali14xx;
-extern int ali14xx_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
 extern int probe_umc8672;
-extern int umc8672_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
 extern int probe_dtc2278;
-extern int dtc2278_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
 extern int probe_ht6560b;
-extern int ht6560b_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
 extern int probe_qd65xx;
-extern int qd65xx_init(void);
-#endif
+extern int cmd640_vlb;
 
 static int __initdata is_chipset_set[MAX_HWIFS];
 
@@ -1327,7 +1306,7 @@ static int __init ide_setup(char *s)
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
                const char *hd_words[] = {
                        "none", "noprobe", "nowerr", "cdrom", "nodma",
-                       "autotune", "noautotune", "minus8", "swapdata", "bswap",
+                       "autotune", "noautotune", "-8", "-9", "-10",
                        "noflush", "remap", "remap63", "scsi", NULL };
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
@@ -1363,10 +1342,6 @@ static int __init ide_setup(char *s)
                        case -7: /* "noautotune" */
                                drive->autotune = IDE_TUNE_NOAUTO;
                                goto obsolete_option;
-                       case -9: /* "swapdata" */
-                       case -10: /* "bswap" */
-                               drive->bswap = 1;
-                               goto done;
                        case -11: /* noflush */
                                drive->noflush = 1;
                                goto done;
@@ -1466,11 +1441,8 @@ static int __init ide_setup(char *s)
 #endif
 #ifdef CONFIG_BLK_DEV_CMD640
                        case -14: /* "cmd640_vlb" */
-                       {
-                               extern int cmd640_vlb; /* flag for cmd640.c */
                                cmd640_vlb = 1;
                                goto done;
-                       }
 #endif
 #ifdef CONFIG_BLK_DEV_HT6560B
                        case -13: /* "ht6560b" */
@@ -1560,79 +1532,6 @@ done:
        return 1;
 }
 
-extern void __init pnpide_init(void);
-extern void __exit pnpide_exit(void);
-extern void __init h8300_ide_init(void);
-
-/*
- * probe_for_hwifs() finds/initializes "known" IDE interfaces
- */
-static void __init probe_for_hwifs (void)
-{
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-       ide_scan_pcibus(ide_scan_direction);
-#endif
-
-#ifdef CONFIG_ETRAX_IDE
-       {
-               extern void init_e100_ide(void);
-               init_e100_ide();
-       }
-#endif /* CONFIG_ETRAX_IDE */
-#ifdef CONFIG_BLK_DEV_CMD640
-       {
-               extern void ide_probe_for_cmd640x(void);
-               ide_probe_for_cmd640x();
-       }
-#endif /* CONFIG_BLK_DEV_CMD640 */
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-       {
-               extern int pmac_ide_probe(void);
-               (void)pmac_ide_probe();
-       }
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#ifdef CONFIG_BLK_DEV_GAYLE
-       {
-               extern void gayle_init(void);
-               gayle_init();
-       }
-#endif /* CONFIG_BLK_DEV_GAYLE */
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-       {
-               extern void falconide_init(void);
-               falconide_init();
-       }
-#endif /* CONFIG_BLK_DEV_FALCON_IDE */
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-       {
-               extern void macide_init(void);
-               macide_init();
-       }
-#endif /* CONFIG_BLK_DEV_MAC_IDE */
-#ifdef CONFIG_BLK_DEV_Q40IDE
-       {
-               extern void q40ide_init(void);
-               q40ide_init();
-       }
-#endif /* CONFIG_BLK_DEV_Q40IDE */
-#ifdef CONFIG_BLK_DEV_BUDDHA
-       {
-               extern void buddha_init(void);
-               buddha_init();
-       }
-#endif /* CONFIG_BLK_DEV_BUDDHA */
-#ifdef CONFIG_BLK_DEV_IDEPNP
-       pnpide_init();
-#endif
-#ifdef CONFIG_H8300
-       h8300_ide_init();
-#endif
-}
-
-/*
- * Probe module
- */
-
 EXPORT_SYMBOL(ide_lock);
 
 static int ide_bus_match(struct device *dev, struct device_driver *drv)
@@ -1779,30 +1678,6 @@ static int __init ide_init(void)
 
        proc_ide_create();
 
-#ifdef CONFIG_BLK_DEV_ALI14XX
-       if (probe_ali14xx)
-               (void)ali14xx_init();
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
-       if (probe_umc8672)
-               (void)umc8672_init();
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
-       if (probe_dtc2278)
-               (void)dtc2278_init();
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
-       if (probe_ht6560b)
-               (void)ht6560b_init();
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
-       if (probe_qd65xx)
-               (void)qd65xx_init();
-#endif
-
-       /* Probe for special PCI and other "known" interface chipsets. */
-       probe_for_hwifs();
-
        return 0;
 }
 
@@ -1838,10 +1713,6 @@ void __exit cleanup_module (void)
        for (index = 0; index < MAX_HWIFS; ++index)
                ide_unregister(index);
 
-#ifdef CONFIG_BLK_DEV_IDEPNP
-       pnpide_exit();
-#endif
-
        proc_ide_destroy();
 
        bus_unregister(&ide_bus_type);
index 409822349f1006c896e98d707cf45a0f9c1eb056..7043ec7d1e056455eda8f7cbf2bdbf9e927fa44d 100644 (file)
@@ -1,15 +1,24 @@
 
+# link order is important here
+
 obj-$(CONFIG_BLK_DEV_ALI14XX)          += ali14xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)          += umc8672.o
 obj-$(CONFIG_BLK_DEV_DTC2278)          += dtc2278.o
 obj-$(CONFIG_BLK_DEV_HT6560B)          += ht6560b.o
 obj-$(CONFIG_BLK_DEV_QD65XX)           += qd65xx.o
-obj-$(CONFIG_BLK_DEV_UMC8672)          += umc8672.o
 
-obj-$(CONFIG_BLK_DEV_IDECS)            += ide-cs.o
+obj-$(CONFIG_BLK_DEV_GAYLE)            += gayle.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)       += falconide.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)          += macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)           += q40ide.o
+obj-$(CONFIG_BLK_DEV_BUDDHA)           += buddha.o
 
-obj-$(CONFIG_BLK_DEV_PLATFORM)         += ide_platform.o
+ifeq ($(CONFIG_BLK_DEV_IDECS), m)
+       obj-m += ide-cs.o
+endif
 
-# Last of all
-obj-$(CONFIG_BLK_DEV_HD)               += hd.o
+ifeq ($(CONFIG_BLK_DEV_PLATFORM), m)
+       obj-m += ide_platform.o
+endif
 
 EXTRA_CFLAGS   := -Idrivers/ide
index 38c3a6d63f301c0e7df0a73a96b6f49353847712..5ec0be4cbad71d1d5f5fc626792db680c8cb09f9 100644 (file)
@@ -231,8 +231,7 @@ int probe_ali14xx = 0;
 module_param_named(probe, probe_ali14xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init ali14xx_init(void)
+static int __init ali14xx_init(void)
 {
        if (probe_ali14xx == 0)
                goto out;
@@ -248,9 +247,7 @@ out:
        return -ENODEV;
 }
 
-#ifdef MODULE
 module_init(ali14xx_init);
-#endif
 
 MODULE_AUTHOR("see local file");
 MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
index 4a0be251a05fd84ddaa606c2b1161c2c99d93a59..74d28e058f55a9038d609683f2bc0078ac6a2e2a 100644 (file)
@@ -112,6 +112,7 @@ typedef enum BuddhaType_Enum {
     BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
 } BuddhaType;
 
+static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
 
     /*
      *  Check and acknowledge the interrupt status
@@ -143,11 +144,11 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
      *  Probe for a Buddha or Catweasel IDE interface
      */
 
-void __init buddha_init(void)
+static int __init buddha_init(void)
 {
        hw_regs_t hw;
        ide_hwif_t *hwif;
-       int i, index;
+       int i;
 
        struct zorro_dev *z = NULL;
        u_long buddha_board = 0;
@@ -156,6 +157,8 @@ void __init buddha_init(void)
 
        while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
                unsigned long board;
+               u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
                if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
                        buddha_num_hwifs = BUDDHA_NUM_HWIFS;
                        type=BOARD_BUDDHA;
@@ -195,7 +198,10 @@ fail_base2:
                /* X-Surf doesn't have this.  IRQs are always on */
                if (type != BOARD_XSURF)
                        z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-               
+
+               printk(KERN_INFO "ide: %s IDE controller\n",
+                                buddha_board_name[type]);
+
                for(i=0;i<buddha_num_hwifs;i++) {
                        if(type != BOARD_XSURF) {
                                ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
@@ -213,23 +219,23 @@ fail_base2:
                                                IRQ_AMIGA_PORTS);
                        }       
 
-                       index = ide_register_hw(&hw, NULL, 1, &hwif);
-                       if (index != -1) {
+                       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+                       if (hwif) {
+                               u8 index = hwif->index;
+
+                               ide_init_port_data(hwif, index);
+                               ide_init_port_hw(hwif, &hw);
+
                                hwif->mmio = 1;
-                               printk("ide%d: ", index);
-                               switch(type) {
-                               case BOARD_BUDDHA:
-                                       printk("Buddha");
-                                       break;
-                               case BOARD_CATWEASEL:
-                                       printk("Catweasel");
-                                       break;
-                               case BOARD_XSURF:
-                                       printk("X-Surf");
-                                       break;
-                               }
-                               printk(" IDE interface\n");         
-                       }                     
+
+                               idx[i] = index;
+                       }
                }
+
+               ide_device_add(idx);
        }
+
+       return 0;
 }
+
+module_init(buddha_init);
index 24a845d45bd29b369001979b9b24cede2c6bda05..13eee6da280656073f657db9ed2a44488eb5d3af 100644 (file)
@@ -150,8 +150,7 @@ int probe_dtc2278 = 0;
 module_param_named(probe, probe_dtc2278, bool, 0);
 MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init dtc2278_init(void)
+static int __init dtc2278_init(void)
 {
        if (probe_dtc2278 == 0)
                return -ENODEV;
@@ -163,9 +162,7 @@ int __init dtc2278_init(void)
        return 0;
 }
 
-#ifdef MODULE
 module_init(dtc2278_init);
-#endif
 
 MODULE_AUTHOR("See Local File");
 MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
index 7d7936f1b9007b06c50bfe477f1171ef49a33150..2860956bdcb079196c199e91af40163615670043 100644 (file)
@@ -62,19 +62,31 @@ EXPORT_SYMBOL(falconide_intr_lock);
      *  Probe for a Falcon IDE interface
      */
 
-void __init falconide_init(void)
+static int __init falconide_init(void)
 {
     if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
        hw_regs_t hw;
-       int index;
+
+       printk(KERN_INFO "ide: Falcon IDE controller\n");
 
        ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
                        0, 0, NULL,
 //                     falconide_iops,
                        IRQ_MFP_IDE);
-       index = ide_register_hw(&hw, NULL, 1, NULL);
 
-       if (index != -1)
-           printk("ide%d: Falcon IDE interface\n", index);
+       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif) {
+               u8 index = hwif->index;
+               u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+               ide_init_port_data(hwif, index);
+               ide_init_port_hw(hwif, &hw);
+
+               ide_device_add(idx);
+       }
     }
+
+    return 0;
 }
+
+module_init(falconide_init);
index 53331ee1e957c9a71c651a2eeb3c5ae2aaa191bf..492fa047efc00bb8da4b114f18f7e6b7b1405d88 100644 (file)
@@ -110,12 +110,13 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
 
-void __init gayle_init(void)
+static int __init gayle_init(void)
 {
     int a4000, i;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
     if (!MACH_IS_AMIGA)
-       return;
+       return -ENODEV;
 
     if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
        goto found;
@@ -125,15 +126,21 @@ void __init gayle_init(void)
                          NULL))
        goto found;
 #endif
-    return;
+    return -ENODEV;
 
 found:
+       printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
+                        a4000 ? 4000 : 1200,
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+                        ide_doubler ? ", IDE doubler" :
+#endif
+                        "");
+
     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
        unsigned long base, ctrlport, irqport;
        ide_ack_intr_t *ack_intr;
        hw_regs_t hw;
        ide_hwif_t *hwif;
-       int index;
        unsigned long phys_base, res_start, res_n;
 
        if (a4000) {
@@ -165,21 +172,23 @@ found:
 //                     &gayle_iops,
                        IRQ_AMIGA_PORTS);
 
-       index = ide_register_hw(&hw, NULL, 1, &hwif);
-       if (index != -1) {
+       hwif = ide_find_port(base);
+       if (hwif) {
+           u8 index = hwif->index;
+
+           ide_init_port_data(hwif, index);
+           ide_init_port_hw(hwif, &hw);
+
            hwif->mmio = 1;
-           switch (i) {
-               case 0:
-                   printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-                          a4000 ? 4000 : 1200);
-                   break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-               case 1:
-                   printk("ide%d: IDE doubler\n", index);
-                   break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-           }
+
+           idx[i] = index;
        } else
            release_mem_region(res_start, res_n);
     }
+
+    ide_device_add(idx);
+
+    return 0;
 }
+
+module_init(gayle_init);
index a4245d13f11b83d2dced3d1f82d33f0caa6c34e7..8da5031a6d05d7a7848033152bcbd57d34fe4f61 100644 (file)
@@ -307,8 +307,7 @@ int probe_ht6560b = 0;
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 
-/* Can be called directly from ide.c. */
-int __init ht6560b_init(void)
+static int __init ht6560b_init(void)
 {
        ide_hwif_t *hwif, *mate;
        static u8 idx[4] = { 0, 1, 0xff, 0xff };
@@ -369,9 +368,7 @@ release_region:
        return -ENODEV;
 }
 
-#ifdef MODULE
 module_init(ht6560b_init);
-#endif
 
 MODULE_AUTHOR("See Local File");
 MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
index 03715c05866408b1d14773e365d265d74b7194c4..f4ea15b32969322d6e29dbd27a87f33dedff35c1 100644 (file)
@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
     hw.irq = irq;
     hw.chipset = ide_pci;
     hw.dev = &handle->dev;
-    return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL);
+    return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
 }
 
 /*======================================================================
index 7bb79f53dac804e708ef6a49e110804d903f993d..69a0fb0e564f9ee5c22af0c6c30cbcaf4f634a28 100644 (file)
@@ -28,39 +28,27 @@ static struct {
        int index;
 } hwif_prop;
 
-static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
-           void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
-           int mmio)
+static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
+                                          void __iomem *base,
+                                          void __iomem *ctrl,
+                                          struct pata_platform_info *pdata,
+                                          int irq)
 {
        unsigned long port = (unsigned long)base;
-       ide_hwif_t *hwif = ide_find_port(port);
        int i;
 
-       if (hwif == NULL)
-               goto out;
-
-       hwif->io_ports[IDE_DATA_OFFSET] = port;
+       hw->io_ports[IDE_DATA_OFFSET] = port;
 
        port += (1 << pdata->ioport_shift);
        for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
             i++, port += (1 << pdata->ioport_shift))
-               hwif->io_ports[i] = port;
-
-       hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+               hw->io_ports[i] = port;
 
-       hwif->irq = irq;
+       hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
 
-       hwif->chipset = ide_generic;
+       hw->irq = irq;
 
-       if (mmio) {
-               hwif->mmio = 1;
-               default_hwif_mmiops(hwif);
-       }
-
-       hwif_prop.hwif = hwif;
-       hwif_prop.index = hwif->index;
-out:
-       return hwif;
+       hw->chipset = ide_generic;
 }
 
 static int __devinit plat_ide_probe(struct platform_device *pdev)
@@ -71,6 +59,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
        int ret = 0;
        int mmio = 0;
+       hw_regs_t hw;
 
        pdata = pdev->dev.platform_data;
 
@@ -106,15 +95,27 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
                        res_alt->start, res_alt->end - res_alt->start + 1);
        }
 
-       hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
-                hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
-
+       hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
        if (!hwif) {
                ret = -ENODEV;
                goto out;
        }
-       hwif->gendev.parent = &pdev->dev;
-       hwif->noprobe = 0;
+
+       memset(&hw, 0, sizeof(hw));
+       plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
+                            hwif_prop.plat_ide_alt_mapbase,
+                            pdata, res_irq->start);
+       hw.dev = &pdev->dev;
+
+       ide_init_port_hw(hwif, &hw);
+
+       if (mmio) {
+               hwif->mmio = 1;
+               default_hwif_mmiops(hwif);
+       }
+
+       hwif_prop.hwif = hwif;
+       hwif_prop.index = hwif->index;
 
        idx[0] = hwif->index;
 
index 5c6aa77c237087d87e14837f6d5239716bb3dc24..782d4c76c0e578f607fdf20635838d8191db7b1d 100644 (file)
@@ -77,15 +77,17 @@ int macide_ack_intr(ide_hwif_t* hwif)
        return 0;
 }
 
+static const char *mac_ide_name[] =
+       { "Quadra", "Powerbook", "Powerbook Baboon" };
+
 /*
  * Probe for a Macintosh IDE interface
  */
 
-void __init macide_init(void)
+static int __init macide_init(void)
 {
        hw_regs_t hw;
        ide_hwif_t *hwif;
-       int index = -1;
 
        switch (macintosh_config->ide_type) {
        case MAC_IDE_QUADRA:
@@ -93,48 +95,50 @@ void __init macide_init(void)
                                0, 0, macide_ack_intr,
 //                             quadra_ide_iops,
                                IRQ_NUBUS_F);
-               index = ide_register_hw(&hw, NULL, 1, &hwif);
                break;
        case MAC_IDE_PB:
                ide_setup_ports(&hw, IDE_BASE, macide_offsets,
                                0, 0, macide_ack_intr,
 //                             macide_pb_iops,
                                IRQ_NUBUS_C);
-               index = ide_register_hw(&hw, NULL, 1, &hwif);
                break;
        case MAC_IDE_BABOON:
                ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
                                0, 0, NULL,
 //                             macide_baboon_iops,
                                IRQ_BABOON_1);
-               index = ide_register_hw(&hw, NULL, 1, &hwif);
-               if (index == -1) break;
-               if (macintosh_config->ident == MAC_MODEL_PB190) {
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
+                        mac_ide_name[macintosh_config->ide_type - 1]);
 
+       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif) {
+               u8 index = hwif->index;
+               u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+               ide_init_port_data(hwif, index);
+               ide_init_port_hw(hwif, &hw);
+
+               if (macintosh_config->ide_type == MAC_IDE_BABOON &&
+                   macintosh_config->ident == MAC_MODEL_PB190) {
                        /* Fix breakage in ide-disk.c: drive capacity   */
                        /* is not initialized for drives without a      */
                        /* hardware ID, and we can't get that without   */
                        /* probing the drive which freezes a 190.       */
-
-                       ide_drive_t *drive = &ide_hwifs[index].drives[0];
+                       ide_drive_t *drive = &hwif->drives[0];
                        drive->capacity64 = drive->cyl*drive->head*drive->sect;
-
                }
-               break;
-
-       default:
-           return;
-       }
 
-        if (index != -1) {
                hwif->mmio = 1;
-               if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-                       printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
-               else if (macintosh_config->ide_type == MAC_IDE_PB)
-                       printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
-               else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-                       printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-               else
-                       printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+
+               ide_device_add(idx);
        }
+
+       return 0;
 }
+
+module_init(macide_init);
index 6ea46a6723e2c3975758a88bba8c304d96390bb6..f5329730df99d17bbd3abe5b2f05485c8e4d3db6 100644 (file)
@@ -111,15 +111,17 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
  *  Probe for Q40 IDE interfaces
  */
 
-void __init q40ide_init(void)
+static int __init q40ide_init(void)
 {
     int i;
     ide_hwif_t *hwif;
-    int index;
     const char *name;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
     if (!MACH_IS_Q40)
-      return ;
+      return -ENODEV;
+
+    printk(KERN_INFO "ide: Q40 IDE controller\n");
 
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
        hw_regs_t hw;
@@ -141,10 +143,20 @@ void __init q40ide_init(void)
                        0, NULL,
 //                     m68kide_iops,
                        q40ide_default_irq(pcide_bases[i]));
-       index = ide_register_hw(&hw, NULL, 1, &hwif);
-       // **FIXME**
-       if (index != -1)
+
+       hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif) {
+               ide_init_port_data(hwif, hwif->index);
+               ide_init_port_hw(hwif, &hw);
                hwif->mmio = 1;
+
+               idx[i] = hwif->index;
+       }
     }
+
+    ide_device_add(idx);
+
+    return 0;
 }
 
+module_init(q40ide_init);
index 912e73853faa1b3fa2082031cd6687e95be94dde..2bac4c1a65324685a9cdd2b85ca318ef40b7b6fe 100644 (file)
@@ -478,8 +478,7 @@ int probe_qd65xx = 0;
 module_param_named(probe, probe_qd65xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init qd65xx_init(void)
+static int __init qd65xx_init(void)
 {
        if (probe_qd65xx == 0)
                return -ENODEV;
@@ -492,9 +491,7 @@ int __init qd65xx_init(void)
        return 0;
 }
 
-#ifdef MODULE
 module_init(qd65xx_init);
-#endif
 
 MODULE_AUTHOR("Samuel Thibault");
 MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
index 79577b916874d085fa96dbf2c2036301e129ef11..a1ae1ae6699d0ecc5e04878a0210304291afdb9d 100644 (file)
@@ -169,8 +169,7 @@ int probe_umc8672 = 0;
 module_param_named(probe, probe_umc8672, bool, 0);
 MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
 
-/* Can be called directly from ide.c. */
-int __init umc8672_init(void)
+static int __init umc8672_init(void)
 {
        if (probe_umc8672 == 0)
                goto out;
@@ -181,9 +180,7 @@ out:
        return -ENODEV;;
 }
 
-#ifdef MODULE
 module_init(umc8672_init);
-#endif
 
 MODULE_AUTHOR("Wolfram Podien");
 MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
index a4ce3ba15d61a0164fc3ee1535060e1121186b8e..2d3e5115b83404db30e4d1a2fcd684fceaadd198 100644 (file)
@@ -198,8 +198,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
                break;
 #endif
-       default:
-               return;
        }
 
        au_writel(mem_sttime,MEM_STTIME2);
@@ -397,26 +395,10 @@ static int auide_dma_test_irq(ide_drive_t *drive)
        return 0;
 }
 
-static void auide_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static int auide_dma_on(ide_drive_t *drive)
-{
-       drive->using_dma = 1;
-
-       return 0;
-}
-
-static void auide_dma_host_off(ide_drive_t *drive)
+static void auide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void auide_dma_off_quietly(ide_drive_t *drive)
-{
-       drive->using_dma = 0;
-}
-
 static void auide_dma_lost_irq(ide_drive_t *drive)
 {
        printk(KERN_ERR "%s: IRQ lost\n", drive->name);
@@ -643,12 +625,13 @@ static int au_ide_probe(struct device *dev)
        /* FIXME:  This might possibly break PCMCIA IDE devices */
 
        hwif                            = &ide_hwifs[pdev->id];
-       hwif->irq                       = ahwif->irq;
-       hwif->chipset                   = ide_au1xxx;
 
        memset(&hw, 0, sizeof(hw));
        auide_setup_ports(&hw, ahwif);
-       memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
+       hw.irq = ahwif->irq;
+       hw.chipset = ide_au1xxx;
+
+       ide_init_port_hw(hwif, &hw);
 
        hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -662,7 +645,6 @@ static int au_ide_probe(struct device *dev)
        hwif->pio_mask = ATA_PIO4;
        hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
 
-       hwif->noprobe = 0;
        hwif->drives[0].unmask          = 1;
        hwif->drives[1].unmask          = 1;
 
@@ -684,29 +666,25 @@ static int au_ide_probe(struct device *dev)
        hwif->set_dma_mode              = &auide_set_dma_mode;
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       hwif->dma_off_quietly           = &auide_dma_off_quietly;
        hwif->dma_timeout               = &auide_dma_timeout;
 
        hwif->mdma_filter               = &auide_mdma_filter;
 
+       hwif->dma_host_set              = &auide_dma_host_set;
        hwif->dma_exec_cmd              = &auide_dma_exec_cmd;
        hwif->dma_start                 = &auide_dma_start;
        hwif->ide_dma_end               = &auide_dma_end;
        hwif->dma_setup                 = &auide_dma_setup;
        hwif->ide_dma_test_irq          = &auide_dma_test_irq;
-       hwif->dma_host_off              = &auide_dma_host_off;
-       hwif->dma_host_on               = &auide_dma_host_on;
        hwif->dma_lost_irq              = &auide_dma_lost_irq;
-       hwif->ide_dma_on                = &auide_dma_on;
-#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
+#endif
        hwif->channel                   = 0;
-       hwif->hold                      = 1;
        hwif->select_data               = 0;    /* no chipset-specific code */
        hwif->config_data               = 0;    /* no chipset-specific code */
 
        hwif->drives[0].autotune        = 1;    /* 1=autotune, 2=noautotune, 0=default */
        hwif->drives[1].autotune        = 1;
-#endif
+
        hwif->drives[0].no_io_32bit     = 1;
        hwif->drives[1].no_io_32bit     = 1;
 
index 521edd41b572b0e9c00a82d218c9ec91acb72046..8b3959dfa2b7b692c806fd979890900065dbd20a 100644 (file)
@@ -117,6 +117,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
        default_hwif_mmiops(hwif);
        /* Prevent resource map manipulation.  */
        hwif->mmio = 1;
+       hwif->chipset = ide_generic;
        hwif->noprobe = 0;
 
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
index 95d1ea8f1f1403d2efd0a14c8bc8569a6a5e51fa..94803253e8af0268d1878833e7600d37035ace3a 100644 (file)
@@ -36,4 +36,8 @@ obj-$(CONFIG_BLK_DEV_VIA82CXXX)               += via82cxxx.o
 # Must appear at the end of the block
 obj-$(CONFIG_BLK_DEV_GENERIC)          += generic.o
 
+ifeq ($(CONFIG_BLK_DEV_CMD640), m)
+       obj-m += cmd640.o
+endif
+
 EXTRA_CFLAGS   := -Idrivers/ide
index 44268504ae433ce8a4065ed048eca4937198966d..7f4d1857d5559f73f5e3ceb6c7e975c79e4b28b6 100644 (file)
@@ -202,6 +202,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .host_flags     = IDE_HFLAG_SERIALIZE |
                                  IDE_HFLAG_NO_ATAPI_DMA |
+                                 IDE_HFLAG_ABUSE_SET_DMA_MODE |
                                  IDE_HFLAG_OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
@@ -211,6 +212,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
                .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
+                                 IDE_HFLAG_ABUSE_SET_DMA_MODE |
                                  IDE_HFLAG_OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
@@ -220,7 +222,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA,
+               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
+                                 IDE_HFLAG_ABUSE_SET_DMA_MODE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA4,
@@ -228,7 +231,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
                .name           = "AEC6280",
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
+                                 IDE_HFLAG_ABUSE_SET_DMA_MODE |
+                                 IDE_HFLAG_OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -237,7 +242,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
+                                 IDE_HFLAG_ABUSE_SET_DMA_MODE |
+                                 IDE_HFLAG_OFF_BOARD,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
index ce293936af4b4fc808a9779ae7e09c6cc8424b67..49aa82e412b6ed1da3fb40b3d2291501a92b232a 100644 (file)
@@ -402,9 +402,6 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
        u8 tmpbyte              = 0x00;
        int m5229_udma          = (hwif->channel) ? 0x57 : 0x56;
 
-       if (speed < XFER_PIO_0)
-               return;
-
        if (speed == XFER_UDMA_6)
                speed1 = 0x47;
 
index 8d4125ec252c102fd982158aeac8dd6e5cb4b4cc..cee51fdafcf6f5353369b9601b99b7c812fff31d 100644 (file)
@@ -266,6 +266,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
 #define IDE_HFLAGS_AMD \
        (IDE_HFLAG_PIO_NO_BLACKLIST | \
         IDE_HFLAG_PIO_NO_DOWNGRADE | \
+        IDE_HFLAG_ABUSE_SET_DMA_MODE | \
         IDE_HFLAG_POST_SET_MODE | \
         IDE_HFLAG_IO_32BIT | \
         IDE_HFLAG_UNMASK_IRQS | \
index ef8e0164ef7a019e560608741d3b880ed6a12452..491871984aaa71213e2820706c8201fea9c2faf2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/atiixp.c     Version 0.03    Aug 3 2007
+ *  linux/drivers/ide/pci/atiixp.c     Version 0.05    Nov 9 2007
  *
  *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
  *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
@@ -43,47 +43,8 @@ static atiixp_ide_timing mdma_timing[] = {
        { 0x02, 0x00 },
 };
 
-static int save_mdma_mode[4];
-
 static DEFINE_SPINLOCK(atiixp_lock);
 
-static void atiixp_dma_host_on(ide_drive_t *drive)
-{
-       struct pci_dev *dev = drive->hwif->pci_dev;
-       unsigned long flags;
-       u16 tmp16;
-
-       spin_lock_irqsave(&atiixp_lock, flags);
-
-       pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
-       if (save_mdma_mode[drive->dn])
-               tmp16 &= ~(1 << drive->dn);
-       else
-               tmp16 |= (1 << drive->dn);
-       pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
-
-       spin_unlock_irqrestore(&atiixp_lock, flags);
-
-       ide_dma_host_on(drive);
-}
-
-static void atiixp_dma_host_off(ide_drive_t *drive)
-{
-       struct pci_dev *dev = drive->hwif->pci_dev;
-       unsigned long flags;
-       u16 tmp16;
-
-       spin_lock_irqsave(&atiixp_lock, flags);
-
-       pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
-       tmp16 &= ~(1 << drive->dn);
-       pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
-
-       spin_unlock_irqrestore(&atiixp_lock, flags);
-
-       ide_dma_host_off(drive);
-}
-
 /**
  *     atiixp_set_pio_mode     -       set host controller for PIO mode
  *     @drive: drive
@@ -132,29 +93,33 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
        int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
        u32 tmp32;
        u16 tmp16;
-
-       if (speed < XFER_MW_DMA_0)
-               return;
+       u16 udma_ctl = 0;
 
        spin_lock_irqsave(&atiixp_lock, flags);
 
-       save_mdma_mode[drive->dn] = 0;
+       pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
+
        if (speed >= XFER_UDMA_0) {
                pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
                tmp16 &= ~(0x07 << (drive->dn * 4));
                tmp16 |= ((speed & 0x07) << (drive->dn * 4));
                pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
-       } else {
-               if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
-                       save_mdma_mode[drive->dn] = speed;
-                       pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
-                       tmp32 &= ~(0xff << timing_shift);
-                       tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
-                               (mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
-                       pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
-               }
+
+               udma_ctl |= (1 << drive->dn);
+       } else if (speed >= XFER_MW_DMA_0) {
+               u8 i = speed & 0x03;
+
+               pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+               tmp32 &= ~(0xff << timing_shift);
+               tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
+                        (mdma_timing[i].command_width << (timing_shift + 4));
+               pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+
+               udma_ctl &= ~(1 << drive->dn);
        }
 
+       pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
+
        spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
@@ -184,9 +149,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
                hwif->cbl = ATA_CBL_PATA80;
        else
                hwif->cbl = ATA_CBL_PATA40;
-
-       hwif->dma_host_on = &atiixp_dma_host_on;
-       hwif->dma_host_off = &atiixp_dma_host_off;
 }
 
 static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
index 4aa48104e0c1c5cb3e7d787efa2983ccd4e4899f..da3565e0071f417628d96fa806daa29c9876cd4a 100644 (file)
@@ -706,9 +706,9 @@ static int pci_conf2(void)
 }
 
 /*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ * Probe for a cmd640 chipset, and initialize it if found.
  */
-int __init ide_probe_for_cmd640x (void)
+static int __init cmd640x_init(void)
 {
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        int second_port_toggled = 0;
@@ -717,6 +717,7 @@ int __init ide_probe_for_cmd640x (void)
        const char *bus_type, *port2;
        unsigned int index;
        u8 b, cfr;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        if (cmd640_vlb && probe_for_cmd640_vlb()) {
                bus_type = "VLB";
@@ -769,6 +770,8 @@ int __init ide_probe_for_cmd640x (void)
        cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
+       idx[0] = cmd_hwif0->index;
+
        /*
         * Ensure compatibility by always using the slowest timings
         * for access to the drive's command register block,
@@ -826,6 +829,8 @@ int __init ide_probe_for_cmd640x (void)
                cmd_hwif1->pio_mask = ATA_PIO5;
                cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+               idx[1] = cmd_hwif1->index;
        }
        printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
                cmd_hwif0->serialized ? "" : "not ", port2);
@@ -872,6 +877,13 @@ int __init ide_probe_for_cmd640x (void)
 #ifdef CMD640_DUMP_REGS
        cmd640_dump_regs();
 #endif
+
+       ide_device_add(idx);
+
        return 1;
 }
 
+module_param_named(probe_vlb, cmd640_vlb, bool, 0);
+MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
+
+module_init(cmd640x_init);
index bc553337b1be38548d155ed6ea4db0fbffa417e0..cd4eb9def1515719d2d3c998a67438a8aefa9bbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cmd64x.c              Version 1.52    Dec 24, 2007
+ * linux/drivers/ide/pci/cmd64x.c              Version 1.53    Dec 24, 2007
  *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Due to massive hardware bugs, UltraDMA is only supported
@@ -22,8 +22,6 @@
 
 #include <asm/io.h>
 
-#define DISPLAY_CMD64X_TIMINGS
-
 #define CMD_DEBUG 0
 
 #if CMD_DEBUG
  */
 #define CFR            0x50
 #define   CFR_INTR_CH0         0x04
-#define CNTRL          0x51
-#define   CNTRL_ENA_1ST        0x04
-#define   CNTRL_ENA_2ND        0x08
-#define   CNTRL_DIS_RA0        0x40
-#define   CNTRL_DIS_RA1        0x80
 
 #define        CMDTIM          0x52
 #define        ARTTIM0         0x53
 #define MRDMODE                0x71
 #define   MRDMODE_INTR_CH0     0x04
 #define   MRDMODE_INTR_CH1     0x08
-#define   MRDMODE_BLK_CH0      0x10
-#define   MRDMODE_BLK_CH1      0x20
-#define BMIDESR0       0x72
 #define UDIDETCR0      0x73
 #define DTPR0          0x74
 #define BMIDECR1       0x78
 #define BMIDECSR       0x79
-#define BMIDESR1       0x7A
 #define UDIDETCR1      0x7B
 #define DTPR1          0x7C
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static u8 cmd64x_proc = 0;
-
-#define CMD_MAX_DEVS           5
-
-static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
-static int n_cmd_devs;
-
-static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
-{
-       char *p = buf;
-       u8 reg72 = 0, reg73 = 0;                        /* primary */
-       u8 reg7a = 0, reg7b = 0;                        /* secondary */
-       u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0;  /* extra */
-
-       p += sprintf(p, "\nController: %d\n", index);
-       p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
-
-       (void) pci_read_config_byte(dev, CFR,       &reg50);
-       (void) pci_read_config_byte(dev, CNTRL,     &reg51);
-       (void) pci_read_config_byte(dev, ARTTIM23,  &reg57);
-       (void) pci_read_config_byte(dev, MRDMODE,   &reg71);
-       (void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
-       (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
-       (void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
-       (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
-
-       /* PCI0643/6 originally didn't have the primary channel enable bit */
-       if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
-           (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3))
-               reg51 |= CNTRL_ENA_1ST;
-
-       p += sprintf(p, "---------------- Primary Channel "
-                       "---------------- Secondary Channel ------------\n");
-       p += sprintf(p, "                 %s                         %s\n",
-                (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
-                (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
-       p += sprintf(p, "---------------- drive0 --------- drive1 "
-                       "-------- drive0 --------- drive1 ------\n");
-       p += sprintf(p, "DMA enabled:     %s              %s"
-                       "             %s              %s\n",
-               (reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
-               (reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
-       p += sprintf(p, "UltraDMA mode:   %s (%c)          %s (%c)",
-               ( reg73 & 0x01) ? " on" : "off",
-               ((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
-               ((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
-               ((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
-               ((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
-               ( reg73 & 0x02) ? " on" : "off",
-               ((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
-               ((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
-               ((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
-               ((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
-       p += sprintf(p, "         %s (%c)          %s (%c)\n",
-               ( reg7b & 0x01) ? " on" : "off",
-               ((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
-               ((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
-               ((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
-               ((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
-               ( reg7b & 0x02) ? " on" : "off",
-               ((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
-               ((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
-               ((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
-               ((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
-       p += sprintf(p, "Interrupt:       %s, %s                 %s, %s\n",
-               (reg71 & MRDMODE_BLK_CH0  ) ? "blocked" : "enabled",
-               (reg50 & CFR_INTR_CH0     ) ? "pending" : "clear  ",
-               (reg71 & MRDMODE_BLK_CH1  ) ? "blocked" : "enabled",
-               (reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear  ");
-
-       return (char *)p;
-}
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-       char *p = buffer;
-       int i;
-
-       for (i = 0; i < n_cmd_devs; i++) {
-               struct pci_dev *dev     = cmd_devs[i];
-               p = print_cmd64x_get_info(p, dev, i);
-       }
-       return p-buffer;        /* => must be less than 4k! */
-}
-
-#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
-
 static u8 quantize_timing(int timing, int quant)
 {
        return (timing + quant - 1) / quant;
@@ -322,8 +220,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
        case XFER_MW_DMA_0:
                program_cycle_times(drive, 480, 215);
                break;
-       default:
-               return;
        }
 
        if (speed >= XFER_SW_DMA_0)
@@ -333,14 +229,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
 static int cmd648_ide_dma_end (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       unsigned long base      = hwif->dma_base - (hwif->channel * 8);
        int err                 = __ide_dma_end(drive);
        u8  irq_mask            = hwif->channel ? MRDMODE_INTR_CH1 :
                                                  MRDMODE_INTR_CH0;
-       u8  mrdmode             = inb(hwif->dma_master + 0x01);
+       u8  mrdmode             = inb(base + 1);
 
        /* clear the interrupt bit */
        outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
-            hwif->dma_master + 0x01);
+            base + 1);
 
        return err;
 }
@@ -365,10 +262,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
 static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       unsigned long base      = hwif->dma_base - (hwif->channel * 8);
        u8 irq_mask             = hwif->channel ? MRDMODE_INTR_CH1 :
                                                  MRDMODE_INTR_CH0;
        u8 dma_stat             = inb(hwif->dma_status);
-       u8 mrdmode              = inb(hwif->dma_master + 0x01);
+       u8 mrdmode              = inb(base + 1);
 
 #ifdef DEBUG
        printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
@@ -472,16 +370,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
        mrdmode &= ~0x30;
        (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-
-       cmd_devs[n_cmd_devs++] = dev;
-
-       if (!cmd64x_proc) {
-               cmd64x_proc = 1;
-               ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
-       }
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
-
        return 0;
 }
 
index 0466462fd21b9a7ce82b9ab6789d0aa7648ff273..6ec00b8d7ec1b1e10f51a7e023b4a9ed6ffed1b4 100644 (file)
@@ -71,7 +71,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
        ide_hwif_t *hwif = HWIF(drive);
        struct pci_dev *pdev = hwif->pci_dev;
        int controller = drive->dn > 1 ? 1 : 0;
-       u8 reg;
 
        /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
 
@@ -91,11 +90,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
        pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
                (cs5520_pio_clocks[pio].recovery << 4) |
                (cs5520_pio_clocks[pio].assert));
-               
-       /* Set the DMA enable/disable flag */
-       reg = inb(hwif->dma_base + 0x02 + 8*controller);
-       reg |= 1<<((drive->dn&1)+5);
-       outb(reg, hwif->dma_base + 0x02 + 8*controller);
 }
 
 static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
@@ -109,13 +103,14 @@ static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
  *     We wrap the DMA activate to set the vdma flag. This is needed
  *     so that the IDE DMA layer issues PIO not DMA commands over the
  *     DMA channel
+ *
+ *     ATAPI is harder so disable it for now using IDE_HFLAG_NO_ATAPI_DMA
  */
-static int cs5520_dma_on(ide_drive_t *drive)
+
+static void cs5520_dma_host_set(ide_drive_t *drive, int on)
 {
-       /* ATAPI is harder so leave it for now */
-       drive->vdma = 1;
-       return 0;
+       drive->vdma = on;
+       ide_dma_host_set(drive, on);
 }
 
 static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
@@ -126,7 +121,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
        if (hwif->dma_base == 0)
                return;
 
-       hwif->ide_dma_on = &cs5520_dma_on;
+       hwif->dma_host_set = &cs5520_dma_host_set;
 }
 
 #define DECLARE_CS_DEV(name_str)                               \
@@ -137,6 +132,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
                                  IDE_HFLAG_CS5520 |            \
                                  IDE_HFLAG_VDMA |              \
                                  IDE_HFLAG_NO_ATAPI_DMA |      \
+                                 IDE_HFLAG_ABUSE_SET_DMA_MODE |\
                                  IDE_HFLAG_BOOTABLE,           \
                .pio_mask       = ATA_PIO4,                     \
        }
index 547690395eee6e3b07bf0c597843ab3a1b0fc106..df5966b334600f66bdfd528d246831dec68bebe6 100644 (file)
@@ -116,8 +116,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
                case XFER_MW_DMA_0:     timings = 0x00077771; break;
                case XFER_MW_DMA_1:     timings = 0x00012121; break;
                case XFER_MW_DMA_2:     timings = 0x00002020; break;
-               default:
-                       return;
        }
        basereg = CS5530_BASEREG(drive->hwif);
        reg = inl(basereg + 4);                 /* get drive0 config register */
index ddcbeba671e19ca749c3dc3f74aefbf898944473..50b3d7791f55110c00d132202b335bb80d1cb6e8 100644 (file)
@@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = {
        .name           = "CS5535",
        .init_hwif      = init_hwif_cs5535,
        .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
-                         IDE_HFLAG_BOOTABLE,
+                         IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE,
        .pio_mask       = ATA_PIO4,
        .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA4,
index 1cd4e9cb0521d0532bc24c21c21506d348b3df9c..3ec4c659a37d2593a1aa7e528217dab371f423e6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cy82c693.c            Version 0.42    Oct 23, 2007
+ * linux/drivers/ide/pci/cy82c693.c            Version 0.44    Nov 8, 2007
  *
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
  *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
@@ -176,17 +176,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
  * set DMA mode a specific channel for CY82C693
  */
 
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
-       u8 index = 0, data = 0;
+       ide_hwif_t *hwif = drive->hwif;
+       u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
 
-       if (mode>2)     /* make sure we set a valid mode */
-               mode = 2;
-                          
-       if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-               mode = drive->id->tDMA;
-       
-       index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+       index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
 
 #if CY82C693_DEBUG_LOGS
        /* for debug let's show the previous values */
@@ -199,7 +194,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
                (data&0x3), ((data>>2)&1));
 #endif /* CY82C693_DEBUG_LOGS */
 
-       data = (u8)mode|(u8)(single<<2);
+       data = (mode & 3) | (single << 2);
 
        outb(index, CY82_INDEX_PORT);
        outb(data, CY82_DATA_PORT);
@@ -207,7 +202,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 #if CY82C693_DEBUG_INFO
        printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
                drive->name, HWIF(drive)->channel, drive->select.b.unit,
-               mode, single);
+               mode & 3, single);
 #endif /* CY82C693_DEBUG_INFO */
 
        /* 
@@ -230,39 +225,6 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 #endif /* CY82C693_DEBUG_INFO */
 }
 
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_ide_dma_on (ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-       printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-       if (id != NULL) {               
-               /* Enable DMA on any drive that has DMA
-                * (multi or single) enabled
-                */
-               if (id->field_valid & 2) {      /* regular DMA */
-                       int mmode, smode;
-
-                       mmode = id->dma_mword & (id->dma_mword >> 8);
-                       smode = id->dma_1word & (id->dma_1word >> 8);
-                                             
-                       if (mmode != 0) {
-                               /* enable multi */
-                               cy82c693_dma_enable(drive, (mmode >> 1), 0);
-                       } else if (smode != 0) {
-                               /* enable single */
-                               cy82c693_dma_enable(drive, (smode >> 1), 1);
-                       }
-               }
-       }
-        return __ide_dma_on(drive);
-}
-
 static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = HWIF(drive);
@@ -429,11 +391,7 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
 static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
 {
        hwif->set_pio_mode = &cy82c693_set_pio_mode;
-
-       if (hwif->dma_base == 0)
-               return;
-
-       hwif->ide_dma_on = &cy82c693_ide_dma_on;
+       hwif->set_dma_mode = &cy82c693_set_dma_mode;
 }
 
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
@@ -454,11 +412,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
        .init_iops      = init_iops_cy82c693,
        .init_hwif      = init_hwif_cy82c693,
        .chipset        = ide_cy82c693,
-       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 |
                          IDE_HFLAG_BOOTABLE,
        .pio_mask       = ATA_PIO4,
-       .swdma_mask     = ATA_SWDMA2_ONLY,
-       .mwdma_mask     = ATA_MWDMA2_ONLY,
+       .swdma_mask     = ATA_SWDMA2,
+       .mwdma_mask     = ATA_MWDMA2,
 };
 
 static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 83829081640a6f84727f18260a169477e8d3d257..26aa492071bb5fddb63ca8b3c3822637480060ef 100644 (file)
@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
        hw.irq = dev->irq;
        hw.chipset = ide_pci;           /* this enables IRQ sharing */
 
-       rc = ide_register_hw(&hw, &ide_undecoded_slave, 0, &hwif);
+       rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
        if (rc < 0) {
                printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
                pci_disable_device(dev);
index ae6307fae4f9311b35ba24b7727e5c21b05c6b54..dfba0d13fcd39f4f4ebc96df5a874d798fc5b65d 100644 (file)
@@ -129,14 +129,18 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
        hwif->set_dma_mode = &hpt34x_set_mode;
 }
 
+#define IDE_HFLAGS_HPT34X \
+       (IDE_HFLAG_NO_ATAPI_DMA | \
+        IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+        IDE_HFLAG_NO_AUTODMA)
+
 static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
        { /* 0 */
                .name           = "HPT343",
                .init_chipset   = init_chipset_hpt34x,
                .init_hwif      = init_hwif_hpt34x,
                .extra          = 16,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_NO_AUTODMA,
+               .host_flags     = IDE_HFLAGS_HPT34X,
                .pio_mask       = ATA_PIO5,
        },
        { /* 1 */
@@ -144,9 +148,7 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_hpt34x,
                .init_hwif      = init_hwif_hpt34x,
                .extra          = 16,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_NO_AUTODMA |
-                                 IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD,
                .pio_mask       = ATA_PIO5,
 #ifdef CONFIG_HPT34X_AUTODMA
                .swdma_mask     = ATA_SWDMA2,
index 9fce25bdec8acc192ec2e4108098da8dfbe8683a..12685939a813f61f0e30521d2b871f2dd9fb9b1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c              Version 1.22    Dec 4, 2007
+ * linux/drivers/ide/pci/hpt366.c              Version 1.30    Dec 12, 2007
  *
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
@@ -88,7 +88,7 @@
  * - rename all the register related variables consistently
  * - move all the interrupt twiddling code from the speedproc handlers into
  *   init_hwif_hpt366(), also grouping all the DMA related code together there
- * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
  *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
  *   when setting an UltraDMA mode
  * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
@@ -458,6 +458,13 @@ enum ata_clock {
        NUM_ATA_CLOCKS
 };
 
+struct hpt_timings {
+       u32 pio_mask;
+       u32 dma_mask;
+       u32 ultra_mask;
+       u32 *clock_table[NUM_ATA_CLOCKS];
+};
+
 /*
  *     Hold all the HighPoint chip information in one place.
  */
@@ -468,7 +475,8 @@ struct hpt_info {
        u8 udma_mask;           /* Allowed UltraDMA modes mask. */
        u8 dpll_clk;            /* DPLL clock in MHz */
        u8 pci_clk;             /* PCI  clock in MHz */
-       u32 **settings;         /* Chipset settings table */
+       struct hpt_timings *timings; /* Chipset timing data */
+       u8 clock;               /* ATA clock selected */
 };
 
 /* Supported HighPoint chips */
@@ -486,20 +494,30 @@ enum {
        HPT371N
 };
 
-static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
-       twenty_five_base_hpt36x,
-       thirty_three_base_hpt36x,
-       forty_base_hpt36x,
-       NULL,
-       NULL
+static struct hpt_timings hpt36x_timings = {
+       .pio_mask       = 0xc1f8ffff,
+       .dma_mask       = 0x303800ff,
+       .ultra_mask     = 0x30070000,
+       .clock_table    = {
+               [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
+               [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
+               [ATA_CLOCK_40MHZ] = forty_base_hpt36x,
+               [ATA_CLOCK_50MHZ] = NULL,
+               [ATA_CLOCK_66MHZ] = NULL
+       }
 };
 
-static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
-       NULL,
-       thirty_three_base_hpt37x,
-       NULL,
-       fifty_base_hpt37x,
-       sixty_six_base_hpt37x
+static struct hpt_timings hpt37x_timings = {
+       .pio_mask       = 0xcfc3ffff,
+       .dma_mask       = 0x31c001ff,
+       .ultra_mask     = 0x303c0000,
+       .clock_table    = {
+               [ATA_CLOCK_25MHZ] = NULL,
+               [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
+               [ATA_CLOCK_40MHZ] = NULL,
+               [ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
+               [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
+       }
 };
 
 static const struct hpt_info hpt36x __devinitdata = {
@@ -507,7 +525,7 @@ static const struct hpt_info hpt36x __devinitdata = {
        .chip_type      = HPT36x,
        .udma_mask      = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
        .dpll_clk       = 0,    /* no DPLL */
-       .settings       = hpt36x_settings
+       .timings        = &hpt36x_timings
 };
 
 static const struct hpt_info hpt370 __devinitdata = {
@@ -515,7 +533,7 @@ static const struct hpt_info hpt370 __devinitdata = {
        .chip_type      = HPT370,
        .udma_mask      = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
        .dpll_clk       = 48,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt370a __devinitdata = {
@@ -523,7 +541,7 @@ static const struct hpt_info hpt370a __devinitdata = {
        .chip_type      = HPT370A,
        .udma_mask      = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
        .dpll_clk       = 48,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt374 __devinitdata = {
@@ -531,7 +549,7 @@ static const struct hpt_info hpt374 __devinitdata = {
        .chip_type      = HPT374,
        .udma_mask      = ATA_UDMA5,
        .dpll_clk       = 48,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt372 __devinitdata = {
@@ -539,7 +557,7 @@ static const struct hpt_info hpt372 __devinitdata = {
        .chip_type      = HPT372,
        .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 55,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt372a __devinitdata = {
@@ -547,7 +565,7 @@ static const struct hpt_info hpt372a __devinitdata = {
        .chip_type      = HPT372A,
        .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 66,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt302 __devinitdata = {
@@ -555,7 +573,7 @@ static const struct hpt_info hpt302 __devinitdata = {
        .chip_type      = HPT302,
        .udma_mask      = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 66,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt371 __devinitdata = {
@@ -563,7 +581,7 @@ static const struct hpt_info hpt371 __devinitdata = {
        .chip_type      = HPT371,
        .udma_mask      = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 66,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt372n __devinitdata = {
@@ -571,7 +589,7 @@ static const struct hpt_info hpt372n __devinitdata = {
        .chip_type      = HPT372N,
        .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 77,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt302n __devinitdata = {
@@ -579,7 +597,7 @@ static const struct hpt_info hpt302n __devinitdata = {
        .chip_type      = HPT302N,
        .udma_mask      = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 77,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static const struct hpt_info hpt371n __devinitdata = {
@@ -587,7 +605,7 @@ static const struct hpt_info hpt371n __devinitdata = {
        .chip_type      = HPT371N,
        .udma_mask      = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
        .dpll_clk       = 77,
-       .settings       = hpt37x_settings
+       .timings        = &hpt37x_timings
 };
 
 static int check_in_drive_list(ide_drive_t *drive, const char **list)
@@ -675,94 +693,50 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
        for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
                if (xfer_speeds[i] == speed)
                        break;
-       /*
-        * NOTE: info->settings only points to the pointer
-        * to the list of the actual register values
-        */
-       return (*info->settings)[i];
+
+       return info->timings->clock_table[info->clock][i];
 }
 
-static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev  *dev    = hwif->pci_dev;
+       struct pci_dev  *dev    = HWIF(drive)->pci_dev;
        struct hpt_info *info   = pci_get_drvdata(dev);
-       u8  itr_addr            = drive->dn ? 0x44 : 0x40;
+       struct hpt_timings *t   = info->timings;
+       u8  itr_addr            = 0x40 + (drive->dn * 4);
        u32 old_itr             = 0;
-       u32 itr_mask, new_itr;
-
-       itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
-                 (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
-
-       new_itr = get_speed_setting(speed, info);
+       u32 new_itr             = get_speed_setting(speed, info);
+       u32 itr_mask            = speed < XFER_MW_DMA_0 ? t->pio_mask :
+                                (speed < XFER_UDMA_0   ? t->dma_mask :
+                                                         t->ultra_mask);
 
+       pci_read_config_dword(dev, itr_addr, &old_itr);
+       new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
        /*
         * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
         * to avoid problems handling I/O errors later
         */
-       pci_read_config_dword(dev, itr_addr, &old_itr);
-       new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
        new_itr &= ~0xc0000000;
 
        pci_write_config_dword(dev, itr_addr, new_itr);
 }
 
-static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev  *dev    = hwif->pci_dev;
-       struct hpt_info *info   = pci_get_drvdata(dev);
-       u8  itr_addr            = 0x40 + (drive->dn * 4);
-       u32 old_itr             = 0;
-       u32 itr_mask, new_itr;
-
-       itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
-                 (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
-
-       new_itr = get_speed_setting(speed, info);
-
-       pci_read_config_dword(dev, itr_addr, &old_itr);
-       new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
-       
-       if (speed < XFER_MW_DMA_0)
-               new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-       pci_write_config_dword(dev, itr_addr, new_itr);
-}
-
-static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct hpt_info *info   = pci_get_drvdata(hwif->pci_dev);
-
-       if (info->chip_type >= HPT370)
-               hpt37x_set_mode(drive, speed);
-       else    /* hpt368: hpt_minimum_revision(dev, 2) */
-               hpt36x_set_mode(drive, speed);
-}
-
 static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
-static int hpt3xx_quirkproc(ide_drive_t *drive)
+static void hpt3xx_quirkproc(ide_drive_t *drive)
 {
        struct hd_driveid *id   = drive->id;
        const  char **list      = quirk_drives;
 
        while (*list)
-               if (strstr(id->model, *list++))
-                       return 1;
-       return 0;
-}
-
-static void hpt3xx_intrproc(ide_drive_t *drive)
-{
-       if (drive->quirk_list)
-               return;
+               if (strstr(id->model, *list++)) {
+                       drive->quirk_list = 1;
+                       return;
+               }
 
-       /* drives in the quirk_list may not like intr setups/cleanups */
-       outb(drive->ctl | 2, IDE_CONTROL_REG);
+       drive->quirk_list = 0;
 }
 
 static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
@@ -914,32 +888,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
 
 static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 {
-       u8 scr2 = inb(hwif->dma_master + 0x7b);
+       unsigned long base = hwif->extra_base;
+       u8 scr2 = inb(base + 0x6b);
 
        if ((scr2 & 0x7f) == mode)
                return;
 
        /* Tristate the bus */
-       outb(0x80, hwif->dma_master + 0x73);
-       outb(0x80, hwif->dma_master + 0x77);
+       outb(0x80, base + 0x63);
+       outb(0x80, base + 0x67);
 
        /* Switch clock and reset channels */
-       outb(mode, hwif->dma_master + 0x7b);
-       outb(0xc0, hwif->dma_master + 0x79);
+       outb(mode, base + 0x6b);
+       outb(0xc0, base + 0x69);
 
        /*
         * Reset the state machines.
         * NOTE: avoid accidentally enabling the disabled channels.
         */
-       outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70);
-       outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74);
+       outb(inb(base + 0x60) | 0x32, base + 0x60);
+       outb(inb(base + 0x64) | 0x32, base + 0x64);
 
        /* Complete reset */
-       outb(0x00, hwif->dma_master + 0x79);
+       outb(0x00, base + 0x69);
 
        /* Reconnect channels to bus */
-       outb(0x00, hwif->dma_master + 0x73);
-       outb(0x00, hwif->dma_master + 0x77);
+       outb(0x00, base + 0x63);
+       outb(0x00, base + 0x67);
 }
 
 /**
@@ -1210,7 +1185,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
         * We also  don't like using  the DPLL because this causes glitches
         * on PRST-/SRST- when the state engine gets reset...
         */
-       if (chip_type >= HPT374 || info->settings[clock] == NULL) {
+       if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
                u16 f_low, delta = pci_clk < 50 ? 2 : 4;
                int adjust;
 
@@ -1226,7 +1201,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
                        clock = ATA_CLOCK_50MHZ;
                }
 
-               if (info->settings[clock] == NULL) {
+               if (info->timings->clock_table[clock] == NULL) {
                        printk(KERN_ERR "%s: unknown bus timing!\n", name);
                        kfree(info);
                        return -EIO;
@@ -1267,15 +1242,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
                printk("%s: using %d MHz PCI clock\n", name, pci_clk);
        }
 
-       /*
-        * Advance the table pointer to a slot which points to the list
-        * of the register values settings matching the clock being used.
-        */
-       info->settings += clock;
-
        /* Store the clock frequencies. */
        info->dpll_clk  = dpll_clk;
        info->pci_clk   = pci_clk;
+       info->clock     = clock;
 
        /* Point to this chip's own instance of the hpt_info structure. */
        pci_set_drvdata(dev, info);
@@ -1320,8 +1290,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 
        hwif->set_pio_mode      = &hpt3xx_set_pio_mode;
        hwif->set_dma_mode      = &hpt3xx_set_mode;
+
        hwif->quirkproc         = &hpt3xx_quirkproc;
-       hwif->intrproc          = &hpt3xx_intrproc;
        hwif->maskproc          = &hpt3xx_maskproc;
        hwif->busproc           = &hpt3xx_busproc;
 
@@ -1494,6 +1464,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
        return 0;
 }
 
+#define IDE_HFLAGS_HPT3XX \
+       (IDE_HFLAG_NO_ATAPI_DMA | \
+        IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+        IDE_HFLAG_OFF_BOARD)
+
 static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
        {       /* 0 */
                .name           = "HPT36x",
@@ -1508,9 +1483,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
                 */
                .enablebits     = {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
                .extra          = 240,
-               .host_flags     = IDE_HFLAG_SINGLE |
-                                 IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
        },{     /* 1 */
@@ -1520,7 +1493,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
                .init_dma       = init_dma_hpt366,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .extra          = 240,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT3XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
        },{     /* 2 */
@@ -1530,7 +1503,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
                .init_dma       = init_dma_hpt366,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .extra          = 240,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT3XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
        },{     /* 3 */
@@ -1540,7 +1513,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
                .init_dma       = init_dma_hpt366,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .extra          = 240,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT3XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
        },{     /* 4 */
@@ -1551,7 +1524,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .udma_mask      = ATA_UDMA5,
                .extra          = 240,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT3XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
        },{     /* 5 */
@@ -1561,7 +1534,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
                .init_dma       = init_dma_hpt366,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .extra          = 240,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_HPT3XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
        }
index 90b52ed37bfc365de2a6041eac56280b5d1ba44e..2a0f45c4f4c4167290db93a4814a2c40facc18c4 100644 (file)
@@ -101,24 +101,11 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
        pci_read_config_byte(dev, 0x54, &reg54);
        pci_read_config_byte(dev, 0x55, &reg55);
 
-       switch(speed) {
-               case XFER_UDMA_6:
-               case XFER_UDMA_4:
-               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
-               case XFER_UDMA_5:
-               case XFER_UDMA_3:
-               case XFER_UDMA_1:       u_speed = 1 << (drive->dn * 4); break;
-               case XFER_UDMA_0:       u_speed = 0 << (drive->dn * 4); break;
-                       break;
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_SW_DMA_2:
-                       break;
-               default:
-                       return;
-       }
-
        if (speed >= XFER_UDMA_0) {
+               u8 udma = speed - XFER_UDMA_0;
+
+               u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
+
                if (!(reg48 & u_flag))
                        pci_write_config_byte(dev, 0x48, reg48 | u_flag);
                if (speed >= XFER_UDMA_5) {
index 99b7d763b6c7a445445e14e038716bbb3d8e9d57..e610a5340fdcb8758a90e4cf1a75c3147ee4487d 100644 (file)
@@ -431,33 +431,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
 }
 
 /**
- *     it821x_fixup    -       post init callback
- *     @hwif: interface
+ *     it821x_quirkproc        -       post init callback
+ *     @drive: drive
  *
- *     This callback is run after the drives have been probed but
+ *     This callback is run after the drive has been probed but
  *     before anything gets attached. It allows drivers to do any
  *     final tuning that is needed, or fixups to work around bugs.
  */
 
-static void __devinit it821x_fixups(ide_hwif_t *hwif)
+static void __devinit it821x_quirkproc(ide_drive_t *drive)
 {
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int i;
+       struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
+       struct hd_driveid *id = drive->id;
+       u16 *idbits = (u16 *)drive->id;
 
-       if(!itdev->smart) {
+       if (!itdev->smart) {
                /*
                 *      If we are in pass through mode then not much
                 *      needs to be done, but we do bother to clear the
                 *      IRQ mask as we may well be in PIO (eg rev 0x10)
                 *      for now and we know unmasking is safe on this chipset.
                 */
-               for (i = 0; i < 2; i++) {
-                       ide_drive_t *drive = &hwif->drives[i];
-                       if(drive->present)
-                               drive->unmask = 1;
-               }
-               return;
-       }
+               drive->unmask = 1;
+       } else {
        /*
         *      Perform fixups on smart mode. We need to "lose" some
         *      capabilities the firmware lacks but does not filter, and
@@ -465,16 +461,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
         *      in RAID mode.
         */
 
-       for(i = 0; i < 2; i++) {
-               ide_drive_t *drive = &hwif->drives[i];
-               struct hd_driveid *id;
-               u16 *idbits;
-
-               if(!drive->present)
-                       continue;
-               id = drive->id;
-               idbits = (u16 *)drive->id;
-
                /* Check for RAID v native */
                if(strstr(id->model, "Integrated Technology Express")) {
                        /* In raid mode the ident block is slightly buggy
@@ -537,6 +523,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
        struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
        u8 conf;
 
+       hwif->quirkproc = &it821x_quirkproc;
+
        if (idev == NULL) {
                printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
                return;
@@ -633,7 +621,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
                .name           = name_str,             \
                .init_chipset   = init_chipset_it821x,  \
                .init_hwif      = init_hwif_it821x,     \
-               .fixup          = it821x_fixups,        \
                .host_flags     = IDE_HFLAG_BOOTABLE,   \
                .pio_mask       = ATA_PIO4,             \
        }
index 2b4f44e45a1a370936300b4c7900f0dbf49f0148..89d2363a1ebdafef4c3a868000e9199588bfe28f 100644 (file)
@@ -146,7 +146,7 @@ static struct udma_timing {
        { 0x1a, 0x01, 0xcb },   /* UDMA mode 6 */
 };
 
-static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
+static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        u8 adj                  = (drive->dn & 1) ? 0x08 : 0x00;
@@ -162,45 +162,18 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
        if (max_dma_rate(hwif->pci_dev) == 4) {
                u8 mode = speed & 0x07;
 
-               switch (speed) {
-                       case XFER_UDMA_6:
-                       case XFER_UDMA_5:
-                       case XFER_UDMA_4:
-                       case XFER_UDMA_3:
-                       case XFER_UDMA_2:
-                       case XFER_UDMA_1:
-                       case XFER_UDMA_0:
-                               set_indexed_reg(hwif, 0x10 + adj,
-                                               udma_timings[mode].reg10);
-                               set_indexed_reg(hwif, 0x11 + adj,
-                                               udma_timings[mode].reg11);
-                               set_indexed_reg(hwif, 0x12 + adj,
-                                               udma_timings[mode].reg12);
-                               break;
-
-                       case XFER_MW_DMA_2:
-                       case XFER_MW_DMA_1:
-                       case XFER_MW_DMA_0:
-                               set_indexed_reg(hwif, 0x0e + adj,
-                                               mwdma_timings[mode].reg0e);
-                               set_indexed_reg(hwif, 0x0f + adj,
-                                               mwdma_timings[mode].reg0f);
-                               break;
-                       case XFER_PIO_4:
-                       case XFER_PIO_3:
-                       case XFER_PIO_2:
-                       case XFER_PIO_1:
-                       case XFER_PIO_0:
-                               set_indexed_reg(hwif, 0x0c + adj,
-                                               pio_timings[mode].reg0c);
-                               set_indexed_reg(hwif, 0x0d + adj,
-                                               pio_timings[mode].reg0d);
-                               set_indexed_reg(hwif, 0x13 + adj,
-                                               pio_timings[mode].reg13);
-                               break;
-                       default:
-                               printk(KERN_ERR "pdc202xx_new: "
-                                      "Unknown speed %d ignored\n", speed);
+               if (speed >= XFER_UDMA_0) {
+                       set_indexed_reg(hwif, 0x10 + adj,
+                                       udma_timings[mode].reg10);
+                       set_indexed_reg(hwif, 0x11 + adj,
+                                       udma_timings[mode].reg11);
+                       set_indexed_reg(hwif, 0x12 + adj,
+                                       udma_timings[mode].reg12);
+               } else {
+                       set_indexed_reg(hwif, 0x0e + adj,
+                                       mwdma_timings[mode].reg0e);
+                       set_indexed_reg(hwif, 0x0f + adj,
+                                       mwdma_timings[mode].reg0f);
                }
        } else if (speed == XFER_UDMA_2) {
                /* Set tHOLD bit to 0 if using UDMA mode 2 */
@@ -212,7 +185,14 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
 
 static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       pdcnew_set_mode(drive, XFER_PIO_0 + pio);
+       ide_hwif_t *hwif = drive->hwif;
+       u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+
+       if (max_dma_rate(hwif->pci_dev) == 4) {
+               set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
+               set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
+               set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
+       }
 }
 
 static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
@@ -223,14 +203,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
                return ATA_CBL_PATA80;
 }
 
-static int pdcnew_quirkproc(ide_drive_t *drive)
+static void pdcnew_quirkproc(ide_drive_t *drive)
 {
        const char **list, *model = drive->id->model;
 
        for (list = pdc_quirk_drives; *list != NULL; list++)
-               if (strstr(model, *list) != NULL)
-                       return 2;
-       return 0;
+               if (strstr(model, *list) != NULL) {
+                       drive->quirk_list = 2;
+                       return;
+               }
+
+       drive->quirk_list = 0;
 }
 
 static void pdcnew_reset(ide_drive_t *drive)
@@ -466,7 +449,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
 static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
 {
        hwif->set_pio_mode = &pdcnew_set_pio_mode;
-       hwif->set_dma_mode = &pdcnew_set_mode;
+       hwif->set_dma_mode = &pdcnew_set_dma_mode;
 
        hwif->quirkproc = &pdcnew_quirkproc;
        hwif->resetproc = &pdcnew_reset;
index e09742e2ba592607e31dd3356099fabf8fae5ea8..3a1e081fe3901c06e70dbaf7054238f28e90e10f 100644 (file)
@@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
  */
 static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
 {
-       unsigned long clock_reg = hwif->dma_master + 0x11;
+       unsigned long clock_reg = hwif->extra_base + 0x01;
        u8 clock = inb(clock_reg);
 
        outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
@@ -170,20 +170,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
 
 static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
 {
-       unsigned long clock_reg = hwif->dma_master + 0x11;
+       unsigned long clock_reg = hwif->extra_base + 0x01;
        u8 clock = inb(clock_reg);
 
        outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
 }
 
-static int pdc202xx_quirkproc (ide_drive_t *drive)
+static void pdc202xx_quirkproc(ide_drive_t *drive)
 {
        const char **list, *model = drive->id->model;
 
        for (list = pdc_quirk_drives; *list != NULL; list++)
-               if (strstr(model, *list) != NULL)
-                       return 2;
-       return 0;
+               if (strstr(model, *list) != NULL) {
+                       drive->quirk_list = 2;
+                       return;
+               }
+
+       drive->quirk_list = 0;
 }
 
 static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
@@ -193,7 +196,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
        if (drive->media != ide_disk || drive->addressing == 1) {
                struct request *rq      = HWGROUP(drive)->rq;
                ide_hwif_t *hwif        = HWIF(drive);
-               unsigned long high_16   = hwif->dma_master;
+               unsigned long high_16   = hwif->extra_base - 16;
                unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
                u32 word_count  = 0;
                u8 clock = inb(high_16 + 0x11);
@@ -212,7 +215,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
 {
        if (drive->media != ide_disk || drive->addressing == 1) {
                ide_hwif_t *hwif        = HWIF(drive);
-               unsigned long high_16   = hwif->dma_master;
+               unsigned long high_16   = hwif->extra_base - 16;
                unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
                u8 clock                = 0;
 
@@ -228,7 +231,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
 static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       unsigned long high_16   = hwif->dma_master;
+       unsigned long high_16   = hwif->extra_base - 16;
        u8 dma_stat             = inb(hwif->dma_status);
        u8 sc1d                 = inb(high_16 + 0x001d);
 
@@ -271,7 +274,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
 
 static void pdc202xx_reset_host (ide_hwif_t *hwif)
 {
-       unsigned long high_16   = hwif->dma_master;
+       unsigned long high_16   = hwif->extra_base - 16;
        u8 udma_speed_flag      = inb(high_16 | 0x001f);
 
        outb(udma_speed_flag | 0x10, high_16 | 0x001f);
@@ -375,6 +378,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
        }
 }
 
+#define IDE_HFLAGS_PDC202XX \
+       (IDE_HFLAG_ERROR_STOPS_FIFO | \
+        IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+        IDE_HFLAG_OFF_BOARD)
+
 #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
        { \
                .name           = name_str, \
@@ -382,9 +390,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
                .init_hwif      = init_hwif_pdc202xx, \
                .init_dma       = init_dma_pdc202xx, \
                .extra          = 48, \
-               .host_flags     = IDE_HFLAG_ERROR_STOPS_FIFO | \
-                                 extra_flags | \
-                                 IDE_HFLAG_OFF_BOARD, \
+               .host_flags     = IDE_HFLAGS_PDC202XX | extra_flags, \
                .pio_mask       = ATA_PIO4, \
                .mwdma_mask     = ATA_MWDMA2, \
                .udma_mask      = udma, \
@@ -397,8 +403,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
                .init_hwif      = init_hwif_pdc202xx,
                .init_dma       = init_dma_pdc202xx,
                .extra          = 16,
-               .host_flags     = IDE_HFLAG_ERROR_STOPS_FIFO |
-                                 IDE_HFLAG_OFF_BOARD,
+               .host_flags     = IDE_HFLAGS_PDC202XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA2,
index 27781d294cea73b29911e845b6cd689679331345..bd6d3f77d30c1c028f44263d4c437f8ac3f27491 100644 (file)
@@ -203,20 +203,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
        pci_read_config_byte(dev, 0x54, &reg54);
        pci_read_config_byte(dev, 0x55, &reg55);
 
-       switch(speed) {
-               case XFER_UDMA_4:
-               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
-               case XFER_UDMA_5:
-               case XFER_UDMA_3:
-               case XFER_UDMA_1:       u_speed = 1 << (drive->dn * 4); break;
-               case XFER_UDMA_0:       u_speed = 0 << (drive->dn * 4); break;
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_SW_DMA_2:     break;
-               default:                return;
-       }
-
        if (speed >= XFER_UDMA_0) {
+               u8 udma = speed - XFER_UDMA_0;
+
+               u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
+
                if (!(reg48 & u_flag))
                        pci_write_config_byte(dev, 0x48, reg48 | u_flag);
                if (speed == XFER_UDMA_5) {
index 707d5ff66b0300941429177d1beed7a26905e229..32fdf53379f5a5bf6cd817628c6543a4dba71182 100644 (file)
@@ -135,59 +135,29 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
        unsigned short          pci_clock;
        unsigned int            basereg = hwif->channel ? 0x50 : 0x40;
 
+       static const u32 udma_timing[3][3] = {
+               { 0x00921250, 0x00911140, 0x00911030 },
+               { 0x00932470, 0x00922260, 0x00922140 },
+               { 0x009436a1, 0x00933481, 0x00923261 },
+       };
+
+       static const u32 mwdma_timing[3][3] = {
+               { 0x00077771, 0x00012121, 0x00002020 },
+               { 0x000bbbb2, 0x00024241, 0x00013131 },
+               { 0x000ffff3, 0x00035352, 0x00015151 },
+       };
+
        pci_clock = sc1200_get_pci_clock();
 
        /*
         * Note that each DMA mode has several timings associated with it.
         * The correct timing depends on the fast PCI clock freq.
         */
-       timings = 0;
-       switch (mode) {
-               case XFER_UDMA_0:
-                       switch (pci_clock) {
-                               case PCI_CLK_33:        timings = 0x00921250;   break;
-                               case PCI_CLK_48:        timings = 0x00932470;   break;
-                               case PCI_CLK_66:        timings = 0x009436a1;   break;
-                       }
-                       break;
-               case XFER_UDMA_1:
-                       switch (pci_clock) {
-                               case PCI_CLK_33:        timings = 0x00911140;   break;
-                               case PCI_CLK_48:        timings = 0x00922260;   break;
-                               case PCI_CLK_66:        timings = 0x00933481;   break;
-                       }
-                       break;
-               case XFER_UDMA_2:
-                       switch (pci_clock) {
-                               case PCI_CLK_33:        timings = 0x00911030;   break;
-                               case PCI_CLK_48:        timings = 0x00922140;   break;
-                               case PCI_CLK_66:        timings = 0x00923261;   break;
-                       }
-                       break;
-               case XFER_MW_DMA_0:
-                       switch (pci_clock) {
-                               case PCI_CLK_33:        timings = 0x00077771;   break;
-                               case PCI_CLK_48:        timings = 0x000bbbb2;   break;
-                               case PCI_CLK_66:        timings = 0x000ffff3;   break;
-                       }
-                       break;
-               case XFER_MW_DMA_1:
-                       switch (pci_clock) {
-                               case PCI_CLK_33:        timings = 0x00012121;   break;
-                               case PCI_CLK_48:        timings = 0x00024241;   break;
-                               case PCI_CLK_66:        timings = 0x00035352;   break;
-                       }
-                       break;
-               case XFER_MW_DMA_2:
-                       switch (pci_clock) {
-                               case PCI_CLK_33:        timings = 0x00002020;   break;
-                               case PCI_CLK_48:        timings = 0x00013131;   break;
-                               case PCI_CLK_66:        timings = 0x00015151;   break;
-                       }
-                       break;
-               default:
-                       return;
-       }
+
+       if (mode >= XFER_UDMA_0)
+               timings =  udma_timing[pci_clock][mode - XFER_UDMA_0];
+       else
+               timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
 
        if (unit == 0) {                        /* are we configuring drive0? */
                pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
@@ -250,9 +220,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
        }
        if (mode != -1) {
                printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
-               hwif->dma_off_quietly(drive);
-               if (ide_set_dma_mode(drive, mode) == 0)
-                       hwif->dma_host_on(drive);
+               ide_dma_off_quietly(drive);
+               if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
+                       hwif->dma_host_set(drive, 1);
                return;
        }
 
@@ -260,66 +230,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
 }
 
 #ifdef CONFIG_PM
-static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
-{
-       int     h;
-
-       for (h = 0; h < MAX_HWIFS; h++) {
-               ide_hwif_t *hwif = &ide_hwifs[h];
-               if (prev) {
-                       if (hwif == prev)
-                               prev = NULL;    // found previous, now look for next match
-               } else {
-                       if (hwif && hwif->pci_dev == dev)
-                               return hwif;    // found next match
-               }
-       }
-       return NULL;    // not found
-}
-
-typedef struct sc1200_saved_state_s {
-       __u32           regs[4];
-} sc1200_saved_state_t;
-
+struct sc1200_saved_state {
+       u32 regs[8];
+};
 
 static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
 {
-       ide_hwif_t              *hwif = NULL;
-
        printk("SC1200: suspend(%u)\n", state.event);
 
+       /*
+        * we only save state when going from full power to less
+        */
        if (state.event == PM_EVENT_ON) {
-               // we only save state when going from full power to less
-
-               //
-               // Loop over all interfaces that are part of this PCI device:
-               //
-               while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
-                       sc1200_saved_state_t    *ss;
-                       unsigned int            basereg, r;
-                       //
-                       // allocate a permanent save area, if not already allocated
-                       //
-                       ss = (sc1200_saved_state_t *)hwif->config_data;
-                       if (ss == NULL) {
-                               ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
-                               if (ss == NULL)
-                                       return -ENOMEM;
-                               hwif->config_data = (unsigned long)ss;
-                       }
-                       ss = (sc1200_saved_state_t *)hwif->config_data;
-                       //
-                       // Save timing registers:  this may be unnecessary if 
-                       // BIOS also does it
-                       //
-                       basereg = hwif->channel ? 0x50 : 0x40;
-                       for (r = 0; r < 4; ++r) {
-                               pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
-                       }
+               struct sc1200_saved_state *ss;
+               unsigned int r;
+
+               /*
+                * allocate a permanent save area, if not already allocated
+                */
+               ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
+               if (ss == NULL) {
+                       ss = kmalloc(sizeof(*ss), GFP_KERNEL);
+                       if (ss == NULL)
+                               return -ENOMEM;
+                       pci_set_drvdata(dev, ss);
                }
-       }
 
-       /* You don't need to iterate over disks -- sysfs should have done that for you already */ 
+               /*
+                * save timing registers
+                * (this may be unnecessary if BIOS also does it)
+                */
+               for (r = 0; r < 8; r++)
+                       pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
+       }
 
        pci_disable_device(dev);
        pci_set_power_state(dev, pci_choose_state(dev, state));
@@ -328,30 +271,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
 
 static int sc1200_resume (struct pci_dev *dev)
 {
-       ide_hwif_t      *hwif = NULL;
-       int             i;
+       struct sc1200_saved_state *ss;
+       unsigned int r;
+       int i;
 
        i = pci_enable_device(dev);
        if (i)
                return i;
 
-       //
-       // loop over all interfaces that are part of this pci device:
-       //
-       while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
-               unsigned int            basereg, r;
-               sc1200_saved_state_t    *ss = (sc1200_saved_state_t *)hwif->config_data;
-
-               //
-               // Restore timing registers:  this may be unnecessary if BIOS also does it
-               //
-               basereg = hwif->channel ? 0x50 : 0x40;
-               if (ss != NULL) {
-                       for (r = 0; r < 4; ++r) {
-                               pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
-                       }
-               }
+       ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
+
+       /*
+        * restore timing registers
+        * (this may be unnecessary if BIOS also does it)
+        */
+       if (ss) {
+               for (r = 0; r < 8; r++)
+                       pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
        }
+
        return 0;
 }
 #endif
index ebb7132b9b848c6c87f92cbe9dc6b92450980c8f..24a85bbcd2a6c3e1db2df10355274fef707fe465 100644 (file)
@@ -254,19 +254,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
                offset = 0; /* 100MHz */
        }
 
-       switch (speed) {
-       case XFER_UDMA_6:
-       case XFER_UDMA_5:
-       case XFER_UDMA_4:
-       case XFER_UDMA_3:
-       case XFER_UDMA_2:
-       case XFER_UDMA_1:
-       case XFER_UDMA_0:
-               idx = speed - XFER_UDMA_0;
-               break;
-       default:
-               return;
-       }
+       idx = speed - XFER_UDMA_0;
 
        jcactsel = JCACTSELtbl[offset][idx];
        if (is_slave) {
index a7280311357b3e539aae503165ed0b9e69603f71..877c09bf482957c3ee067724a35ee535fde7bc31 100644 (file)
@@ -164,25 +164,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
        ultra_timing    &= ~(0x0F << (4*unit));
        ultra_enable    &= ~(0x01 << drive->dn);
 
-       switch(speed) {
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_MW_DMA_0:
-                       dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-                       break;
-
-               case XFER_UDMA_5:
-               case XFER_UDMA_4:
-               case XFER_UDMA_3:
-               case XFER_UDMA_2:
-               case XFER_UDMA_1:
-               case XFER_UDMA_0:
-                       dma_timing   |= dma_modes[2];
-                       ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-                       ultra_enable |= (0x01 << drive->dn);
-               default:
-                       break;
-       }
+       if (speed >= XFER_UDMA_0) {
+               dma_timing   |= dma_modes[2];
+               ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
+               ultra_enable |= (0x01 << drive->dn);
+       } else if (speed >= XFER_MW_DMA_0)
+               dma_timing   |= dma_modes[speed - XFER_MW_DMA_0];
 
        pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
        pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
@@ -366,12 +353,17 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
        }
 }
 
+#define IDE_HFLAGS_SVWKS \
+       (IDE_HFLAG_LEGACY_IRQS | \
+        IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+        IDE_HFLAG_BOOTABLE)
+
 static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
        {       /* 0 */
                .name           = "SvrWks OSB4",
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .host_flags     = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+               .host_flags     = IDE_HFLAGS_SVWKS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = 0x00, /* UDMA is problematic on OSB4 */
@@ -379,7 +371,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = "SvrWks CSB5",
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .host_flags     = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+               .host_flags     = IDE_HFLAGS_SVWKS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -387,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = "SvrWks CSB6",
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .host_flags     = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+               .host_flags     = IDE_HFLAGS_SVWKS,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -395,8 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = "SvrWks CSB6",
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .host_flags     = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
-                                 IDE_HFLAG_BOOTABLE,
+               .host_flags     = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
@@ -404,8 +395,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
                .name           = "SvrWks HT1000",
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .host_flags     = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
-                                 IDE_HFLAG_BOOTABLE,
+               .host_flags     = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
index de820aa58cd0e47057b9a8028d9fd3b8c1bfe515..9e0be7d549800e2a4304a99fb54d75b74d0fdcf2 100644 (file)
@@ -277,21 +277,6 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
        return dma_stat;
 }
 
-static int
-sgiioc4_ide_dma_on(ide_drive_t * drive)
-{
-       drive->using_dma = 1;
-
-       return 0;
-}
-
-static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
-{
-       drive->using_dma = 0;
-
-       drive->hwif->dma_host_off(drive);
-}
-
 static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
 }
@@ -303,13 +288,10 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
        return sgiioc4_checkirq(HWIF(drive));
 }
 
-static void sgiioc4_dma_host_on(ide_drive_t * drive)
-{
-}
-
-static void sgiioc4_dma_host_off(ide_drive_t * drive)
+static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
 {
-       sgiioc4_clearirq(drive);
+       if (!on)
+               sgiioc4_clearirq(drive);
 }
 
 static void
@@ -582,7 +564,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
        hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
                                                clear interrupts */
-       hwif->intrproc = NULL;  /* Enable or Disable interrupt from drive */
        hwif->maskproc = &sgiioc4_maskproc;     /* Mask on/off NIEN register */
        hwif->quirkproc = NULL;
        hwif->busproc = NULL;
@@ -594,14 +575,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
 
        hwif->mwdma_mask = ATA_MWDMA2_ONLY;
 
+       hwif->dma_host_set = &sgiioc4_dma_host_set;
        hwif->dma_setup = &sgiioc4_ide_dma_setup;
        hwif->dma_start = &sgiioc4_ide_dma_start;
        hwif->ide_dma_end = &sgiioc4_ide_dma_end;
-       hwif->ide_dma_on = &sgiioc4_ide_dma_on;
-       hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
        hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
-       hwif->dma_host_on = &sgiioc4_dma_host_on;
-       hwif->dma_host_off = &sgiioc4_dma_host_off;
        hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
        hwif->dma_timeout = &ide_dma_timeout;
 }
@@ -615,6 +593,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        ide_hwif_t *hwif;
        int h;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+       hw_regs_t hw;
 
        /*
         * Find an empty HWIF; if none available, return -ENOMEM.
@@ -654,21 +633,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
                return -ENOMEM;
        }
 
-       if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
-               hw_regs_t hw;
-
-               /* Initialize the IO registers */
-               memset(&hw, 0, sizeof(hw));
-               sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
-               memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-               hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-       }
+       /* Initialize the IO registers */
+       memset(&hw, 0, sizeof(hw));
+       sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
+       hw.irq = dev->irq;
+       hw.chipset = ide_pci;
+       hw.dev = &dev->dev;
+       ide_init_port_hw(hwif, &hw);
 
-       hwif->irq = dev->irq;
-       hwif->chipset = ide_pci;
        hwif->pci_dev = dev;
        hwif->channel = 0;      /* Single Channel chip */
-       hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
 
        /* The IOC4 uses MMIO rather than Port IO. */
        default_hwif_mmiops(hwif);
index 5709c252543b5c7a68a4b04064f26e85ef8ac2dc..908f37b4e0ee140f7dca78f6c6e5c6de2efc3484 100644 (file)
@@ -278,27 +278,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
        scsc = is_sata(hwif) ? 1 : scsc;
 
-       switch(speed) {
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_MW_DMA_0:
-                       multi = dma[speed - XFER_MW_DMA_0];
-                       mode |= ((unit) ? 0x20 : 0x02);
-                       break;
-               case XFER_UDMA_6:
-               case XFER_UDMA_5:
-               case XFER_UDMA_4:
-               case XFER_UDMA_3:
-               case XFER_UDMA_2:
-               case XFER_UDMA_1:
-               case XFER_UDMA_0:
-                       multi = dma[2];
-                       ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
-                                          (ultra5[speed - XFER_UDMA_0]));
-                       mode |= ((unit) ? 0x30 : 0x03);
-                       break;
-               default:
-                       return;
+       if (speed >= XFER_UDMA_0) {
+               multi = dma[2];
+               ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] :
+                                ultra5[speed - XFER_UDMA_0]);
+               mode |= (unit ? 0x30 : 0x03);
+       } else {
+               multi = dma[speed - XFER_MW_DMA_0];
+               mode |= (unit ? 0x20 : 0x02);
        }
 
        if (hwif->mmio) {
@@ -726,9 +713,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
        const char *s = &drive->id->model[0];
        unsigned len;
 
-       if (!drive->present)
-               return 0;
-
        len = strnlen(s, sizeof(drive->id->model));
 
        if ((len > 4) && (!memcmp(s, "ST", 2))) {
@@ -743,18 +727,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
 }
 
 /**
- *     siimage_fixup           -       post probe fixups
- *     @hwif: interface to fix up
+ *     sil_quirkproc           -       post probe fixups
+ *     @drive: drive
  *
  *     Called after drive probe we use this to decide whether the
  *     Seagate fixup must be applied. This used to be in init_iops but
  *     that can occur before we know what drives are present.
  */
 
-static void __devinit siimage_fixup(ide_hwif_t *hwif)
+static void __devinit sil_quirkproc(ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = drive->hwif;
+
        /* Try and raise the rqsize */
-       if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0]))
+       if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
                hwif->rqsize = 128;
 }
 
@@ -817,6 +803,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
 
        hwif->set_pio_mode = &sil_set_pio_mode;
        hwif->set_dma_mode = &sil_set_dma_mode;
+       hwif->quirkproc = &sil_quirkproc;
 
        if (sata) {
                static int first = 1;
@@ -855,7 +842,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
                .init_chipset   = init_chipset_siimage, \
                .init_iops      = init_iops_siimage,    \
                .init_hwif      = init_hwif_siimage,    \
-               .fixup          = siimage_fixup,        \
                .host_flags     = IDE_HFLAG_BOOTABLE,   \
                .pio_mask       = ATA_PIO4,             \
                .mwdma_mask     = ATA_MWDMA2,           \
index d90b42917775dc3e5345b16b836f0ab649142cfc..85d36996e6af768ed2f23be7ab2bd23968eb6ac4 100644 (file)
@@ -305,59 +305,56 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
        sis_program_timings(drive, XFER_PIO_0 + pio);
 }
 
-static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev = drive->hwif->pci_dev;
+       u32 regdw = 0;
+       u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
 
-       /* Config chip for mode */
-       switch(speed) {
-               case XFER_UDMA_6:
-               case XFER_UDMA_5:
-               case XFER_UDMA_4:
-               case XFER_UDMA_3:
-               case XFER_UDMA_2:
-               case XFER_UDMA_1:
-               case XFER_UDMA_0:
-                       if (chipset_family >= ATA_133) {
-                               u32 regdw = 0;
-                               u8 drive_pci = sis_ata133_get_base(drive);
-
-                               pci_read_config_dword(dev, drive_pci, &regdw);
-                               regdw |= 0x04;
-                               regdw &= 0xfffff00f;
-                               /* check if ATA133 enable */
-                               if (regdw & 0x08) {
-                                       regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
-                                       regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
-                               } else {
-                                       regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
-                                       regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
-                               }
-                               pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
-                       } else {
-                               u8 drive_pci = 0x40 + drive->dn * 2, reg = 0;
-
-                               pci_read_config_byte(dev, drive_pci+1, &reg);
-                               /* Force the UDMA bit on if we want to use UDMA */
-                               reg |= 0x80;
-                               /* clean reg cycle time bits */
-                               reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
-                                        << cycle_time_offset[chipset_family]);
-                               /* set reg cycle time bits */
-                               reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0]
-                                       << cycle_time_offset[chipset_family];
-                               pci_write_config_byte(dev, drive_pci+1, reg);
-                       }
-                       break;
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_MW_DMA_0:
-                       sis_program_timings(drive, speed);
-                       break;
-               default:
-                       break;
-       }
+       pci_read_config_dword(dev, drive_pci, &regdw);
+
+       regdw |= 0x04;
+       regdw &= 0xfffff00f;
+       /* check if ATA133 enable */
+       clk = (regdw & 0x08) ? ATA_133 : ATA_100;
+       idx = mode - XFER_UDMA_0;
+       regdw |= cycle_time_value[clk][idx] << 4;
+       regdw |= cvs_time_value[clk][idx] << 8;
+
+       pci_write_config_dword(dev, drive_pci, regdw);
+}
+
+static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+       struct pci_dev *dev = drive->hwif->pci_dev;
+       u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
+
+       pci_read_config_byte(dev, drive_pci + 1, &reg);
+
+       /* force the UDMA bit on if we want to use UDMA */
+       reg |= 0x80;
+       /* clean reg cycle time bits */
+       reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
+       /* set reg cycle time bits */
+       reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
+
+       pci_write_config_byte(dev, drive_pci + 1, reg);
+}
+
+static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+       if (chipset_family >= ATA_133)  /* ATA_133 */
+               sis_ata133_program_udma_timings(drive, mode);
+       else                            /* ATA_33/66/100a/100/133a */
+               sis_ata33_program_udma_timings(drive, mode);
+}
+
+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+       if (speed >= XFER_UDMA_0)
+               sis_program_udma_timings(drive, speed);
+       else
+               sis_program_timings(drive, speed);
 }
 
 static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
index 147d783f7529e681fb1d69645942d00780bd42e0..c7a125b66c297504bea97c933b0f1b50044a9a46 100644 (file)
@@ -13,6 +13,7 @@
  *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
  *
  * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  */
 
 #include <linux/types.h>
@@ -90,14 +91,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
        drive->drive_data &= 0xffff0000;
        drive->drive_data |= drv_ctrl;
 
-       if (!drive->using_dma) {
-               /*
-                * If we are actually using MW DMA, then we can not
-                * reprogram the interface drive control register.
-                */
-               pci_write_config_word(dev, reg,  drv_ctrl);
-               pci_read_config_word (dev, reg, &drv_ctrl);
-       }
+       pci_write_config_word(dev, reg,  drv_ctrl);
+       pci_read_config_word (dev, reg, &drv_ctrl);
 
        printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
                          ide_xfer_verbose(pio + XFER_PIO_0),
@@ -115,33 +110,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
        DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
             drive->name, ide_xfer_verbose(speed)));
 
-       switch (speed) {
-       case XFER_MW_DMA_2:
-       case XFER_MW_DMA_1:
-       case XFER_MW_DMA_0:
-               drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
+       drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
 
-               /*
-                * Store the DMA timings so that we can actually program
-                * them when DMA will be turned on...
-                */
-               drive->drive_data &= 0x0000ffff;
-               drive->drive_data |= (unsigned long)drv_ctrl << 16;
-
-               /*
-                * If we are already using DMA, we just reprogram
-                * the drive control register.
-                */
-               if (drive->using_dma) {
-                       struct pci_dev *dev     = HWIF(drive)->pci_dev;
-                       int reg                 = 0x44 + drive->dn * 4;
-
-                       pci_write_config_word(dev, reg, drv_ctrl);
-               }
-               break;
-       default:
-               return;
-       }
+       /*
+        * Store the DMA timings so that we can actually program
+        * them when DMA will be turned on...
+        */
+       drive->drive_data &= 0x0000ffff;
+       drive->drive_data |= (unsigned long)drv_ctrl << 16;
 }
 
 /*
@@ -209,6 +185,11 @@ static void sl82c105_dma_start(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
+       int reg                 = 0x44 + drive->dn * 4;
+
+       DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+
+       pci_write_config_word(dev, reg, drive->drive_data >> 16);
 
        sl82c105_reset_host(dev);
        ide_dma_start(drive);
@@ -222,64 +203,24 @@ static void sl82c105_dma_timeout(ide_drive_t *drive)
        ide_dma_timeout(drive);
 }
 
-static int sl82c105_ide_dma_on(ide_drive_t *drive)
-{
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       int rc, reg             = 0x44 + drive->dn * 4;
-
-       DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
-
-       rc = __ide_dma_on(drive);
-       if (rc == 0) {
-               pci_write_config_word(dev, reg, drive->drive_data >> 16);
-
-               printk(KERN_INFO "%s: DMA enabled\n", drive->name);
-       }
-       return rc;
-}
-
-static void sl82c105_dma_off_quietly(ide_drive_t *drive)
+static int sl82c105_dma_end(ide_drive_t *drive)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
        int reg                 = 0x44 + drive->dn * 4;
+       int ret;
 
-       DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
+       DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
 
-       pci_write_config_word(dev, reg, drive->drive_data);
+       ret = __ide_dma_end(drive);
 
-       ide_dma_off_quietly(drive);
-}
+       pci_write_config_word(dev, reg, drive->drive_data);
 
-/*
- * Ok, that is nasty, but we must make sure the DMA timings
- * won't be used for a PIO access. The solution here is
- * to make sure the 16 bits mode is diabled on the channel
- * when DMA is enabled, thus causing the chip to use PIO0
- * timings for those operations.
- */
-static void sl82c105_selectproc(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
-       u32 val, old, mask;
-
-       //DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
-
-       mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
-       old = val = (u32)pci_get_drvdata(dev);
-       if (drive->using_dma)
-               val &= ~mask;
-       else
-               val |= mask;
-       if (old != val) {
-               pci_write_config_dword(dev, 0x40, val); 
-               pci_set_drvdata(dev, (void *)val);
-       }
+       return ret;
 }
 
 /*
  * ATA reset will clear the 16 bits mode in the control
- * register, we need to update our cache
+ * register, we need to reprogram it
  */
 static void sl82c105_resetproc(ide_drive_t *drive)
 {
@@ -289,7 +230,8 @@ static void sl82c105_resetproc(ide_drive_t *drive)
        DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
 
        pci_read_config_dword(dev, 0x40, &val);
-       pci_set_drvdata(dev, (void *)val);
+       val |= (CTRL_P1F16 | CTRL_P0F16);
+       pci_write_config_dword(dev, 0x40, val);
 }
 
 /*
@@ -342,7 +284,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
        pci_read_config_dword(dev, 0x40, &val);
        val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
        pci_write_config_dword(dev, 0x40, val);
-       pci_set_drvdata(dev, (void *)val);
 
        return dev->irq;
 }
@@ -358,7 +299,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 
        hwif->set_pio_mode      = &sl82c105_set_pio_mode;
        hwif->set_dma_mode      = &sl82c105_set_dma_mode;
-       hwif->selectproc        = &sl82c105_selectproc;
        hwif->resetproc         = &sl82c105_resetproc;
 
        if (!hwif->dma_base)
@@ -377,10 +317,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 
        hwif->mwdma_mask = ATA_MWDMA2;
 
-       hwif->ide_dma_on                = &sl82c105_ide_dma_on;
-       hwif->dma_off_quietly           = &sl82c105_dma_off_quietly;
        hwif->dma_lost_irq              = &sl82c105_dma_lost_irq;
        hwif->dma_start                 = &sl82c105_dma_start;
+       hwif->ide_dma_end               = &sl82c105_dma_end;
        hwif->dma_timeout               = &sl82c105_dma_timeout;
 
        if (hwif->mate)
index eb4445b229ed431602bff6bfe7e65d94b8ac53d7..dbbb46819a2dbdae2ba1a9d52830639985e7456f 100644 (file)
@@ -91,19 +91,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
        pci_read_config_word(dev, 0x48, &reg48);
        pci_read_config_word(dev, 0x4a, &reg4a);
 
-       switch(speed) {
-               case XFER_UDMA_4:       u_speed = 4 << (drive->dn * 4); break;
-               case XFER_UDMA_3:       u_speed = 3 << (drive->dn * 4); break;
-               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
-               case XFER_UDMA_1:       u_speed = 1 << (drive->dn * 4); break;
-               case XFER_UDMA_0:       u_speed = 0 << (drive->dn * 4); break;
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_SW_DMA_2:     break;
-               default:                return;
-       }
-
        if (speed >= XFER_UDMA_0) {
+               u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
+
                if (!(reg48 & u_flag))
                        pci_write_config_word(dev, 0x48, reg48|u_flag);
                /* FIXME: (reg4a & a_speed) ? */
index a66ebd14664e66149bce9ada527692a7acd7977b..e1faf6c2fe1678ba442fbfae9516144e4cbfeb1e 100644 (file)
@@ -222,7 +222,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = {
        .name           = "TC86C001",
        .init_chipset   = init_chipset_tc86c001,
        .init_hwif      = init_hwif_tc86c001,
-       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
+       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD |
+                         IDE_HFLAG_ABUSE_SET_DMA_MODE,
        .pio_mask       = ATA_PIO4,
        .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA4,
index a227c41d23a3110e0efaaec5cebe40ac7718cc2b..ae52a96a1cf9d5770660637ea19d44f9b71bff4b 100644 (file)
@@ -81,8 +81,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
                case XFER_PIO_0:
                        timing = 0x0808;
                        break;
-               default:
-                       return;
        }
 
        triflex_timings &= ~(0xFFFF << (16 * unit));
index 0895e753a35d34af4ba8b508fe3422fa82b4c461..04cd893e1ab053e8621aa486fdfe2087725ace49 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *  linux/drivers/ide/pci/trm290.c             Version 1.02    Mar. 18, 2000
+ *  linux/drivers/ide/pci/trm290.c             Version 1.05    Dec. 26, 2007
  *
  *  Copyright (c) 1997-1998  Mark Lord
+ *  Copyright (c) 2007       MontaVista Software, Inc. <source@mvista.com>
  *  May be copied or modified under the terms of the GNU General Public License
  *
  *  June 22, 2004 - get rid of check_region
@@ -177,7 +178,7 @@ static void trm290_selectproc (ide_drive_t *drive)
        trm290_prepare_drive(drive, drive->using_dma);
 }
 
-static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
 {
        BUG_ON(HWGROUP(drive)->handler != NULL);        /* paranoia check */
        ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
@@ -185,7 +186,7 @@ static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
        outb(command, IDE_COMMAND_REG);
 }
 
-static int trm290_ide_dma_setup(ide_drive_t *drive)
+static int trm290_dma_setup(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = hwif->hwgroup->rq;
@@ -215,7 +216,7 @@ static int trm290_ide_dma_setup(ide_drive_t *drive)
        return 0;
 }
 
-static void trm290_ide_dma_start(ide_drive_t *drive)
+static void trm290_dma_start(ide_drive_t *drive)
 {
 }
 
@@ -240,6 +241,10 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
        return (status == 0x00ff);
 }
 
+static void trm290_dma_host_set(ide_drive_t *drive, int on)
+{
+}
+
 static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 {
        unsigned int cfgbase = 0;
@@ -280,11 +285,12 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 
        ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
 
-       hwif->dma_setup = &trm290_ide_dma_setup;
-       hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd;
-       hwif->dma_start = &trm290_ide_dma_start;
-       hwif->ide_dma_end = &trm290_ide_dma_end;
-       hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
+       hwif->dma_host_set      = &trm290_dma_host_set;
+       hwif->dma_setup         = &trm290_dma_setup;
+       hwif->dma_exec_cmd      = &trm290_dma_exec_cmd;
+       hwif->dma_start         = &trm290_dma_start;
+       hwif->ide_dma_end       = &trm290_ide_dma_end;
+       hwif->ide_dma_test_irq  = &trm290_ide_dma_test_irq;
 
        hwif->selectproc = &trm290_selectproc;
 #if 1
index a0d3c16b68ec4fdba9d4d54d9a2bcb6e7181860e..4b32c90f489695b212883a868e55b7c3f6b9f948 100644 (file)
@@ -439,6 +439,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = {
        .enablebits     = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
        .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST |
                          IDE_HFLAG_PIO_NO_DOWNGRADE |
+                         IDE_HFLAG_ABUSE_SET_DMA_MODE |
                          IDE_HFLAG_POST_SET_MODE |
                          IDE_HFLAG_IO_32BIT |
                          IDE_HFLAG_BOOTABLE,
diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
new file mode 100644 (file)
index 0000000..65af584
--- /dev/null
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)         += pmac.o
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)       += mpc8xx.o
index 5f0da35ab5ad0a3ef977ab67c8145c0733f47245..3fd5d45b5e0e2584cbdcfbfa2de47b62a47e8f08 100644 (file)
@@ -838,3 +838,21 @@ void m8xx_ide_init(void)
        ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
        ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
 }
+
+static int __init mpc8xx_ide_probe(void)
+{
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
+#ifdef IDE0_BASE_OFFSET
+       idx[0] = 0;
+#ifdef IDE1_BASE_OFFSET
+       idx[1] = 1;
+#endif
+#endif
+
+       ide_device_add(idx);
+
+       return 0;
+}
+
+module_init(mpc8xx_ide_probe);
index 7f7a59885777b41dcf4dd0556377102dda1a5089..736d12c8e68afb5170653119d90472d4e63013bf 100644 (file)
@@ -438,13 +438,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
                if (data_port == pmac_ide[ix].regbase)
                        break;
 
-       if (ix >= MAX_HWIFS) {
-               /* Probably a PCI interface... */
-               for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-                       hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-               return;
-       }
+       if (ix >= MAX_HWIFS)
+               return;         /* not an IDE PMAC interface */
 
        for (i = 0; i < 8; ++i)
                hw->io_ports[i] = data_port + i * 0x10;
@@ -833,38 +828,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
        tl[0] = *timings;
        tl[1] = *timings2;
 
-       switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-               case XFER_UDMA_6:
-               case XFER_UDMA_5:
-               case XFER_UDMA_4:
-               case XFER_UDMA_3:
-               case XFER_UDMA_2:
-               case XFER_UDMA_1:
-               case XFER_UDMA_0:
-                       if (pmif->kind == controller_kl_ata4)
-                               ret = set_timings_udma_ata4(&tl[0], speed);
-                       else if (pmif->kind == controller_un_ata6
-                                || pmif->kind == controller_k2_ata6)
-                               ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
-                       else if (pmif->kind == controller_sh_ata6)
-                               ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
-                       else
-                               ret = 1;
-                       break;
-               case XFER_MW_DMA_2:
-               case XFER_MW_DMA_1:
-               case XFER_MW_DMA_0:
-                       set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
-                       break;
-               case XFER_SW_DMA_2:
-               case XFER_SW_DMA_1:
-               case XFER_SW_DMA_0:
-                       return;
+       if (speed >= XFER_UDMA_0) {
+               if (pmif->kind == controller_kl_ata4)
+                       ret = set_timings_udma_ata4(&tl[0], speed);
+               else if (pmif->kind == controller_un_ata6
+                        || pmif->kind == controller_k2_ata6)
+                       ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
+               else if (pmif->kind == controller_sh_ata6)
+                       ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
+               else
+                       ret = -1;
+       } else
+               set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-               default:
-                       ret = 1;
-       }
        if (ret)
                return;
 
@@ -1035,12 +1012,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
  * rare machines unfortunately, but it's better this way.
  */
 static int
-pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
 {
        struct device_node *np = pmif->node;
        const int *bidp;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-       hw_regs_t hw;
 
        pmif->cable_80 = 0;
        pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1126,11 +1102,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        /* Tell common code _not_ to mess with resources */
        hwif->mmio = 1;
        hwif->hwif_data = pmif;
-       memset(&hw, 0, sizeof(hw));
-       pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq);
-       memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-       hwif->chipset = ide_pmac;
-       hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
+       hw->chipset = ide_pmac;
+       ide_init_port_hw(hwif, hw);
+       hwif->noprobe = pmif->mediabay;
        hwif->hold = pmif->mediabay;
        hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
        hwif->drives[0].unmask = 1;
@@ -1159,8 +1133,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
                hwif->noprobe = 0;
 #endif /* CONFIG_PMAC_MEDIABAY */
 
-       hwif->sg_max_nents = MAX_DCMDS;
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
        /* has a DBDMA controller channel */
        if (pmif->dma_regs)
@@ -1186,6 +1158,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        ide_hwif_t *hwif;
        pmac_ide_hwif_t *pmif;
        int i, rc;
+       hw_regs_t hw;
 
        i = 0;
        while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
@@ -1228,7 +1201,6 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        regbase = (unsigned long) base;
 
        hwif->pci_dev = mdev->bus->pdev;
-       hwif->gendev.parent = &mdev->ofdev.dev;
 
        pmif->mdev = mdev;
        pmif->node = mdev->ofdev.node;
@@ -1246,7 +1218,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
        dev_set_drvdata(&mdev->ofdev.dev, hwif);
 
-       rc = pmac_ide_setup_device(pmif, hwif);
+       memset(&hw, 0, sizeof(hw));
+       pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
+       hw.irq = irq;
+       hw.dev = &mdev->ofdev.dev;
+
+       rc = pmac_ide_setup_device(pmif, hwif, &hw);
        if (rc != 0) {
                /* The inteface is released to the common IDE layer */
                dev_set_drvdata(&mdev->ofdev.dev, NULL);
@@ -1305,6 +1282,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        void __iomem *base;
        unsigned long rbase, rlen;
        int i, rc;
+       hw_regs_t hw;
 
        np = pci_device_to_OF_node(pdev);
        if (np == NULL) {
@@ -1338,7 +1316,6 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        hwif->pci_dev = pdev;
-       hwif->gendev.parent = &pdev->dev;
        pmif->mdev = NULL;
        pmif->node = np;
 
@@ -1355,7 +1332,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        pci_set_drvdata(pdev, hwif);
 
-       rc = pmac_ide_setup_device(pmif, hwif);
+       memset(&hw, 0, sizeof(hw));
+       pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
+       hw.irq = pdev->irq;
+       hw.dev = &pdev->dev;
+
+       rc = pmac_ide_setup_device(pmif, hwif, &hw);
        if (rc != 0) {
                /* The inteface is released to the common IDE layer */
                pci_set_drvdata(pdev, NULL);
@@ -1721,11 +1703,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
        return 1;
 }
 
-static void pmac_ide_dma_host_off(ide_drive_t *drive)
-{
-}
-
-static void pmac_ide_dma_host_on(ide_drive_t *drive)
+static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -1771,15 +1749,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
                return;
        }
 
-       hwif->dma_off_quietly = &ide_dma_off_quietly;
-       hwif->ide_dma_on = &__ide_dma_on;
+       hwif->sg_max_nents = MAX_DCMDS;
+
+       hwif->dma_host_set = &pmac_ide_dma_host_set;
        hwif->dma_setup = &pmac_ide_dma_setup;
        hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
        hwif->dma_start = &pmac_ide_dma_start;
        hwif->ide_dma_end = &pmac_ide_dma_end;
        hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
-       hwif->dma_host_off = &pmac_ide_dma_host_off;
-       hwif->dma_host_on = &pmac_ide_dma_host_on;
        hwif->dma_timeout = &ide_dma_timeout;
        hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
 
@@ -1809,3 +1786,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+module_init(pmac_ide_probe);
index d2cd5a3d38f82e6a18b12024cf7ad14777eb5612..676c66e728818aac177442847d50b1d73413ef6e 100644 (file)
@@ -165,13 +165,17 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
 
                dma_base = pci_resource_start(dev, baridx);
 
-               if (dma_base == 0)
+               if (dma_base == 0) {
                        printk(KERN_ERR "%s: DMA base is invalid\n", d->name);
+                       return 0;
+               }
        }
 
-       if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
+       if (hwif->channel)
+               dma_base += 8;
+
+       if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
                u8 simplex_stat = 0;
-               dma_base += hwif->channel ? 8 : 0;
 
                switch(dev->device) {
                        case PCI_DEVICE_ID_AL_M5219:
@@ -359,6 +363,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
        unsigned long ctl = 0, base = 0;
        ide_hwif_t *hwif;
        u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
+       u8 oldnoprobe = 0;
+       struct hw_regs_s hw;
 
        if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
                /*  Possibly we should fail if these checks report true */
@@ -381,26 +387,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
        }
        if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
                return NULL;    /* no room in ide_hwifs[] */
-       if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
-           hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
-               hw_regs_t hw;
-
-               memset(&hw, 0, sizeof(hw));
-#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT
-               ide_std_init_ports(&hw, base, ctl | 2);
-#else
-               ide_init_hwif_ports(&hw, base, ctl | 2, NULL);
-#endif
-               memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-               hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-       }
-       hwif->chipset = d->chipset ? d->chipset : ide_pci;
+
+       memset(&hw, 0, sizeof(hw));
+       hw.irq = hwif->irq ? hwif->irq : irq;
+       hw.dev = &dev->dev;
+       hw.chipset = d->chipset ? d->chipset : ide_pci;
+       ide_std_init_ports(&hw, base, ctl | 2);
+
+       if (hwif->io_ports[IDE_DATA_OFFSET] == base &&
+           hwif->io_ports[IDE_CONTROL_OFFSET] == (ctl | 2))
+               oldnoprobe = hwif->noprobe;
+
+       ide_init_port_hw(hwif, &hw);
+
+       hwif->noprobe = oldnoprobe;
+
        hwif->pci_dev = dev;
        hwif->cds = d;
        hwif->channel = port;
 
-       if (!hwif->irq)
-               hwif->irq = irq;
        if (mate) {
                hwif->mate = mate;
                mate->mate = hwif;
@@ -535,12 +540,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
                if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
                        continue;
 
-               /* setup proper ancestral information */
-               hwif->gendev.parent = &dev->dev;
-
                *(idx + port) = hwif->index;
 
-               
                if (d->init_iops)
                        d->init_iops(hwif);
 
@@ -551,8 +552,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
                    (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
                        hwif->irq = port ? 15 : 14;
 
-               hwif->fixup = d->fixup;
-
                hwif->host_flags = d->host_flags;
                hwif->pio_mask = d->pio_mask;
 
@@ -699,105 +698,3 @@ out:
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
-
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-/*
- *     Module interfaces
- */
-
-static int pre_init = 1;               /* Before first ordered IDE scan */
-static LIST_HEAD(ide_pci_drivers);
-
-/*
- *     __ide_pci_register_driver       -       attach IDE driver
- *     @driver: pci driver
- *     @module: owner module of the driver
- *
- *     Registers a driver with the IDE layer. The IDE layer arranges that
- *     boot time setup is done in the expected device order and then
- *     hands the controllers off to the core PCI code to do the rest of
- *     the work.
- *
- *     Returns are the same as for pci_register_driver
- */
-
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
-                             const char *mod_name)
-{
-       if (!pre_init)
-               return __pci_register_driver(driver, module, mod_name);
-       driver->driver.owner = module;
-       list_add_tail(&driver->node, &ide_pci_drivers);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
-
-/**
- *     ide_scan_pcidev         -       find an IDE driver for a device
- *     @dev: PCI device to check
- *
- *     Look for an IDE driver to handle the device we are considering.
- *     This is only used during boot up to get the ordering correct. After
- *     boot up the pci layer takes over the job.
- */
-
-static int __init ide_scan_pcidev(struct pci_dev *dev)
-{
-       struct list_head *l;
-       struct pci_driver *d;
-
-       list_for_each(l, &ide_pci_drivers) {
-               d = list_entry(l, struct pci_driver, node);
-               if (d->id_table) {
-                       const struct pci_device_id *id =
-                               pci_match_id(d->id_table, dev);
-
-                       if (id != NULL && d->probe(dev, id) >= 0) {
-                               dev->driver = d;
-                               pci_dev_get(dev);
-                               return 1;
-                       }
-               }
-       }
-       return 0;
-}
-
-/**
- *     ide_scan_pcibus         -       perform the initial IDE driver scan
- *     @scan_direction: set for reverse order scanning
- *
- *     Perform the initial bus rather than driver ordered scan of the
- *     PCI drivers. After this all IDE pci handling becomes standard
- *     module ordering not traditionally ordered.
- */
-       
-void __init ide_scan_pcibus (int scan_direction)
-{
-       struct pci_dev *dev = NULL;
-       struct pci_driver *d;
-       struct list_head *l, *n;
-
-       pre_init = 0;
-       if (!scan_direction)
-               while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
-                       ide_scan_pcidev(dev);
-       else
-               while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
-                                                    dev)))
-                       ide_scan_pcidev(dev);
-
-       /*
-        *      Hand the drivers over to the PCI layer now we
-        *      are post init.
-        */
-
-       list_for_each_safe(l, n, &ide_pci_drivers) {
-               list_del(l);
-               d = list_entry(l, struct pci_driver, node);
-               if (__pci_register_driver(d, d->driver.owner,
-                                         d->driver.mod_name))
-                       printk(KERN_ERR "%s: failed to register %s driver\n",
-                                       __FUNCTION__, d->driver.mod_name);
-       }
-}
-#endif
index 90dc75be3418c91f0baab414181577f62ded696f..511e4321c6b6220916a37b05c81d490bce9f4a47 100644 (file)
@@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
 
 static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
 
+static int __match_ne(struct device *dev, void *data)
+{
+       struct unit_directory *ud;
+       struct node_entry *ne = (struct node_entry *)data;
+
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       return ud->ne == ne;
+}
+
 static void nodemgr_remove_uds(struct node_entry *ne)
 {
        struct device *dev;
-       struct unit_directory *tmp, *ud;
-
-       /* Iteration over nodemgr_ud_class.devices has to be protected by
-        * nodemgr_ud_class.sem, but device_unregister() will eventually
-        * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
-        * release the semaphore, and then unregister the ud. Since this code
-        * may be called from other contexts besides the knodemgrds, protect the
-        * gap after release of the semaphore by nodemgr_serialize_remove_uds.
+       struct unit_directory *ud;
+
+       /* Use class_find device to iterate the devices. Since this code
+        * may be called from other contexts besides the knodemgrds,
+        * protect it by nodemgr_serialize_remove_uds.
         */
        mutex_lock(&nodemgr_serialize_remove_uds);
        for (;;) {
-               ud = NULL;
-               down(&nodemgr_ud_class.sem);
-               list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-                       tmp = container_of(dev, struct unit_directory,
-                                          unit_dev);
-                       if (tmp->ne == ne) {
-                               ud = tmp;
-                               break;
-                       }
-               }
-               up(&nodemgr_ud_class.sem);
-               if (ud == NULL)
+               dev = class_find_device(&nodemgr_ud_class, ne, __match_ne);
+               if (!dev)
                        break;
+               ud = container_of(dev, struct unit_directory, unit_dev);
+               put_device(dev);
                device_unregister(&ud->unit_dev);
                device_unregister(&ud->device);
        }
@@ -882,45 +880,66 @@ fail_alloc:
        return NULL;
 }
 
+static int __match_ne_guid(struct device *dev, void *data)
+{
+       struct node_entry *ne;
+       u64 *guid = (u64 *)data;
+
+       ne = container_of(dev, struct node_entry, node_dev);
+       return ne->guid == *guid;
+}
 
 static struct node_entry *find_entry_by_guid(u64 guid)
 {
        struct device *dev;
-       struct node_entry *ne, *ret_ne = NULL;
-
-       down(&nodemgr_ne_class.sem);
-       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-               ne = container_of(dev, struct node_entry, node_dev);
+       struct node_entry *ne;
 
-               if (ne->guid == guid) {
-                       ret_ne = ne;
-                       break;
-               }
-       }
-       up(&nodemgr_ne_class.sem);
+       dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid);
+       if (!dev)
+               return NULL;
+       ne = container_of(dev, struct node_entry, node_dev);
+       put_device(dev);
 
-       return ret_ne;
+       return ne;
 }
 
+struct match_nodeid_param {
+       struct hpsb_host *host;
+       nodeid_t nodeid;
+};
+
+static int __match_ne_nodeid(struct device *dev, void *data)
+{
+       int found = 0;
+       struct node_entry *ne;
+       struct match_nodeid_param *param = (struct match_nodeid_param *)data;
+
+       if (!dev)
+               goto ret;
+       ne = container_of(dev, struct node_entry, node_dev);
+       if (ne->host == param->host && ne->nodeid == param->nodeid)
+               found = 1;
+ret:
+       return found;
+}
 
 static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
                                               nodeid_t nodeid)
 {
        struct device *dev;
-       struct node_entry *ne, *ret_ne = NULL;
+       struct node_entry *ne;
+       struct match_nodeid_param param;
 
-       down(&nodemgr_ne_class.sem);
-       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-               ne = container_of(dev, struct node_entry, node_dev);
+       param.host = host;
+       param.nodeid = nodeid;
 
-               if (ne->host == host && ne->nodeid == nodeid) {
-                       ret_ne = ne;
-                       break;
-               }
-       }
-       up(&nodemgr_ne_class.sem);
+       dev = class_find_device(&nodemgr_ne_class, &param, __match_ne_nodeid);
+       if (!dev)
+               return NULL;
+       ne = container_of(dev, struct node_entry, node_dev);
+       put_device(dev);
 
-       return ret_ne;
+       return ne;
 }
 
 
@@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
        }
 }
 
-
-static void nodemgr_suspend_ne(struct node_entry *ne)
+static int __nodemgr_driver_suspend(struct device *dev, void *data)
 {
-       struct device *dev;
        struct unit_directory *ud;
        struct device_driver *drv;
+       struct node_entry *ne = (struct node_entry *)data;
        int error;
 
-       HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-                  NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       if (ud->ne == ne) {
+               drv = get_driver(ud->device.driver);
+               if (drv) {
+                       error = 1; /* release if suspend is not implemented */
+                       if (drv->suspend) {
+                               down(&ud->device.sem);
+                               error = drv->suspend(&ud->device, PMSG_SUSPEND);
+                               up(&ud->device.sem);
+                       }
+                       if (error)
+                               device_release_driver(&ud->device);
+                       put_driver(drv);
+               }
+       }
 
-       ne->in_limbo = 1;
-       WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
+       return 0;
+}
 
-       down(&nodemgr_ud_class.sem);
-       list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-               ud = container_of(dev, struct unit_directory, unit_dev);
-               if (ud->ne != ne)
-                       continue;
+static int __nodemgr_driver_resume(struct device *dev, void *data)
+{
+       struct unit_directory *ud;
+       struct device_driver *drv;
+       struct node_entry *ne = (struct node_entry *)data;
 
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       if (ud->ne == ne) {
                drv = get_driver(ud->device.driver);
-               if (!drv)
-                       continue;
-
-               error = 1; /* release if suspend is not implemented */
-               if (drv->suspend) {
-                       down(&ud->device.sem);
-                       error = drv->suspend(&ud->device, PMSG_SUSPEND);
-                       up(&ud->device.sem);
+               if (drv) {
+                       if (drv->resume) {
+                               down(&ud->device.sem);
+                               drv->resume(&ud->device);
+                               up(&ud->device.sem);
+                       }
+                       put_driver(drv);
                }
-               if (error)
-                       device_release_driver(&ud->device);
-               put_driver(drv);
        }
-       up(&nodemgr_ud_class.sem);
-}
 
+       return 0;
+}
 
-static void nodemgr_resume_ne(struct node_entry *ne)
+static void nodemgr_suspend_ne(struct node_entry *ne)
 {
-       struct device *dev;
-       struct unit_directory *ud;
-       struct device_driver *drv;
+       HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+                  NODE_BUS_ARGS(ne->host, ne->nodeid),
+                  (unsigned long long)ne->guid);
 
-       ne->in_limbo = 0;
-       device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
+       ne->in_limbo = 1;
+       WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
 
-       down(&nodemgr_ud_class.sem);
-       list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-               ud = container_of(dev, struct unit_directory, unit_dev);
-               if (ud->ne != ne)
-                       continue;
+       class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend);
+}
 
-               drv = get_driver(ud->device.driver);
-               if (!drv)
-                       continue;
 
-               if (drv->resume) {
-                       down(&ud->device.sem);
-                       drv->resume(&ud->device);
-                       up(&ud->device.sem);
-               }
-               put_driver(drv);
-       }
-       up(&nodemgr_ud_class.sem);
+static void nodemgr_resume_ne(struct node_entry *ne)
+{
+       ne->in_limbo = 0;
+       device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
 
+       class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume);
        HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
                   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
 }
 
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
+static int __nodemgr_update_pdrv(struct device *dev, void *data)
 {
-       struct device *dev;
        struct unit_directory *ud;
        struct device_driver *drv;
        struct hpsb_protocol_driver *pdrv;
+       struct node_entry *ne = (struct node_entry *)data;
        int error;
 
-       down(&nodemgr_ud_class.sem);
-       list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-               ud = container_of(dev, struct unit_directory, unit_dev);
-               if (ud->ne != ne)
-                       continue;
-
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       if (ud->ne == ne) {
                drv = get_driver(ud->device.driver);
-               if (!drv)
-                       continue;
-
-               error = 0;
-               pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
-               if (pdrv->update) {
-                       down(&ud->device.sem);
-                       error = pdrv->update(ud);
-                       up(&ud->device.sem);
+               if (drv) {
+                       error = 0;
+                       pdrv = container_of(drv, struct hpsb_protocol_driver,
+                                           driver);
+                       if (pdrv->update) {
+                               down(&ud->device.sem);
+                               error = pdrv->update(ud);
+                               up(&ud->device.sem);
+                       }
+                       if (error)
+                               device_release_driver(&ud->device);
+                       put_driver(drv);
                }
-               if (error)
-                       device_release_driver(&ud->device);
-               put_driver(drv);
        }
-       up(&nodemgr_ud_class.sem);
+
+       return 0;
+}
+
+static void nodemgr_update_pdrv(struct node_entry *ne)
+{
+       class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv);
 }
 
 
@@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
        put_device(dev);
 }
 
+struct probe_param {
+       struct host_info *hi;
+       int generation;
+};
+
+static int __nodemgr_node_probe(struct device *dev, void *data)
+{
+       struct probe_param *param = (struct probe_param *)data;
+       struct node_entry *ne;
+
+       ne = container_of(dev, struct node_entry, node_dev);
+       if (!ne->needs_probe)
+               nodemgr_probe_ne(param->hi, ne, param->generation);
+       if (ne->needs_probe)
+               nodemgr_probe_ne(param->hi, ne, param->generation);
+       return 0;
+}
 
 static void nodemgr_node_probe(struct host_info *hi, int generation)
 {
        struct hpsb_host *host = hi->host;
-       struct device *dev;
-       struct node_entry *ne;
+       struct probe_param param;
 
+       param.hi = hi;
+       param.generation = generation;
        /* Do some processing of the nodes we've probed. This pulls them
         * into the sysfs layer if needed, and can result in processing of
         * unit-directories, or just updating the node and it's
@@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
         * while probes are time-consuming. (Well, those probes need some
         * improvement...) */
 
-       down(&nodemgr_ne_class.sem);
-       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-               ne = container_of(dev, struct node_entry, node_dev);
-               if (!ne->needs_probe)
-                       nodemgr_probe_ne(hi, ne, generation);
-       }
-       list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-               ne = container_of(dev, struct node_entry, node_dev);
-               if (ne->needs_probe)
-                       nodemgr_probe_ne(hi, ne, generation);
-       }
-       up(&nodemgr_ne_class.sem);
-
+       class_for_each_device(&nodemgr_ne_class, &param, __nodemgr_node_probe);
 
        /* If we had a bus reset while we were scanning the bus, it is
         * possible that we did not probe all nodes.  In that case, we
@@ -1757,6 +1784,22 @@ exit:
        return 0;
 }
 
+struct host_iter_param {
+       void *data;
+       int (*cb)(struct hpsb_host *, void *);
+};
+
+static int __nodemgr_for_each_host(struct device *dev, void *data)
+{
+       struct hpsb_host *host;
+       struct host_iter_param *hip = (struct host_iter_param *)data;
+       int error = 0;
+
+       host = container_of(dev, struct hpsb_host, host_dev);
+       error = hip->cb(host, hip->data);
+
+       return error;
+}
 /**
  * nodemgr_for_each_host - call a function for each IEEE 1394 host
  * @data: an address to supply to the callback
@@ -1771,18 +1814,13 @@ exit:
  */
 int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
 {
-       struct device *dev;
-       struct hpsb_host *host;
-       int error = 0;
-
-       down(&hpsb_host_class.sem);
-       list_for_each_entry(dev, &hpsb_host_class.devices, node) {
-               host = container_of(dev, struct hpsb_host, host_dev);
+       struct host_iter_param hip;
+       int error;
 
-               if ((error = cb(host, data)))
-                       break;
-       }
-       up(&hpsb_host_class.sem);
+       hip.cb = cb;
+       hip.data = data;
+       error = class_for_each_device(&hpsb_host_class, &hip,
+                                     __nodemgr_for_each_host);
 
        return error;
 }
index b83d254bc86edec605f1f78ba510a59566f2baef..1eda11abeb1e0b3cb912cb7e0c9bcac196b79810 100644 (file)
@@ -1963,6 +1963,12 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
        lu->sdev = sdev;
        sdev->allow_restart = 1;
 
+       /*
+        * Update the dma alignment (minimum alignment requirements for
+        * start and end of DMA transfers) to be a sector
+        */
+       blk_queue_update_dma_alignment(sdev->request_queue, 511);
+
        if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
                sdev->inquiry_len = 36;
        return 0;
index 2e39236d189ff88e3d919629c9f756e61a7d4d6b..c0150147d3478d5c539d2e3e320e1722c4b408ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2006 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2004-2007 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 
 #include <linux/completion.h>
 #include <linux/dma-mapping.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/random.h>
 #include <linux/rbtree.h>
 #include <linux/spinlock.h>
+#include <linux/sysfs.h>
 #include <linux/workqueue.h>
 
 #include <rdma/ib_cache.h>
@@ -78,17 +80,94 @@ static struct ib_cm {
        struct workqueue_struct *wq;
 } cm;
 
+/* Counter indexes ordered by attribute ID */
+enum {
+       CM_REQ_COUNTER,
+       CM_MRA_COUNTER,
+       CM_REJ_COUNTER,
+       CM_REP_COUNTER,
+       CM_RTU_COUNTER,
+       CM_DREQ_COUNTER,
+       CM_DREP_COUNTER,
+       CM_SIDR_REQ_COUNTER,
+       CM_SIDR_REP_COUNTER,
+       CM_LAP_COUNTER,
+       CM_APR_COUNTER,
+       CM_ATTR_COUNT,
+       CM_ATTR_ID_OFFSET = 0x0010,
+};
+
+enum {
+       CM_XMIT,
+       CM_XMIT_RETRIES,
+       CM_RECV,
+       CM_RECV_DUPLICATES,
+       CM_COUNTER_GROUPS
+};
+
+static char const counter_group_names[CM_COUNTER_GROUPS]
+                                    [sizeof("cm_rx_duplicates")] = {
+       "cm_tx_msgs", "cm_tx_retries",
+       "cm_rx_msgs", "cm_rx_duplicates"
+};
+
+struct cm_counter_group {
+       struct kobject obj;
+       atomic_long_t counter[CM_ATTR_COUNT];
+};
+
+struct cm_counter_attribute {
+       struct attribute attr;
+       int index;
+};
+
+#define CM_COUNTER_ATTR(_name, _index) \
+struct cm_counter_attribute cm_##_name##_counter_attr = { \
+       .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
+       .index = _index \
+}
+
+static CM_COUNTER_ATTR(req, CM_REQ_COUNTER);
+static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER);
+static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER);
+static CM_COUNTER_ATTR(rep, CM_REP_COUNTER);
+static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER);
+static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER);
+static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER);
+static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER);
+static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER);
+static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER);
+static CM_COUNTER_ATTR(apr, CM_APR_COUNTER);
+
+static struct attribute *cm_counter_default_attrs[] = {
+       &cm_req_counter_attr.attr,
+       &cm_mra_counter_attr.attr,
+       &cm_rej_counter_attr.attr,
+       &cm_rep_counter_attr.attr,
+       &cm_rtu_counter_attr.attr,
+       &cm_dreq_counter_attr.attr,
+       &cm_drep_counter_attr.attr,
+       &cm_sidr_req_counter_attr.attr,
+       &cm_sidr_rep_counter_attr.attr,
+       &cm_lap_counter_attr.attr,
+       &cm_apr_counter_attr.attr,
+       NULL
+};
+
 struct cm_port {
        struct cm_device *cm_dev;
        struct ib_mad_agent *mad_agent;
+       struct kobject port_obj;
        u8 port_num;
+       struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
 };
 
 struct cm_device {
        struct list_head list;
        struct ib_device *device;
+       struct kobject dev_obj;
        u8 ack_delay;
-       struct cm_port port[0];
+       struct cm_port *port[0];
 };
 
 struct cm_av {
@@ -278,7 +357,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
        list_for_each_entry(cm_dev, &cm.device_list, list) {
                if (!ib_find_cached_gid(cm_dev->device, &path->sgid,
                                        &p, NULL)) {
-                       port = &cm_dev->port[p-1];
+                       port = cm_dev->port[p-1];
                        break;
                }
        }
@@ -1270,6 +1349,9 @@ static void cm_dup_req_handler(struct cm_work *work,
        struct ib_mad_send_buf *msg = NULL;
        int ret;
 
+       atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                       counter[CM_REQ_COUNTER]);
+
        /* Quick state check to discard duplicate REQs. */
        if (cm_id_priv->id.state == IB_CM_REQ_RCVD)
                return;
@@ -1616,6 +1698,8 @@ static void cm_dup_rep_handler(struct cm_work *work)
        if (!cm_id_priv)
                return;
 
+       atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                       counter[CM_REP_COUNTER]);
        ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
        if (ret)
                goto deref;
@@ -1781,6 +1865,8 @@ static int cm_rtu_handler(struct cm_work *work)
        if (cm_id_priv->id.state != IB_CM_REP_SENT &&
            cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
                spin_unlock_irq(&cm_id_priv->lock);
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_RTU_COUNTER]);
                goto out;
        }
        cm_id_priv->id.state = IB_CM_ESTABLISHED;
@@ -1958,6 +2044,8 @@ static int cm_dreq_handler(struct cm_work *work)
        cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
                                   dreq_msg->local_comm_id);
        if (!cm_id_priv) {
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_DREQ_COUNTER]);
                cm_issue_drep(work->port, work->mad_recv_wc);
                return -EINVAL;
        }
@@ -1977,6 +2065,8 @@ static int cm_dreq_handler(struct cm_work *work)
        case IB_CM_MRA_REP_RCVD:
                break;
        case IB_CM_TIMEWAIT:
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_DREQ_COUNTER]);
                if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
                        goto unlock;
 
@@ -1988,6 +2078,10 @@ static int cm_dreq_handler(struct cm_work *work)
                if (ib_post_send_mad(msg, NULL))
                        cm_free_msg(msg);
                goto deref;
+       case IB_CM_DREQ_RCVD:
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_DREQ_COUNTER]);
+               goto unlock;
        default:
                goto unlock;
        }
@@ -2339,10 +2433,20 @@ static int cm_mra_handler(struct cm_work *work)
                if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER ||
                    cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
                    ib_modify_mad(cm_id_priv->av.port->mad_agent,
-                                 cm_id_priv->msg, timeout))
+                                 cm_id_priv->msg, timeout)) {
+                       if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
+                               atomic_long_inc(&work->port->
+                                               counter_group[CM_RECV_DUPLICATES].
+                                               counter[CM_MRA_COUNTER]);
                        goto out;
+               }
                cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
                break;
+       case IB_CM_MRA_REQ_RCVD:
+       case IB_CM_MRA_REP_RCVD:
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_MRA_COUNTER]);
+               /* fall through */
        default:
                goto out;
        }
@@ -2502,6 +2606,8 @@ static int cm_lap_handler(struct cm_work *work)
        case IB_CM_LAP_IDLE:
                break;
        case IB_CM_MRA_LAP_SENT:
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_LAP_COUNTER]);
                if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
                        goto unlock;
 
@@ -2515,6 +2621,10 @@ static int cm_lap_handler(struct cm_work *work)
                if (ib_post_send_mad(msg, NULL))
                        cm_free_msg(msg);
                goto deref;
+       case IB_CM_LAP_RCVD:
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_LAP_COUNTER]);
+               goto unlock;
        default:
                goto unlock;
        }
@@ -2796,6 +2906,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
        cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
        if (cur_cm_id_priv) {
                spin_unlock_irq(&cm.lock);
+               atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+                               counter[CM_SIDR_REQ_COUNTER]);
                goto out; /* Duplicate message. */
        }
        cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
@@ -2990,6 +3102,27 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent,
                            struct ib_mad_send_wc *mad_send_wc)
 {
        struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
+       struct cm_port *port;
+       u16 attr_index;
+
+       port = mad_agent->context;
+       attr_index = be16_to_cpu(((struct ib_mad_hdr *)
+                                 msg->mad)->attr_id) - CM_ATTR_ID_OFFSET;
+
+       /*
+        * If the send was in response to a received message (context[0] is not
+        * set to a cm_id), and is not a REJ, then it is a send that was
+        * manually retried.
+        */
+       if (!msg->context[0] && (attr_index != CM_REJ_COUNTER))
+               msg->retries = 1;
+
+       atomic_long_add(1 + msg->retries,
+                       &port->counter_group[CM_XMIT].counter[attr_index]);
+       if (msg->retries)
+               atomic_long_add(msg->retries,
+                               &port->counter_group[CM_XMIT_RETRIES].
+                               counter[attr_index]);
 
        switch (mad_send_wc->status) {
        case IB_WC_SUCCESS:
@@ -3148,8 +3281,10 @@ EXPORT_SYMBOL(ib_cm_notify);
 static void cm_recv_handler(struct ib_mad_agent *mad_agent,
                            struct ib_mad_recv_wc *mad_recv_wc)
 {
+       struct cm_port *port = mad_agent->context;
        struct cm_work *work;
        enum ib_cm_event_type event;
+       u16 attr_id;
        int paths = 0;
 
        switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
@@ -3194,6 +3329,10 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
                return;
        }
 
+       attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
+       atomic_long_inc(&port->counter_group[CM_RECV].
+                       counter[attr_id - CM_ATTR_ID_OFFSET]);
+
        work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths,
                       GFP_KERNEL);
        if (!work) {
@@ -3204,7 +3343,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
        INIT_DELAYED_WORK(&work->work, cm_work_handler);
        work->cm_event.event = event;
        work->mad_recv_wc = mad_recv_wc;
-       work->port = (struct cm_port *)mad_agent->context;
+       work->port = port;
        queue_delayed_work(cm.wq, &work->work, 0);
 }
 
@@ -3379,6 +3518,108 @@ static void cm_get_ack_delay(struct cm_device *cm_dev)
                cm_dev->ack_delay = attr.local_ca_ack_delay;
 }
 
+static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
+                              char *buf)
+{
+       struct cm_counter_group *group;
+       struct cm_counter_attribute *cm_attr;
+
+       group = container_of(obj, struct cm_counter_group, obj);
+       cm_attr = container_of(attr, struct cm_counter_attribute, attr);
+
+       return sprintf(buf, "%ld\n",
+                      atomic_long_read(&group->counter[cm_attr->index]));
+}
+
+static struct sysfs_ops cm_counter_ops = {
+       .show = cm_show_counter
+};
+
+static struct kobj_type cm_counter_obj_type = {
+       .sysfs_ops = &cm_counter_ops,
+       .default_attrs = cm_counter_default_attrs
+};
+
+static void cm_release_port_obj(struct kobject *obj)
+{
+       struct cm_port *cm_port;
+
+       printk(KERN_ERR "free cm port\n");
+
+       cm_port = container_of(obj, struct cm_port, port_obj);
+       kfree(cm_port);
+}
+
+static struct kobj_type cm_port_obj_type = {
+       .release = cm_release_port_obj
+};
+
+static void cm_release_dev_obj(struct kobject *obj)
+{
+       struct cm_device *cm_dev;
+
+       printk(KERN_ERR "free cm dev\n");
+
+       cm_dev = container_of(obj, struct cm_device, dev_obj);
+       kfree(cm_dev);
+}
+
+static struct kobj_type cm_dev_obj_type = {
+       .release = cm_release_dev_obj
+};
+
+struct class cm_class = {
+       .name    = "infiniband_cm",
+};
+EXPORT_SYMBOL(cm_class);
+
+static void cm_remove_fs_obj(struct kobject *obj)
+{
+       kobject_put(obj->parent);
+       kobject_put(obj);
+}
+
+static int cm_create_port_fs(struct cm_port *port)
+{
+       int i, ret;
+
+       ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type,
+                                  kobject_get(&port->cm_dev->dev_obj),
+                                  "%d", port->port_num);
+       if (ret) {
+               kfree(port);
+               return ret;
+       }
+
+       for (i = 0; i < CM_COUNTER_GROUPS; i++) {
+               ret = kobject_init_and_add(&port->counter_group[i].obj,
+                                          &cm_counter_obj_type,
+                                          kobject_get(&port->port_obj),
+                                          "%s", counter_group_names[i]);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+
+error:
+       while (i--)
+               cm_remove_fs_obj(&port->counter_group[i].obj);
+       cm_remove_fs_obj(&port->port_obj);
+       return ret;
+
+}
+
+static void cm_remove_port_fs(struct cm_port *port)
+{
+       int i;
+
+       for (i = 0; i < CM_COUNTER_GROUPS; i++)
+               cm_remove_fs_obj(&port->counter_group[i].obj);
+
+       cm_remove_fs_obj(&port->port_obj);
+}
+
 static void cm_add_one(struct ib_device *device)
 {
        struct cm_device *cm_dev;
@@ -3397,7 +3638,7 @@ static void cm_add_one(struct ib_device *device)
        if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
                return;
 
-       cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
+       cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) *
                         device->phys_port_cnt, GFP_KERNEL);
        if (!cm_dev)
                return;
@@ -3405,11 +3646,27 @@ static void cm_add_one(struct ib_device *device)
        cm_dev->device = device;
        cm_get_ack_delay(cm_dev);
 
+       ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type,
+                                  &cm_class.subsys.kobj, "%s", device->name);
+       if (ret) {
+               kfree(cm_dev);
+               return;
+       }
+
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= device->phys_port_cnt; i++) {
-               port = &cm_dev->port[i-1];
+               port = kzalloc(sizeof *port, GFP_KERNEL);
+               if (!port)
+                       goto error1;
+
+               cm_dev->port[i-1] = port;
                port->cm_dev = cm_dev;
                port->port_num = i;
+
+               ret = cm_create_port_fs(port);
+               if (ret)
+                       goto error1;
+
                port->mad_agent = ib_register_mad_agent(device, i,
                                                        IB_QPT_GSI,
                                                        &reg_req,
@@ -3418,11 +3675,11 @@ static void cm_add_one(struct ib_device *device)
                                                        cm_recv_handler,
                                                        port);
                if (IS_ERR(port->mad_agent))
-                       goto error1;
+                       goto error2;
 
                ret = ib_modify_port(device, i, 0, &port_modify);
                if (ret)
-                       goto error2;
+                       goto error3;
        }
        ib_set_client_data(device, &cm_client, cm_dev);
 
@@ -3431,17 +3688,20 @@ static void cm_add_one(struct ib_device *device)
        write_unlock_irqrestore(&cm.device_lock, flags);
        return;
 
-error2:
+error3:
        ib_unregister_mad_agent(port->mad_agent);
+error2:
+       cm_remove_port_fs(port);
 error1:
        port_modify.set_port_cap_mask = 0;
        port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
        while (--i) {
-               port = &cm_dev->port[i-1];
+               port = cm_dev->port[i-1];
                ib_modify_port(device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
+               cm_remove_port_fs(port);
        }
-       kfree(cm_dev);
+       cm_remove_fs_obj(&cm_dev->dev_obj);
 }
 
 static void cm_remove_one(struct ib_device *device)
@@ -3463,11 +3723,12 @@ static void cm_remove_one(struct ib_device *device)
        write_unlock_irqrestore(&cm.device_lock, flags);
 
        for (i = 1; i <= device->phys_port_cnt; i++) {
-               port = &cm_dev->port[i-1];
+               port = cm_dev->port[i-1];
                ib_modify_port(device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
+               cm_remove_port_fs(port);
        }
-       kfree(cm_dev);
+       cm_remove_fs_obj(&cm_dev->dev_obj);
 }
 
 static int __init ib_cm_init(void)
@@ -3488,17 +3749,25 @@ static int __init ib_cm_init(void)
        idr_pre_get(&cm.local_id_table, GFP_KERNEL);
        INIT_LIST_HEAD(&cm.timewait_list);
 
-       cm.wq = create_workqueue("ib_cm");
-       if (!cm.wq)
+       ret = class_register(&cm_class);
+       if (ret)
                return -ENOMEM;
 
+       cm.wq = create_workqueue("ib_cm");
+       if (!cm.wq) {
+               ret = -ENOMEM;
+               goto error1;
+       }
+
        ret = ib_register_client(&cm_client);
        if (ret)
-               goto error;
+               goto error2;
 
        return 0;
-error:
+error2:
        destroy_workqueue(cm.wq);
+error1:
+       class_unregister(&cm_class);
        return ret;
 }
 
@@ -3519,6 +3788,7 @@ static void __exit ib_cm_cleanup(void)
        }
 
        ib_unregister_client(&cm_client);
+       class_unregister(&cm_class);
        idr_destroy(&cm.local_id_table);
 }
 
index 0751697ef984a87e7f688238a10760127fd7383f..637efead97a0ac67e79c0e3f6019449b474b0cd9 100644 (file)
@@ -488,7 +488,8 @@ void rdma_destroy_qp(struct rdma_cm_id *id)
 }
 EXPORT_SYMBOL(rdma_destroy_qp);
 
-static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
+static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
+                            struct rdma_conn_param *conn_param)
 {
        struct ib_qp_attr qp_attr;
        int qp_attr_mask, ret;
@@ -514,13 +515,16 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
        if (ret)
                goto out;
 
+       if (conn_param)
+               qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
        ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
 out:
        mutex_unlock(&id_priv->qp_mutex);
        return ret;
 }
 
-static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
+static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
+                            struct rdma_conn_param *conn_param)
 {
        struct ib_qp_attr qp_attr;
        int qp_attr_mask, ret;
@@ -536,6 +540,8 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
        if (ret)
                goto out;
 
+       if (conn_param)
+               qp_attr.max_rd_atomic = conn_param->initiator_depth;
        ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
 out:
        mutex_unlock(&id_priv->qp_mutex);
@@ -866,11 +872,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
 {
        int ret;
 
-       ret = cma_modify_qp_rtr(id_priv);
+       ret = cma_modify_qp_rtr(id_priv, NULL);
        if (ret)
                goto reject;
 
-       ret = cma_modify_qp_rts(id_priv);
+       ret = cma_modify_qp_rts(id_priv, NULL);
        if (ret)
                goto reject;
 
@@ -1122,8 +1128,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
        cm_id->cm_handler = cma_ib_handler;
 
        ret = conn_id->id.event_handler(&conn_id->id, &event);
-       if (!ret)
+       if (!ret) {
+               cma_enable_remove(conn_id);
                goto out;
+       }
 
        /* Destroy the CM ID by returning a non-zero value. */
        conn_id->cm_id.ib = NULL;
@@ -1262,6 +1270,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
        struct net_device *dev = NULL;
        struct rdma_cm_event event;
        int ret;
+       struct ib_device_attr attr;
 
        listen_id = cm_id->context;
        if (cma_disable_remove(listen_id, CMA_LISTEN))
@@ -1311,10 +1320,19 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
        sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
        *sin = iw_event->remote_addr;
 
+       ret = ib_query_device(conn_id->id.device, &attr);
+       if (ret) {
+               cma_enable_remove(conn_id);
+               rdma_destroy_id(new_cm_id);
+               goto out;
+       }
+
        memset(&event, 0, sizeof event);
        event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
        event.param.conn.private_data = iw_event->private_data;
        event.param.conn.private_data_len = iw_event->private_data_len;
+       event.param.conn.initiator_depth = attr.max_qp_init_rd_atom;
+       event.param.conn.responder_resources = attr.max_qp_rd_atom;
        ret = conn_id->id.event_handler(&conn_id->id, &event);
        if (ret) {
                /* User wants to destroy the CM ID */
@@ -2272,7 +2290,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
        sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
        cm_id->remote_addr = *sin;
 
-       ret = cma_modify_qp_rtr(id_priv);
+       ret = cma_modify_qp_rtr(id_priv, conn_param);
        if (ret)
                goto out;
 
@@ -2335,25 +2353,15 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
                         struct rdma_conn_param *conn_param)
 {
        struct ib_cm_rep_param rep;
-       struct ib_qp_attr qp_attr;
-       int qp_attr_mask, ret;
-
-       if (id_priv->id.qp) {
-               ret = cma_modify_qp_rtr(id_priv);
-               if (ret)
-                       goto out;
+       int ret;
 
-               qp_attr.qp_state = IB_QPS_RTS;
-               ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr,
-                                        &qp_attr_mask);
-               if (ret)
-                       goto out;
+       ret = cma_modify_qp_rtr(id_priv, conn_param);
+       if (ret)
+               goto out;
 
-               qp_attr.max_rd_atomic = conn_param->initiator_depth;
-               ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
-               if (ret)
-                       goto out;
-       }
+       ret = cma_modify_qp_rts(id_priv, conn_param);
+       if (ret)
+               goto out;
 
        memset(&rep, 0, sizeof rep);
        rep.qp_num = id_priv->qp_num;
@@ -2378,7 +2386,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
        struct iw_cm_conn_param iw_param;
        int ret;
 
-       ret = cma_modify_qp_rtr(id_priv);
+       ret = cma_modify_qp_rtr(id_priv, conn_param);
        if (ret)
                return ret;
 
@@ -2598,11 +2606,9 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
                /* IPv6 address is an SA assigned MGID. */
                memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
        } else {
-               ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
+               ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
                if (id_priv->id.ps == RDMA_PS_UDP)
                        mc_map[7] = 0x01;       /* Use RDMA CM signature */
-               mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8;
-               mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr);
                *mgid = *(union ib_gid *) (mc_map + 4);
        }
 }
index e8d5f6b6499823893a38c263dd8428a214813d59..6c7aa59794d4ebb248f8e16fe789e7bdace6f81d 100644 (file)
@@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool,
 static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
 {
        int                 ret;
-       struct ib_pool_fmr *fmr;
+       struct ib_pool_fmr *fmr, *next;
        LIST_HEAD(unmap_list);
        LIST_HEAD(fmr_list);
 
@@ -158,6 +158,20 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
 #endif
        }
 
+       /*
+        * The free_list may hold FMRs that have been put there
+        * because they haven't reached the max_remap count.
+        * Invalidate their mapping as well.
+        */
+       list_for_each_entry_safe(fmr, next, &pool->free_list, list) {
+               if (fmr->remap_count == 0)
+                       continue;
+               hlist_del_init(&fmr->cache_node);
+               fmr->remap_count = 0;
+               list_add_tail(&fmr->fmr->list, &fmr_list);
+               list_move(&fmr->list, &unmap_list);
+       }
+
        list_splice(&pool->dirty_list, &unmap_list);
        INIT_LIST_HEAD(&pool->dirty_list);
        pool->dirty_len = 0;
@@ -182,8 +196,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
        struct ib_fmr_pool *pool = pool_ptr;
 
        do {
-               if (pool->dirty_len >= pool->dirty_watermark ||
-                   atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
+               if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
                        ib_fmr_batch_release(pool);
 
                        atomic_inc(&pool->flush_ser);
@@ -194,8 +207,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
                }
 
                set_current_state(TASK_INTERRUPTIBLE);
-               if (pool->dirty_len < pool->dirty_watermark &&
-                   atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
+               if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
                    !kthread_should_stop())
                        schedule();
                __set_current_state(TASK_RUNNING);
@@ -369,11 +381,6 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
 
        i = 0;
        list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) {
-               if (fmr->remap_count) {
-                       INIT_LIST_HEAD(&fmr_list);
-                       list_add_tail(&fmr->fmr->list, &fmr_list);
-                       ib_unmap_fmr(&fmr_list);
-               }
                ib_dealloc_fmr(fmr->fmr);
                list_del(&fmr->list);
                kfree(fmr);
@@ -511,8 +518,10 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
                        list_add_tail(&fmr->list, &pool->free_list);
                } else {
                        list_add_tail(&fmr->list, &pool->dirty_list);
-                       ++pool->dirty_len;
-                       wake_up_process(pool->thread);
+                       if (++pool->dirty_len >= pool->dirty_watermark) {
+                               atomic_inc(&pool->req_ser);
+                               wake_up_process(pool->thread);
+                       }
                }
        }
 
index 6f4287716ab1b63516e89197282925e30e86a279..fbe16d5250a49bf587864234203aed6b43dbd494 100644 (file)
@@ -701,7 +701,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
        }
 
        /* Check to post send on QP or process locally */
-       if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD)
+       if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD &&
+           smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD)
                goto out;
 
        local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -752,8 +753,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
                port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
                                            mad_agent_priv->agent.port_num);
                if (port_priv) {
-                       mad_priv->mad.mad.mad_hdr.tid =
-                               ((struct ib_mad *)smp)->mad_hdr.tid;
+                       memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad));
                        recv_mad_agent = find_mad_agent(port_priv,
                                                        &mad_priv->mad.mad);
                }
@@ -1100,7 +1100,9 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
                mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid;
                /* Timeout will be updated after send completes */
                mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms);
-               mad_send_wr->retries = send_buf->retries;
+               mad_send_wr->max_retries = send_buf->retries;
+               mad_send_wr->retries_left = send_buf->retries;
+               send_buf->retries = 0;
                /* Reference for work request to QP + response */
                mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
                mad_send_wr->status = IB_WC_SUCCESS;
@@ -1931,15 +1933,6 @@ local:
        if (port_priv->device->process_mad) {
                int ret;
 
-               if (!response) {
-                       printk(KERN_ERR PFX "No memory for response MAD\n");
-                       /*
-                        * Is it better to assume that
-                        * it wouldn't be processed ?
-                        */
-                       goto out;
-               }
-
                ret = port_priv->device->process_mad(port_priv->device, 0,
                                                     port_priv->port_num,
                                                     wc, &recv->grh,
@@ -2282,8 +2275,6 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
 
        /* Empty wait list to prevent receives from finding a request */
        list_splice_init(&mad_agent_priv->wait_list, &cancel_list);
-       /* Empty local completion list as well */
-       list_splice_init(&mad_agent_priv->local_list, &cancel_list);
        spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 
        /* Report all cancelled requests */
@@ -2445,9 +2436,12 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr)
 {
        int ret;
 
-       if (!mad_send_wr->retries--)
+       if (!mad_send_wr->retries_left)
                return -ETIMEDOUT;
 
+       mad_send_wr->retries_left--;
+       mad_send_wr->send_buf.retries++;
+
        mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
 
        if (mad_send_wr->mad_agent_priv->agent.rmpp_version) {
index 9be5cc00a3a95e320e3a58330eeecb954d6a4b91..8b75010016ecab62ed591d4d687bca6ed9a4ca38 100644 (file)
@@ -131,7 +131,8 @@ struct ib_mad_send_wr_private {
        struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
        __be64 tid;
        unsigned long timeout;
-       int retries;
+       int max_retries;
+       int retries_left;
        int retry;
        int refcount;
        enum ib_wc_status status;
index d43bc62005b3d151607f212d2a66f90003b8639f..a5e2a310f312f6dfc447a83704e2e169f0348cb5 100644 (file)
@@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
 
        if (seg_num > mad_send_wr->last_ack) {
                adjust_last_ack(mad_send_wr, seg_num);
-               mad_send_wr->retries = mad_send_wr->send_buf.retries;
+               mad_send_wr->retries_left = mad_send_wr->max_retries;
        }
        mad_send_wr->newwin = newwin;
        if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
index 1bc1fe60528296251f7ddf86ba85f20dcb65a8d4..107f170c57cdb12cc05786551b21d29b01ecc6de 100644 (file)
@@ -73,11 +73,20 @@ struct mcast_device {
 };
 
 enum mcast_state {
-       MCAST_IDLE,
        MCAST_JOINING,
        MCAST_MEMBER,
+       MCAST_ERROR,
+};
+
+enum mcast_group_state {
+       MCAST_IDLE,
        MCAST_BUSY,
-       MCAST_ERROR
+       MCAST_GROUP_ERROR,
+       MCAST_PKEY_EVENT
+};
+
+enum {
+       MCAST_INVALID_PKEY_INDEX = 0xFFFF
 };
 
 struct mcast_member;
@@ -93,9 +102,10 @@ struct mcast_group {
        struct mcast_member     *last_join;
        int                     members[3];
        atomic_t                refcount;
-       enum mcast_state        state;
+       enum mcast_group_state  state;
        struct ib_sa_query      *query;
        int                     query_id;
+       u16                     pkey_index;
 };
 
 struct mcast_member {
@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
 static void process_group_error(struct mcast_group *group)
 {
        struct mcast_member *member;
-       int ret;
+       int ret = 0;
+       u16 pkey_index;
+
+       if (group->state == MCAST_PKEY_EVENT)
+               ret = ib_find_pkey(group->port->dev->device,
+                                  group->port->port_num,
+                                  be16_to_cpu(group->rec.pkey), &pkey_index);
 
        spin_lock_irq(&group->lock);
+       if (group->state == MCAST_PKEY_EVENT && !ret &&
+           group->pkey_index == pkey_index)
+               goto out;
+
        while (!list_empty(&group->active_list)) {
                member = list_entry(group->active_list.next,
                                    struct mcast_member, list);
@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
        }
 
        group->rec.join_state = 0;
+out:
        group->state = MCAST_BUSY;
        spin_unlock_irq(&group->lock);
 }
@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
 retest:
        spin_lock_irq(&group->lock);
        while (!list_empty(&group->pending_list) ||
-              (group->state == MCAST_ERROR)) {
+              (group->state != MCAST_BUSY)) {
 
-               if (group->state == MCAST_ERROR) {
+               if (group->state != MCAST_BUSY) {
                        spin_unlock_irq(&group->lock);
                        process_group_error(group);
                        goto retest;
@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
                         void *context)
 {
        struct mcast_group *group = context;
+       u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
 
        if (status)
                process_join_error(group, status);
        else {
+               ib_find_pkey(group->port->dev->device, group->port->port_num,
+                            be16_to_cpu(rec->pkey), &pkey_index);
+
                spin_lock_irq(&group->port->lock);
                group->rec = *rec;
+               if (group->state == MCAST_BUSY &&
+                   group->pkey_index == MCAST_INVALID_PKEY_INDEX)
+                       group->pkey_index = pkey_index;
                if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
                        rb_erase(&group->node, &group->port->table);
                        mcast_insert(group->port, group, 1);
@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
 
        group->port = port;
        group->rec.mgid = *mgid;
+       group->pkey_index = MCAST_INVALID_PKEY_INDEX;
        INIT_LIST_HEAD(&group->pending_list);
        INIT_LIST_HEAD(&group->active_list);
        INIT_WORK(&group->work, mcast_work_handler);
@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
 }
 EXPORT_SYMBOL(ib_init_ah_from_mcmember);
 
-static void mcast_groups_lost(struct mcast_port *port)
+static void mcast_groups_event(struct mcast_port *port,
+                              enum mcast_group_state state)
 {
        struct mcast_group *group;
        struct rb_node *node;
@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
                        atomic_inc(&group->refcount);
                        queue_work(mcast_wq, &group->work);
                }
-               group->state = MCAST_ERROR;
+               if (group->state != MCAST_GROUP_ERROR)
+                       group->state = state;
                spin_unlock(&group->lock);
        }
        spin_unlock_irqrestore(&port->lock, flags);
@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
                                struct ib_event *event)
 {
        struct mcast_device *dev;
+       int index;
 
        dev = container_of(handler, struct mcast_device, event_handler);
+       index = event->element.port_num - dev->start_port;
 
        switch (event->event) {
        case IB_EVENT_PORT_ERR:
        case IB_EVENT_LID_CHANGE:
        case IB_EVENT_SM_CHANGE:
        case IB_EVENT_CLIENT_REREGISTER:
-               mcast_groups_lost(&dev->port[event->element.port_num -
-                                            dev->start_port]);
+               mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
+               break;
+       case IB_EVENT_PKEY_CHANGE:
+               mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
                break;
        default:
                break;
index 1cfc2984434fe517e99c1004fe3fc6b5176c49bc..aff96bac49b4c9e126a1e4b6fd309bc4b3b256aa 100644 (file)
@@ -59,7 +59,8 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
                                              u8 node_type, int port_num);
 
 /*
- * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
+ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
+ * via process_mad
  */
 static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
                                                  struct ib_device *device)
@@ -71,4 +72,19 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
                (smp->hop_ptr == smp->hop_cnt + 1)) ?
                IB_SMI_HANDLE : IB_SMI_DISCARD);
 }
+
+/*
+ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
+ * via process_mad
+ */
+static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp,
+                                                  struct ib_device *device)
+{
+       /* C14-13:3 -- We're at the end of the DR segment of path */
+       /* C14-13:4 -- Hop Pointer == 0 -> give to SM */
+       return ((device->process_mad &&
+               ib_get_smp_direction(smp) &&
+               !smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD);
+}
+
 #endif /* __SMI_H_ */
index 3d40506813250e6ba429e8e71224a9e077ce032e..c864ef70fdf9633db07e00723aeceb47bd0cba4a 100644 (file)
@@ -508,19 +508,10 @@ static int add_port(struct ib_device *device, int port_num)
 
        p->ibdev      = device;
        p->port_num   = port_num;
-       p->kobj.ktype = &port_type;
 
-       p->kobj.parent = kobject_get(&device->ports_parent);
-       if (!p->kobj.parent) {
-               ret = -EBUSY;
-               goto err;
-       }
-
-       ret = kobject_set_name(&p->kobj, "%d", port_num);
-       if (ret)
-               goto err_put;
-
-       ret = kobject_register(&p->kobj);
+       ret = kobject_init_and_add(&p->kobj, &port_type,
+                                  kobject_get(device->ports_parent),
+                                  "%d", port_num);
        if (ret)
                goto err_put;
 
@@ -549,6 +540,7 @@ static int add_port(struct ib_device *device, int port_num)
 
        list_add_tail(&p->kobj.entry, &device->port_list);
 
+       kobject_uevent(&p->kobj, KOBJ_ADD);
        return 0;
 
 err_free_pkey:
@@ -570,9 +562,7 @@ err_remove_pma:
        sysfs_remove_group(&p->kobj, &pma_group);
 
 err_put:
-       kobject_put(&device->ports_parent);
-
-err:
+       kobject_put(device->ports_parent);
        kfree(p);
        return ret;
 }
@@ -694,16 +684,9 @@ int ib_device_register_sysfs(struct ib_device *device)
                        goto err_unregister;
        }
 
-       device->ports_parent.parent = kobject_get(&class_dev->kobj);
-       if (!device->ports_parent.parent) {
-               ret = -EBUSY;
-               goto err_unregister;
-       }
-       ret = kobject_set_name(&device->ports_parent, "ports");
-       if (ret)
-               goto err_put;
-       ret = kobject_register(&device->ports_parent);
-       if (ret)
+       device->ports_parent = kobject_create_and_add("ports",
+                                       kobject_get(&class_dev->kobj));
+       if (!device->ports_parent)
                goto err_put;
 
        if (device->node_type == RDMA_NODE_IB_SWITCH) {
@@ -731,7 +714,7 @@ err_put:
                        sysfs_remove_group(p, &pma_group);
                        sysfs_remove_group(p, &port->pkey_group);
                        sysfs_remove_group(p, &port->gid_group);
-                       kobject_unregister(p);
+                       kobject_put(p);
                }
        }
 
@@ -755,10 +738,10 @@ void ib_device_unregister_sysfs(struct ib_device *device)
                sysfs_remove_group(p, &pma_group);
                sysfs_remove_group(p, &port->pkey_group);
                sysfs_remove_group(p, &port->gid_group);
-               kobject_unregister(p);
+               kobject_put(p);
        }
 
-       kobject_unregister(&device->ports_parent);
+       kobject_put(device->ports_parent);
        class_device_unregister(&device->class_dev);
 }
 
index 424983f5b1ee249f5685907d6f695c03c20d4c4a..4291ab42a5b9c60fb78eeecdf09087b9af10f58b 100644 (file)
@@ -106,6 +106,9 @@ enum {
        IB_UCM_MAX_DEVICES = 32
 };
 
+/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */
+extern struct class cm_class;
+
 #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)
 
 static void ib_ucm_add_one(struct ib_device *device);
@@ -1199,7 +1202,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static void ib_ucm_release_class_dev(struct class_device *class_dev)
+static void ucm_release_class_dev(struct class_device *class_dev)
 {
        struct ib_ucm_device *dev;
 
@@ -1217,11 +1220,6 @@ static const struct file_operations ucm_fops = {
        .poll    = ib_ucm_poll,
 };
 
-static struct class ucm_class = {
-       .name    = "infiniband_cm",
-       .release = ib_ucm_release_class_dev
-};
-
 static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
 {
        struct ib_ucm_device *dev;
@@ -1257,9 +1255,10 @@ static void ib_ucm_add_one(struct ib_device *device)
        if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1))
                goto err;
 
-       ucm_dev->class_dev.class = &ucm_class;
+       ucm_dev->class_dev.class = &cm_class;
        ucm_dev->class_dev.dev = device->dma_device;
        ucm_dev->class_dev.devt = ucm_dev->dev.dev;
+       ucm_dev->class_dev.release = ucm_release_class_dev;
        snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d",
                 ucm_dev->devnum);
        if (class_device_register(&ucm_dev->class_dev))
@@ -1306,40 +1305,34 @@ static int __init ib_ucm_init(void)
                                     "infiniband_cm");
        if (ret) {
                printk(KERN_ERR "ucm: couldn't register device number\n");
-               goto err;
+               goto error1;
        }
 
-       ret = class_register(&ucm_class);
-       if (ret) {
-               printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n");
-               goto err_chrdev;
-       }
-
-       ret = class_create_file(&ucm_class, &class_attr_abi_version);
+       ret = class_create_file(&cm_class, &class_attr_abi_version);
        if (ret) {
                printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
-               goto err_class;
+               goto error2;
        }
 
        ret = ib_register_client(&ucm_client);
        if (ret) {
                printk(KERN_ERR "ucm: couldn't register client\n");
-               goto err_class;
+               goto error3;
        }
        return 0;
 
-err_class:
-       class_unregister(&ucm_class);
-err_chrdev:
+error3:
+       class_remove_file(&cm_class, &class_attr_abi_version);
+error2:
        unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
-err:
+error1:
        return ret;
 }
 
 static void __exit ib_ucm_cleanup(void)
 {
        ib_unregister_client(&ucm_client);
-       class_unregister(&ucm_class);
+       class_remove_file(&cm_class, &class_attr_abi_version);
        unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
        idr_destroy(&ctx_id_table);
 }
index 90d675ad9ec8af51acaea573a58ea91f8ebc40de..15937eb38aae42f440a71ae6f8240ffc16c057bb 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <linux/completion.h>
+#include <linux/file.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/idr.h>
@@ -991,6 +992,96 @@ out:
        return ret;
 }
 
+static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
+{
+       /* Acquire mutex's based on pointer comparison to prevent deadlock. */
+       if (file1 < file2) {
+               mutex_lock(&file1->mut);
+               mutex_lock(&file2->mut);
+       } else {
+               mutex_lock(&file2->mut);
+               mutex_lock(&file1->mut);
+       }
+}
+
+static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
+{
+       if (file1 < file2) {
+               mutex_unlock(&file2->mut);
+               mutex_unlock(&file1->mut);
+       } else {
+               mutex_unlock(&file1->mut);
+               mutex_unlock(&file2->mut);
+       }
+}
+
+static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
+{
+       struct ucma_event *uevent, *tmp;
+
+       list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
+               if (uevent->ctx == ctx)
+                       list_move_tail(&uevent->list, &file->event_list);
+}
+
+static ssize_t ucma_migrate_id(struct ucma_file *new_file,
+                              const char __user *inbuf,
+                              int in_len, int out_len)
+{
+       struct rdma_ucm_migrate_id cmd;
+       struct rdma_ucm_migrate_resp resp;
+       struct ucma_context *ctx;
+       struct file *filp;
+       struct ucma_file *cur_file;
+       int ret = 0;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       /* Get current fd to protect against it being closed */
+       filp = fget(cmd.fd);
+       if (!filp)
+               return -ENOENT;
+
+       /* Validate current fd and prevent destruction of id. */
+       ctx = ucma_get_ctx(filp->private_data, cmd.id);
+       if (IS_ERR(ctx)) {
+               ret = PTR_ERR(ctx);
+               goto file_put;
+       }
+
+       cur_file = ctx->file;
+       if (cur_file == new_file) {
+               resp.events_reported = ctx->events_reported;
+               goto response;
+       }
+
+       /*
+        * Migrate events between fd's, maintaining order, and avoiding new
+        * events being added before existing events.
+        */
+       ucma_lock_files(cur_file, new_file);
+       mutex_lock(&mut);
+
+       list_move_tail(&ctx->list, &new_file->ctx_list);
+       ucma_move_events(ctx, new_file);
+       ctx->file = new_file;
+       resp.events_reported = ctx->events_reported;
+
+       mutex_unlock(&mut);
+       ucma_unlock_files(cur_file, new_file);
+
+response:
+       if (copy_to_user((void __user *)(unsigned long)cmd.response,
+                        &resp, sizeof(resp)))
+               ret = -EFAULT;
+
+       ucma_put_ctx(ctx);
+file_put:
+       fput(filp);
+       return ret;
+}
+
 static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
                                   const char __user *inbuf,
                                   int in_len, int out_len) = {
@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
        [RDMA_USER_CM_CMD_NOTIFY]       = ucma_notify,
        [RDMA_USER_CM_CMD_JOIN_MCAST]   = ucma_join_multicast,
        [RDMA_USER_CM_CMD_LEAVE_MCAST]  = ucma_leave_multicast,
+       [RDMA_USER_CM_CMD_MIGRATE_ID]   = ucma_migrate_id
 };
 
 static ssize_t ucma_write(struct file *filp, const char __user *buf,
index b53eac4611de387b6eb8f831108810205204d5c1..4e915104ac4ca38e70569896a746c5686fba28ac 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Cisco. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -42,7 +43,7 @@
 #include <linux/cdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/poll.h>
-#include <linux/rwsem.h>
+#include <linux/mutex.h>
 #include <linux/kref.h>
 #include <linux/compat.h>
 
@@ -94,7 +95,7 @@ struct ib_umad_port {
        struct class_device   *sm_class_dev;
        struct semaphore       sm_sem;
 
-       struct rw_semaphore    mutex;
+       struct mutex           file_mutex;
        struct list_head       file_list;
 
        struct ib_device      *ib_dev;
@@ -110,11 +111,11 @@ struct ib_umad_device {
 };
 
 struct ib_umad_file {
+       struct mutex            mutex;
        struct ib_umad_port    *port;
        struct list_head        recv_list;
        struct list_head        send_list;
        struct list_head        port_list;
-       spinlock_t              recv_lock;
        spinlock_t              send_lock;
        wait_queue_head_t       recv_wait;
        struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
@@ -156,7 +157,7 @@ static int hdr_size(struct ib_umad_file *file)
                sizeof (struct ib_user_mad_hdr_old);
 }
 
-/* caller must hold port->mutex at least for reading */
+/* caller must hold file->mutex */
 static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
 {
        return file->agents_dead ? NULL : file->agent[id];
@@ -168,32 +169,30 @@ static int queue_packet(struct ib_umad_file *file,
 {
        int ret = 1;
 
-       down_read(&file->port->mutex);
+       mutex_lock(&file->mutex);
 
        for (packet->mad.hdr.id = 0;
             packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
             packet->mad.hdr.id++)
                if (agent == __get_agent(file, packet->mad.hdr.id)) {
-                       spin_lock_irq(&file->recv_lock);
                        list_add_tail(&packet->list, &file->recv_list);
-                       spin_unlock_irq(&file->recv_lock);
                        wake_up_interruptible(&file->recv_wait);
                        ret = 0;
                        break;
                }
 
-       up_read(&file->port->mutex);
+       mutex_unlock(&file->mutex);
 
        return ret;
 }
 
 static void dequeue_send(struct ib_umad_file *file,
                         struct ib_umad_packet *packet)
- {
+{
        spin_lock_irq(&file->send_lock);
        list_del(&packet->list);
        spin_unlock_irq(&file->send_lock);
- }
+}
 
 static void send_handler(struct ib_mad_agent *agent,
                         struct ib_mad_send_wc *send_wc)
@@ -341,10 +340,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
        if (count < hdr_size(file))
                return -EINVAL;
 
-       spin_lock_irq(&file->recv_lock);
+       mutex_lock(&file->mutex);
 
        while (list_empty(&file->recv_list)) {
-               spin_unlock_irq(&file->recv_lock);
+               mutex_unlock(&file->mutex);
 
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
@@ -353,13 +352,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
                                             !list_empty(&file->recv_list)))
                        return -ERESTARTSYS;
 
-               spin_lock_irq(&file->recv_lock);
+               mutex_lock(&file->mutex);
        }
 
        packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
        list_del(&packet->list);
 
-       spin_unlock_irq(&file->recv_lock);
+       mutex_unlock(&file->mutex);
 
        if (packet->recv_wc)
                ret = copy_recv_mad(file, buf, packet, count);
@@ -368,9 +367,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
 
        if (ret < 0) {
                /* Requeue packet */
-               spin_lock_irq(&file->recv_lock);
+               mutex_lock(&file->mutex);
                list_add(&packet->list, &file->recv_list);
-               spin_unlock_irq(&file->recv_lock);
+               mutex_unlock(&file->mutex);
        } else {
                if (packet->recv_wc)
                        ib_free_recv_mad(packet->recv_wc);
@@ -481,7 +480,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
                goto err;
        }
 
-       down_read(&file->port->mutex);
+       mutex_lock(&file->mutex);
 
        agent = __get_agent(file, packet->mad.hdr.id);
        if (!agent) {
@@ -577,7 +576,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
        if (ret)
                goto err_send;
 
-       up_read(&file->port->mutex);
+       mutex_unlock(&file->mutex);
        return count;
 
 err_send:
@@ -587,7 +586,7 @@ err_msg:
 err_ah:
        ib_destroy_ah(ah);
 err_up:
-       up_read(&file->port->mutex);
+       mutex_unlock(&file->mutex);
 err:
        kfree(packet);
        return ret;
@@ -613,11 +612,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
 {
        struct ib_user_mad_reg_req ureq;
        struct ib_mad_reg_req req;
-       struct ib_mad_agent *agent;
+       struct ib_mad_agent *agent = NULL;
        int agent_id;
        int ret;
 
-       down_write(&file->port->mutex);
+       mutex_lock(&file->port->file_mutex);
+       mutex_lock(&file->mutex);
 
        if (!file->port->ib_dev) {
                ret = -EPIPE;
@@ -666,13 +666,13 @@ found:
                                      send_handler, recv_handler, file);
        if (IS_ERR(agent)) {
                ret = PTR_ERR(agent);
+               agent = NULL;
                goto out;
        }
 
        if (put_user(agent_id,
                     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
                ret = -EFAULT;
-               ib_unregister_mad_agent(agent);
                goto out;
        }
 
@@ -690,7 +690,13 @@ found:
        ret = 0;
 
 out:
-       up_write(&file->port->mutex);
+       mutex_unlock(&file->mutex);
+
+       if (ret && agent)
+               ib_unregister_mad_agent(agent);
+
+       mutex_unlock(&file->port->file_mutex);
+
        return ret;
 }
 
@@ -703,7 +709,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
        if (get_user(id, arg))
                return -EFAULT;
 
-       down_write(&file->port->mutex);
+       mutex_lock(&file->port->file_mutex);
+       mutex_lock(&file->mutex);
 
        if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
                ret = -EINVAL;
@@ -714,11 +721,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
        file->agent[id] = NULL;
 
 out:
-       up_write(&file->port->mutex);
+       mutex_unlock(&file->mutex);
 
        if (agent)
                ib_unregister_mad_agent(agent);
 
+       mutex_unlock(&file->port->file_mutex);
+
        return ret;
 }
 
@@ -726,12 +735,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file)
 {
        int ret = 0;
 
-       down_write(&file->port->mutex);
+       mutex_lock(&file->mutex);
        if (file->already_used)
                ret = -EINVAL;
        else
                file->use_pkey_index = 1;
-       up_write(&file->port->mutex);
+       mutex_unlock(&file->mutex);
 
        return ret;
 }
@@ -783,7 +792,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
        if (!port)
                return -ENXIO;
 
-       down_write(&port->mutex);
+       mutex_lock(&port->file_mutex);
 
        if (!port->ib_dev) {
                ret = -ENXIO;
@@ -797,7 +806,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
                goto out;
        }
 
-       spin_lock_init(&file->recv_lock);
+       mutex_init(&file->mutex);
        spin_lock_init(&file->send_lock);
        INIT_LIST_HEAD(&file->recv_list);
        INIT_LIST_HEAD(&file->send_list);
@@ -809,7 +818,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
        list_add_tail(&file->port_list, &port->file_list);
 
 out:
-       up_write(&port->mutex);
+       mutex_unlock(&port->file_mutex);
        return ret;
 }
 
@@ -821,7 +830,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
        int already_dead;
        int i;
 
-       down_write(&file->port->mutex);
+       mutex_lock(&file->port->file_mutex);
+       mutex_lock(&file->mutex);
 
        already_dead = file->agents_dead;
        file->agents_dead = 1;
@@ -834,14 +844,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
 
        list_del(&file->port_list);
 
-       downgrade_write(&file->port->mutex);
+       mutex_unlock(&file->mutex);
 
        if (!already_dead)
                for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
                        if (file->agent[i])
                                ib_unregister_mad_agent(file->agent[i]);
 
-       up_read(&file->port->mutex);
+       mutex_unlock(&file->port->file_mutex);
 
        kfree(file);
        kref_put(&dev->ref, ib_umad_release_dev);
@@ -914,10 +924,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
        };
        int ret = 0;
 
-       down_write(&port->mutex);
+       mutex_lock(&port->file_mutex);
        if (port->ib_dev)
                ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
-       up_write(&port->mutex);
+       mutex_unlock(&port->file_mutex);
 
        up(&port->sm_sem);
 
@@ -981,7 +991,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
        port->ib_dev   = device;
        port->port_num = port_num;
        init_MUTEX(&port->sm_sem);
-       init_rwsem(&port->mutex);
+       mutex_init(&port->file_mutex);
        INIT_LIST_HEAD(&port->file_list);
 
        port->dev = cdev_alloc();
@@ -1052,6 +1062,7 @@ err_cdev:
 static void ib_umad_kill_port(struct ib_umad_port *port)
 {
        struct ib_umad_file *file;
+       int already_dead;
        int id;
 
        class_set_devdata(port->class_dev,    NULL);
@@ -1067,42 +1078,22 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
        umad_port[port->dev_num] = NULL;
        spin_unlock(&port_lock);
 
-       down_write(&port->mutex);
+       mutex_lock(&port->file_mutex);
 
        port->ib_dev = NULL;
 
-       /*
-        * Now go through the list of files attached to this port and
-        * unregister all of their MAD agents.  We need to hold
-        * port->mutex while doing this to avoid racing with
-        * ib_umad_close(), but we can't hold the mutex for writing
-        * while calling ib_unregister_mad_agent(), since that might
-        * deadlock by calling back into queue_packet().  So we
-        * downgrade our lock to a read lock, and then drop and
-        * reacquire the write lock for the next iteration.
-        *
-        * We do list_del_init() on the file's list_head so that the
-        * list_del in ib_umad_close() is still OK, even after the
-        * file is removed from the list.
-        */
-       while (!list_empty(&port->file_list)) {
-               file = list_entry(port->file_list.next, struct ib_umad_file,
-                                 port_list);
-
+       list_for_each_entry(file, &port->file_list, port_list) {
+               mutex_lock(&file->mutex);
+               already_dead = file->agents_dead;
                file->agents_dead = 1;
-               list_del_init(&file->port_list);
-
-               downgrade_write(&port->mutex);
+               mutex_unlock(&file->mutex);
 
                for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
                        if (file->agent[id])
                                ib_unregister_mad_agent(file->agent[id]);
-
-               up_read(&port->mutex);
-               down_write(&port->mutex);
        }
 
-       up_write(&port->mutex);
+       mutex_unlock(&port->file_mutex);
 
        clear_bit(port->dev_num, dev_map);
 }
index eec6a30840ca0a16763105b67702c00f3e7c6836..03c5ff62889a25c60b01e54afcefc44f89c503de 100644 (file)
@@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
        setup.size = 1UL << cq->size_log2;
        setup.credits = 65535;
        setup.credit_thres = 1;
-       if (rdev_p->t3cdev_p->type == T3B)
+       if (rdev_p->t3cdev_p->type != T3A)
                setup.ovfl_mode = 0;
        else
                setup.ovfl_mode = 1;
@@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
 {
        u32 i, nr_wqe, copy_len;
        u8 *copy_data;
-       u8 wr_len, utx_len;     /* lenght in 8 byte flit */
+       u8 wr_len, utx_len;     /* length in 8 byte flit */
        enum t3_wr_flags flag;
        __be64 *wqe;
        u64 utx_cmd;
index c84d4ac49355b3bc2f3d41f265b4e75c8cb568cf..969d4d928455b237ac97deda8f7a1e1cf38b63df 100644 (file)
@@ -315,7 +315,7 @@ struct t3_rdma_init_wr {
        __be32 ird;
        __be64 qp_dma_addr;     /* 7 */
        __be32 qp_dma_size;     /* 8 */
-       u32 irs;
+       __be32 irs;
 };
 
 struct t3_genbit {
@@ -324,7 +324,8 @@ struct t3_genbit {
 };
 
 enum rdma_init_wr_flags {
-       RECVS_POSTED = 1,
+       RECVS_POSTED = (1<<0),
+       PRIV_QP = (1<<1),
 };
 
 union t3_wr {
index 20ba372dd182268bb5614c8c62f4dd9992445fb3..f8cb0fe748c37d61f798076c465b062c3e05e73b 100644 (file)
@@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
             status2errno(rpl->status));
        connect_reply_upcall(ep, status2errno(rpl->status));
        state_set(&ep->com, DEAD);
-       if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status))
+       if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status))
                release_tid(ep->com.tdev, GET_TID(rpl), NULL);
        cxgb3_free_atid(ep->com.tdev, ep->atid);
        dst_release(ep->dst);
@@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
        skb_trim(skb, sizeof(struct cpl_tid_release));
        skb_get(skb);
 
-       if (tdev->type == T3B)
+       if (tdev->type != T3A)
                release_tid(tdev, hwtid, skb);
        else {
                struct cpl_pass_accept_rpl *rpl;
index a6c2c4ba29e69244b896849b376698a5c2ab7cd2..73bfd1656f86434bae2c36215a6d073607a07a7c 100644 (file)
@@ -122,6 +122,13 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
                *total_size += buffer_list[i].size;
                if (i > 0)
                        mask |= buffer_list[i].addr;
+               else
+                       mask |= buffer_list[i].addr & PAGE_MASK;
+               if (i != num_phys_buf - 1)
+                       mask |= buffer_list[i].addr + buffer_list[i].size;
+               else
+                       mask |= (buffer_list[i].addr + buffer_list[i].size +
+                               PAGE_SIZE - 1) & PAGE_MASK;
        }
 
        if (*total_size > 0xFFFFFFFFULL)
index b5436ca92e68cdb8d09063861ecd7af6bb89eeb5..df1838f8f94d9b59b700fa1212fb622b5f1e3811 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -645,7 +646,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
        if (err)
                goto err;
 
-       if (udata && t3b_device(rhp)) {
+       if (udata && !t3a_device(rhp)) {
                uresp.pbl_addr = (mhp->attr.pbl_addr -
                                 rhp->rdev.rnic_info.pbl_base) >> 3;
                PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__,
@@ -1053,7 +1054,9 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
        struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
 
        PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+       rtnl_lock();
        lldev->ethtool_ops->get_drvinfo(lldev, &info);
+       rtnl_unlock();
        return sprintf(buf, "%s\n", info.fw_version);
 }
 
@@ -1065,7 +1068,9 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
        struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
 
        PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+       rtnl_lock();
        lldev->ethtool_ops->get_drvinfo(lldev, &info);
+       rtnl_unlock();
        return sprintf(buf, "%s\n", info.driver);
 }
 
index dd89b6b91f9c3f90ec564c7f95f3bdc9090aea75..ea2cdd73dd850d780307c4d530ba685500eaa264 100644 (file)
@@ -208,36 +208,19 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
 static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
                                struct ib_recv_wr *wr)
 {
-       int i, err = 0;
-       u32 pbl_addr[4];
-       u8 page_size[4];
+       int i;
        if (wr->num_sge > T3_MAX_SGE)
                return -EINVAL;
-       err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr,
-                              page_size);
-       if (err)
-               return err;
-       wqe->recv.pagesz[0] = page_size[0];
-       wqe->recv.pagesz[1] = page_size[1];
-       wqe->recv.pagesz[2] = page_size[2];
-       wqe->recv.pagesz[3] = page_size[3];
        wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);
        for (i = 0; i < wr->num_sge; i++) {
                wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);
                wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);
-
-               /* to in the WQE == the offset into the page */
-               wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) %
-                               (1UL << (12 + page_size[i])));
-
-               /* pbl_addr is the adapters address in the PBL */
-               wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);
+               wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);
        }
        for (; i < T3_MAX_SGE; i++) {
                wqe->recv.sgl[i].stag = 0;
                wqe->recv.sgl[i].len = 0;
                wqe->recv.sgl[i].to = 0;
-               wqe->recv.pbl_addr[i] = 0;
        }
        return 0;
 }
@@ -659,6 +642,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
        cxio_flush_rq(&qhp->wq, &rchp->cq, count);
        spin_unlock(&qhp->lock);
        spin_unlock_irqrestore(&rchp->lock, *flag);
+       (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
 
        /* locking heirarchy: cq lock first, then qp lock. */
        spin_lock_irqsave(&schp->lock, *flag);
@@ -668,6 +652,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
        cxio_flush_sq(&qhp->wq, &schp->cq, count);
        spin_unlock(&qhp->lock);
        spin_unlock_irqrestore(&schp->lock, *flag);
+       (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
 
        /* deref */
        if (atomic_dec_and_test(&qhp->refcnt))
@@ -678,7 +663,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 
 static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 {
-       if (t3b_device(qhp->rhp))
+       if (qhp->ibqp.uobject)
                cxio_set_wq_in_error(&qhp->wq);
        else
                __flush_qp(qhp, flag);
@@ -732,6 +717,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
        init_attr.qp_dma_addr = qhp->wq.dma_addr;
        init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
        init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
+       init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
        init_attr.irs = qhp->ep->rcv_seq;
        PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
             "flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
@@ -847,10 +833,11 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
                                disconnect = 1;
                                ep = qhp->ep;
                        }
+                       flush_qp(qhp, &flag);
                        break;
                case IWCH_QP_STATE_TERMINATE:
                        qhp->attr.state = IWCH_QP_STATE_TERMINATE;
-                       if (t3b_device(qhp->rhp))
+                       if (qhp->ibqp.uobject)
                                cxio_set_wq_in_error(&qhp->wq);
                        if (!internal)
                                terminate = 1;
index f7782c882ab4c9cfb9c6c49ee116efb1107f639d..194c1c30cf63c4d2fd16a75619e6d4ec2aac4dc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  IBM eServer eHCA Infiniband device driver for Linux on POWER
  *
- *  adress vector functions
+ *  address vector functions
  *
  *  Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
  *           Khadija Souissi <souissik@de.ibm.com>
index 74d2b72a11d833851f72da709b328eafe6373272..f281d16040f5ac794e14e28820b37e537a7db51f 100644 (file)
@@ -94,7 +94,11 @@ struct ehca_sma_attr {
 
 struct ehca_sport {
        struct ib_cq *ibcq_aqp1;
-       struct ib_qp *ibqp_aqp1;
+       struct ib_qp *ibqp_sqp[2];
+       /* lock to serialze modify_qp() calls for sqp in normal
+        * and irq path (when event PORT_ACTIVE is received first time)
+        */
+       spinlock_t mod_sqp_lock;
        enum ib_port_state port_state;
        struct ehca_sma_attr saved_attr;
 };
@@ -141,6 +145,14 @@ enum ehca_ext_qp_type {
        EQPT_SRQ       = 3,
 };
 
+/* struct to cache modify_qp()'s parms for GSI/SMI qp */
+struct ehca_mod_qp_parm {
+       int mask;
+       struct ib_qp_attr attr;
+};
+
+#define EHCA_MOD_QP_PARM_MAX 4
+
 struct ehca_qp {
        union {
                struct ib_qp ib_qp;
@@ -164,10 +176,18 @@ struct ehca_qp {
        struct ehca_cq *recv_cq;
        unsigned int sqerr_purgeflag;
        struct hlist_node list_entries;
+       /* array to cache modify_qp()'s parms for GSI/SMI qp */
+       struct ehca_mod_qp_parm *mod_qp_parm;
+       int mod_qp_parm_idx;
        /* mmap counter for resources mapped into user space */
        u32 mm_count_squeue;
        u32 mm_count_rqueue;
        u32 mm_count_galpa;
+       /* unsolicited ack circumvention */
+       int unsol_ack_circ;
+       int mtu_shift;
+       u32 message_count;
+       u32 packet_count;
 };
 
 #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
@@ -323,6 +343,7 @@ extern int ehca_port_act_time;
 extern int ehca_use_hp_mr;
 extern int ehca_scaling_code;
 extern int ehca_lock_hcalls;
+extern int ehca_nr_ports;
 
 struct ipzu_queue_resp {
        u32 qe_size;      /* queue entry size */
index 79c25f51c21e82997b1215bcea2935764cdc5773..0467c158d4a997f2254b52f06d5fe281ae5f88f6 100644 (file)
@@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
                } else {
                        if (h_ret != H_PAGE_REGISTERED) {
                                ehca_err(device, "Registration of page failed "
-                                        "ehca_cq=%p cq_num=%x h_ret=%li"
+                                        "ehca_cq=%p cq_num=%x h_ret=%li "
                                         "counter=%i act_pages=%i",
                                         my_cq, my_cq->cq_number,
                                         h_ret, counter, param.act_pages);
index 3f617b27b9543658d901dd1de36caca52371f9e5..863b34fa9ff9391c85fa1411d13ee4ce759436db 100644 (file)
@@ -62,6 +62,7 @@
 #define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
 #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
 #define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
+#define NEQE_SPECIFIC_EVENT    EHCA_BMASK_IBM(16, 23)
 
 #define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
 #define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
@@ -354,17 +355,34 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
 {
        u8 ec   = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
        u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
+       u8 spec_event;
+       struct ehca_sport *sport = &shca->sport[port - 1];
+       unsigned long flags;
 
        switch (ec) {
        case 0x30: /* port availability change */
                if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
-                       shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+                       int suppress_event;
+                       /* replay modify_qp for sqps */
+                       spin_lock_irqsave(&sport->mod_sqp_lock, flags);
+                       suppress_event = !sport->ibqp_sqp[IB_QPT_GSI];
+                       if (sport->ibqp_sqp[IB_QPT_SMI])
+                               ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]);
+                       if (!suppress_event)
+                               ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]);
+                       spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+
+                       /* AQP1 was destroyed, ignore this event */
+                       if (suppress_event)
+                               break;
+
+                       sport->port_state = IB_PORT_ACTIVE;
                        dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
                                            "is active");
                        ehca_query_sma_attr(shca, port,
-                                           &shca->sport[port - 1].saved_attr);
+                                           &sport->saved_attr);
                } else {
-                       shca->sport[port - 1].port_state = IB_PORT_DOWN;
+                       sport->port_state = IB_PORT_DOWN;
                        dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
                                            "is inactive");
                }
@@ -378,11 +396,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
                        ehca_warn(&shca->ib_device, "disruptive port "
                                  "%d configuration change", port);
 
-                       shca->sport[port - 1].port_state = IB_PORT_DOWN;
+                       sport->port_state = IB_PORT_DOWN;
                        dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
                                            "is inactive");
 
-                       shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+                       sport->port_state = IB_PORT_ACTIVE;
                        dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
                                            "is active");
                } else
@@ -394,6 +412,16 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
        case 0x33:  /* trace stopped */
                ehca_err(&shca->ib_device, "Traced stopped.");
                break;
+       case 0x34: /* util async event */
+               spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe);
+               if (spec_event == 0x80) /* client reregister required */
+                       dispatch_port_event(shca, port,
+                                           IB_EVENT_CLIENT_REREGISTER,
+                                           "client reregister req.");
+               else
+                       ehca_warn(&shca->ib_device, "Unknown util async "
+                                 "event %x on port %x", spec_event, port);
+               break;
        default:
                ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
                         ec, shca->ib_device.name);
index 5485799cdc8d633360b0174c350a42fa16956f0b..c469bfde270875521f91411df5ea51b4f4bed13e 100644 (file)
@@ -200,4 +200,6 @@ void ehca_free_fw_ctrlblock(void *ptr);
 #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
 #endif
 
+void ehca_recover_sqp(struct ib_qp *sqp);
+
 #endif
index 6a56d86a295105549c0a41205601f7b6c1fd8106..84c9b7b8669b0edc1833ff3c18c388d6feeb5999 100644 (file)
@@ -90,7 +90,8 @@ MODULE_PARM_DESC(hw_level,
                 "hardware level"
                 " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
 MODULE_PARM_DESC(nr_ports,
-                "number of connected ports (default: 2)");
+                "number of connected ports (-1: autodetect, 1: port one only, "
+                "2: two ports (default)");
 MODULE_PARM_DESC(use_hp_mr,
                 "high performance MRs (0: no (default), 1: yes)");
 MODULE_PARM_DESC(port_act_time,
@@ -511,7 +512,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
        }
        sport->ibcq_aqp1 = ibcq;
 
-       if (sport->ibqp_aqp1) {
+       if (sport->ibqp_sqp[IB_QPT_GSI]) {
                ehca_err(&shca->ib_device, "AQP1 QP is already created.");
                ret = -EPERM;
                goto create_aqp1;
@@ -537,7 +538,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
                ret = PTR_ERR(ibqp);
                goto create_aqp1;
        }
-       sport->ibqp_aqp1 = ibqp;
+       sport->ibqp_sqp[IB_QPT_GSI] = ibqp;
 
        return 0;
 
@@ -550,7 +551,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
 {
        int ret;
 
-       ret = ib_destroy_qp(sport->ibqp_aqp1);
+       ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);
        if (ret) {
                ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
                return ret;
@@ -590,6 +591,11 @@ static struct attribute_group ehca_drv_attr_grp = {
        .attrs = ehca_drv_attrs
 };
 
+static struct attribute_group *ehca_drv_attr_groups[] = {
+       &ehca_drv_attr_grp,
+       NULL,
+};
+
 #define EHCA_RESOURCE_ATTR(name)                                           \
 static ssize_t  ehca_show_##name(struct device *dev,                       \
                                 struct device_attribute *attr,            \
@@ -688,7 +694,7 @@ static int __devinit ehca_probe(struct of_device *dev,
        struct ehca_shca *shca;
        const u64 *handle;
        struct ib_pd *ibpd;
-       int ret;
+       int ret, i;
 
        handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
        if (!handle) {
@@ -709,6 +715,8 @@ static int __devinit ehca_probe(struct of_device *dev,
                return -ENOMEM;
        }
        mutex_init(&shca->modify_mutex);
+       for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
+               spin_lock_init(&shca->sport[i].mod_sqp_lock);
 
        shca->ofdev = dev;
        shca->ipz_hca_handle.handle = *handle;
@@ -899,6 +907,9 @@ static struct of_platform_driver ehca_driver = {
        .match_table = ehca_device_table,
        .probe       = ehca_probe,
        .remove      = ehca_remove,
+       .driver      = {
+               .groups = ehca_drv_attr_groups,
+       },
 };
 
 void ehca_poll_eqs(unsigned long data)
@@ -926,7 +937,7 @@ void ehca_poll_eqs(unsigned long data)
                                ehca_process_eq(shca, 0);
                }
        }
-       mod_timer(&poll_eqs_timer, jiffies + HZ);
+       mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));
        spin_unlock(&shca_list_lock);
 }
 
@@ -957,10 +968,6 @@ int __init ehca_module_init(void)
                goto module_init2;
        }
 
-       ret = sysfs_create_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
-       if (ret) /* only complain; we can live without attributes */
-               ehca_gen_err("Cannot create driver attributes  ret=%d", ret);
-
        if (ehca_poll_all_eqs != 1) {
                ehca_gen_err("WARNING!!!");
                ehca_gen_err("It is possible to lose interrupts.");
@@ -986,7 +993,6 @@ void __exit ehca_module_exit(void)
        if (ehca_poll_all_eqs == 1)
                del_timer_sync(&poll_eqs_timer);
 
-       sysfs_remove_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
        ibmebus_unregister_driver(&ehca_driver);
 
        ehca_destroy_slab_caches();
index eff5fb55604b4c5b218a693bf61eef9bc0c0063b..1012f15a7140e11cf579548069a80f890389ce6a 100644 (file)
@@ -592,10 +592,8 @@ static struct ehca_qp *internal_create_qp(
                goto create_qp_exit1;
        }
 
-       if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
-               parms.sigtype = HCALL_SIGT_EVERY;
-       else
-               parms.sigtype = HCALL_SIGT_BY_WQE;
+       /* Always signal by WQE so we can hide circ. WQEs */
+       parms.sigtype = HCALL_SIGT_BY_WQE;
 
        /* UD_AV CIRCUMVENTION */
        max_send_sge = init_attr->cap.max_send_sge;
@@ -618,6 +616,10 @@ static struct ehca_qp *internal_create_qp(
        parms.squeue.max_sge = max_send_sge;
        parms.rqueue.max_sge = max_recv_sge;
 
+       /* RC QPs need one more SWQE for unsolicited ack circumvention */
+       if (qp_type == IB_QPT_RC)
+               parms.squeue.max_wr++;
+
        if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
                if (HAS_SQ(my_qp))
                        ehca_determine_small_queue(
@@ -650,6 +652,8 @@ static struct ehca_qp *internal_create_qp(
                        parms.squeue.act_nr_sges = 1;
                        parms.rqueue.act_nr_sges = 1;
                }
+               /* hide the extra WQE */
+               parms.squeue.act_nr_wqes--;
                break;
        case IB_QPT_UD:
        case IB_QPT_GSI:
@@ -729,12 +733,31 @@ static struct ehca_qp *internal_create_qp(
        init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
        my_qp->init_attr = *init_attr;
 
+       if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
+               shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
+                       &my_qp->ib_qp;
+               if (ehca_nr_ports < 0) {
+                       /* alloc array to cache subsequent modify qp parms
+                        * for autodetect mode
+                        */
+                       my_qp->mod_qp_parm =
+                               kzalloc(EHCA_MOD_QP_PARM_MAX *
+                                       sizeof(*my_qp->mod_qp_parm),
+                                       GFP_KERNEL);
+                       if (!my_qp->mod_qp_parm) {
+                               ehca_err(pd->device,
+                                        "Could not alloc mod_qp_parm");
+                               goto create_qp_exit4;
+                       }
+               }
+       }
+
        /* NOTE: define_apq0() not supported yet */
        if (qp_type == IB_QPT_GSI) {
                h_ret = ehca_define_sqp(shca, my_qp, init_attr);
                if (h_ret != H_SUCCESS) {
                        ret = ehca2ib_return_code(h_ret);
-                       goto create_qp_exit4;
+                       goto create_qp_exit5;
                }
        }
 
@@ -743,7 +766,7 @@ static struct ehca_qp *internal_create_qp(
                if (ret) {
                        ehca_err(pd->device,
                                 "Couldn't assign qp to send_cq ret=%i", ret);
-                       goto create_qp_exit4;
+                       goto create_qp_exit5;
                }
        }
 
@@ -769,12 +792,18 @@ static struct ehca_qp *internal_create_qp(
                if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
                        ehca_err(pd->device, "Copy to udata failed");
                        ret = -EINVAL;
-                       goto create_qp_exit4;
+                       goto create_qp_exit6;
                }
        }
 
        return my_qp;
 
+create_qp_exit6:
+       ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
+
+create_qp_exit5:
+       kfree(my_qp->mod_qp_parm);
+
 create_qp_exit4:
        if (HAS_RQ(my_qp))
                ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
@@ -858,7 +887,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
                                update_mask,
                                mqpcb, my_qp->galpas.kernel);
        if (hret != H_SUCCESS) {
-               ehca_err(pd->device, "Could not modify SRQ to INIT"
+               ehca_err(pd->device, "Could not modify SRQ to INIT "
                         "ehca_qp=%p qp_num=%x h_ret=%li",
                         my_qp, my_qp->real_qp_num, hret);
                goto create_srq2;
@@ -872,7 +901,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
                                update_mask,
                                mqpcb, my_qp->galpas.kernel);
        if (hret != H_SUCCESS) {
-               ehca_err(pd->device, "Could not enable SRQ"
+               ehca_err(pd->device, "Could not enable SRQ "
                         "ehca_qp=%p qp_num=%x h_ret=%li",
                         my_qp, my_qp->real_qp_num, hret);
                goto create_srq2;
@@ -886,7 +915,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
                                update_mask,
                                mqpcb, my_qp->galpas.kernel);
        if (hret != H_SUCCESS) {
-               ehca_err(pd->device, "Could not modify SRQ to RTR"
+               ehca_err(pd->device, "Could not modify SRQ to RTR "
                         "ehca_qp=%p qp_num=%x h_ret=%li",
                         my_qp, my_qp->real_qp_num, hret);
                goto create_srq2;
@@ -992,7 +1021,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
        unsigned long flags = 0;
 
        /* do query_qp to obtain current attr values */
-       mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
        if (!mqpcb) {
                ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
                         "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
@@ -1180,6 +1209,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
        }
        if (attr_mask & IB_QP_PORT) {
+               struct ehca_sport *sport;
+               struct ehca_qp *aqp1;
                if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
                        ret = -EINVAL;
                        ehca_err(ibqp->device, "Invalid port=%x. "
@@ -1188,6 +1219,29 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                                 shca->num_ports);
                        goto modify_qp_exit2;
                }
+               sport = &shca->sport[attr->port_num - 1];
+               if (!sport->ibqp_sqp[IB_QPT_GSI]) {
+                       /* should not occur */
+                       ret = -EFAULT;
+                       ehca_err(ibqp->device, "AQP1 was not created for "
+                                "port=%x", attr->port_num);
+                       goto modify_qp_exit2;
+               }
+               aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI],
+                                   struct ehca_qp, ib_qp);
+               if (ibqp->qp_type != IB_QPT_GSI &&
+                   ibqp->qp_type != IB_QPT_SMI &&
+                   aqp1->mod_qp_parm) {
+                       /*
+                        * firmware will reject this modify_qp() because
+                        * port is not activated/initialized fully
+                        */
+                       ret = -EFAULT;
+                       ehca_warn(ibqp->device, "Couldn't modify qp port=%x: "
+                                 "either port is being activated (try again) "
+                                 "or cabling issue", attr->port_num);
+                       goto modify_qp_exit2;
+               }
                mqpcb->prim_phys_port = attr->port_num;
                update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
        }
@@ -1244,6 +1298,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
        }
 
        if (attr_mask & IB_QP_PATH_MTU) {
+               /* store ld(MTU) */
+               my_qp->mtu_shift = attr->path_mtu + 7;
                mqpcb->path_mtu = attr->path_mtu;
                update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
        }
@@ -1467,6 +1523,8 @@ modify_qp_exit1:
 int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
                   struct ib_udata *udata)
 {
+       struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
+                                             ib_device);
        struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
        struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
                                             ib_pd);
@@ -1479,9 +1537,100 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
                return -EINVAL;
        }
 
+       /* The if-block below caches qp_attr to be modified for GSI and SMI
+        * qps during the initialization by ib_mad. When the respective port
+        * is activated, ie we got an event PORT_ACTIVE, we'll replay the
+        * cached modify calls sequence, see ehca_recover_sqs() below.
+        * Why that is required:
+        * 1) If one port is connected, older code requires that port one
+        *    to be connected and module option nr_ports=1 to be given by
+        *    user, which is very inconvenient for end user.
+        * 2) Firmware accepts modify_qp() only if respective port has become
+        *    active. Older code had a wait loop of 30sec create_qp()/
+        *    define_aqp1(), which is not appropriate in practice. This
+        *    code now removes that wait loop, see define_aqp1(), and always
+        *    reports all ports to ib_mad resp. users. Only activated ports
+        *    will then usable for the users.
+        */
+       if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
+               int port = my_qp->init_attr.port_num;
+               struct ehca_sport *sport = &shca->sport[port - 1];
+               unsigned long flags;
+               spin_lock_irqsave(&sport->mod_sqp_lock, flags);
+               /* cache qp_attr only during init */
+               if (my_qp->mod_qp_parm) {
+                       struct ehca_mod_qp_parm *p;
+                       if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) {
+                               ehca_err(&shca->ib_device,
+                                        "mod_qp_parm overflow state=%x port=%x"
+                                        " type=%x", attr->qp_state,
+                                        my_qp->init_attr.port_num,
+                                        ibqp->qp_type);
+                               spin_unlock_irqrestore(&sport->mod_sqp_lock,
+                                                      flags);
+                               return -EINVAL;
+                       }
+                       p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx];
+                       p->mask = attr_mask;
+                       p->attr = *attr;
+                       my_qp->mod_qp_parm_idx++;
+                       ehca_dbg(&shca->ib_device,
+                                "Saved qp_attr for state=%x port=%x type=%x",
+                                attr->qp_state, my_qp->init_attr.port_num,
+                                ibqp->qp_type);
+                       spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+                       return 0;
+               }
+               spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+       }
+
        return internal_modify_qp(ibqp, attr, attr_mask, 0);
 }
 
+void ehca_recover_sqp(struct ib_qp *sqp)
+{
+       struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp);
+       int port = my_sqp->init_attr.port_num;
+       struct ib_qp_attr attr;
+       struct ehca_mod_qp_parm *qp_parm;
+       int i, qp_parm_idx, ret;
+       unsigned long flags, wr_cnt;
+
+       if (!my_sqp->mod_qp_parm)
+               return;
+       ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num);
+
+       qp_parm = my_sqp->mod_qp_parm;
+       qp_parm_idx = my_sqp->mod_qp_parm_idx;
+       for (i = 0; i < qp_parm_idx; i++) {
+               attr = qp_parm[i].attr;
+               ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0);
+               if (ret) {
+                       ehca_err(sqp->device, "Could not modify SQP port=%x "
+                                "qp_num=%x ret=%x", port, sqp->qp_num, ret);
+                       goto free_qp_parm;
+               }
+               ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x",
+                        port, sqp->qp_num, attr.qp_state);
+       }
+
+       /* re-trigger posted recv wrs */
+       wr_cnt =  my_sqp->ipz_rqueue.current_q_offset /
+               my_sqp->ipz_rqueue.qe_size;
+       if (wr_cnt) {
+               spin_lock_irqsave(&my_sqp->spinlock_r, flags);
+               hipz_update_rqa(my_sqp, wr_cnt);
+               spin_unlock_irqrestore(&my_sqp->spinlock_r, flags);
+               ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx",
+                        port, sqp->qp_num, wr_cnt);
+       }
+
+free_qp_parm:
+       kfree(qp_parm);
+       /* this prevents subsequent calls to modify_qp() to cache qp_attr */
+       my_sqp->mod_qp_parm = NULL;
+}
+
 int ehca_query_qp(struct ib_qp *qp,
                  struct ib_qp_attr *qp_attr,
                  int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
@@ -1769,6 +1918,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
        struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
        struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
                                             ib_pd);
+       struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1];
        u32 cur_pid = current->tgid;
        u32 qp_num = my_qp->real_qp_num;
        int ret;
@@ -1815,6 +1965,14 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
        port_num = my_qp->init_attr.port_num;
        qp_type  = my_qp->init_attr.qp_type;
 
+       if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
+               spin_lock_irqsave(&sport->mod_sqp_lock, flags);
+               kfree(my_qp->mod_qp_parm);
+               my_qp->mod_qp_parm = NULL;
+               shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL;
+               spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+       }
+
        /* no support for IB_QPT_SMI yet */
        if (qp_type == IB_QPT_GSI) {
                struct ib_event event;
index ea91360835d3279a27b885a5fd045b7fc9fbfff7..3aacc8cf1e448391feb37accef997118c5ca6f08 100644 (file)
@@ -50,6 +50,9 @@
 #include "hcp_if.h"
 #include "hipz_fns.h"
 
+/* in RC traffic, insert an empty RDMA READ every this many packets */
+#define ACK_CIRC_THRESHOLD 2000000
+
 static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
                                  struct ehca_wqe *wqe_p,
                                  struct ib_recv_wr *recv_wr)
@@ -81,7 +84,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
        if (ehca_debug_level) {
                ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
                             ipz_rqueue);
-               ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
+               ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
        }
 
        return 0;
@@ -135,7 +138,8 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
 
 static inline int ehca_write_swqe(struct ehca_qp *qp,
                                  struct ehca_wqe *wqe_p,
-                                 const struct ib_send_wr *send_wr)
+                                 const struct ib_send_wr *send_wr,
+                                 int hidden)
 {
        u32 idx;
        u64 dma_length;
@@ -176,7 +180,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
 
        wqe_p->wr_flag = 0;
 
-       if (send_wr->send_flags & IB_SEND_SIGNALED)
+       if ((send_wr->send_flags & IB_SEND_SIGNALED ||
+           qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR)
+           && !hidden)
                wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
 
        if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
@@ -199,7 +205,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
 
                wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
                wqe_p->local_ee_context_qkey = remote_qkey;
-               if (!send_wr->wr.ud.ah) {
+               if (unlikely(!send_wr->wr.ud.ah)) {
                        ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
                        return -EINVAL;
                }
@@ -255,6 +261,15 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
                } /* eof idx */
                wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
 
+               /* unsolicited ack circumvention */
+               if (send_wr->opcode == IB_WR_RDMA_READ) {
+                       /* on RDMA read, switch on and reset counters */
+                       qp->message_count = qp->packet_count = 0;
+                       qp->unsol_ack_circ = 1;
+               } else
+                       /* else estimate #packets */
+                       qp->packet_count += (dma_length >> qp->mtu_shift) + 1;
+
                break;
 
        default:
@@ -355,13 +370,49 @@ static inline void map_ib_wc_status(u32 cqe_status,
                *wc_status = IB_WC_SUCCESS;
 }
 
+static inline int post_one_send(struct ehca_qp *my_qp,
+                        struct ib_send_wr *cur_send_wr,
+                        struct ib_send_wr **bad_send_wr,
+                        int hidden)
+{
+       struct ehca_wqe *wqe_p;
+       int ret;
+       u64 start_offset = my_qp->ipz_squeue.current_q_offset;
+
+       /* get pointer next to free WQE */
+       wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
+       if (unlikely(!wqe_p)) {
+               /* too many posted work requests: queue overflow */
+               if (bad_send_wr)
+                       *bad_send_wr = cur_send_wr;
+               ehca_err(my_qp->ib_qp.device, "Too many posted WQEs "
+                        "qp_num=%x", my_qp->ib_qp.qp_num);
+               return -ENOMEM;
+       }
+       /* write a SEND WQE into the QUEUE */
+       ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden);
+       /*
+        * if something failed,
+        * reset the free entry pointer to the start value
+        */
+       if (unlikely(ret)) {
+               my_qp->ipz_squeue.current_q_offset = start_offset;
+               if (bad_send_wr)
+                       *bad_send_wr = cur_send_wr;
+               ehca_err(my_qp->ib_qp.device, "Could not write WQE "
+                        "qp_num=%x", my_qp->ib_qp.qp_num);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int ehca_post_send(struct ib_qp *qp,
                   struct ib_send_wr *send_wr,
                   struct ib_send_wr **bad_send_wr)
 {
        struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
        struct ib_send_wr *cur_send_wr;
-       struct ehca_wqe *wqe_p;
        int wqe_cnt = 0;
        int ret = 0;
        unsigned long flags;
@@ -369,37 +420,33 @@ int ehca_post_send(struct ib_qp *qp,
        /* LOCK the QUEUE */
        spin_lock_irqsave(&my_qp->spinlock_s, flags);
 
+       /* Send an empty extra RDMA read if:
+        *  1) there has been an RDMA read on this connection before
+        *  2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets
+        *  3) we can be sure that any previous extra RDMA read has been
+        *     processed so we don't overflow the SQ
+        */
+       if (unlikely(my_qp->unsol_ack_circ &&
+                    my_qp->packet_count > ACK_CIRC_THRESHOLD &&
+                    my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) {
+               /* insert an empty RDMA READ to fix up the remote QP state */
+               struct ib_send_wr circ_wr;
+               memset(&circ_wr, 0, sizeof(circ_wr));
+               circ_wr.opcode = IB_WR_RDMA_READ;
+               post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */
+               wqe_cnt++;
+               ehca_dbg(qp->device, "posted circ wr  qp_num=%x", qp->qp_num);
+               my_qp->message_count = my_qp->packet_count = 0;
+       }
+
        /* loop processes list of send reqs */
        for (cur_send_wr = send_wr; cur_send_wr != NULL;
             cur_send_wr = cur_send_wr->next) {
-               u64 start_offset = my_qp->ipz_squeue.current_q_offset;
-               /* get pointer next to free WQE */
-               wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
-               if (unlikely(!wqe_p)) {
-                       /* too many posted work requests: queue overflow */
-                       if (bad_send_wr)
-                               *bad_send_wr = cur_send_wr;
-                       if (wqe_cnt == 0) {
-                               ret = -ENOMEM;
-                               ehca_err(qp->device, "Too many posted WQEs "
-                                        "qp_num=%x", qp->qp_num);
-                       }
-                       goto post_send_exit0;
-               }
-               /* write a SEND WQE into the QUEUE */
-               ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
-               /*
-                * if something failed,
-                * reset the free entry pointer to the start value
-                */
+               ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0);
                if (unlikely(ret)) {
-                       my_qp->ipz_squeue.current_q_offset = start_offset;
-                       *bad_send_wr = cur_send_wr;
-                       if (wqe_cnt == 0) {
-                               ret = -EINVAL;
-                               ehca_err(qp->device, "Could not write WQE "
-                                        "qp_num=%x", qp->qp_num);
-                       }
+                       /* if one or more WQEs were successful, don't fail */
+                       if (wqe_cnt)
+                               ret = 0;
                        goto post_send_exit0;
                }
                wqe_cnt++;
@@ -410,6 +457,7 @@ int ehca_post_send(struct ib_qp *qp,
 post_send_exit0:
        iosync(); /* serialize GAL register access */
        hipz_update_sqa(my_qp, wqe_cnt);
+       my_qp->message_count += wqe_cnt;
        spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
        return ret;
 }
index f0792e5fbd02eccf7e6a02040df994a86505cc66..79e72b25b252f33fd6d1d6d5c1ac18b1e12969bd 100644 (file)
  */
 
 
-#include <linux/module.h>
-#include <linux/err.h>
 #include "ehca_classes.h"
 #include "ehca_tools.h"
-#include "ehca_qes.h"
 #include "ehca_iverbs.h"
 #include "hcp_if.h"
 
@@ -93,6 +90,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
                return H_PARAMETER;
        }
 
+       if (ehca_nr_ports < 0) /* autodetect mode */
+               return H_SUCCESS;
+
        for (counter = 0;
             shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
                     counter < ehca_port_act_time;
index 851df8a75e79cfc6ea5dc386530966f9a8c0206d..414621095540e4eb38d18708109bd550a7b7a0c0 100644 (file)
 #define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */
 #define IPATH_IB_LINK_EXTERNAL 7 /* normal, disable local loopback */
 
+/*
+ * These 3 values (SDR and DDR may be ORed for auto-speed
+ * negotiation) are used for the 3rd argument to path_f_set_ib_cfg
+ * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs.  They
+ * are also the the possible values for ipath_link_speed_enabled and active
+ * The values were chosen to match values used within the IB spec.
+ */
+#define IPATH_IB_SDR 1
+#define IPATH_IB_DDR 2
+
 /*
  * stats maintained by the driver.  For now, at least, this is global
  * to all minor devices.
@@ -433,8 +443,9 @@ struct ipath_user_info {
 #define IPATH_CMD_UNUSED_2     26
 #define IPATH_CMD_PIOAVAILUPD  27      /* force an update of PIOAvail reg */
 #define IPATH_CMD_POLL_TYPE    28      /* set the kind of polling we want */
+#define IPATH_CMD_ARMLAUNCH_CTRL       29 /* armlaunch detection control */
 
-#define IPATH_CMD_MAX          28
+#define IPATH_CMD_MAX          29
 
 /*
  * Poll types
@@ -477,6 +488,8 @@ struct ipath_cmd {
                __u64 port_info;
                /* enable/disable receipt of packets */
                __u32 recv_ctrl;
+               /* enable/disable armlaunch errors (non-zero to enable) */
+               __u32 armlaunch_ctrl;
                /* partition key to set */
                __u16 part_key;
                /* user address of __u32 bitmask of active slaves */
@@ -579,7 +592,7 @@ struct ipath_flash {
 struct infinipath_counters {
        __u64 LBIntCnt;
        __u64 LBFlowStallCnt;
-       __u64 Reserved1;
+       __u64 TxSDmaDescCnt;    /* was Reserved1 */
        __u64 TxUnsupVLErrCnt;
        __u64 TxDataPktCnt;
        __u64 TxFlowPktCnt;
@@ -615,12 +628,26 @@ struct infinipath_counters {
        __u64 RxP6HdrEgrOvflCnt;
        __u64 RxP7HdrEgrOvflCnt;
        __u64 RxP8HdrEgrOvflCnt;
-       __u64 Reserved6;
-       __u64 Reserved7;
+       __u64 RxP9HdrEgrOvflCnt;        /* was Reserved6 */
+       __u64 RxP10HdrEgrOvflCnt;       /* was Reserved7 */
+       __u64 RxP11HdrEgrOvflCnt;       /* new for IBA7220 */
+       __u64 RxP12HdrEgrOvflCnt;       /* new for IBA7220 */
+       __u64 RxP13HdrEgrOvflCnt;       /* new for IBA7220 */
+       __u64 RxP14HdrEgrOvflCnt;       /* new for IBA7220 */
+       __u64 RxP15HdrEgrOvflCnt;       /* new for IBA7220 */
+       __u64 RxP16HdrEgrOvflCnt;       /* new for IBA7220 */
        __u64 IBStatusChangeCnt;
        __u64 IBLinkErrRecoveryCnt;
        __u64 IBLinkDownedCnt;
        __u64 IBSymbolErrCnt;
+       /* The following are new for IBA7220 */
+       __u64 RxVL15DroppedPktCnt;
+       __u64 RxOtherLocalPhyErrCnt;
+       __u64 PcieRetryBufDiagQwordCnt;
+       __u64 ExcessBufferOvflCnt;
+       __u64 LocalLinkIntegrityErrCnt;
+       __u64 RxVlErrCnt;
+       __u64 RxDlidFltrCnt;
 };
 
 /*
index d1380c7a1703bf463776699f366fa3c490a6e9af..a03bd28d9b487e1f21f81ce0ff3e826a31412bb6 100644 (file)
@@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
        else
                n = head - tail;
        if (unlikely((u32)cqe < n)) {
-               ret = -EOVERFLOW;
+               ret = -EINVAL;
                goto bail_unlock;
        }
        for (n = 0; tail != head; n++) {
index 19c56e6491eb0c65183a7ff1a344cf5f4447d0e7..d6f69532d83f9d63e9df00bcee3d2a976ac4649b 100644 (file)
@@ -55,7 +55,7 @@
 #define __IPATH_PKTDBG      0x80       /* print packet data */
 /* print process startup (init)/exit messages */
 #define __IPATH_PROCDBG     0x100
-/* print mmap/nopage stuff, not using VDBG any more */
+/* print mmap/fault stuff, not using VDBG any more */
 #define __IPATH_MMDBG       0x200
 #define __IPATH_ERRPKTDBG   0x400
 #define __IPATH_USER_SEND   0x1000     /* use user mode send */
@@ -81,7 +81,7 @@
 #define __IPATH_VERBDBG   0x0  /* very verbose debug */
 #define __IPATH_PKTDBG    0x0  /* print packet data */
 #define __IPATH_PROCDBG   0x0  /* process startup (init)/exit messages */
-/* print mmap/nopage stuff, not using VDBG any more */
+/* print mmap/fault stuff, not using VDBG any more */
 #define __IPATH_MMDBG     0x0
 #define __IPATH_EPKTDBG   0x0  /* print ethernet packet data */
 #define __IPATH_IPATHDBG  0x0  /* Ethernet (IPATH) table dump on */
index 1f152ded1e3c48083840e8119aecea8738be1cd3..d5ff6ca2db30aaaba1ecb0265c9527e7c917621f 100644 (file)
@@ -121,6 +121,9 @@ static struct pci_driver ipath_driver = {
        .probe = ipath_init_one,
        .remove = __devexit_p(ipath_remove_one),
        .id_table = ipath_pci_tbl,
+       .driver = {
+               .groups = ipath_driver_attr_groups,
+       },
 };
 
 static void ipath_check_status(struct work_struct *work)
@@ -331,6 +334,8 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
                udelay(1);
        }
 
+       ipath_disable_armlaunch(dd);
+
        writeq(0, piobuf); /* length 0, no dwords actually sent */
        ipath_flush_wc();
 
@@ -362,6 +367,7 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
 done:
        /* disarm piobuf, so it's available again */
        ipath_disarm_piobufs(dd, pbnum, 1);
+       ipath_enable_armlaunch(dd);
 }
 
 static int __devinit ipath_init_one(struct pci_dev *pdev,
@@ -800,31 +806,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
                          unsigned cnt)
 {
        unsigned i, last = first + cnt;
-       u64 sendctrl, sendorig;
+       unsigned long flags;
 
        ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
-       sendorig = dd->ipath_sendctrl;
        for (i = first; i < last; i++) {
-               sendctrl = sendorig  | INFINIPATH_S_DISARM |
-                       (i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
+               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+               /*
+                * The disarm-related bits are write-only, so it
+                * is ok to OR them in with our copy of sendctrl
+                * while we hold the lock.
+                */
                ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                                sendctrl);
+                       dd->ipath_sendctrl | INFINIPATH_S_DISARM |
+                       (i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
+               /* can't disarm bufs back-to-back per iba7220 spec */
+               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
        }
 
        /*
-        * Write it again with current value, in case ipath_sendctrl changed
-        * while we were looping; no critical bits that would require
-        * locking.
-        *
-        * disable PIOAVAILUPD, then re-enable, reading scratch in
+        * Disable PIOAVAILUPD, then re-enable, reading scratch in
         * between.  This seems to avoid a chip timing race that causes
-        * pioavail updates to memory to stop.
+        * pioavail updates to memory to stop.  We xor as we don't
+        * know the state of the bit when we're called.
         */
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                        sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
-       sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+               dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                         dd->ipath_sendctrl);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 }
 
 /**
@@ -1000,12 +1012,10 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
  * ipath_get_egrbuf - get an eager buffer
  * @dd: the infinipath device
  * @bufnum: the eager buffer to get
- * @err: unused
  *
  * must only be called if ipath_pd[port] is known to be allocated
  */
-static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
-                                    int err)
+static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum)
 {
        return dd->ipath_port0_skbinfo ?
                (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
@@ -1097,13 +1107,14 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
 
 /*
  * ipath_kreceive - receive a packet
- * @dd: the infinipath device
+ * @pd: the infinipath port
  *
  * called from interrupt handler for errors or receive interrupt
  */
-void ipath_kreceive(struct ipath_devdata *dd)
+void ipath_kreceive(struct ipath_portdata *pd)
 {
        u64 *rc;
+       struct ipath_devdata *dd = pd->port_dd;
        void *ebuf;
        const u32 rsize = dd->ipath_rcvhdrentsize;      /* words */
        const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */
@@ -1118,8 +1129,8 @@ void ipath_kreceive(struct ipath_devdata *dd)
                goto bail;
        }
 
-       l = dd->ipath_port0head;
-       hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
+       l = pd->port_head;
+       hdrqtail = ipath_get_rcvhdrtail(pd);
        if (l == hdrqtail)
                goto bail;
 
@@ -1128,7 +1139,7 @@ reloop:
                u32 qp;
                u8 *bthbytes;
 
-               rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2));
+               rc = (u64 *) (pd->port_rcvhdrq + (l << 2));
                hdr = (struct ipath_message_header *)&rc[1];
                /*
                 * could make a network order version of IPATH_KD_QP, and
@@ -1153,7 +1164,7 @@ reloop:
                        etail = ipath_hdrget_index((__le32 *) rc);
                        if (tlen > sizeof(*hdr) ||
                            etype == RCVHQ_RCV_TYPE_NON_KD)
-                               ebuf = ipath_get_egrbuf(dd, etail, 0);
+                               ebuf = ipath_get_egrbuf(dd, etail);
                }
 
                /*
@@ -1188,7 +1199,7 @@ reloop:
                                  be32_to_cpu(hdr->bth[0]) & 0xff);
                else {
                        /*
-                        * error packet, type of error  unknown.
+                        * error packet, type of error unknown.
                         * Probably type 3, but we don't know, so don't
                         * even try to print the opcode, etc.
                         */
@@ -1238,7 +1249,7 @@ reloop:
                 * earlier packets, we "almost" guarantee we have covered
                 * that case.
                 */
-               u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
+               u32 hqtail = ipath_get_rcvhdrtail(pd);
                if (hqtail != hdrqtail) {
                        hdrqtail = hqtail;
                        reloop = 1; /* loop 1 extra time at most */
@@ -1248,7 +1259,7 @@ reloop:
 
        pkttot += i;
 
-       dd->ipath_port0head = l;
+       pd->port_head = l;
 
        if (pkttot > ipath_stats.sps_maxpkts_call)
                ipath_stats.sps_maxpkts_call = pkttot;
@@ -1332,14 +1343,9 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
                /*
                 * Chip Errata: bug 6641; even and odd qwords>3 are swapped
                 */
-               if (i > 3) {
-                       if (i & 1)
-                               piov = le64_to_cpu(
-                                       dd->ipath_pioavailregs_dma[i - 1]);
-                       else
-                               piov = le64_to_cpu(
-                                       dd->ipath_pioavailregs_dma[i + 1]);
-               } else
+               if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
+                       piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]);
+               else
                        piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]);
                pchg = _IPATH_ALL_CHECKBITS &
                        ~(dd->ipath_pioavailshadow[i] ^ piov);
@@ -1598,7 +1604,8 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
 
        /* clear for security and sanity on each use */
        memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
-       memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+       if (pd->port_rcvhdrtail_kvaddr)
+               memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
 
        /*
         * tell chip each time we init it, even if we are re-using previous
@@ -1614,77 +1621,6 @@ bail:
        return ret;
 }
 
-int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id,
-                          u64 bits_to_wait_for, u64 * valp)
-{
-       unsigned long timeout;
-       u64 lastval, val;
-       int ret;
-
-       lastval = ipath_read_kreg64(dd, reg_id);
-       /* wait a ridiculously long time */
-       timeout = jiffies + msecs_to_jiffies(5);
-       do {
-               val = ipath_read_kreg64(dd, reg_id);
-               /* set so they have something, even on failures. */
-               *valp = val;
-               if ((val & bits_to_wait_for) == bits_to_wait_for) {
-                       ret = 0;
-                       break;
-               }
-               if (val != lastval)
-                       ipath_cdbg(VERBOSE, "Changed from %llx to %llx, "
-                                  "waiting for %llx bits\n",
-                                  (unsigned long long) lastval,
-                                  (unsigned long long) val,
-                                  (unsigned long long) bits_to_wait_for);
-               cond_resched();
-               if (time_after(jiffies, timeout)) {
-                       ipath_dbg("Didn't get bits %llx in register 0x%x, "
-                                 "got %llx\n",
-                                 (unsigned long long) bits_to_wait_for,
-                                 reg_id, (unsigned long long) *valp);
-                       ret = -ENODEV;
-                       break;
-               }
-       } while (1);
-
-       return ret;
-}
-
-/**
- * ipath_waitfor_mdio_cmdready - wait for last command to complete
- * @dd: the infinipath device
- *
- * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go
- * away indicating the last command has completed.  It doesn't return data
- */
-int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
-{
-       unsigned long timeout;
-       u64 val;
-       int ret;
-
-       /* wait a ridiculously long time */
-       timeout = jiffies + msecs_to_jiffies(5);
-       do {
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio);
-               if (!(val & IPATH_MDIO_CMDVALID)) {
-                       ret = 0;
-                       break;
-               }
-               cond_resched();
-               if (time_after(jiffies, timeout)) {
-                       ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n",
-                                 (unsigned long long) val);
-                       ret = -ENODEV;
-                       break;
-               }
-       } while (1);
-
-       return ret;
-}
-
 
 /*
  * Flush all sends that might be in the ready to send state, as well as any
@@ -2053,6 +1989,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
  */
 void ipath_shutdown_device(struct ipath_devdata *dd)
 {
+       unsigned long flags;
+
        ipath_dbg("Shutting down the device\n");
 
        dd->ipath_flags |= IPATH_LINKUNK;
@@ -2073,9 +2011,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
         * gracefully stop all sends allowing any in progress to trickle out
         * first.
         */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl = 0;
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
        /* flush it */
        ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+
        /*
         * enough for anything that's going to trickle out to have actually
         * done so.
@@ -2217,25 +2159,15 @@ static int __init infinipath_init(void)
                goto bail_unit;
        }
 
-       ret = ipath_driver_create_group(&ipath_driver.driver);
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver "
-                      "sysfs entries: error %d\n", -ret);
-               goto bail_pci;
-       }
-
        ret = ipath_init_ipathfs();
        if (ret < 0) {
                printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
                       "ipathfs: error %d\n", -ret);
-               goto bail_group;
+               goto bail_pci;
        }
 
        goto bail;
 
-bail_group:
-       ipath_driver_remove_group(&ipath_driver.driver);
-
 bail_pci:
        pci_unregister_driver(&ipath_driver);
 
@@ -2250,8 +2182,6 @@ static void __exit infinipath_cleanup(void)
 {
        ipath_exit_ipathfs();
 
-       ipath_driver_remove_group(&ipath_driver.driver);
-
        ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
        pci_unregister_driver(&ipath_driver);
 
@@ -2344,5 +2274,34 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
        }
        return 0;
 }
+
+/*
+ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing on
+ * the 7220, which is count-based, rather than trigger-based.  Safe for the
+ * driver check, since it's at init.   Not completely safe when used for
+ * user-mode checking, since some error checking can be lost, but not
+ * particularly risky, and only has problematic side-effects in the face of
+ * very buggy user code.  There is no reference counting, but that's also
+ * fine, given the intended use.
+ */
+void ipath_enable_armlaunch(struct ipath_devdata *dd)
+{
+       dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH;
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
+               INFINIPATH_E_SPIOARMLAUNCH);
+       dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH;
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+               dd->ipath_errormask);
+}
+
+void ipath_disable_armlaunch(struct ipath_devdata *dd)
+{
+       /* so don't re-enable if already set */
+       dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH;
+       dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH;
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+               dd->ipath_errormask);
+}
+
 module_init(infinipath_init);
 module_exit(infinipath_cleanup);
index e7c25dbbcdc9ba77f5018ce06fe52b3cb6b84b73..e28a42f5376920667d3f93bdfe8166fde26abda8 100644 (file)
@@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
 {
        int ret;
 
-       ret = down_interruptible(&dd->ipath_eep_sem);
+       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
        if (!ret) {
                ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
-               up(&dd->ipath_eep_sem);
+               mutex_unlock(&dd->ipath_eep_lock);
        }
 
        return ret;
@@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
 {
        int ret;
 
-       ret = down_interruptible(&dd->ipath_eep_sem);
+       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
        if (!ret) {
                ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
-               up(&dd->ipath_eep_sem);
+               mutex_unlock(&dd->ipath_eep_lock);
        }
 
        return ret;
@@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
        struct ipath_devdata *dd0 = ipath_lookup(0);
 
        if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
-               u8 *bguid, oguid;
+               u8 oguid;
                dd->ipath_guid = dd0->ipath_guid;
                bguid = (u8 *) & dd->ipath_guid;
 
@@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
                goto bail;
        }
 
-       down(&dd->ipath_eep_sem);
+       mutex_lock(&dd->ipath_eep_lock);
        eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
-       up(&dd->ipath_eep_sem);
+       mutex_unlock(&dd->ipath_eep_lock);
 
        if (eep_stat) {
                ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
@@ -674,7 +674,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
                 * elsewhere for backward-compatibility.
                 */
                char *snp = dd->ipath_serial;
-               int len;
                memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
                snp[sizeof ifp->if_sprefix] = '\0';
                len = strlen(snp);
@@ -764,14 +763,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
        /* Grab semaphore and read current EEPROM. If we get an
         * error, let go, but if not, keep it until we finish write.
         */
-       ret = down_interruptible(&dd->ipath_eep_sem);
+       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
        if (ret) {
                ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
                goto free_bail;
        }
        ret = ipath_eeprom_internal_read(dd, 0, buf, len);
        if (ret) {
-               up(&dd->ipath_eep_sem);
+               mutex_unlock(&dd->ipath_eep_lock);
                ipath_dev_err(dd, "Unable read EEPROM for logging\n");
                goto free_bail;
        }
@@ -779,7 +778,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
 
        csum = flash_csum(ifp, 0);
        if (csum != ifp->if_csum) {
-               up(&dd->ipath_eep_sem);
+               mutex_unlock(&dd->ipath_eep_lock);
                ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
                                csum, ifp->if_csum);
                ret = 1;
@@ -849,7 +848,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
                csum = flash_csum(ifp, 1);
                ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
        }
-       up(&dd->ipath_eep_sem);
+       mutex_unlock(&dd->ipath_eep_lock);
        if (ret)
                ipath_dev_err(dd, "Failed updating EEPROM\n");
 
index 5de3243a47c38bf023fc6fc0ee97dcdc69886fbb..7e025c8e01b6d9d1efe6bc0e787061159b1b1380 100644 (file)
@@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp,
                kinfo->spi_piocnt = dd->ipath_pbufsport;
                kinfo->spi_piobufbase = (u64) pd->port_piobufs;
                kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
-                       dd->ipath_palign * pd->port_port;
+                       dd->ipath_ureg_align * pd->port_port;
        } else if (master) {
                kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
                                    (dd->ipath_pbufsport % subport_cnt);
@@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp,
        }
        if (shared) {
                kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
-                       dd->ipath_palign * pd->port_port;
+                       dd->ipath_ureg_align * pd->port_port;
                kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
                kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
                kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
@@ -742,11 +742,12 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
                 * updated and correct itself, even in the face of software
                 * bugs.
                 */
-               *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
-               set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+               if (pd->port_rcvhdrtail_kvaddr)
+                       ipath_clear_rcvhdrtail(pd);
+               set_bit(dd->ipath_r_portenable_shift + pd->port_port,
                        &dd->ipath_rcvctrl);
        } else
-               clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+               clear_bit(dd->ipath_r_portenable_shift + pd->port_port,
                          &dd->ipath_rcvctrl);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
                         dd->ipath_rcvctrl);
@@ -881,7 +882,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
 
        egrcnt = dd->ipath_rcvegrcnt;
        /* TID number offset for this port */
-       egroff = pd->port_port * egrcnt;
+       egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt;
        egrsize = dd->ipath_rcvegrbufsize;
        ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
                   "offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
@@ -1049,11 +1050,6 @@ static int mmap_piobufs(struct vm_area_struct *vma,
 
        phys = dd->ipath_physaddr + piobufs;
 
-       /*
-        * Don't mark this as non-cached, or we don't get the
-        * write combining behavior we want on the PIO buffers!
-        */
-
 #if defined(__powerpc__)
        /* There isn't a generic way to specify writethrough mappings */
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
@@ -1120,33 +1116,24 @@ bail:
 }
 
 /*
- * ipath_file_vma_nopage - handle a VMA page fault.
+ * ipath_file_vma_fault - handle a VMA page fault.
  */
-static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
-                                         unsigned long address, int *type)
+static int ipath_file_vma_fault(struct vm_area_struct *vma,
+                                       struct vm_fault *vmf)
 {
-       unsigned long offset = address - vma->vm_start;
-       struct page *page = NOPAGE_SIGBUS;
-       void *pageptr;
+       struct page *page;
 
-       /*
-        * Convert the vmalloc address into a struct page.
-        */
-       pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
-       page = vmalloc_to_page(pageptr);
+       page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
        if (!page)
-               goto out;
-
-       /* Increment the reference count. */
+               return VM_FAULT_SIGBUS;
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-out:
-       return page;
+       vmf->page = page;
+
+       return 0;
 }
 
 static struct vm_operations_struct ipath_file_vm_ops = {
-       .nopage = ipath_file_vma_nopage,
+       .fault = ipath_file_vma_fault,
 };
 
 static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
@@ -1284,7 +1271,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
                goto bail;
        }
 
-       ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+       ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
        if (!pd->port_subport_cnt) {
                /* port is not shared */
                piocnt = dd->ipath_pbufsport;
@@ -1400,7 +1387,10 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
        pollflag = ipath_poll_hdrqfull(pd);
 
        head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
-       tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
+       if (pd->port_rcvhdrtail_kvaddr)
+               tail = ipath_get_rcvhdrtail(pd);
+       else
+               tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
 
        if (head != tail)
                pollflag |= POLLIN | POLLRDNORM;
@@ -1410,7 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
                /* flush waiting flag so we don't miss an event */
                wmb();
 
-               set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+               set_bit(pd->port_port + dd->ipath_r_intravail_shift,
                        &dd->ipath_rcvctrl);
 
                ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
@@ -1790,6 +1780,7 @@ static int find_shared_port(struct file *fp,
                        }
                        port_fp(fp) = pd;
                        subport_fp(fp) = pd->port_cnt++;
+                       pd->port_subpid[subport_fp(fp)] = current->pid;
                        tidcursor_fp(fp) = 0;
                        pd->active_slaves |= 1 << subport_fp(fp);
                        ipath_cdbg(PROC,
@@ -1920,8 +1911,7 @@ static int ipath_do_user_init(struct file *fp,
         */
        head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
        ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
-       dd->ipath_lastegrheads[pd->port_port] = -1;
-       dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
+       pd->port_lastrcvhdrqtail = -1;
        ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
                pd->port_port, head32);
        pd->port_tidcursor = 0; /* start at beginning after open */
@@ -1941,11 +1931,13 @@ static int ipath_do_user_init(struct file *fp,
         * We explictly set the in-memory copy to 0 beforehand, so we don't
         * have to wait to be sure the DMA update has happened.
         */
-       *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
-       set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+       if (pd->port_rcvhdrtail_kvaddr)
+               ipath_clear_rcvhdrtail(pd);
+       set_bit(dd->ipath_r_portenable_shift + pd->port_port,
                &dd->ipath_rcvctrl);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
+                       dd->ipath_rcvctrl &
+                       ~(1ULL << dd->ipath_r_tailupd_shift));
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
                         dd->ipath_rcvctrl);
        /* Notify any waiting slaves */
@@ -2022,6 +2014,7 @@ static int ipath_close(struct inode *in, struct file *fp)
                 * the slave(s) don't wait for receive data forever.
                 */
                pd->active_slaves &= ~(1 << fd->subport);
+               pd->port_subpid[fd->subport] = 0;
                mutex_unlock(&ipath_mutex);
                goto bail;
        }
@@ -2054,9 +2047,9 @@ static int ipath_close(struct inode *in, struct file *fp)
        if (dd->ipath_kregbase) {
                int i;
                /* atomically clear receive enable port and intr avail. */
-               clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
+               clear_bit(dd->ipath_r_portenable_shift + port,
                          &dd->ipath_rcvctrl);
-               clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+               clear_bit(pd->port_port + dd->ipath_r_intravail_shift,
                          &dd->ipath_rcvctrl);
                ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
                        dd->ipath_rcvctrl);
@@ -2149,11 +2142,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
 
 static int ipath_force_pio_avail_update(struct ipath_devdata *dd)
 {
-       u64 reg = dd->ipath_sendctrl;
+       unsigned long flags;
 
-       clear_bit(IPATH_S_PIOBUFAVAILUPD, &reg);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg);
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+               dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
        return 0;
 }
@@ -2227,6 +2224,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
                dest = &cmd.cmd.poll_type;
                src = &ucmd->cmd.poll_type;
                break;
+       case IPATH_CMD_ARMLAUNCH_CTRL:
+               copy = sizeof(cmd.cmd.armlaunch_ctrl);
+               dest = &cmd.cmd.armlaunch_ctrl;
+               src = &ucmd->cmd.armlaunch_ctrl;
+               break;
        default:
                ret = -EINVAL;
                goto bail;
@@ -2302,6 +2304,12 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
        case IPATH_CMD_POLL_TYPE:
                pd->poll_type = cmd.cmd.poll_type;
                break;
+       case IPATH_CMD_ARMLAUNCH_CTRL:
+               if (cmd.cmd.armlaunch_ctrl)
+                       ipath_enable_armlaunch(pd->port_dd);
+               else
+                       ipath_disable_armlaunch(pd->port_dd);
+               break;
        }
 
        if (ret >= 0)
index 262c25db05cde8a4888096f7ae7e92f592a88052..23faba9d21eb34aab1337782fecd24f7a3871ec8 100644 (file)
@@ -108,21 +108,16 @@ static const struct file_operations atomic_stats_ops = {
        .read = atomic_stats_read,
 };
 
-#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64)
-
 static ssize_t atomic_counters_read(struct file *file, char __user *buf,
                                    size_t count, loff_t *ppos)
 {
-       u64 counters[NUM_COUNTERS];
-       u16 i;
+       struct infinipath_counters counters;
        struct ipath_devdata *dd;
 
        dd = file->f_path.dentry->d_inode->i_private;
+       dd->ipath_f_read_counters(dd, &counters);
 
-       for (i = 0; i < NUM_COUNTERS; i++)
-               counters[i] = ipath_snap_cntr(dd, i);
-
-       return simple_read_from_buffer(buf, count, ppos, counters,
+       return simple_read_from_buffer(buf, count, ppos, &counters,
                                       sizeof counters);
 }
 
@@ -243,8 +238,7 @@ static int create_device_files(struct super_block *sb,
 
        snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
        ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
-                         (struct file_operations *) &simple_dir_operations,
-                         dd);
+                         &simple_dir_operations, dd);
        if (ret) {
                printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
                goto bail;
index ddbebe4bdb2703f08182d5304c1c93d11dac63a1..9e2ced3cdc5e656af160b48cd5b53ba8753f19c6 100644 (file)
@@ -148,10 +148,57 @@ struct _infinipath_do_not_use_kernel_regs {
        unsigned long long ReservedSW2[4];
 };
 
-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
-    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+struct _infinipath_do_not_use_counters {
+       __u64 LBIntCnt;
+       __u64 LBFlowStallCnt;
+       __u64 Reserved1;
+       __u64 TxUnsupVLErrCnt;
+       __u64 TxDataPktCnt;
+       __u64 TxFlowPktCnt;
+       __u64 TxDwordCnt;
+       __u64 TxLenErrCnt;
+       __u64 TxMaxMinLenErrCnt;
+       __u64 TxUnderrunCnt;
+       __u64 TxFlowStallCnt;
+       __u64 TxDroppedPktCnt;
+       __u64 RxDroppedPktCnt;
+       __u64 RxDataPktCnt;
+       __u64 RxFlowPktCnt;
+       __u64 RxDwordCnt;
+       __u64 RxLenErrCnt;
+       __u64 RxMaxMinLenErrCnt;
+       __u64 RxICRCErrCnt;
+       __u64 RxVCRCErrCnt;
+       __u64 RxFlowCtrlErrCnt;
+       __u64 RxBadFormatCnt;
+       __u64 RxLinkProblemCnt;
+       __u64 RxEBPCnt;
+       __u64 RxLPCRCErrCnt;
+       __u64 RxBufOvflCnt;
+       __u64 RxTIDFullErrCnt;
+       __u64 RxTIDValidErrCnt;
+       __u64 RxPKeyMismatchCnt;
+       __u64 RxP0HdrEgrOvflCnt;
+       __u64 RxP1HdrEgrOvflCnt;
+       __u64 RxP2HdrEgrOvflCnt;
+       __u64 RxP3HdrEgrOvflCnt;
+       __u64 RxP4HdrEgrOvflCnt;
+       __u64 RxP5HdrEgrOvflCnt;
+       __u64 RxP6HdrEgrOvflCnt;
+       __u64 RxP7HdrEgrOvflCnt;
+       __u64 RxP8HdrEgrOvflCnt;
+       __u64 Reserved6;
+       __u64 Reserved7;
+       __u64 IBStatusChangeCnt;
+       __u64 IBLinkErrRecoveryCnt;
+       __u64 IBLinkDownedCnt;
+       __u64 IBSymbolErrCnt;
+};
+
+#define IPATH_KREG_OFFSET(field) (offsetof( \
+       struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
 #define IPATH_CREG_OFFSET(field) (offsetof( \
-    struct infinipath_counters, field) / sizeof(u64))
+       struct _infinipath_do_not_use_counters, field) / sizeof(u64))
 
 static const struct ipath_kregs ipath_ht_kregs = {
        .kr_control = IPATH_KREG_OFFSET(Control),
@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_ht_cregs = {
 #define INFINIPATH_HWE_HTAPLL_RFSLIP        0x1000000000000000ULL
 #define INFINIPATH_HWE_SERDESPLLFAILED      0x2000000000000000ULL
 
+#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf
+#define IBA6110_IBCS_LINKSTATE_SHIFT 4
+
 /* kr_extstatus bits */
 #define INFINIPATH_EXTS_FREQSEL 0x2
 #define INFINIPATH_EXTS_SERDESSEL 0x4
@@ -296,6 +346,12 @@ static const struct ipath_cregs ipath_ht_cregs = {
 #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
 #define INFINIPATH_RT_BUFSIZE_SHIFT 48
 
+#define INFINIPATH_R_INTRAVAIL_SHIFT 16
+#define INFINIPATH_R_TAILUPD_SHIFT 31
+
+/* kr_xgxsconfig bits */
+#define INFINIPATH_XGXS_RESET          0x7ULL
+
 /*
  * masks and bits that are different in different chips, or present only
  * in one
@@ -652,7 +708,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
                              "with ID %u\n", boardrev);
                snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
                         boardrev);
-               ret = 1;
                break;
        }
        if (n)
@@ -686,6 +741,13 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
                              dd->ipath_htspeed);
        ret = 0;
 
+       /*
+        * set here, not in ipath_init_*_funcs because we have to do
+        * it after we can read chip registers.
+        */
+       dd->ipath_ureg_align =
+               ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
+
 bail:
        return ret;
 }
@@ -969,7 +1031,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
        do {
                u8 cap_type;
 
-               /* the HT capability type byte is 3 bytes after the
+               /*
+                * The HT capability type byte is 3 bytes after the
                 * capability byte.
                 */
                if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
@@ -982,6 +1045,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
        } while ((pos = pci_find_next_capability(pdev, pos,
                                                 PCI_CAP_ID_HT)));
 
+       dd->ipath_flags |= IPATH_SWAP_PIOBUFS;
+
 bail:
        return ret;
 }
@@ -1074,11 +1139,55 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
 
 static void ipath_init_ht_variables(struct ipath_devdata *dd)
 {
+       /*
+        * setup the register offsets, since they are different for each
+        * chip
+        */
+       dd->ipath_kregs = &ipath_ht_kregs;
+       dd->ipath_cregs = &ipath_ht_cregs;
+
        dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
        dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
        dd->ipath_gpio_sda = IPATH_GPIO_SDA;
        dd->ipath_gpio_scl = IPATH_GPIO_SCL;
 
+       /*
+        * Fill in data for field-values that change in newer chips.
+        * We dynamically specify only the mask for LINKTRAININGSTATE
+        * and only the shift for LINKSTATE, as they are the only ones
+        * that change.  Also precalculate the 3 link states of interest
+        * and the combined mask.
+        */
+       dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT;
+       dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK;
+       dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
+               dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
+       dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+               (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
+       dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+               (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
+       dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+               (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
+
+       /*
+        * Fill in data for ibcc field-values that change in newer chips.
+        * We dynamically specify only the mask for LINKINITCMD
+        * and only the shift for LINKCMD and MAXPKTLEN, as they are
+        * the only ones that change.
+        */
+       dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
+       dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
+       dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
+
+       /* Fill in shifts for RcvCtrl. */
+       dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
+       dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
+       dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
+       dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */
+
        dd->ipath_i_bitsextant =
                (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
                (INFINIPATH_I_RCVAVAIL_MASK <<
@@ -1135,6 +1244,8 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
 
        dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
        dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+       dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
+       dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
 
        /*
         * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
@@ -1148,9 +1259,17 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
                INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
                INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
 
-       dd->ipath_eep_st_masks[2].errs_to_log =
-               INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
+       dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
 
+       dd->delay_mult = 2; /* SDR, 4X, can't change */
+
+       dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+       dd->ipath_link_speed_supported = IPATH_IB_SDR;
+       dd->ipath_link_width_enabled = IB_WIDTH_4X;
+       dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
+       /* these can't change for this chip, so set once */
+       dd->ipath_link_width_active = dd->ipath_link_width_enabled;
+       dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
 }
 
 /**
@@ -1205,14 +1324,16 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
        val &= ~INFINIPATH_HWE_HTCMISCERR4;
 
        /*
-        * PLL ignored because MDIO interface has a logic problem
-        * for reads, on Comstock and Ponderosa.  BRINGUP
+        * PLL ignored because unused MDIO interface has a logic problem
         */
        if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
                val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
        dd->ipath_hwerrmask = val;
 }
 
+
+
+
 /**
  * ipath_ht_bringup_serdes - bring up the serdes
  * @dd: the infinipath device
@@ -1284,16 +1405,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
        }
 
        val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
-            INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
-               val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
-                        INFINIPATH_XGXS_MDIOADDR_SHIFT);
-               /*
-                * we use address 3
-                */
-               val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
-               change = 1;
-       }
        if (val & INFINIPATH_XGXS_RESET) {
                /* normally true after boot */
                val &= ~INFINIPATH_XGXS_RESET;
@@ -1329,21 +1440,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
                   (unsigned long long)
                   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
 
-       if (!ipath_waitfor_mdio_cmdready(dd)) {
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
-                                ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
-                                               IPATH_MDIO_CTRL_XGXS_REG_8,
-                                               0));
-               if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
-                                          IPATH_MDIO_DATAVALID, &val))
-                       ipath_dbg("Never got MDIO data for XGXS status "
-                                 "read\n");
-               else
-                       ipath_cdbg(VERBOSE, "MDIO Read reg8, "
-                                  "'bank' 31 %x\n", (u32) val);
-       } else
-               ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
-
        return ret;             /* for now, say we always succeeded */
 }
 
@@ -1396,6 +1492,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
                        pa |= lenvalid | INFINIPATH_RT_VALID;
                }
        }
+
        writeq(pa, tidptr);
 }
 
@@ -1526,8 +1623,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
        }
 
        ipath_get_eeprom_info(dd);
-       if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
-               dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
+       if (dd->ipath_boardrev == 5) {
                /*
                 * Later production QHT7040 has same changes as QHT7140, so
                 * can use GPIO interrupts.  They have serial #'s starting
@@ -1602,6 +1698,210 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd)
        dd->ipath_intconfig = 0;
 }
 
+static struct ipath_message_header *
+ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
+{
+       return (struct ipath_message_header *)
+               &rhf_addr[sizeof(u64) / sizeof(u32)];
+}
+
+static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports)
+{
+       dd->ipath_portcnt =
+               ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+       dd->ipath_p0_rcvegrcnt =
+               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
+}
+
+static void ipath_ht_read_counters(struct ipath_devdata *dd,
+                                  struct infinipath_counters *cntrs)
+{
+       cntrs->LBIntCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
+       cntrs->LBFlowStallCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
+       cntrs->TxSDmaDescCnt = 0;
+       cntrs->TxUnsupVLErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
+       cntrs->TxDataPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
+       cntrs->TxFlowPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
+       cntrs->TxDwordCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
+       cntrs->TxLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
+       cntrs->TxMaxMinLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
+       cntrs->TxUnderrunCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
+       cntrs->TxFlowStallCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
+       cntrs->TxDroppedPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
+       cntrs->RxDroppedPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
+       cntrs->RxDataPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
+       cntrs->RxFlowPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
+       cntrs->RxDwordCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
+       cntrs->RxLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
+       cntrs->RxMaxMinLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
+       cntrs->RxICRCErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
+       cntrs->RxVCRCErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
+       cntrs->RxFlowCtrlErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
+       cntrs->RxBadFormatCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
+       cntrs->RxLinkProblemCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
+       cntrs->RxEBPCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
+       cntrs->RxLPCRCErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
+       cntrs->RxBufOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
+       cntrs->RxTIDFullErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
+       cntrs->RxTIDValidErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
+       cntrs->RxPKeyMismatchCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
+       cntrs->RxP0HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
+       cntrs->RxP1HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
+       cntrs->RxP2HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
+       cntrs->RxP3HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
+       cntrs->RxP4HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
+       cntrs->RxP5HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt));
+       cntrs->RxP6HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt));
+       cntrs->RxP7HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt));
+       cntrs->RxP8HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt));
+       cntrs->RxP9HdrEgrOvflCnt = 0;
+       cntrs->RxP10HdrEgrOvflCnt = 0;
+       cntrs->RxP11HdrEgrOvflCnt = 0;
+       cntrs->RxP12HdrEgrOvflCnt = 0;
+       cntrs->RxP13HdrEgrOvflCnt = 0;
+       cntrs->RxP14HdrEgrOvflCnt = 0;
+       cntrs->RxP15HdrEgrOvflCnt = 0;
+       cntrs->RxP16HdrEgrOvflCnt = 0;
+       cntrs->IBStatusChangeCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
+       cntrs->IBLinkErrRecoveryCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
+       cntrs->IBLinkDownedCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
+       cntrs->IBSymbolErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
+       cntrs->RxVL15DroppedPktCnt = 0;
+       cntrs->RxOtherLocalPhyErrCnt = 0;
+       cntrs->PcieRetryBufDiagQwordCnt = 0;
+       cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
+       cntrs->LocalLinkIntegrityErrCnt =
+               (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
+               dd->ipath_lli_errs : dd->ipath_lli_errors;
+       cntrs->RxVlErrCnt = 0;
+       cntrs->RxDlidFltrCnt = 0;
+}
+
+
+/* no interrupt fallback for these chips */
+static int ipath_ht_nointr_fallback(struct ipath_devdata *dd)
+{
+       return 0;
+}
+
+
+/*
+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well.
+ */
+static void ipath_ht_xgxs_reset(struct ipath_devdata *dd)
+{
+       u64 val, prev_val;
+
+       prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+       val = prev_val | INFINIPATH_XGXS_RESET;
+       prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+                        dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+                        dd->ipath_control);
+}
+
+
+static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which)
+{
+       int ret;
+
+       switch (which) {
+       case IPATH_IB_CFG_LWID:
+               ret = dd->ipath_link_width_active;
+               break;
+       case IPATH_IB_CFG_SPD:
+               ret = dd->ipath_link_speed_active;
+               break;
+       case IPATH_IB_CFG_LWID_ENB:
+               ret = dd->ipath_link_width_enabled;
+               break;
+       case IPATH_IB_CFG_SPD_ENB:
+               ret = dd->ipath_link_speed_enabled;
+               break;
+       default:
+               ret =  -ENOTSUPP;
+               break;
+       }
+       return ret;
+}
+
+
+/* we assume range checking is already done, if needed */
+static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
+{
+       int ret = 0;
+
+       if (which == IPATH_IB_CFG_LWID_ENB)
+               dd->ipath_link_width_enabled = val;
+       else if (which == IPATH_IB_CFG_SPD_ENB)
+               dd->ipath_link_speed_enabled = val;
+       else
+               ret = -ENOTSUPP;
+       return ret;
+}
+
+
+static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
+{
+}
+
+
+static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
+{
+       ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs),
+               ipath_ib_linktrstate(dd, ibcs));
+       return 0;
+}
+
+
 /**
  * ipath_init_iba6110_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
@@ -1626,22 +1926,19 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
        dd->ipath_f_setextled = ipath_setup_ht_setextled;
        dd->ipath_f_get_base_info = ipath_ht_get_base_info;
        dd->ipath_f_free_irq = ipath_ht_free_irq;
-
-       /*
-        * initialize chip-specific variables
-        */
        dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
+       dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback;
+       dd->ipath_f_get_msgheader = ipath_ht_get_msgheader;
+       dd->ipath_f_config_ports = ipath_ht_config_ports;
+       dd->ipath_f_read_counters = ipath_ht_read_counters;
+       dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset;
+       dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg;
+       dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg;
+       dd->ipath_f_config_jint = ipath_ht_config_jint;
+       dd->ipath_f_ib_updown = ipath_ht_ib_updown;
 
        /*
-        * setup the register offsets, since they are different for each
-        * chip
-        */
-       dd->ipath_kregs = &ipath_ht_kregs;
-       dd->ipath_cregs = &ipath_ht_cregs;
-
-       /*
-        * do very early init that is needed before ipath_f_bus is
-        * called
+        * initialize chip-specific variables
         */
        ipath_init_ht_variables(dd);
 }
index 0103d6f4847b7dcd354548a281b58fac48b1f8f7..c7a2f50824c08357be3620725077e83035bde4c0 100644 (file)
@@ -145,10 +145,57 @@ struct _infinipath_do_not_use_kernel_regs {
        unsigned long long Reserved12;
 };
 
-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
-    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+struct _infinipath_do_not_use_counters {
+       __u64 LBIntCnt;
+       __u64 LBFlowStallCnt;
+       __u64 Reserved1;
+       __u64 TxUnsupVLErrCnt;
+       __u64 TxDataPktCnt;
+       __u64 TxFlowPktCnt;
+       __u64 TxDwordCnt;
+       __u64 TxLenErrCnt;
+       __u64 TxMaxMinLenErrCnt;
+       __u64 TxUnderrunCnt;
+       __u64 TxFlowStallCnt;
+       __u64 TxDroppedPktCnt;
+       __u64 RxDroppedPktCnt;
+       __u64 RxDataPktCnt;
+       __u64 RxFlowPktCnt;
+       __u64 RxDwordCnt;
+       __u64 RxLenErrCnt;
+       __u64 RxMaxMinLenErrCnt;
+       __u64 RxICRCErrCnt;
+       __u64 RxVCRCErrCnt;
+       __u64 RxFlowCtrlErrCnt;
+       __u64 RxBadFormatCnt;
+       __u64 RxLinkProblemCnt;
+       __u64 RxEBPCnt;
+       __u64 RxLPCRCErrCnt;
+       __u64 RxBufOvflCnt;
+       __u64 RxTIDFullErrCnt;
+       __u64 RxTIDValidErrCnt;
+       __u64 RxPKeyMismatchCnt;
+       __u64 RxP0HdrEgrOvflCnt;
+       __u64 RxP1HdrEgrOvflCnt;
+       __u64 RxP2HdrEgrOvflCnt;
+       __u64 RxP3HdrEgrOvflCnt;
+       __u64 RxP4HdrEgrOvflCnt;
+       __u64 RxP5HdrEgrOvflCnt;
+       __u64 RxP6HdrEgrOvflCnt;
+       __u64 RxP7HdrEgrOvflCnt;
+       __u64 RxP8HdrEgrOvflCnt;
+       __u64 Reserved6;
+       __u64 Reserved7;
+       __u64 IBStatusChangeCnt;
+       __u64 IBLinkErrRecoveryCnt;
+       __u64 IBLinkDownedCnt;
+       __u64 IBSymbolErrCnt;
+};
+
+#define IPATH_KREG_OFFSET(field) (offsetof( \
+       struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
 #define IPATH_CREG_OFFSET(field) (offsetof( \
-    struct infinipath_counters, field) / sizeof(u64))
+       struct _infinipath_do_not_use_counters, field) / sizeof(u64))
 
 static const struct ipath_kregs ipath_pe_kregs = {
        .kr_control = IPATH_KREG_OFFSET(Control),
@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
 #define INFINIPATH_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
 #define INFINIPATH_HWE_SERDESPLLFAILED      0x1000000000000000ULL
 
+#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf
+#define IBA6120_IBCS_LINKSTATE_SHIFT 4
+
 /* kr_extstatus bits */
 #define INFINIPATH_EXTS_FREQSEL 0x2
 #define INFINIPATH_EXTS_SERDESSEL 0x4
@@ -296,6 +346,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
 #define IPATH_GPIO_SCL (1ULL << \
        (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
 
+#define INFINIPATH_R_INTRAVAIL_SHIFT 16
+#define INFINIPATH_R_TAILUPD_SHIFT 31
+
 /* 6120 specific hardware errors... */
 static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
        INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
@@ -320,10 +373,28 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
                        INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
                        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
 
-static int ipath_pe_txe_recover(struct ipath_devdata *);
 static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
                               u32, unsigned long);
 
+/*
+ * On platforms using this chip, and not having ordered WC stores, we
+ * can get TXE parity errors due to speculative reads to the PIO buffers,
+ * and this, due to a chip bug can result in (many) false parity error
+ * reports.  So it's a debug print on those, and an info print on systems
+ * where the speculative reads don't occur.
+ */
+static void ipath_pe_txe_recover(struct ipath_devdata *dd)
+{
+       if (ipath_unordered_wc())
+               ipath_dbg("Recovering from TXE PIO parity error\n");
+       else {
+               ++ipath_stats.sps_txeparity;
+               dev_info(&dd->pcidev->dev,
+                       "Recovering from TXE PIO parity error\n");
+       }
+}
+
+
 /**
  * ipath_pe_handle_hwerrors - display hardware errors.
  * @dd: the infinipath device
@@ -403,35 +474,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                 * occur if a processor speculative read is done to the PIO
                 * buffer while we are sending a packet, for example.
                 */
-               if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
+               if (hwerrs & TXE_PIO_PARITY) {
+                       ipath_pe_txe_recover(dd);
                        hwerrs &= ~TXE_PIO_PARITY;
-               if (hwerrs) {
-                       /*
-                        * if any set that we aren't ignoring only make the
-                        * complaint once, in case it's stuck or recurring,
-                        * and we get here multiple times
-                        * Force link down, so switch knows, and
-                        * LEDs are turned off
-                        */
-                       if (dd->ipath_flags & IPATH_INITTED) {
-                               ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
-                               ipath_setup_pe_setextled(dd,
-                                       INFINIPATH_IBCS_L_STATE_DOWN,
-                                       INFINIPATH_IBCS_LT_STATE_DISABLED);
-                               ipath_dev_err(dd, "Fatal Hardware Error (freeze "
-                                             "mode), no longer usable, SN %.16s\n",
-                                                 dd->ipath_serial);
-                               isfatal = 1;
-                       }
-                       /*
-                        * Mark as having had an error for driver, and also
-                        * for /sys and status word mapped to user programs.
-                        * This marks unit as not usable, until reset
-                        */
-                       *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-                       *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-                       dd->ipath_flags &= ~IPATH_INITTED;
-               } else {
+               }
+               if (!hwerrs) {
                        static u32 freeze_cnt;
 
                        freeze_cnt++;
@@ -485,7 +532,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
 
        if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
                /*
-                * If it occurs, it is left masked since the eternal
+                * If it occurs, it is left masked since the external
                 * interface is unused
                 */
                dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
@@ -563,6 +610,14 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
                        dd->ipath_f_put_tid = ipath_pe_put_tid_2;
        }
 
+
+       /*
+        * set here, not in ipath_init_*_funcs because we have to do
+        * it after we can read chip registers.
+        */
+       dd->ipath_ureg_align =
+               ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
+
        return ret;
 }
 
@@ -667,17 +722,8 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
 
        val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
        prev_val = val;
-       if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
-            INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
-               val &=
-                       ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
-                         INFINIPATH_XGXS_MDIOADDR_SHIFT);
-               /* MDIO address 3 */
-               val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
-       }
-       if (val & INFINIPATH_XGXS_RESET) {
+       if (val & INFINIPATH_XGXS_RESET)
                val &= ~INFINIPATH_XGXS_RESET;
-       }
        if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
             INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
                /* need to compensate for Tx inversion in partner */
@@ -707,21 +753,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
                   (unsigned long long)
                   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
 
-       if (!ipath_waitfor_mdio_cmdready(dd)) {
-               ipath_write_kreg(
-                       dd, dd->ipath_kregs->kr_mdio,
-                       ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
-                                      IPATH_MDIO_CTRL_XGXS_REG_8, 0));
-               if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
-                                          IPATH_MDIO_DATAVALID, &val))
-                       ipath_dbg("Never got MDIO data for XGXS "
-                                 "status read\n");
-               else
-                       ipath_cdbg(VERBOSE, "MDIO Read reg8, "
-                                  "'bank' 31 %x\n", (u32) val);
-       } else
-               ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
-
        return ret;
 }
 
@@ -902,11 +933,26 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
        else
                ipath_dev_err(dd, "Can't find PCI Express "
                              "capability!\n");
+
+       dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+       dd->ipath_link_speed_supported = IPATH_IB_SDR;
+       dd->ipath_link_width_enabled = IB_WIDTH_4X;
+       dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
+       /* these can't change for this chip, so set once */
+       dd->ipath_link_width_active = dd->ipath_link_width_enabled;
+       dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
        return 0;
 }
 
 static void ipath_init_pe_variables(struct ipath_devdata *dd)
 {
+       /*
+        * setup the register offsets, since they are different for each
+        * chip
+        */
+       dd->ipath_kregs = &ipath_pe_kregs;
+       dd->ipath_cregs = &ipath_pe_cregs;
+
        /*
         * bits for selecting i2c direction and values,
         * used for I2C serial flash
@@ -916,6 +962,43 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
        dd->ipath_gpio_sda = IPATH_GPIO_SDA;
        dd->ipath_gpio_scl = IPATH_GPIO_SCL;
 
+       /*
+        * Fill in data for field-values that change in newer chips.
+        * We dynamically specify only the mask for LINKTRAININGSTATE
+        * and only the shift for LINKSTATE, as they are the only ones
+        * that change.  Also precalculate the 3 link states of interest
+        * and the combined mask.
+        */
+       dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT;
+       dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK;
+       dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
+               dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
+       dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+               (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
+       dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+               (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
+       dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+               (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
+
+       /*
+        * Fill in data for ibcc field-values that change in newer chips.
+        * We dynamically specify only the mask for LINKINITCMD
+        * and only the shift for LINKCMD and MAXPKTLEN, as they are
+        * the only ones that change.
+        */
+       dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
+       dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
+       dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
+
+       /* Fill in shifts for RcvCtrl. */
+       dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
+       dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
+       dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
+       dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */
+
        /* variables for sanity checking interrupt and errors */
        dd->ipath_hwe_bitsextant =
                (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
@@ -963,6 +1046,8 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
 
        dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
        dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+       dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
+       dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
 
        /*
         * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
@@ -984,6 +1069,7 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
                INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
 
 
+       dd->delay_mult = 2; /* SDR, 4X, can't change */
 }
 
 /* setup the MSI stuff again after a reset.  I'd like to just call
@@ -1289,6 +1375,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
         */
        dd->ipath_rcvhdrentsize = 24;
        dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
+       dd->ipath_rhf_offset = 0;
+       dd->ipath_egrtidbase = (u64 __iomem *)
+               ((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase);
 
        /*
         * To truly support a 4KB MTU (for usermode), we need to
@@ -1359,34 +1448,204 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd)
        dd->ipath_irq = 0;
 }
 
+
+static struct ipath_message_header *
+ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
+{
+       return (struct ipath_message_header *)
+               &rhf_addr[sizeof(u64) / sizeof(u32)];
+}
+
+static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports)
+{
+       dd->ipath_portcnt =
+               ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+       dd->ipath_p0_rcvegrcnt =
+               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
+}
+
+static void ipath_pe_read_counters(struct ipath_devdata *dd,
+                                  struct infinipath_counters *cntrs)
+{
+       cntrs->LBIntCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
+       cntrs->LBFlowStallCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
+       cntrs->TxSDmaDescCnt = 0;
+       cntrs->TxUnsupVLErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
+       cntrs->TxDataPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
+       cntrs->TxFlowPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
+       cntrs->TxDwordCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
+       cntrs->TxLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
+       cntrs->TxMaxMinLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
+       cntrs->TxUnderrunCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
+       cntrs->TxFlowStallCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
+       cntrs->TxDroppedPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
+       cntrs->RxDroppedPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
+       cntrs->RxDataPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
+       cntrs->RxFlowPktCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
+       cntrs->RxDwordCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
+       cntrs->RxLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
+       cntrs->RxMaxMinLenErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
+       cntrs->RxICRCErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
+       cntrs->RxVCRCErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
+       cntrs->RxFlowCtrlErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
+       cntrs->RxBadFormatCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
+       cntrs->RxLinkProblemCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
+       cntrs->RxEBPCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
+       cntrs->RxLPCRCErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
+       cntrs->RxBufOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
+       cntrs->RxTIDFullErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
+       cntrs->RxTIDValidErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
+       cntrs->RxPKeyMismatchCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
+       cntrs->RxP0HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
+       cntrs->RxP1HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
+       cntrs->RxP2HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
+       cntrs->RxP3HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
+       cntrs->RxP4HdrEgrOvflCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
+       cntrs->RxP5HdrEgrOvflCnt = 0;
+       cntrs->RxP6HdrEgrOvflCnt = 0;
+       cntrs->RxP7HdrEgrOvflCnt = 0;
+       cntrs->RxP8HdrEgrOvflCnt = 0;
+       cntrs->RxP9HdrEgrOvflCnt = 0;
+       cntrs->RxP10HdrEgrOvflCnt = 0;
+       cntrs->RxP11HdrEgrOvflCnt = 0;
+       cntrs->RxP12HdrEgrOvflCnt = 0;
+       cntrs->RxP13HdrEgrOvflCnt = 0;
+       cntrs->RxP14HdrEgrOvflCnt = 0;
+       cntrs->RxP15HdrEgrOvflCnt = 0;
+       cntrs->RxP16HdrEgrOvflCnt = 0;
+       cntrs->IBStatusChangeCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
+       cntrs->IBLinkErrRecoveryCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
+       cntrs->IBLinkDownedCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
+       cntrs->IBSymbolErrCnt =
+               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
+       cntrs->RxVL15DroppedPktCnt = 0;
+       cntrs->RxOtherLocalPhyErrCnt = 0;
+       cntrs->PcieRetryBufDiagQwordCnt = 0;
+       cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
+       cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs;
+       cntrs->RxVlErrCnt = 0;
+       cntrs->RxDlidFltrCnt = 0;
+}
+
+
+/* no interrupt fallback for these chips */
+static int ipath_pe_nointr_fallback(struct ipath_devdata *dd)
+{
+       return 0;
+}
+
+
 /*
- * On platforms using this chip, and not having ordered WC stores, we
- * can get TXE parity errors due to speculative reads to the PIO buffers,
- * and this, due to a chip bug can result in (many) false parity error
- * reports.  So it's a debug print on those, and an info print on systems
- * where the speculative reads don't occur.
- * Because we can get lots of false errors, we have no upper limit
- * on recovery attempts on those platforms.
+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well.
  */
-static int ipath_pe_txe_recover(struct ipath_devdata *dd)
+static void ipath_pe_xgxs_reset(struct ipath_devdata *dd)
 {
-       if (ipath_unordered_wc())
-               ipath_dbg("Recovering from TXE PIO parity error\n");
-       else {
-               int cnt = ++ipath_stats.sps_txeparity;
-               if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
-                       if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
-                               ipath_dev_err(dd,
-                                       "Too many attempts to recover from "
-                                       "TXE parity, giving up\n");
-                       return 0;
-               }
-               dev_info(&dd->pcidev->dev,
-                       "Recovering from TXE PIO parity error\n");
+       u64 val, prev_val;
+
+       prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+       val = prev_val | INFINIPATH_XGXS_RESET;
+       prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+                        dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+                        dd->ipath_control);
+}
+
+
+static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which)
+{
+       int ret;
+
+       switch (which) {
+       case IPATH_IB_CFG_LWID:
+               ret = dd->ipath_link_width_active;
+               break;
+       case IPATH_IB_CFG_SPD:
+               ret = dd->ipath_link_speed_active;
+               break;
+       case IPATH_IB_CFG_LWID_ENB:
+               ret = dd->ipath_link_width_enabled;
+               break;
+       case IPATH_IB_CFG_SPD_ENB:
+               ret = dd->ipath_link_speed_enabled;
+               break;
+       default:
+               ret =  -ENOTSUPP;
+               break;
        }
-       return 1;
+       return ret;
+}
+
+
+/* we assume range checking is already done, if needed */
+static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
+{
+       int ret = 0;
+
+       if (which == IPATH_IB_CFG_LWID_ENB)
+               dd->ipath_link_width_enabled = val;
+       else if (which == IPATH_IB_CFG_SPD_ENB)
+               dd->ipath_link_speed_enabled = val;
+       else
+               ret = -ENOTSUPP;
+       return ret;
 }
 
+static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
+{
+}
+
+
+static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
+{
+       ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
+               ipath_ib_linktrstate(dd, ibcs));
+       return 0;
+}
+
+
 /**
  * ipath_init_iba6120_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
@@ -1407,7 +1666,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
        dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
        dd->ipath_f_clear_tids = ipath_pe_clear_tids;
        /*
-        * this may get changed after we read the chip revision,
+        * _f_put_tid may get changed after we read the chip revision,
         * but we start with the safe version for all revs
         */
        dd->ipath_f_put_tid = ipath_pe_put_tid;
@@ -1415,17 +1674,19 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
        dd->ipath_f_setextled = ipath_setup_pe_setextled;
        dd->ipath_f_get_base_info = ipath_pe_get_base_info;
        dd->ipath_f_free_irq = ipath_pe_free_irq;
-
-       /* initialize chip-specific variables */
        dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
+       dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback;
+       dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset;
+       dd->ipath_f_get_msgheader = ipath_pe_get_msgheader;
+       dd->ipath_f_config_ports = ipath_pe_config_ports;
+       dd->ipath_f_read_counters = ipath_pe_read_counters;
+       dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg;
+       dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg;
+       dd->ipath_f_config_jint = ipath_pe_config_jint;
+       dd->ipath_f_ib_updown = ipath_pe_ib_updown;
 
-       /*
-        * setup the register offsets, since they are different for each
-        * chip
-        */
-       dd->ipath_kregs = &ipath_pe_kregs;
-       dd->ipath_cregs = &ipath_pe_cregs;
 
+       /* initialize chip-specific variables */
        ipath_init_pe_variables(dd);
 }
 
index 9dd0bacf84610847f94270b79e5f243e2dd1ceb3..4471674975cd11e41fa15800ab3b8f9cfedeb104 100644 (file)
@@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd)
        struct ipath_skbinfo *skbinfo;
        int ret;
 
-       egrcnt = dd->ipath_rcvegrcnt;
+       egrcnt = dd->ipath_p0_rcvegrcnt;
 
        skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
        if (skbinfo == NULL) {
@@ -244,8 +244,7 @@ static int init_chip_first(struct ipath_devdata *dd,
         * cfgports.  We do still check and report a difference, if
         * not same (should be impossible).
         */
-       dd->ipath_portcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+       dd->ipath_f_config_ports(dd, ipath_cfgports);
        if (!ipath_cfgports)
                dd->ipath_cfgports = dd->ipath_portcnt;
        else if (ipath_cfgports <= dd->ipath_portcnt) {
@@ -272,22 +271,7 @@ static int init_chip_first(struct ipath_devdata *dd,
                goto done;
        }
 
-       dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads)
-                                        * dd->ipath_cfgports,
-                                        GFP_KERNEL);
-       dd->ipath_lastrcvhdrqtails =
-               kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails)
-                       * dd->ipath_cfgports, GFP_KERNEL);
-
-       if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) {
-               ipath_dev_err(dd, "Unable to allocate head arrays, "
-                             "failing\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-
        pd = create_portdata0(dd);
-
        if (!pd) {
                ipath_dev_err(dd, "Unable to allocate portdata for port "
                              "0, failing\n");
@@ -345,10 +329,10 @@ static int init_chip_first(struct ipath_devdata *dd,
                       dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
 
        spin_lock_init(&dd->ipath_tid_lock);
-
+       spin_lock_init(&dd->ipath_sendctrl_lock);
        spin_lock_init(&dd->ipath_gpio_lock);
        spin_lock_init(&dd->ipath_eep_st_lock);
-       sema_init(&dd->ipath_eep_sem, 1);
+       mutex_init(&dd->ipath_eep_lock);
 
 done:
        *pdp = pd;
@@ -372,9 +356,9 @@ static int init_chip_reset(struct ipath_devdata *dd,
        *pdp = dd->ipath_pd[0];
        /* ensure chip does no sends or receives while we re-initialize */
        dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control);
 
        rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
        if (dd->ipath_portcnt != rtmp)
@@ -487,6 +471,7 @@ static void enable_chip(struct ipath_devdata *dd,
                        struct ipath_portdata *pd, int reinit)
 {
        u32 val;
+       unsigned long flags;
        int i;
 
        if (!reinit)
@@ -495,19 +480,21 @@ static void enable_chip(struct ipath_devdata *dd,
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
                         dd->ipath_rcvctrl);
 
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
        /* Enable PIO send, and update of PIOavail regs to memory. */
        dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
                INFINIPATH_S_PIOBUFAVAILUPD;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                        dd->ipath_sendctrl);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
        /*
         * enable port 0 receive, and receive interrupt.  other ports
         * done as user opens and inits them.
         */
-       dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD |
-               (1ULL << INFINIPATH_R_PORTENABLE_SHIFT) |
-               (1ULL << INFINIPATH_R_INTRAVAIL_SHIFT);
+       dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) |
+               (1ULL << dd->ipath_r_portenable_shift) |
+               (1ULL << dd->ipath_r_intravail_shift);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
                         dd->ipath_rcvctrl);
 
@@ -523,12 +510,11 @@ static void enable_chip(struct ipath_devdata *dd,
         */
        val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);
        (void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);
-       dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0);
 
        /* Initialize so we interrupt on next packet received */
        (void)ipath_write_ureg(dd, ur_rcvhdrhead,
                               dd->ipath_rhdrhead_intr_off |
-                              dd->ipath_port0head, 0);
+                              dd->ipath_pd[0]->port_head, 0);
 
        /*
         * by now pioavail updates to memory should have occurred, so
@@ -542,12 +528,8 @@ static void enable_chip(struct ipath_devdata *dd,
                /*
                 * Chip Errata bug 6641; even and odd qwords>3 are swapped.
                 */
-               if (i > 3) {
-                       if (i & 1)
-                               val = dd->ipath_pioavailregs_dma[i - 1];
-                       else
-                               val = dd->ipath_pioavailregs_dma[i + 1];
-               }
+               if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
+                       val = dd->ipath_pioavailregs_dma[i ^ 1];
                else
                        val = dd->ipath_pioavailregs_dma[i];
                dd->ipath_pioavailshadow[i] = le64_to_cpu(val);
@@ -690,12 +672,13 @@ done:
  */
 int ipath_init_chip(struct ipath_devdata *dd, int reinit)
 {
-       int ret = 0, i;
+       int ret = 0;
        u32 val32, kpiobufs;
        u32 piobufs, uports;
        u64 val;
        struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
        gfp_t gfp_flags = GFP_USER | __GFP_COMP;
+       unsigned long flags;
 
        ret = init_housekeeping(dd, &pd, reinit);
        if (ret)
@@ -746,7 +729,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
                kpiobufs = ipath_kpiobufs;
 
        if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
-               i = (int) piobufs -
+               int i = (int) piobufs -
                        (int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
                if (i < 0)
                        i = 0;
@@ -827,8 +810,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
        ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
                         ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                        INFINIPATH_S_PIOENABLE);
+
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
        /*
         * before error clears, since we expect serdes pll errors during
index c61f9da2964ab25a51bb686808ffaa3c4ceb1e33..92e58c921522c2e1eae807e077b9322e65c74ae3 100644 (file)
@@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                for (i = 0; i < dd->ipath_cfgports; i++) {
                        struct ipath_portdata *pd = dd->ipath_pd[i];
                        if (i == 0) {
-                               hd = dd->ipath_port0head;
+                               hd = pd->port_head;
                                tl = (u32) le64_to_cpu(
                                        *dd->ipath_hdrqtailptr);
                        } else if (pd && pd->port_cnt &&
@@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                                 * except kernel
                                 */
                                tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
-                               if (tl == dd->ipath_lastrcvhdrqtails[i])
+                               if (tl == pd->port_lastrcvhdrqtail)
                                        continue;
                                hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
                                                       i);
@@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                            (!hd && tl == dd->ipath_hdrqlast)) {
                                if (i == 0)
                                        chkerrpkts = 1;
-                               dd->ipath_lastrcvhdrqtails[i] = tl;
+                               pd->port_lastrcvhdrqtail = tl;
                                pd->port_hdrqfull++;
                                /* flush hdrqfull so that poll() sees it */
                                wmb();
@@ -712,6 +712,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                }
        }
        if (errs & INFINIPATH_E_RRCVEGRFULL) {
+               struct ipath_portdata *pd = dd->ipath_pd[0];
+
                /*
                 * since this is of less importance and not likely to
                 * happen without also getting hdrfull, only count
@@ -719,7 +721,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                 * vs user)
                 */
                ipath_stats.sps_etidfull++;
-               if (dd->ipath_port0head !=
+               if (pd->port_head !=
                    (u32) le64_to_cpu(*dd->ipath_hdrqtailptr))
                        chkerrpkts = 1;
        }
@@ -795,6 +797,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 {
        int i, im;
        __le64 val;
+       unsigned long flags;
 
        /* disable error interrupts, to avoid confusion */
        ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
@@ -813,11 +816,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
                         dd->ipath_control);
 
        /* ensure pio avail updates continue */
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                 dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
        ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                dd->ipath_sendctrl);
+                        dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
        /*
         * We just enabled pioavailupdate, so dma copy is almost certainly
@@ -825,8 +831,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
         */
        for (i = 0; i < dd->ipath_pioavregs; i++) {
                /* deal with 6110 chip bug */
-               im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
-               val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
+               im = i > 3 ? i ^ 1 : i;
+               val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
                dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
                        = le64_to_cpu(val);
        }
@@ -849,7 +855,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 
 /* this is separate to allow for better optimization of ipath_intr() */
 
-static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
+static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
 {
        /*
         * sometimes happen during driver init and unload, don't want
@@ -877,7 +883,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
                                dd->ipath_f_free_irq(dd);
                        }
                }
-               if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
+               if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) {
                        ipath_dev_err(dd, "%u unexpected interrupts, "
                                      "disabling interrupts completely\n",
                                      *unexpectp);
@@ -892,7 +898,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
                          "ignoring\n");
 }
 
-static void ipath_bad_regread(struct ipath_devdata *dd)
+static noinline void ipath_bad_regread(struct ipath_devdata *dd)
 {
        static int allbits;
 
@@ -920,31 +926,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
        }
 }
 
-static void handle_port_pioavail(struct ipath_devdata *dd)
-{
-       u32 i;
-       /*
-        * start from port 1, since for now port 0  is never using
-        * wait_event for PIO
-        */
-       for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) {
-               struct ipath_portdata *pd = dd->ipath_pd[i];
-
-               if (pd && pd->port_cnt &&
-                   dd->ipath_portpiowait & (1U << i)) {
-                       clear_bit(i, &dd->ipath_portpiowait);
-                       if (test_bit(IPATH_PORT_WAITING_PIO,
-                                    &pd->port_flag)) {
-                               clear_bit(IPATH_PORT_WAITING_PIO,
-                                         &pd->port_flag);
-                               wake_up_interruptible(&pd->port_wait);
-                       }
-               }
-       }
-}
-
 static void handle_layer_pioavail(struct ipath_devdata *dd)
 {
+       unsigned long flags;
        int ret;
 
        ret = ipath_ib_piobufavail(dd->verbs_dev);
@@ -953,9 +937,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
 
        return;
 set:
-       set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                         dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 }
 
 /*
@@ -969,7 +956,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
        int i;
        int rcvdint = 0;
 
-       /* test_bit below needs this... */
+       /*
+        * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
+        * test_and_clear_bit(IPATH_PORT_WAITING_URG) below
+        * would both like timely updates of the bits so that
+        * we don't pass them by unnecessarily.  the rmb()
+        * here ensures that we see them promptly -- the
+        * corresponding wmb()'s are in ipath_poll_urgent()
+        * and ipath_poll_next()...
+        */
        rmb();
        portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
                 dd->ipath_i_rcvavail_mask)
@@ -980,7 +975,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
                if (portr & (1 << i) && pd && pd->port_cnt) {
                        if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
                                               &pd->port_flag)) {
-                               clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
+                               clear_bit(i + dd->ipath_r_intravail_shift,
                                          &dd->ipath_rcvctrl);
                                wake_up_interruptible(&pd->port_wait);
                                rcvdint = 1;
@@ -1039,7 +1034,7 @@ irqreturn_t ipath_intr(int irq, void *data)
                goto bail;
        }
 
-       istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
+       istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus);
 
        if (unlikely(!istat)) {
                ipath_stats.sps_nullintr++;
@@ -1180,7 +1175,7 @@ irqreturn_t ipath_intr(int irq, void *data)
         * for receive are at the bottom.
         */
        if (chk0rcv) {
-               ipath_kreceive(dd);
+               ipath_kreceive(dd->ipath_pd[0]);
                istat &= ~port0rbits;
        }
 
@@ -1191,12 +1186,14 @@ irqreturn_t ipath_intr(int irq, void *data)
                handle_urcv(dd, istat);
 
        if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
-               clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+               unsigned long flags;
+
+               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+               dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                                 dd->ipath_sendctrl);
-
-               if (dd->ipath_portpiowait)
-                       handle_port_pioavail(dd);
+               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
                handle_layer_pioavail(dd);
        }
index 8786dd7922e4e3916170af24d8cb8752793ea7ba..4cc0f95ea8777ee7aaf040e1089fe48d9d7cba66 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <rdma/ib_verbs.h>
 
@@ -140,6 +141,11 @@ struct ipath_portdata {
        u32 port_pionowait;
        /* total number of rcvhdrqfull errors */
        u32 port_hdrqfull;
+       /*
+        * Used to suppress multiple instances of same
+        * port staying stuck at same point.
+        */
+       u32 port_lastrcvhdrqtail;
        /* saved total number of rcvhdrqfull errors for poll edge trigger */
        u32 port_hdrqfull_poll;
        /* total number of polled urgent packets */
@@ -148,6 +154,7 @@ struct ipath_portdata {
        u32 port_urgent_poll;
        /* pid of process using this port */
        pid_t port_pid;
+       pid_t port_subpid[INFINIPATH_MAX_SUBPORT];
        /* same size as task_struct .comm[] */
        char port_comm[16];
        /* pkeys set by this use of this port */
@@ -166,6 +173,8 @@ struct ipath_portdata {
        u32 active_slaves;
        /* Type of packets or conditions we want to poll for */
        u16 poll_type;
+       /* port rcvhdrq head offset */
+       u32 port_head;
 };
 
 struct sk_buff;
@@ -182,6 +191,22 @@ struct ipath_skbinfo {
        dma_addr_t phys;
 };
 
+/*
+ * Possible IB config parameters for ipath_f_get/set_ib_cfg()
+ */
+#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */
+#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */
+#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */
+#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */
+#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */
+#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */
+#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */
+#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */
+#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */
+#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */
+#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */
+
+
 struct ipath_devdata {
        struct list_head ipath_list;
 
@@ -222,6 +247,8 @@ struct ipath_devdata {
        struct _ipath_layer ipath_layer;
        /* setup intr */
        int (*ipath_f_intrsetup)(struct ipath_devdata *);
+       /* fallback to alternate interrupt type if possible */
+       int (*ipath_f_intr_fallback)(struct ipath_devdata *);
        /* setup on-chip bus config */
        int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *);
        /* hard reset chip */
@@ -244,6 +271,18 @@ struct ipath_devdata {
        int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
        /* free irq */
        void (*ipath_f_free_irq)(struct ipath_devdata *);
+       struct ipath_message_header *(*ipath_f_get_msgheader)
+                                       (struct ipath_devdata *, __le32 *);
+       void (*ipath_f_config_ports)(struct ipath_devdata *, ushort);
+       int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int);
+       int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32);
+       void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16);
+       void (*ipath_f_read_counters)(struct ipath_devdata *,
+                                       struct infinipath_counters *);
+       void (*ipath_f_xgxs_reset)(struct ipath_devdata *);
+       /* per chip actions needed for IB Link up/down changes */
+       int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64);
+
        struct ipath_ibdev *verbs_dev;
        struct timer_list verbs_timer;
        /* total dwords sent (summed from counter) */
@@ -313,21 +352,11 @@ struct ipath_devdata {
         * supports, less gives more pio bufs/port, etc.
         */
        u32 ipath_cfgports;
-       /* port0 rcvhdrq head offset */
-       u32 ipath_port0head;
        /* count of port 0 hdrqfull errors */
        u32 ipath_p0_hdrqfull;
+       /* port 0 number of receive eager buffers */
+       u32 ipath_p0_rcvegrcnt;
 
-       /*
-        * (*cfgports) used to suppress multiple instances of same
-        * port staying stuck at same point
-        */
-       u32 *ipath_lastrcvhdrqtails;
-       /*
-        * (*cfgports) used to suppress multiple instances of same
-        * port staying stuck at same point
-        */
-       u32 *ipath_lastegrheads;
        /*
         * index of last piobuffer we used.  Speeds up searching, by
         * starting at this point.  Doesn't matter if multiple cpu's use and
@@ -367,14 +396,15 @@ struct ipath_devdata {
        unsigned long ipath_wc_len;
        /* ref count for each pkey */
        atomic_t ipath_pkeyrefs[4];
-       /* shadow copy of all exptids physaddr; used only by funcsim */
-       u64 *ipath_tidsimshadow;
        /* shadow copy of struct page *'s for exp tid pages */
        struct page **ipath_pageshadow;
        /* shadow copy of dma handles for exp tid pages */
        dma_addr_t *ipath_physshadow;
-       /* lock to workaround chip bug 9437 */
+       u64 __iomem *ipath_egrtidbase;
+       /* lock to workaround chip bug 9437 and others */
+       spinlock_t ipath_kernel_tid_lock;
        spinlock_t ipath_tid_lock;
+       spinlock_t ipath_sendctrl_lock;
 
        /*
         * IPATH_STATUS_*,
@@ -395,6 +425,8 @@ struct ipath_devdata {
        void *ipath_dummy_hdrq; /* used after port close */
        dma_addr_t ipath_dummy_hdrq_phys;
 
+       unsigned long ipath_ureg_align; /* user register alignment */
+
        /*
         * Shadow copies of registers; size indicates read access size.
         * Most of them are readonly, but some are write-only register,
@@ -456,8 +488,6 @@ struct ipath_devdata {
        unsigned long ipath_rcvctrl;
        /* shadow kr_sendctrl */
        unsigned long ipath_sendctrl;
-       /* ports waiting for PIOavail intr */
-       unsigned long ipath_portpiowait;
        unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
 
        /* value we put in kr_rcvhdrcnt */
@@ -550,12 +580,26 @@ struct ipath_devdata {
        u8 ipath_minrev;
        /* board rev, from ipath_revision */
        u8 ipath_boardrev;
+
+       u8 ipath_r_portenable_shift;
+       u8 ipath_r_intravail_shift;
+       u8 ipath_r_tailupd_shift;
+       u8 ipath_r_portcfg_shift;
+
        /* unit # of this chip, if present */
        int ipath_unit;
        /* saved for restore after reset */
        u8 ipath_pci_cacheline;
        /* LID mask control */
        u8 ipath_lmc;
+       /* link width supported */
+       u8 ipath_link_width_supported;
+       /* link speed supported */
+       u8 ipath_link_speed_supported;
+       u8 ipath_link_width_enabled;
+       u8 ipath_link_speed_enabled;
+       u8 ipath_link_width_active;
+       u8 ipath_link_speed_active;
        /* Rx Polarity inversion (compensate for ~tx on partner) */
        u8 ipath_rx_pol_inv;
 
@@ -590,6 +634,8 @@ struct ipath_devdata {
         */
        u32 ipath_i_rcvavail_mask;
        u32 ipath_i_rcvurg_mask;
+       u16 ipath_i_rcvurg_shift;
+       u16 ipath_i_rcvavail_shift;
 
        /*
         * Register bits for selecting i2c direction and values, used for
@@ -603,6 +649,29 @@ struct ipath_devdata {
        /* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
        spinlock_t ipath_gpio_lock;
 
+       /*
+        * IB link and linktraining states and masks that vary per chip in
+        * some way.  Set at init, to avoid each IB status change interrupt
+        */
+       u8 ibcs_ls_shift;
+       u8 ibcs_lts_mask;
+       u32 ibcs_mask;
+       u32 ib_init;
+       u32 ib_arm;
+       u32 ib_active;
+
+       u16 ipath_rhf_offset; /* offset of RHF within receive header entry */
+
+       /*
+        * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol
+        * reg. Changes for IBA7220
+        */
+       u8 ibcc_lic_mask; /* LinkInitCmd */
+       u8 ibcc_lc_shift; /* LinkCmd */
+       u8 ibcc_mpl_shift; /* Maxpktlen */
+
+       u8 delay_mult;
+
        /* used to override LED behavior */
        u8 ipath_led_override;  /* Substituted for normal value, if non-zero */
        u16 ipath_led_override_timeoff; /* delta to next timer event */
@@ -616,7 +685,7 @@ struct ipath_devdata {
        /* control access to actual counters, timer */
        spinlock_t ipath_eep_st_lock;
        /* control high-level access to EEPROM */
-       struct semaphore ipath_eep_sem;
+       struct mutex ipath_eep_lock;
        /* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
        uint64_t ipath_traffic_wds;
        /* active time is kept in seconds, but logged in hours */
@@ -630,6 +699,10 @@ struct ipath_devdata {
         * each of the counters to increment.
         */
        struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
+
+       /* interrupt mitigation reload register info */
+       u16 ipath_jint_idle_ticks;      /* idle clock ticks */
+       u16 ipath_jint_max_packets;     /* max packets across all ports */
 };
 
 /* Private data for file operations */
@@ -690,7 +763,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
 
 int ipath_parse_ushort(const char *str, unsigned short *valp);
 
-void ipath_kreceive(struct ipath_devdata *);
+void ipath_kreceive(struct ipath_portdata *);
 int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
 int ipath_reset_device(int);
 void ipath_get_faststats(unsigned long);
@@ -698,6 +771,8 @@ int ipath_set_linkstate(struct ipath_devdata *, u8);
 int ipath_set_mtu(struct ipath_devdata *, u16);
 int ipath_set_lid(struct ipath_devdata *, u32, u8);
 int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
+void ipath_enable_armlaunch(struct ipath_devdata *);
+void ipath_disable_armlaunch(struct ipath_devdata *);
 
 /* for use in system calls, where we want to know device type, etc. */
 #define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
@@ -744,9 +819,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
                 * are 64bit */
 #define IPATH_32BITCOUNTERS 0x20000
                /* can miss port0 rx interrupts */
+               /* Interrupt register is 64 bits */
+#define IPATH_INTREG_64     0x40000
 #define IPATH_DISABLED      0x80000 /* administratively disabled */
                /* Use GPIO interrupts for new counters */
 #define IPATH_GPIO_ERRINTRS 0x100000
+#define IPATH_SWAP_PIOBUFS  0x200000
+               /* Suppress heartbeat, even if turning off loopback */
+#define IPATH_NO_HRTBT      0x1000000
+#define IPATH_HAS_MULT_IB_SPEED 0x8000000
 
 /* Bits in GPIO for the added interrupts */
 #define IPATH_GPIO_PORT0_BIT 2
@@ -758,8 +839,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
 /* portdata flag bit offsets */
                /* waiting for a packet to arrive */
 #define IPATH_PORT_WAITING_RCV   2
-               /* waiting for a PIO buffer to be available */
-#define IPATH_PORT_WAITING_PIO   3
                /* master has not finished initializing */
 #define IPATH_PORT_MASTER_UNINIT 4
                /* waiting for an urgent packet to arrive */
@@ -767,8 +846,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
 
 /* free up any allocated data at closes */
 void ipath_free_data(struct ipath_portdata *dd);
-int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
-int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
 u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
 void ipath_init_iba6120_funcs(struct ipath_devdata *);
 void ipath_init_iba6110_funcs(struct ipath_devdata *);
@@ -792,33 +869,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
  */
 #define IPATH_DFLT_RCVHDRSIZE 9
 
-#define IPATH_MDIO_CMD_WRITE   1
-#define IPATH_MDIO_CMD_READ    2
-#define IPATH_MDIO_CLD_DIV     25      /* to get 2.5 Mhz mdio clock */
-#define IPATH_MDIO_CMDVALID    0x40000000      /* bit 30 */
-#define IPATH_MDIO_DATAVALID   0x80000000      /* bit 31 */
-#define IPATH_MDIO_CTRL_STD    0x0
-
-static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
-{
-       return (((u64) IPATH_MDIO_CLD_DIV) << 32) |
-               (cmd << 26) |
-               (dev << 21) |
-               (reg << 16) |
-               (data & 0xFFFF);
-}
-
-               /* signal and fifo status, in bank 31 */
-#define IPATH_MDIO_CTRL_XGXS_REG_8  0x8
-               /* controls loopback, redundancy */
-#define IPATH_MDIO_CTRL_8355_REG_1  0x10
-               /* premph, encdec, etc. */
-#define IPATH_MDIO_CTRL_8355_REG_2  0x11
-               /* Kchars, etc. */
-#define IPATH_MDIO_CTRL_8355_REG_6  0x15
-#define IPATH_MDIO_CTRL_8355_REG_9  0x18
-#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
-
 int ipath_get_user_pages(unsigned long, size_t, struct page **);
 void ipath_release_user_pages(struct page **, size_t);
 void ipath_release_user_pages_on_close(struct page **, size_t);
@@ -863,7 +913,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
        return readl(regno + (u64 __iomem *)
                     (dd->ipath_uregbase +
                      (char __iomem *)dd->ipath_kregbase +
-                     dd->ipath_palign * port));
+                     dd->ipath_ureg_align * port));
 }
 
 /**
@@ -880,7 +930,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd,
 {
        u64 __iomem *ubase = (u64 __iomem *)
                (dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase +
-                dd->ipath_palign * port);
+                dd->ipath_ureg_align * port);
        if (dd->ipath_kregbase)
                writeq(value, &ubase[regno]);
 }
@@ -930,6 +980,53 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
                      (char __iomem *)dd->ipath_kregbase));
 }
 
+static inline void ipath_write_creg(const struct ipath_devdata *dd,
+                                   ipath_creg regno, u64 value)
+{
+       if (dd->ipath_kregbase)
+               writeq(value, regno + (u64 __iomem *)
+                      (dd->ipath_cregbase +
+                       (char __iomem *)dd->ipath_kregbase));
+}
+
+static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd)
+{
+       *((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL;
+}
+
+static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd)
+{
+       return (u32) le64_to_cpu(*((volatile __le64 *)
+                               pd->port_rcvhdrtail_kvaddr));
+}
+
+static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r)
+{
+       return (dd->ipath_flags & IPATH_INTREG_64) ?
+               ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r);
+}
+
+/*
+ * from contents of IBCStatus (or a saved copy), return linkstate
+ * Report ACTIVE_DEFER as ACTIVE, because we treat them the same
+ * everywhere, anyway (and should be, for almost all purposes).
+ */
+static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
+{
+       u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) &
+               INFINIPATH_IBCS_LINKSTATE_MASK;
+       if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER)
+               state = INFINIPATH_IBCS_L_STATE_ACTIVE;
+       return state;
+}
+
+/* from contents of IBCStatus (or a saved copy), return linktrainingstate */
+static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs)
+{
+       return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
+               dd->ibcs_lts_mask;
+}
+
 /*
  * sysfs interface.
  */
@@ -938,8 +1035,7 @@ struct device_driver;
 
 extern const char ib_ipath_version[];
 
-int ipath_driver_create_group(struct device_driver *);
-void ipath_driver_remove_group(struct device_driver *);
+extern struct attribute_group *ipath_driver_attr_groups[];
 
 int ipath_device_create_group(struct device *, struct ipath_devdata *);
 void ipath_device_remove_group(struct device *, struct ipath_devdata *);
index 85a4aefc6c03cbbb94f63af4eade1f92a36f91fe..8f32b17a5eed019d304a4b3c4283019274e69170 100644 (file)
@@ -128,9 +128,8 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
        int ret;
 
        /*
-        * We use LKEY == zero to mean a physical kmalloc() address.
-        * This is a bit of a hack since we rely on dma_map_single()
-        * being reversible by calling bus_to_virt().
+        * We use LKEY == zero for kernel virtual addresses
+        * (see ipath_get_dma_mr and ipath_dma.c).
         */
        if (sge->lkey == 0) {
                struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
index 3d1432d1e3f40dbe7a3da11e7dbde429c21c7e19..d98d5f103700faab9fd94373f18604d61c214115 100644 (file)
@@ -934,6 +934,7 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
        struct ib_pma_portsamplescontrol *p =
                (struct ib_pma_portsamplescontrol *)pmp->data;
        struct ipath_ibdev *dev = to_idev(ibdev);
+       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
        unsigned long flags;
        u8 port_select = p->port_select;
 
@@ -955,7 +956,10 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
        p->counter_width = 4;   /* 32 bit counters */
        p->counter_mask0_9 = COUNTER_MASK0_9;
        spin_lock_irqsave(&dev->pending_lock, flags);
-       p->sample_status = dev->pma_sample_status;
+       if (crp->cr_psstat)
+               p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+       else
+               p->sample_status = dev->pma_sample_status;
        p->sample_start = cpu_to_be32(dev->pma_sample_start);
        p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
        p->tag = cpu_to_be16(dev->pma_tag);
@@ -975,8 +979,9 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
        struct ib_pma_portsamplescontrol *p =
                (struct ib_pma_portsamplescontrol *)pmp->data;
        struct ipath_ibdev *dev = to_idev(ibdev);
+       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
        unsigned long flags;
-       u32 start;
+       u8 status;
        int ret;
 
        if (pmp->attr_mod != 0 ||
@@ -986,59 +991,67 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
                goto bail;
        }
 
-       start = be32_to_cpu(p->sample_start);
-       if (start != 0) {
-               spin_lock_irqsave(&dev->pending_lock, flags);
-               if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) {
-                       dev->pma_sample_status =
-                               IB_PMA_SAMPLE_STATUS_STARTED;
-                       dev->pma_sample_start = start;
-                       dev->pma_sample_interval =
-                               be32_to_cpu(p->sample_interval);
-                       dev->pma_tag = be16_to_cpu(p->tag);
-                       if (p->counter_select[0])
-                               dev->pma_counter_select[0] =
-                                       p->counter_select[0];
-                       if (p->counter_select[1])
-                               dev->pma_counter_select[1] =
-                                       p->counter_select[1];
-                       if (p->counter_select[2])
-                               dev->pma_counter_select[2] =
-                                       p->counter_select[2];
-                       if (p->counter_select[3])
-                               dev->pma_counter_select[3] =
-                                       p->counter_select[3];
-                       if (p->counter_select[4])
-                               dev->pma_counter_select[4] =
-                                       p->counter_select[4];
-               }
-               spin_unlock_irqrestore(&dev->pending_lock, flags);
+       spin_lock_irqsave(&dev->pending_lock, flags);
+       if (crp->cr_psstat)
+               status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+       else
+               status = dev->pma_sample_status;
+       if (status == IB_PMA_SAMPLE_STATUS_DONE) {
+               dev->pma_sample_start = be32_to_cpu(p->sample_start);
+               dev->pma_sample_interval = be32_to_cpu(p->sample_interval);
+               dev->pma_tag = be16_to_cpu(p->tag);
+               dev->pma_counter_select[0] = p->counter_select[0];
+               dev->pma_counter_select[1] = p->counter_select[1];
+               dev->pma_counter_select[2] = p->counter_select[2];
+               dev->pma_counter_select[3] = p->counter_select[3];
+               dev->pma_counter_select[4] = p->counter_select[4];
+               if (crp->cr_psstat) {
+                       ipath_write_creg(dev->dd, crp->cr_psinterval,
+                                        dev->pma_sample_interval);
+                       ipath_write_creg(dev->dd, crp->cr_psstart,
+                                        dev->pma_sample_start);
+               } else
+                       dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
        }
+       spin_unlock_irqrestore(&dev->pending_lock, flags);
+
        ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
 
 bail:
        return ret;
 }
 
-static u64 get_counter(struct ipath_ibdev *dev, __be16 sel)
+static u64 get_counter(struct ipath_ibdev *dev,
+                      struct ipath_cregs const *crp,
+                      __be16 sel)
 {
        u64 ret;
 
        switch (sel) {
        case IB_PMA_PORT_XMIT_DATA:
-               ret = dev->ipath_sword;
+               ret = (crp->cr_psxmitdatacount) ?
+                       ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) :
+                       dev->ipath_sword;
                break;
        case IB_PMA_PORT_RCV_DATA:
-               ret = dev->ipath_rword;
+               ret = (crp->cr_psrcvdatacount) ?
+                       ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) :
+                       dev->ipath_rword;
                break;
        case IB_PMA_PORT_XMIT_PKTS:
-               ret = dev->ipath_spkts;
+               ret = (crp->cr_psxmitpktscount) ?
+                       ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) :
+                       dev->ipath_spkts;
                break;
        case IB_PMA_PORT_RCV_PKTS:
-               ret = dev->ipath_rpkts;
+               ret = (crp->cr_psrcvpktscount) ?
+                       ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) :
+                       dev->ipath_rpkts;
                break;
        case IB_PMA_PORT_XMIT_WAIT:
-               ret = dev->ipath_xmit_wait;
+               ret = (crp->cr_psxmitwaitcount) ?
+                       ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) :
+                       dev->ipath_xmit_wait;
                break;
        default:
                ret = 0;
@@ -1053,14 +1066,21 @@ static int recv_pma_get_portsamplesresult(struct ib_perf *pmp,
        struct ib_pma_portsamplesresult *p =
                (struct ib_pma_portsamplesresult *)pmp->data;
        struct ipath_ibdev *dev = to_idev(ibdev);
+       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
+       u8 status;
        int i;
 
        memset(pmp->data, 0, sizeof(pmp->data));
        p->tag = cpu_to_be16(dev->pma_tag);
-       p->sample_status = cpu_to_be16(dev->pma_sample_status);
+       if (crp->cr_psstat)
+               status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+       else
+               status = dev->pma_sample_status;
+       p->sample_status = cpu_to_be16(status);
        for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
-               p->counter[i] = cpu_to_be32(
-                       get_counter(dev, dev->pma_counter_select[i]));
+               p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
+                   cpu_to_be32(
+                       get_counter(dev, crp, dev->pma_counter_select[i]));
 
        return reply((struct ib_smp *) pmp);
 }
@@ -1071,16 +1091,23 @@ static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp,
        struct ib_pma_portsamplesresult_ext *p =
                (struct ib_pma_portsamplesresult_ext *)pmp->data;
        struct ipath_ibdev *dev = to_idev(ibdev);
+       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
+       u8 status;
        int i;
 
        memset(pmp->data, 0, sizeof(pmp->data));
        p->tag = cpu_to_be16(dev->pma_tag);
-       p->sample_status = cpu_to_be16(dev->pma_sample_status);
+       if (crp->cr_psstat)
+               status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+       else
+               status = dev->pma_sample_status;
+       p->sample_status = cpu_to_be16(status);
        /* 64 bits */
        p->extended_width = __constant_cpu_to_be32(0x80000000);
        for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
-               p->counter[i] = cpu_to_be64(
-                       get_counter(dev, dev->pma_counter_select[i]));
+               p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
+                   cpu_to_be64(
+                       get_counter(dev, crp, dev->pma_counter_select[i]));
 
        return reply((struct ib_smp *) pmp);
 }
@@ -1113,6 +1140,8 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
                dev->z_local_link_integrity_errors;
        cntrs.excessive_buffer_overrun_errors -=
                dev->z_excessive_buffer_overrun_errors;
+       cntrs.vl15_dropped -= dev->z_vl15_dropped;
+       cntrs.vl15_dropped += dev->n_vl15_dropped;
 
        memset(pmp->data, 0, sizeof(pmp->data));
 
@@ -1156,10 +1185,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
                cntrs.excessive_buffer_overrun_errors = 0xFUL;
        p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
                cntrs.excessive_buffer_overrun_errors;
-       if (dev->n_vl15_dropped > 0xFFFFUL)
+       if (cntrs.vl15_dropped > 0xFFFFUL)
                p->vl15_dropped = __constant_cpu_to_be16(0xFFFF);
        else
-               p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped);
+               p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
        if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
                p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF);
        else
@@ -1262,8 +1291,10 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp,
                dev->z_excessive_buffer_overrun_errors =
                        cntrs.excessive_buffer_overrun_errors;
 
-       if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED)
+       if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
                dev->n_vl15_dropped = 0;
+               dev->z_vl15_dropped = cntrs.vl15_dropped;
+       }
 
        if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
                dev->z_port_xmit_data = cntrs.port_xmit_data;
@@ -1434,7 +1465,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
                 * before checking for other consumers.
                 * Just tell the caller to process it normally.
                 */
-               ret = IB_MAD_RESULT_FAILURE;
+               ret = IB_MAD_RESULT_SUCCESS;
                goto bail;
        default:
                smp->status |= IB_SMP_UNSUP_METHOD;
@@ -1516,7 +1547,7 @@ static int process_perf(struct ib_device *ibdev, u8 port_num,
                 * before checking for other consumers.
                 * Just tell the caller to process it normally.
                 */
-               ret = IB_MAD_RESULT_FAILURE;
+               ret = IB_MAD_RESULT_SUCCESS;
                goto bail;
        default:
                pmp->status |= IB_SMP_UNSUP_METHOD;
index b997ff88401bf5f3ceca581a48ac05d4a94ba079..80dc623cee403637c5d828cc33a519204b869b1d 100644 (file)
@@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
        struct ib_wc wc;
        int ret = 0;
 
-       ipath_dbg("QP%d/%d in error state\n",
-                 qp->ibqp.qp_num, qp->remote_qpn);
+       ipath_dbg("QP%d/%d in error state (%d)\n",
+                 qp->ibqp.qp_num, qp->remote_qpn, err);
 
        spin_lock(&dev->pending_lock);
        /* XXX What if its already removed by the timeout code? */
@@ -855,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
         * See ipath_mmap() for details.
         */
        if (udata && udata->outlen >= sizeof(__u64)) {
-               int err;
-
                if (!qp->r_rq.wq) {
                        __u64 offset = 0;
 
index 120a61b03bc4846de8423c436767806e563e97d6..459e46e2c016b93926c2221fc2a3f73a2deeaefd 100644 (file)
@@ -647,6 +647,7 @@ static void send_rc_ack(struct ipath_qp *qp)
 
 queue_ack:
        spin_lock_irqsave(&qp->s_lock, flags);
+       dev->n_rc_qacks++;
        qp->s_flags |= IPATH_S_ACK_PENDING;
        qp->s_nak_state = qp->r_nak_state;
        qp->s_ack_psn = qp->r_ack_psn;
@@ -798,11 +799,13 @@ bail:
 
 static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
 {
-       if (qp->s_wait_credit) {
-               qp->s_wait_credit = 0;
-               tasklet_hi_schedule(&qp->s_task);
+       if (qp->s_last_psn != psn) {
+               qp->s_last_psn = psn;
+               if (qp->s_wait_credit) {
+                       qp->s_wait_credit = 0;
+                       tasklet_hi_schedule(&qp->s_task);
+               }
        }
-       qp->s_last_psn = psn;
 }
 
 /**
@@ -1653,13 +1656,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
        case OP(SEND_FIRST):
                if (!ipath_get_rwqe(qp, 0)) {
                rnr_nak:
-                       /*
-                        * A RNR NAK will ACK earlier sends and RDMA writes.
-                        * Don't queue the NAK if a RDMA read or atomic
-                        * is pending though.
-                        */
-                       if (qp->r_nak_state)
-                               goto done;
                        qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
                        qp->r_ack_psn = qp->r_psn;
                        goto send_ack;
index 708eba3165d764f0c54b45084bb1cfb927b5ff73..6d2a17f9c1da919193e260160033ad57bf3e05f8 100644 (file)
@@ -82,8 +82,7 @@
 
 /* kr_rcvctrl bits */
 #define INFINIPATH_R_PORTENABLE_SHIFT 0
-#define INFINIPATH_R_INTRAVAIL_SHIFT 16
-#define INFINIPATH_R_TAILUPD   0x80000000
+#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38)
 
 /* kr_intstatus, kr_intclear, kr_intmask bits */
 #define INFINIPATH_I_RCVURG_SHIFT 0
 #define INFINIPATH_EXTC_LEDGBLOK_ON          0x00000002ULL
 #define INFINIPATH_EXTC_LEDGBLERR_OFF        0x00000001ULL
 
-/* kr_mdio bits */
-#define INFINIPATH_MDIO_CLKDIV_MASK 0x7FULL
-#define INFINIPATH_MDIO_CLKDIV_SHIFT 32
-#define INFINIPATH_MDIO_COMMAND_MASK 0x7ULL
-#define INFINIPATH_MDIO_COMMAND_SHIFT 26
-#define INFINIPATH_MDIO_DEVADDR_MASK 0x1FULL
-#define INFINIPATH_MDIO_DEVADDR_SHIFT 21
-#define INFINIPATH_MDIO_REGADDR_MASK 0x1FULL
-#define INFINIPATH_MDIO_REGADDR_SHIFT 16
-#define INFINIPATH_MDIO_DATA_MASK 0xFFFFULL
-#define INFINIPATH_MDIO_DATA_SHIFT 0
-#define INFINIPATH_MDIO_CMDVALID    0x0000000040000000ULL
-#define INFINIPATH_MDIO_RDDATAVALID 0x0000000080000000ULL
-
 /* kr_partitionkey bits */
 #define INFINIPATH_PKEY_SIZE 16
 #define INFINIPATH_PKEY_MASK 0xFFFF
 
 /* kr_xgxsconfig bits */
 #define INFINIPATH_XGXS_RESET          0x7ULL
-#define INFINIPATH_XGXS_MDIOADDR_MASK  0xfULL
-#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4
 #define INFINIPATH_XGXS_RX_POL_SHIFT 19
 #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
 
@@ -470,6 +453,20 @@ struct ipath_cregs {
        ipath_creg cr_unsupvlcnt;
        ipath_creg cr_wordrcvcnt;
        ipath_creg cr_wordsendcnt;
+       ipath_creg cr_vl15droppedpktcnt;
+       ipath_creg cr_rxotherlocalphyerrcnt;
+       ipath_creg cr_excessbufferovflcnt;
+       ipath_creg cr_locallinkintegrityerrcnt;
+       ipath_creg cr_rxvlerrcnt;
+       ipath_creg cr_rxdlidfltrcnt;
+       ipath_creg cr_psstat;
+       ipath_creg cr_psstart;
+       ipath_creg cr_psinterval;
+       ipath_creg cr_psrcvdatacount;
+       ipath_creg cr_psrcvpktscount;
+       ipath_creg cr_psxmitdatacount;
+       ipath_creg cr_psxmitpktscount;
+       ipath_creg cr_psxmitwaitcount;
 };
 
 #endif                         /* _IPATH_REGISTERS_H */
index 54c61a972de24153ad7940ba93f080d190765646..a59bdbd0ed87b30bbe0853ce47376084fee77007 100644 (file)
@@ -98,11 +98,15 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
                while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) {
                        qp->s_rnr_timeout -= nqp->s_rnr_timeout;
                        l = l->next;
-                       if (l->next == &dev->rnrwait)
+                       if (l->next == &dev->rnrwait) {
+                               nqp = NULL;
                                break;
+                       }
                        nqp = list_entry(l->next, struct ipath_qp,
                                         timerwait);
                }
+               if (nqp)
+                       nqp->s_rnr_timeout -= qp->s_rnr_timeout;
                list_add(&qp->timerwait, l);
        }
        spin_unlock_irqrestore(&dev->pending_lock, flags);
@@ -479,9 +483,14 @@ done:
 
 static void want_buffer(struct ipath_devdata *dd)
 {
-       set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
                         dd->ipath_sendctrl);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 }
 
 /**
index 2fef36f4b675a8d0022bb1819bc4d560d977a0e2..f772102e4713813e805f251d5981a50535f7aaf3 100644 (file)
@@ -94,8 +94,8 @@ bail:
 /**
  * ipath_create_srq - create a shared receive queue
  * @ibpd: the protection domain of the SRQ to create
- * @attr: the attributes of the SRQ
- * @udata: not used by the InfiniPath verbs driver
+ * @srq_init_attr: the attributes of the SRQ
+ * @udata: data from libipathverbs when creating a user SRQ
  */
 struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
                                struct ib_srq_init_attr *srq_init_attr,
index f0271415cd5b19558f7fae74baaef2330a96490d..d2725cd11bdccd701150d00bfaae8be7f7c96d57 100644 (file)
@@ -133,15 +133,16 @@ bail:
 static void ipath_qcheck(struct ipath_devdata *dd)
 {
        static u64 last_tot_hdrqfull;
+       struct ipath_portdata *pd = dd->ipath_pd[0];
        size_t blen = 0;
        char buf[128];
 
        *buf = 0;
-       if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) {
+       if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) {
                blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u",
-                               dd->ipath_pd[0]->port_hdrqfull -
+                               pd->port_hdrqfull -
                                dd->ipath_p0_hdrqfull);
-               dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull;
+               dd->ipath_p0_hdrqfull = pd->port_hdrqfull;
        }
        if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) {
                blen += snprintf(buf + blen, sizeof buf - blen,
@@ -173,7 +174,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
        if (blen)
                ipath_dbg("%s\n", buf);
 
-       if (dd->ipath_port0head != (u32)
+       if (pd->port_head != (u32)
            le64_to_cpu(*dd->ipath_hdrqtailptr)) {
                if (dd->ipath_lastport0rcv_cnt ==
                    ipath_stats.sps_port0pkts) {
@@ -181,7 +182,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
                                   "port0 hd=%llx tl=%x; port0pkts %llx\n",
                                   (unsigned long long)
                                   le64_to_cpu(*dd->ipath_hdrqtailptr),
-                                  dd->ipath_port0head,
+                                  pd->port_head,
                                   (unsigned long long)
                                   ipath_stats.sps_port0pkts);
                }
@@ -237,7 +238,7 @@ static void ipath_chk_errormask(struct ipath_devdata *dd)
 void ipath_get_faststats(unsigned long opaque)
 {
        struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
-       u32 val;
+       int i;
        static unsigned cnt;
        unsigned long flags;
        u64 traffic_wds;
@@ -321,12 +322,11 @@ void ipath_get_faststats(unsigned long opaque)
 
        /* limit qfull messages to ~one per minute per port */
        if ((++cnt & 0x10)) {
-               for (val = dd->ipath_cfgports - 1; ((int)val) >= 0;
-                    val--) {
-                       if (dd->ipath_lastegrheads[val] != -1)
-                               dd->ipath_lastegrheads[val] = -1;
-                       if (dd->ipath_lastrcvhdrqtails[val] != -1)
-                               dd->ipath_lastrcvhdrqtails[val] = -1;
+               for (i = (int) dd->ipath_cfgports; --i >= 0; ) {
+                       struct ipath_portdata *pd = dd->ipath_pd[i];
+
+                       if (pd && pd->port_lastrcvhdrqtail != -1)
+                               pd->port_lastrcvhdrqtail = -1;
                }
        }
 
index e1ad7cfc21fd66b89e5f46055fb611b730aa94ab..56dfc8a2344c31d7d3d7c18a8c7cb36b302b9a28 100644 (file)
@@ -363,6 +363,60 @@ static ssize_t show_unit(struct device *dev,
        return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit);
 }
 
+static ssize_t show_jint_max_packets(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets);
+}
+
+static ssize_t store_jint_max_packets(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf,
+                                     size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       u16 v = 0;
+       int ret;
+
+       ret = ipath_parse_ushort(buf, &v);
+       if (ret < 0)
+               ipath_dev_err(dd, "invalid jint_max_packets.\n");
+       else
+               dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v);
+
+       return ret;
+}
+
+static ssize_t show_jint_idle_ticks(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks);
+}
+
+static ssize_t store_jint_idle_ticks(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf,
+                                    size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       u16 v = 0;
+       int ret;
+
+       ret = ipath_parse_ushort(buf, &v);
+       if (ret < 0)
+               ipath_dev_err(dd, "invalid jint_idle_ticks.\n");
+       else
+               dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets);
+
+       return ret;
+}
+
 #define DEVICE_COUNTER(name, attr) \
        static ssize_t show_counter_##name(struct device *dev, \
                                           struct device_attribute *attr, \
@@ -670,6 +724,257 @@ static ssize_t show_logged_errs(struct device *dev,
        return count;
 }
 
+/*
+ * New sysfs entries to control various IB config. These all turn into
+ * accesses via ipath_f_get/set_ib_cfg.
+ *
+ * Get/Set heartbeat enable. Or of 1=enabled, 2=auto
+ */
+static ssize_t show_hrtbt_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_hrtbt_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && val > 3)
+               ret = -EINVAL;
+       if (ret < 0) {
+               ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
+               goto bail;
+       }
+
+       /*
+        * Set the "intentional" heartbeat enable per either of
+        * "Enable" and "Auto", as these are normally set together.
+        * This bit is consulted when leaving loopback mode,
+        * because entering loopback mode overrides it and automatically
+        * disables heartbeat.
+        */
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val);
+       if (r < 0)
+               ret = r;
+       else if (val == IPATH_IB_HRTBT_OFF)
+               dd->ipath_flags |= IPATH_NO_HRTBT;
+       else
+               dd->ipath_flags &= ~IPATH_NO_HRTBT;
+
+bail:
+       return ret;
+}
+
+/*
+ * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric,
+ * _not_ the particular encoding of any given chip)
+ */
+static ssize_t show_lwid_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_lwid_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && (val == 0 || val > 3))
+               ret = -EINVAL;
+       if (ret < 0) {
+               ipath_dev_err(dd,
+                       "attempt to set invalid Link Width (enable)\n");
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
+
+/* Get current link width */
+static ssize_t show_lwid(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+/*
+ * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR.
+ */
+static ssize_t show_spd_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_spd_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR)))
+               ret = -EINVAL;
+       if (ret < 0) {
+               ipath_dev_err(dd,
+                       "attempt to set invalid Link Speed (enable)\n");
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
+
+/* Get current link speed */
+static ssize_t show_spd(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+/*
+ * Get/Set RX polarity-invert enable. 0=no, 1=yes.
+ */
+static ssize_t show_rx_polinv_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_rx_polinv_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret < 0 || val > 1)
+               goto invalid;
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val);
+       if (r < 0) {
+               ret = r;
+               goto bail;
+       }
+
+       goto bail;
+invalid:
+       ipath_dev_err(dd, "attempt to set invalid Rx Polarity (enable)\n");
+bail:
+       return ret;
+}
+/*
+ * Get/Set RX lane-reversal enable. 0=no, 1=yes.
+ */
+static ssize_t show_lanerev_enb(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB);
+       if (ret >= 0)
+               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return ret;
+}
+
+static ssize_t store_lanerev_enb(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf,
+                         size_t count)
+{
+       struct ipath_devdata *dd = dev_get_drvdata(dev);
+       int ret, r;
+       u16 val;
+
+       ret = ipath_parse_ushort(buf, &val);
+       if (ret >= 0 && val > 1) {
+               ret = -EINVAL;
+               ipath_dev_err(dd,
+                       "attempt to set invalid Lane reversal (enable)\n");
+               goto bail;
+       }
+
+       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val);
+       if (r < 0)
+               ret = r;
+
+bail:
+       return ret;
+}
+
 static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
 static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
 
@@ -683,6 +988,11 @@ static struct attribute_group driver_attr_group = {
        .attrs = driver_attributes
 };
 
+struct attribute_group *ipath_driver_attr_groups[] = {
+       &driver_attr_group,
+       NULL,
+};
+
 static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
 static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
 static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
@@ -701,6 +1011,10 @@ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
 static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
 static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
 static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
+static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO,
+                  show_jint_max_packets, store_jint_max_packets);
+static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO,
+                  show_jint_idle_ticks, store_jint_idle_ticks);
 
 static struct attribute *dev_attributes[] = {
        &dev_attr_guid.attr,
@@ -727,6 +1041,34 @@ static struct attribute_group dev_attr_group = {
        .attrs = dev_attributes
 };
 
+static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
+                  store_hrtbt_enb);
+static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb,
+                  store_lwid_enb);
+static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL);
+static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb,
+                  store_spd_enb);
+static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL);
+static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb,
+                  store_rx_polinv_enb);
+static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb,
+                  store_lanerev_enb);
+
+static struct attribute *dev_ibcfg_attributes[] = {
+       &dev_attr_hrtbt_enable.attr,
+       &dev_attr_link_width_enable.attr,
+       &dev_attr_link_width.attr,
+       &dev_attr_link_speed_enable.attr,
+       &dev_attr_link_speed.attr,
+       &dev_attr_rx_pol_inv_enable.attr,
+       &dev_attr_rx_lane_rev_enable.attr,
+       NULL
+};
+
+static struct attribute_group dev_ibcfg_attr_group = {
+       .attrs = dev_ibcfg_attributes
+};
+
 /**
  * ipath_expose_reset - create a device reset file
  * @dev: the device structure
@@ -753,24 +1095,9 @@ int ipath_expose_reset(struct device *dev)
        return ret;
 }
 
-int ipath_driver_create_group(struct device_driver *drv)
-{
-       int ret;
-
-       ret = sysfs_create_group(&drv->kobj, &driver_attr_group);
-
-       return ret;
-}
-
-void ipath_driver_remove_group(struct device_driver *drv)
-{
-       sysfs_remove_group(&drv->kobj, &driver_attr_group);
-}
-
 int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
 {
        int ret;
-       char unit[5];
 
        ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
        if (ret)
@@ -780,11 +1107,26 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
        if (ret)
                goto bail_attrs;
 
-       snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
-       ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit);
-       if (ret == 0)
-               goto bail;
+       if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
+               ret = device_create_file(dev, &dev_attr_jint_idle_ticks);
+               if (ret)
+                       goto bail_counter;
+               ret = device_create_file(dev, &dev_attr_jint_max_packets);
+               if (ret)
+                       goto bail_idle;
 
+               ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group);
+               if (ret)
+                       goto bail_max;
+       }
+
+       return 0;
+
+bail_max:
+       device_remove_file(dev, &dev_attr_jint_max_packets);
+bail_idle:
+       device_remove_file(dev, &dev_attr_jint_idle_ticks);
+bail_counter:
        sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 bail_attrs:
        sysfs_remove_group(&dev->kobj, &dev_attr_group);
@@ -794,12 +1136,14 @@ bail:
 
 void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd)
 {
-       char unit[5];
+       sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 
-       snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
-       sysfs_remove_link(&dev->driver->kobj, unit);
+       if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
+               sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group);
+               device_remove_file(dev, &dev_attr_jint_idle_ticks);
+               device_remove_file(dev, &dev_attr_jint_max_packets);
+       }
 
-       sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
        sysfs_remove_group(&dev->kobj, &dev_attr_group);
 
        device_remove_file(dev, &dev_attr_reset);
index 16a2a938b520517ae74c9746450df2a0d436c06a..de67eed08ed0193f2c991a1f07a1058bca87b466 100644 (file)
@@ -301,8 +301,6 @@ int ipath_make_ud_req(struct ipath_qp *qp)
 
        /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
        qp->s_hdrwords = 7;
-       if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
-               qp->s_hdrwords++;
        qp->s_cur_size = wqe->length;
        qp->s_cur_sge = &qp->s_sge;
        qp->s_wqe = wqe;
@@ -327,6 +325,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                ohdr = &qp->s_hdr.u.oth;
        }
        if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+               qp->s_hdrwords++;
                ohdr->u.ud.imm_data = wqe->wr.imm_data;
                bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
        } else
@@ -455,6 +454,28 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                }
        }
 
+       /*
+        * The opcode is in the low byte when its in network order
+        * (top byte when in host order).
+        */
+       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
+       if (qp->ibqp.qp_num > 1 &&
+           opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
+               if (header_in_data) {
+                       wc.imm_data = *(__be32 *) data;
+                       data += sizeof(__be32);
+               } else
+                       wc.imm_data = ohdr->u.ud.imm_data;
+               wc.wc_flags = IB_WC_WITH_IMM;
+               hdrsize += sizeof(u32);
+       } else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
+               wc.imm_data = 0;
+               wc.wc_flags = 0;
+       } else {
+               dev->n_pkt_drops++;
+               goto bail;
+       }
+
        /* Get the number of bytes the message was padded by. */
        pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
        if (unlikely(tlen < (hdrsize + pad + 4))) {
@@ -481,28 +502,6 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
         */
        wc.byte_len = tlen + sizeof(struct ib_grh);
 
-       /*
-        * The opcode is in the low byte when its in network order
-        * (top byte when in host order).
-        */
-       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
-       if (qp->ibqp.qp_num > 1 &&
-           opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
-               if (header_in_data) {
-                       wc.imm_data = *(__be32 *) data;
-                       data += sizeof(__be32);
-               } else
-                       wc.imm_data = ohdr->u.ud.imm_data;
-               wc.wc_flags = IB_WC_WITH_IMM;
-               hdrsize += sizeof(u32);
-       } else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
-               wc.imm_data = 0;
-               wc.wc_flags = 0;
-       } else {
-               dev->n_pkt_drops++;
-               goto bail;
-       }
-
        /*
         * Get the next work request entry to find where to put the data.
         */
index c4c998446c7b421976b57087ffa63e4f77739f6b..32d8f882e56c4e1ce20c7d01b1a7b95e12492a57 100644 (file)
@@ -943,7 +943,7 @@ bail:
  * ipath_verbs_send - send a packet
  * @qp: the QP to send on
  * @hdr: the packet header
- * @hdrwords: the number of words in the header
+ * @hdrwords: the number of 32-bit words in the header
  * @ss: the SGE to send
  * @len: the length of the packet in bytes
  */
@@ -955,7 +955,10 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
        int ret;
        u32 dwords = (len + 3) >> 2;
 
-       /* +1 is for the qword padding of pbc */
+       /*
+        * Calculate the send buffer trigger address.
+        * The +1 counts for the pbc control dword following the pbc length.
+        */
        plen = hdrwords + dwords + 1;
 
        /* Drop non-VL15 packets if we are not in the active state */
@@ -1130,20 +1133,34 @@ static int ipath_query_device(struct ib_device *ibdev,
        return 0;
 }
 
-const u8 ipath_cvt_physportstate[16] = {
-       [INFINIPATH_IBCS_LT_STATE_DISABLED] = 3,
-       [INFINIPATH_IBCS_LT_STATE_LINKUP] = 5,
-       [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2,
-       [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2,
-       [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1,
-       [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1,
-       [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4,
-       [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4,
-       [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4,
-       [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4,
-       [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6,
-       [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6,
-       [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6,
+const u8 ipath_cvt_physportstate[32] = {
+       [INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
+       [INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
+       [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
+       [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
+       [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
+       [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
+       [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] =
+               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+       [0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
+       [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
 };
 
 u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
@@ -1168,8 +1185,9 @@ static int ipath_query_port(struct ib_device *ibdev,
        ibcstat = dd->ipath_lastibcstat;
        props->state = ((ibcstat >> 4) & 0x3) + 1;
        /* See phys_state_show() */
-       props->phys_state = ipath_cvt_physportstate[
-               dd->ipath_lastibcstat & 0xf];
+       props->phys_state = /* MEA: assumes shift == 0 */
+               ipath_cvt_physportstate[dd->ipath_lastibcstat &
+               dd->ibcs_lts_mask];
        props->port_cap_flags = dev->port_cap_flags;
        props->gid_tbl_len = 1;
        props->max_msg_sz = 0x80000000;
@@ -1641,6 +1659,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
                cntrs.local_link_integrity_errors;
        idev->z_excessive_buffer_overrun_errors =
                cntrs.excessive_buffer_overrun_errors;
+       idev->z_vl15_dropped = cntrs.vl15_dropped;
 
        /*
         * The system image GUID is supposed to be the same for all
index 6ccb54f104a3fff2ddc6e08746949a29f1cb5a1e..3d59736b49b238592d64e9e71b62e0d2b6b5df6f 100644 (file)
@@ -554,6 +554,7 @@ struct ipath_ibdev {
        u32 z_pkey_violations;                  /* starting count for PMA */
        u32 z_local_link_integrity_errors;      /* starting count for PMA */
        u32 z_excessive_buffer_overrun_errors;  /* starting count for PMA */
+       u32 z_vl15_dropped;                     /* starting count for PMA */
        u32 n_rc_resends;
        u32 n_rc_acks;
        u32 n_rc_qacks;
@@ -598,6 +599,7 @@ struct ipath_verbs_counters {
        u64 port_rcv_packets;
        u32 local_link_integrity_errors;
        u32 excessive_buffer_overrun_errors;
+       u32 vl15_dropped;
 };
 
 static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
@@ -830,7 +832,17 @@ unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
 
 extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
 
+/*
+ * Below converts HCA-specific LinkTrainingState to IB PhysPortState
+ * values.
+ */
 extern const u8 ipath_cvt_physportstate[];
+#define IB_PHYSPORTSTATE_SLEEP 1
+#define IB_PHYSPORTSTATE_POLL 2
+#define IB_PHYSPORTSTATE_DISABLED 3
+#define IB_PHYSPORTSTATE_CFG_TRAIN 4
+#define IB_PHYSPORTSTATE_LINKUP 5
+#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6
 
 extern const int ib_ipath_state_ops[];
 
index 8bf44daf45ecd851e858bc72b12678ada60be0d8..7950aa6e8184b1441a5dcfd2e6daad7f21d64e43 100644 (file)
@@ -313,6 +313,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
        struct mlx4_ib_srq *srq;
        int is_send;
        int is_error;
+       u32 g_mlpath_rqpn;
        u16 wqe_ctr;
 
        cqe = next_cqe_sw(cq);
@@ -426,11 +427,11 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
 
                wc->slid           = be16_to_cpu(cqe->rlid);
                wc->sl             = cqe->sl >> 4;
-               wc->src_qp         = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff;
-               wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f;
-               wc->wc_flags      |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ?
-                       IB_WC_GRH : 0;
-               wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) >> 16;
+               g_mlpath_rqpn      = be32_to_cpu(cqe->g_mlpath_rqpn);
+               wc->src_qp         = g_mlpath_rqpn & 0xffffff;
+               wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f;
+               wc->wc_flags      |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0;
+               wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
        }
 
        return 0;
index 15aa32eb78b6b6b093c42e8f419448d042a4596d..7bbdd1f4e6c708c14ee3dc0ab031c64b24140779 100644 (file)
 enum {
        MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
        MTHCA_FLAG_SRQ        = 1 << 2,
-       MTHCA_FLAG_MSI        = 1 << 3,
-       MTHCA_FLAG_MSI_X      = 1 << 4,
-       MTHCA_FLAG_NO_LAM     = 1 << 5,
-       MTHCA_FLAG_FMR        = 1 << 6,
-       MTHCA_FLAG_MEMFREE    = 1 << 7,
-       MTHCA_FLAG_PCIE       = 1 << 8,
-       MTHCA_FLAG_SINAI_OPT  = 1 << 9
+       MTHCA_FLAG_MSI_X      = 1 << 3,
+       MTHCA_FLAG_NO_LAM     = 1 << 4,
+       MTHCA_FLAG_FMR        = 1 << 5,
+       MTHCA_FLAG_MEMFREE    = 1 << 6,
+       MTHCA_FLAG_PCIE       = 1 << 7,
+       MTHCA_FLAG_SINAI_OPT  = 1 << 8
 };
 
 enum {
index b29de51b7f350affcafbfd49aabb8f06805f6784..b60eb5df96e8bc2d521f19253203a46098b50c28 100644 (file)
@@ -827,8 +827,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
        if (err)
                goto err_out_free;
 
-       if (dev->mthca_flags & MTHCA_FLAG_MSI ||
-           dev->mthca_flags & MTHCA_FLAG_MSI_X) {
+       if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
                dev->eq_table.clr_mask = 0;
        } else {
                dev->eq_table.clr_mask =
@@ -839,8 +838,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
 
        dev->eq_table.arm_mask = 0;
 
-       intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
-               128 : dev->eq_table.inta_pin;
+       intr = dev->eq_table.inta_pin;
 
        err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
                              (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
index 60de6f93869e7487fa91696950507b82e22b4267..5cf8250d4e164003312fed79579b578267c94eed 100644 (file)
@@ -65,14 +65,9 @@ static int msi_x = 1;
 module_param(msi_x, int, 0444);
 MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
-static int msi = 0;
-module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
-
 #else /* CONFIG_PCI_MSI */
 
 #define msi_x (0)
-#define msi   (0)
 
 #endif /* CONFIG_PCI_MSI */
 
@@ -816,13 +811,11 @@ static int mthca_setup_hca(struct mthca_dev *dev)
 
        err = mthca_NOP(dev, &status);
        if (err || status) {
-               if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
+               if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
                        mthca_warn(dev, "NOP command failed to generate interrupt "
                                   "(IRQ %d).\n",
-                                  dev->mthca_flags & MTHCA_FLAG_MSI_X ?
-                                  dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
-                                  dev->pdev->irq);
-                       mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
+                                  dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector);
+                       mthca_warn(dev, "Trying again with MSI-X disabled.\n");
                } else {
                        mthca_err(dev, "NOP command failed to generate interrupt "
                                  "(IRQ %d), aborting.\n",
@@ -1005,7 +998,7 @@ static struct {
                           .flags     = 0 },
        [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200),
                           .flags     = MTHCA_FLAG_PCIE },
-       [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0),
+       [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0),
                           .flags     = MTHCA_FLAG_MEMFREE |
                                        MTHCA_FLAG_PCIE },
        [SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 2, 0),
@@ -1128,29 +1121,12 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
 
        if (msi_x && !mthca_enable_msi_x(mdev))
                mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
-       else if (msi) {
-               static int warned;
-
-               if (!warned) {
-                       printk(KERN_WARNING PFX "WARNING: MSI support will be "
-                              "removed from the ib_mthca driver in January 2008.\n");
-                       printk(KERN_WARNING "    If you are using MSI and cannot "
-                              "switch to MSI-X, please tell "
-                              "<general@lists.openfabrics.org>.\n");
-                       ++warned;
-               }
-
-               if (!pci_enable_msi(pdev))
-                       mdev->mthca_flags |= MTHCA_FLAG_MSI;
-       }
 
        err = mthca_setup_hca(mdev);
-       if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
+       if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) {
                if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
                        pci_disable_msix(pdev);
-               if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-                       pci_disable_msi(pdev);
-               mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
+               mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X;
 
                err = mthca_setup_hca(mdev);
        }
@@ -1192,8 +1168,6 @@ err_cleanup:
 err_close:
        if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
                pci_disable_msix(pdev);
-       if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-               pci_disable_msi(pdev);
 
        mthca_close_hca(mdev);
 
@@ -1246,8 +1220,6 @@ static void __mthca_remove_one(struct pci_dev *pdev)
 
                if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
                        pci_disable_msix(pdev);
-               if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-                       pci_disable_msi(pdev);
 
                ib_dealloc_device(&mdev->ib_dev);
                mthca_release_regions(pdev, mdev->mthca_flags &
index eb7edab0e836041f444061889ddf3acf4ad7786c..fe250c60607d9a4a700ff0e6461cf586c6d547e5 100644 (file)
 /* constants */
 
 enum {
-       IPOIB_PACKET_SIZE         = 2048,
-       IPOIB_BUF_SIZE            = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
+       IPOIB_PACKET_SIZE         = 2048,
+       IPOIB_BUF_SIZE            = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
 
-       IPOIB_ENCAP_LEN           = 4,
+       IPOIB_ENCAP_LEN           = 4,
 
-       IPOIB_CM_MTU              = 0x10000 - 0x10, /* padding to align header to 16 */
-       IPOIB_CM_BUF_SIZE         = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
-       IPOIB_CM_HEAD_SIZE        = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
-       IPOIB_CM_RX_SG            = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
-       IPOIB_RX_RING_SIZE        = 128,
-       IPOIB_TX_RING_SIZE        = 64,
+       IPOIB_CM_MTU              = 0x10000 - 0x10, /* padding to align header to 16 */
+       IPOIB_CM_BUF_SIZE         = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
+       IPOIB_CM_HEAD_SIZE        = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
+       IPOIB_CM_RX_SG            = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
+       IPOIB_RX_RING_SIZE        = 128,
+       IPOIB_TX_RING_SIZE        = 64,
        IPOIB_MAX_QUEUE_SIZE      = 8192,
        IPOIB_MIN_QUEUE_SIZE      = 2,
+       IPOIB_CM_MAX_CONN_QP      = 4096,
 
-       IPOIB_NUM_WC              = 4,
+       IPOIB_NUM_WC              = 4,
 
        IPOIB_MAX_PATH_REC_QUEUE  = 3,
-       IPOIB_MAX_MCAST_QUEUE     = 3,
-
-       IPOIB_FLAG_OPER_UP        = 0,
-       IPOIB_FLAG_INITIALIZED    = 1,
-       IPOIB_FLAG_ADMIN_UP       = 2,
-       IPOIB_PKEY_ASSIGNED       = 3,
-       IPOIB_PKEY_STOP           = 4,
-       IPOIB_FLAG_SUBINTERFACE   = 5,
-       IPOIB_MCAST_RUN           = 6,
-       IPOIB_STOP_REAPER         = 7,
-       IPOIB_MCAST_STARTED       = 8,
-       IPOIB_FLAG_ADMIN_CM       = 9,
+       IPOIB_MAX_MCAST_QUEUE     = 3,
+
+       IPOIB_FLAG_OPER_UP        = 0,
+       IPOIB_FLAG_INITIALIZED    = 1,
+       IPOIB_FLAG_ADMIN_UP       = 2,
+       IPOIB_PKEY_ASSIGNED       = 3,
+       IPOIB_PKEY_STOP           = 4,
+       IPOIB_FLAG_SUBINTERFACE   = 5,
+       IPOIB_MCAST_RUN           = 6,
+       IPOIB_STOP_REAPER         = 7,
+       IPOIB_MCAST_STARTED       = 8,
+       IPOIB_FLAG_ADMIN_CM       = 9,
        IPOIB_FLAG_UMCAST         = 10,
 
        IPOIB_MAX_BACKOFF_SECONDS = 16,
 
-       IPOIB_MCAST_FLAG_FOUND    = 0,  /* used in set_multicast_list */
+       IPOIB_MCAST_FLAG_FOUND    = 0,  /* used in set_multicast_list */
        IPOIB_MCAST_FLAG_SENDONLY = 1,
-       IPOIB_MCAST_FLAG_BUSY     = 2,  /* joining or already joined */
+       IPOIB_MCAST_FLAG_BUSY     = 2,  /* joining or already joined */
        IPOIB_MCAST_FLAG_ATTACHED = 3,
 };
 
@@ -117,7 +118,7 @@ struct ipoib_pseudoheader {
 struct ipoib_mcast {
        struct ib_sa_mcmember_rec mcmember;
        struct ib_sa_multicast   *mc;
-       struct ipoib_ah          *ah;
+       struct ipoib_ah          *ah;
 
        struct rb_node    rb_node;
        struct list_head  list;
@@ -186,27 +187,29 @@ enum ipoib_cm_state {
 };
 
 struct ipoib_cm_rx {
-       struct ib_cm_id     *id;
-       struct ib_qp        *qp;
-       struct list_head     list;
-       struct net_device   *dev;
-       unsigned long        jiffies;
-       enum ipoib_cm_state  state;
+       struct ib_cm_id        *id;
+       struct ib_qp           *qp;
+       struct ipoib_cm_rx_buf *rx_ring;
+       struct list_head        list;
+       struct net_device      *dev;
+       unsigned long           jiffies;
+       enum ipoib_cm_state     state;
+       int                     recv_count;
 };
 
 struct ipoib_cm_tx {
-       struct ib_cm_id     *id;
-       struct ib_qp        *qp;
+       struct ib_cm_id     *id;
+       struct ib_qp        *qp;
        struct list_head     list;
        struct net_device   *dev;
        struct ipoib_neigh  *neigh;
        struct ipoib_path   *path;
        struct ipoib_tx_buf *tx_ring;
-       unsigned             tx_head;
-       unsigned             tx_tail;
-       unsigned long        flags;
-       u32                  mtu;
-       struct ib_wc         ibwc[IPOIB_NUM_WC];
+       unsigned             tx_head;
+       unsigned             tx_tail;
+       unsigned long        flags;
+       u32                  mtu;
+       struct ib_wc         ibwc[IPOIB_NUM_WC];
 };
 
 struct ipoib_cm_rx_buf {
@@ -215,25 +218,28 @@ struct ipoib_cm_rx_buf {
 };
 
 struct ipoib_cm_dev_priv {
-       struct ib_srq          *srq;
+       struct ib_srq          *srq;
        struct ipoib_cm_rx_buf *srq_ring;
-       struct ib_cm_id        *id;
-       struct list_head        passive_ids;   /* state: LIVE */
-       struct list_head        rx_error_list; /* state: ERROR */
-       struct list_head        rx_flush_list; /* state: FLUSH, drain not started */
-       struct list_head        rx_drain_list; /* state: FLUSH, drain started */
-       struct list_head        rx_reap_list;  /* state: FLUSH, drain done */
+       struct ib_cm_id        *id;
+       struct list_head        passive_ids;   /* state: LIVE */
+       struct list_head        rx_error_list; /* state: ERROR */
+       struct list_head        rx_flush_list; /* state: FLUSH, drain not started */
+       struct list_head        rx_drain_list; /* state: FLUSH, drain started */
+       struct list_head        rx_reap_list;  /* state: FLUSH, drain done */
        struct work_struct      start_task;
        struct work_struct      reap_task;
        struct work_struct      skb_task;
        struct work_struct      rx_reap_task;
        struct delayed_work     stale_task;
        struct sk_buff_head     skb_queue;
-       struct list_head        start_list;
-       struct list_head        reap_list;
-       struct ib_wc            ibwc[IPOIB_NUM_WC];
-       struct ib_sge           rx_sge[IPOIB_CM_RX_SG];
+       struct list_head        start_list;
+       struct list_head        reap_list;
+       struct ib_wc            ibwc[IPOIB_NUM_WC];
+       struct ib_sge           rx_sge[IPOIB_CM_RX_SG];
        struct ib_recv_wr       rx_wr;
+       int                     nonsrq_conn_qp;
+       int                     max_cm_mtu;
+       int                     num_frags;
 };
 
 /*
@@ -269,30 +275,30 @@ struct ipoib_dev_priv {
        struct work_struct pkey_event_task;
 
        struct ib_device *ca;
-       u8                port;
-       u16               pkey;
-       u16               pkey_index;
-       struct ib_pd     *pd;
-       struct ib_mr     *mr;
-       struct ib_cq     *cq;
-       struct ib_qp     *qp;
-       u32               qkey;
+       u8                port;
+       u16               pkey;
+       u16               pkey_index;
+       struct ib_pd     *pd;
+       struct ib_mr     *mr;
+       struct ib_cq     *cq;
+       struct ib_qp     *qp;
+       u32               qkey;
 
        union ib_gid local_gid;
-       u16          local_lid;
+       u16          local_lid;
 
        unsigned int admin_mtu;
        unsigned int mcast_mtu;
 
        struct ipoib_rx_buf *rx_ring;
 
-       spinlock_t           tx_lock;
+       spinlock_t           tx_lock;
        struct ipoib_tx_buf *tx_ring;
-       unsigned             tx_head;
-       unsigned             tx_tail;
-       struct ib_sge        tx_sge;
+       unsigned             tx_head;
+       unsigned             tx_tail;
+       struct ib_sge        tx_sge;
        struct ib_send_wr    tx_wr;
-       unsigned             tx_outstanding;
+       unsigned             tx_outstanding;
 
        struct ib_wc ibwc[IPOIB_NUM_WC];
 
@@ -317,10 +323,10 @@ struct ipoib_dev_priv {
 
 struct ipoib_ah {
        struct net_device *dev;
-       struct ib_ah      *ah;
+       struct ib_ah      *ah;
        struct list_head   list;
-       struct kref        ref;
-       unsigned           last_send;
+       struct kref        ref;
+       unsigned           last_send;
 };
 
 struct ipoib_path {
@@ -331,11 +337,11 @@ struct ipoib_path {
 
        struct list_head      neigh_list;
 
-       int                   query_id;
+       int                   query_id;
        struct ib_sa_query   *query;
        struct completion     done;
 
-       struct rb_node        rb_node;
+       struct rb_node        rb_node;
        struct list_head      list;
 };
 
@@ -344,7 +350,7 @@ struct ipoib_neigh {
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
        struct ipoib_cm_tx *cm;
 #endif
-       union ib_gid        dgid;
+       union ib_gid        dgid;
        struct sk_buff_head queue;
 
        struct neighbour   *neighbour;
@@ -455,12 +461,14 @@ void ipoib_drain_cq(struct net_device *dev);
 
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
 
-#define IPOIB_FLAGS_RC          0x80
-#define IPOIB_FLAGS_UC          0x40
+#define IPOIB_FLAGS_RC         0x80
+#define IPOIB_FLAGS_UC         0x40
 
 /* We don't support UC connections at the moment */
 #define IPOIB_CM_SUPPORTED(ha)   (ha[0] & (IPOIB_FLAGS_RC))
 
+extern int ipoib_max_conn_qp;
+
 static inline int ipoib_cm_admin_enabled(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -491,6 +499,18 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
        neigh->cm = tx;
 }
 
+static inline int ipoib_cm_has_srq(struct net_device *dev)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       return !!priv->cm.srq;
+}
+
+static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       return priv->cm.max_cm_mtu;
+}
+
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx);
 int ipoib_cm_dev_open(struct net_device *dev);
 void ipoib_cm_dev_stop(struct net_device *dev);
@@ -500,7 +520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev);
 struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
                                    struct ipoib_neigh *neigh);
 void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
-void ipoib_cm_skb_too_long(struct net_devicedev, struct sk_buff *skb,
+void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
                           unsigned int mtu);
 void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
 void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
@@ -508,6 +528,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
 
 struct ipoib_cm_tx;
 
+#define ipoib_max_conn_qp 0
+
 static inline int ipoib_cm_admin_enabled(struct net_device *dev)
 {
        return 0;
@@ -533,6 +555,16 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
 {
 }
 
+static inline int ipoib_cm_has_srq(struct net_device *dev)
+{
+       return 0;
+}
+
+static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
+{
+       return 0;
+}
+
 static inline
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
 {
@@ -582,7 +614,7 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
        return 0;
 }
 
-static inline void ipoib_cm_skb_too_long(struct net_devicedev, struct sk_buff *skb,
+static inline void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
                                         unsigned int mtu)
 {
        dev_kfree_skb_any(skb);
@@ -624,12 +656,12 @@ extern struct ib_sa_client ipoib_sa_client;
 extern int ipoib_debug_level;
 
 #define ipoib_dbg(priv, format, arg...)                        \
-       do {                                            \
+       do {                                            \
                if (ipoib_debug_level > 0)                      \
                        ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
        } while (0)
 #define ipoib_dbg_mcast(priv, format, arg...)          \
-       do {                                            \
+       do {                                            \
                if (mcast_debug_level > 0)              \
                        ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
        } while (0)
@@ -642,7 +674,7 @@ extern int ipoib_debug_level;
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
 #define ipoib_dbg_data(priv, format, arg...)           \
-       do {                                            \
+       do {                                            \
                if (data_debug_level > 0)               \
                        ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
        } while (0)
index 059cf92b60a5a540b9754edfafad93134a8958bc..1818f958c25027543aa2b36890b2ae0c5464aa85 100644 (file)
 #include <linux/icmpv6.h>
 #include <linux/delay.h>
 
+#include "ipoib.h"
+
+int ipoib_max_conn_qp = 128;
+
+module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444);
+MODULE_PARM_DESC(max_nonsrq_conn_qp,
+                "Max number of connected-mode QPs per interface "
+                "(applied only if shared receive queue is not available)");
+
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
 static int data_debug_level;
 
@@ -47,8 +56,6 @@ MODULE_PARM_DESC(cm_data_debug_level,
                 "Enable data path debug tracing for connected mode if > 0");
 #endif
 
-#include "ipoib.h"
-
 #define IPOIB_CM_IETF_ID 0x1000000000000000ULL
 
 #define IPOIB_CM_RX_UPDATE_TIME (256 * HZ)
@@ -81,7 +88,7 @@ static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags,
                ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
-static int ipoib_cm_post_receive(struct net_device *dev, int id)
+static int ipoib_cm_post_receive_srq(struct net_device *dev, int id)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_recv_wr *bad_wr;
@@ -89,13 +96,13 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
 
        priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
 
-       for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+       for (i = 0; i < priv->cm.num_frags; ++i)
                priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
 
        ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
        if (unlikely(ret)) {
                ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
-               ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+               ipoib_cm_dma_unmap_rx(priv, priv->cm.num_frags - 1,
                                      priv->cm.srq_ring[id].mapping);
                dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
                priv->cm.srq_ring[id].skb = NULL;
@@ -104,7 +111,33 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
        return ret;
 }
 
-static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags,
+static int ipoib_cm_post_receive_nonsrq(struct net_device *dev,
+                                       struct ipoib_cm_rx *rx, int id)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       struct ib_recv_wr *bad_wr;
+       int i, ret;
+
+       priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
+
+       for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+               priv->cm.rx_sge[i].addr = rx->rx_ring[id].mapping[i];
+
+       ret = ib_post_recv(rx->qp, &priv->cm.rx_wr, &bad_wr);
+       if (unlikely(ret)) {
+               ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret);
+               ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+                                     rx->rx_ring[id].mapping);
+               dev_kfree_skb_any(rx->rx_ring[id].skb);
+               rx->rx_ring[id].skb = NULL;
+       }
+
+       return ret;
+}
+
+static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev,
+                                            struct ipoib_cm_rx_buf *rx_ring,
+                                            int id, int frags,
                                             u64 mapping[IPOIB_CM_RX_SG])
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -141,7 +174,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int
                        goto partial_error;
        }
 
-       priv->cm.srq_ring[id].skb = skb;
+       rx_ring[id].skb = skb;
        return skb;
 
 partial_error:
@@ -155,7 +188,23 @@ partial_error:
        return NULL;
 }
 
-static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv)
+static void ipoib_cm_free_rx_ring(struct net_device *dev,
+                                 struct ipoib_cm_rx_buf *rx_ring)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < ipoib_recvq_size; ++i)
+               if (rx_ring[i].skb) {
+                       ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+                                             rx_ring[i].mapping);
+                       dev_kfree_skb_any(rx_ring[i].skb);
+               }
+
+       kfree(rx_ring);
+}
+
+static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv)
 {
        struct ib_send_wr *bad_wr;
        struct ipoib_cm_rx *p;
@@ -208,12 +257,18 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
                .qp_type = IB_QPT_RC,
                .qp_context = p,
        };
+
+       if (!ipoib_cm_has_srq(dev)) {
+               attr.cap.max_recv_wr  = ipoib_recvq_size;
+               attr.cap.max_recv_sge = IPOIB_CM_RX_SG;
+       }
+
        return ib_create_qp(priv->pd, &attr);
 }
 
 static int ipoib_cm_modify_rx_qp(struct net_device *dev,
-                                 struct ib_cm_id *cm_id, struct ib_qp *qp,
-                                 unsigned psn)
+                                struct ib_cm_id *cm_id, struct ib_qp *qp,
+                                unsigned psn)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_qp_attr qp_attr;
@@ -266,6 +321,60 @@ static int ipoib_cm_modify_rx_qp(struct net_device *dev,
        return 0;
 }
 
+static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_id,
+                                  struct ipoib_cm_rx *rx)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       int ret;
+       int i;
+
+       rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL);
+       if (!rx->rx_ring)
+               return -ENOMEM;
+
+       spin_lock_irq(&priv->lock);
+
+       if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) {
+               spin_unlock_irq(&priv->lock);
+               ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0);
+               ret = -EINVAL;
+               goto err_free;
+       } else
+               ++priv->cm.nonsrq_conn_qp;
+
+       spin_unlock_irq(&priv->lock);
+
+       for (i = 0; i < ipoib_recvq_size; ++i) {
+               if (!ipoib_cm_alloc_rx_skb(dev, rx->rx_ring, i, IPOIB_CM_RX_SG - 1,
+                                          rx->rx_ring[i].mapping)) {
+                       ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
+                               ret = -ENOMEM;
+                               goto err_count;
+                       }
+               ret = ipoib_cm_post_receive_nonsrq(dev, rx, i);
+               if (ret) {
+                       ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq "
+                                  "failed for buf %d\n", i);
+                       ret = -EIO;
+                       goto err_count;
+               }
+       }
+
+       rx->recv_count = ipoib_recvq_size;
+
+       return 0;
+
+err_count:
+       spin_lock_irq(&priv->lock);
+       --priv->cm.nonsrq_conn_qp;
+       spin_unlock_irq(&priv->lock);
+
+err_free:
+       ipoib_cm_free_rx_ring(dev, rx->rx_ring);
+
+       return ret;
+}
+
 static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
                             struct ib_qp *qp, struct ib_cm_req_event_param *req,
                             unsigned psn)
@@ -281,7 +390,7 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
        rep.private_data_len = sizeof data;
        rep.flow_control = 0;
        rep.rnr_retry_count = req->rnr_retry_count;
-       rep.srq = 1;
+       rep.srq = ipoib_cm_has_srq(dev);
        rep.qp_num = qp->qp_num;
        rep.starting_psn = psn;
        return ib_send_cm_rep(cm_id, &rep);
@@ -317,6 +426,12 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
        if (ret)
                goto err_modify;
 
+       if (!ipoib_cm_has_srq(dev)) {
+               ret = ipoib_cm_nonsrq_init_rx(dev, cm_id, p);
+               if (ret)
+                       goto err_modify;
+       }
+
        spin_lock_irq(&priv->lock);
        queue_delayed_work(ipoib_workqueue,
                           &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
@@ -401,12 +516,14 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
 void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
+       struct ipoib_cm_rx_buf *rx_ring;
        unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
        struct sk_buff *skb, *newskb;
        struct ipoib_cm_rx *p;
        unsigned long flags;
        u64 mapping[IPOIB_CM_RX_SG];
        int frags;
+       int has_srq;
 
        ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n",
                       wr_id, wc->status);
@@ -424,18 +541,32 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
                return;
        }
 
-       skb  = priv->cm.srq_ring[wr_id].skb;
+       p = wc->qp->qp_context;
+
+       has_srq = ipoib_cm_has_srq(dev);
+       rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring;
+
+       skb = rx_ring[wr_id].skb;
 
        if (unlikely(wc->status != IB_WC_SUCCESS)) {
                ipoib_dbg(priv, "cm recv error "
                           "(status=%d, wrid=%d vend_err %x)\n",
                           wc->status, wr_id, wc->vendor_err);
                ++dev->stats.rx_dropped;
-               goto repost;
+               if (has_srq)
+                       goto repost;
+               else {
+                       if (!--p->recv_count) {
+                               spin_lock_irqsave(&priv->lock, flags);
+                               list_move(&p->list, &priv->cm.rx_reap_list);
+                               spin_unlock_irqrestore(&priv->lock, flags);
+                               queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
+                       }
+                       return;
+               }
        }
 
        if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
-               p = wc->qp->qp_context;
                if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
                        spin_lock_irqsave(&priv->lock, flags);
                        p->jiffies = jiffies;
@@ -450,7 +581,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
                                              (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
 
-       newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping);
+       newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags, mapping);
        if (unlikely(!newskb)) {
                /*
                 * If we can't allocate a new RX buffer, dump
@@ -461,8 +592,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
                goto repost;
        }
 
-       ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping);
-       memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
+       ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping);
+       memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
 
        ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
                       wc->byte_len, wc->slid);
@@ -483,9 +614,17 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        netif_receive_skb(skb);
 
 repost:
-       if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
-               ipoib_warn(priv, "ipoib_cm_post_receive failed "
-                          "for buf %d\n", wr_id);
+       if (has_srq) {
+               if (unlikely(ipoib_cm_post_receive_srq(dev, wr_id)))
+                       ipoib_warn(priv, "ipoib_cm_post_receive_srq failed "
+                                  "for buf %d\n", wr_id);
+       } else {
+               if (unlikely(ipoib_cm_post_receive_nonsrq(dev, p, wr_id))) {
+                       --p->recv_count;
+                       ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed "
+                                  "for buf %d\n", wr_id);
+               }
+       }
 }
 
 static inline int post_send(struct ipoib_dev_priv *priv,
@@ -495,10 +634,10 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 {
        struct ib_send_wr *bad_wr;
 
-       priv->tx_sge.addr             = addr;
-       priv->tx_sge.length           = len;
+       priv->tx_sge.addr       = addr;
+       priv->tx_sge.length     = len;
 
-       priv->tx_wr.wr_id             = wr_id | IPOIB_OP_CM;
+       priv->tx_wr.wr_id       = wr_id | IPOIB_OP_CM;
 
        return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
 }
@@ -540,7 +679,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
        tx_req->mapping = addr;
 
        if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
-                               addr, skb->len))) {
+                              addr, skb->len))) {
                ipoib_warn(priv, "post_send failed\n");
                ++dev->stats.tx_errors;
                ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
@@ -657,10 +796,33 @@ err_cm:
        return ret;
 }
 
+static void ipoib_cm_free_rx_reap_list(struct net_device *dev)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       struct ipoib_cm_rx *rx, *n;
+       LIST_HEAD(list);
+
+       spin_lock_irq(&priv->lock);
+       list_splice_init(&priv->cm.rx_reap_list, &list);
+       spin_unlock_irq(&priv->lock);
+
+       list_for_each_entry_safe(rx, n, &list, list) {
+               ib_destroy_cm_id(rx->id);
+               ib_destroy_qp(rx->qp);
+               if (!ipoib_cm_has_srq(dev)) {
+                       ipoib_cm_free_rx_ring(priv->dev, rx->rx_ring);
+                       spin_lock_irq(&priv->lock);
+                       --priv->cm.nonsrq_conn_qp;
+                       spin_unlock_irq(&priv->lock);
+               }
+               kfree(rx);
+       }
+}
+
 void ipoib_cm_dev_stop(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
-       struct ipoib_cm_rx *p, *n;
+       struct ipoib_cm_rx *p;
        unsigned long begin;
        LIST_HEAD(list);
        int ret;
@@ -706,15 +868,9 @@ void ipoib_cm_dev_stop(struct net_device *dev)
                spin_lock_irq(&priv->lock);
        }
 
-       list_splice_init(&priv->cm.rx_reap_list, &list);
-
        spin_unlock_irq(&priv->lock);
 
-       list_for_each_entry_safe(p, n, &list, list) {
-               ib_destroy_cm_id(p->id);
-               ib_destroy_qp(p->qp);
-               kfree(p);
-       }
+       ipoib_cm_free_rx_reap_list(dev);
 
        cancel_delayed_work(&priv->cm.stale_task);
 }
@@ -799,7 +955,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
                .sq_sig_type            = IB_SIGNAL_ALL_WR,
                .qp_type                = IB_QPT_RC,
                .qp_context             = tx
-        };
+       };
 
        return ib_create_qp(priv->pd, &attr);
 }
@@ -816,28 +972,28 @@ static int ipoib_cm_send_req(struct net_device *dev,
        data.qpn = cpu_to_be32(priv->qp->qp_num);
        data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
 
-       req.primary_path              = pathrec;
-       req.alternate_path            = NULL;
-       req.service_id                = cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
-       req.qp_num                    = qp->qp_num;
-       req.qp_type                   = qp->qp_type;
-       req.private_data              = &data;
-       req.private_data_len          = sizeof data;
-       req.flow_control              = 0;
+       req.primary_path                = pathrec;
+       req.alternate_path              = NULL;
+       req.service_id                  = cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
+       req.qp_num                      = qp->qp_num;
+       req.qp_type                     = qp->qp_type;
+       req.private_data                = &data;
+       req.private_data_len            = sizeof data;
+       req.flow_control                = 0;
 
-       req.starting_psn              = 0; /* FIXME */
+       req.starting_psn                = 0; /* FIXME */
 
        /*
         * Pick some arbitrary defaults here; we could make these
         * module parameters if anyone cared about setting them.
         */
-       req.responder_resources       = 4;
-       req.remote_cm_response_timeout = 20;
-       req.local_cm_response_timeout  = 20;
-       req.retry_count               = 0; /* RFC draft warns against retries */
-       req.rnr_retry_count           = 0; /* RFC draft warns against retries */
-       req.max_cm_retries            = 15;
-       req.srq                       = 1;
+       req.responder_resources         = 4;
+       req.remote_cm_response_timeout  = 20;
+       req.local_cm_response_timeout   = 20;
+       req.retry_count                 = 0; /* RFC draft warns against retries */
+       req.rnr_retry_count             = 0; /* RFC draft warns against retries */
+       req.max_cm_retries              = 15;
+       req.srq                         = ipoib_cm_has_srq(dev);
        return ib_send_cm_req(id, &req);
 }
 
@@ -1150,7 +1306,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
        spin_unlock_irq(&priv->tx_lock);
 }
 
-void ipoib_cm_skb_too_long(struct net_devicedev, struct sk_buff *skb,
+void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
                           unsigned int mtu)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -1166,20 +1322,8 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
 
 static void ipoib_cm_rx_reap(struct work_struct *work)
 {
-       struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
-                                                  cm.rx_reap_task);
-       struct ipoib_cm_rx *p, *n;
-       LIST_HEAD(list);
-
-       spin_lock_irq(&priv->lock);
-       list_splice_init(&priv->cm.rx_reap_list, &list);
-       spin_unlock_irq(&priv->lock);
-
-       list_for_each_entry_safe(p, n, &list, list) {
-               ib_destroy_cm_id(p->id);
-               ib_destroy_qp(p->qp);
-               kfree(p);
-       }
+       ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv,
+                                               cm.rx_reap_task)->dev);
 }
 
 static void ipoib_cm_stale_task(struct work_struct *work)
@@ -1212,7 +1356,7 @@ static void ipoib_cm_stale_task(struct work_struct *work)
 }
 
 
-static ssize_t show_mode(struct device *d, struct device_attribute *attr, 
+static ssize_t show_mode(struct device *d, struct device_attribute *attr,
                         char *buf)
 {
        struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d));
@@ -1255,16 +1399,40 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
        return device_create_file(&dev->dev, &dev_attr_mode);
 }
 
-int ipoib_cm_dev_init(struct net_device *dev)
+static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_srq_init_attr srq_init_attr = {
                .attr = {
                        .max_wr  = ipoib_recvq_size,
-                       .max_sge = IPOIB_CM_RX_SG
+                       .max_sge = max_sge
                }
        };
-       int ret, i;
+
+       priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
+       if (IS_ERR(priv->cm.srq)) {
+               if (PTR_ERR(priv->cm.srq) != -ENOSYS)
+                       printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n",
+                              priv->ca->name, PTR_ERR(priv->cm.srq));
+               priv->cm.srq = NULL;
+               return;
+       }
+
+       priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
+                                   GFP_KERNEL);
+       if (!priv->cm.srq_ring) {
+               printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n",
+                      priv->ca->name, ipoib_recvq_size);
+               ib_destroy_srq(priv->cm.srq);
+               priv->cm.srq = NULL;
+       }
+}
+
+int ipoib_cm_dev_init(struct net_device *dev)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       int i, ret;
+       struct ib_device_attr attr;
 
        INIT_LIST_HEAD(&priv->cm.passive_ids);
        INIT_LIST_HEAD(&priv->cm.reap_list);
@@ -1281,43 +1449,53 @@ int ipoib_cm_dev_init(struct net_device *dev)
 
        skb_queue_head_init(&priv->cm.skb_queue);
 
-       priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
-       if (IS_ERR(priv->cm.srq)) {
-               ret = PTR_ERR(priv->cm.srq);
-               priv->cm.srq = NULL;
+       ret = ib_query_device(priv->ca, &attr);
+       if (ret) {
+               printk(KERN_WARNING "ib_query_device() failed with %d\n", ret);
                return ret;
        }
 
-       priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
-                                   GFP_KERNEL);
-       if (!priv->cm.srq_ring) {
-               printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n",
-                      priv->ca->name, ipoib_recvq_size);
-               ipoib_cm_dev_cleanup(dev);
-               return -ENOMEM;
+       ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge);
+
+       attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge);
+       ipoib_cm_create_srq(dev, attr.max_srq_sge);
+       if (ipoib_cm_has_srq(dev)) {
+               priv->cm.max_cm_mtu = attr.max_srq_sge * PAGE_SIZE - 0x10;
+               priv->cm.num_frags  = attr.max_srq_sge;
+               ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n",
+                         priv->cm.max_cm_mtu, priv->cm.num_frags);
+       } else {
+               priv->cm.max_cm_mtu = IPOIB_CM_MTU;
+               priv->cm.num_frags  = IPOIB_CM_RX_SG;
        }
 
-       for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+       for (i = 0; i < priv->cm.num_frags; ++i)
                priv->cm.rx_sge[i].lkey = priv->mr->lkey;
 
        priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE;
-       for (i = 1; i < IPOIB_CM_RX_SG; ++i)
+       for (i = 1; i < priv->cm.num_frags; ++i)
                priv->cm.rx_sge[i].length = PAGE_SIZE;
        priv->cm.rx_wr.next = NULL;
        priv->cm.rx_wr.sg_list = priv->cm.rx_sge;
-       priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
+       priv->cm.rx_wr.num_sge = priv->cm.num_frags;
+
+       if (ipoib_cm_has_srq(dev)) {
+               for (i = 0; i < ipoib_recvq_size; ++i) {
+                       if (!ipoib_cm_alloc_rx_skb(dev, priv->cm.srq_ring, i,
+                                                  priv->cm.num_frags - 1,
+                                                  priv->cm.srq_ring[i].mapping)) {
+                               ipoib_warn(priv, "failed to allocate "
+                                          "receive buffer %d\n", i);
+                               ipoib_cm_dev_cleanup(dev);
+                               return -ENOMEM;
+                       }
 
-       for (i = 0; i < ipoib_recvq_size; ++i) {
-               if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1,
-                                          priv->cm.srq_ring[i].mapping)) {
-                       ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
-                       ipoib_cm_dev_cleanup(dev);
-                       return -ENOMEM;
-               }
-               if (ipoib_cm_post_receive(dev, i)) {
-                       ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i);
-                       ipoib_cm_dev_cleanup(dev);
-                       return -EIO;
+                       if (ipoib_cm_post_receive_srq(dev, i)) {
+                               ipoib_warn(priv, "ipoib_cm_post_receive_srq "
+                                          "failed for buf %d\n", i);
+                               ipoib_cm_dev_cleanup(dev);
+                               return -EIO;
+                       }
                }
        }
 
@@ -1328,7 +1506,7 @@ int ipoib_cm_dev_init(struct net_device *dev)
 void ipoib_cm_dev_cleanup(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
-       int i, ret;
+       int ret;
 
        if (!priv->cm.srq)
                return;
@@ -1342,13 +1520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev)
        priv->cm.srq = NULL;
        if (!priv->cm.srq_ring)
                return;
-       for (i = 0; i < ipoib_recvq_size; ++i)
-               if (priv->cm.srq_ring[i].skb) {
-                       ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
-                                             priv->cm.srq_ring[i].mapping);
-                       dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
-                       priv->cm.srq_ring[i].skb = NULL;
-               }
-       kfree(priv->cm.srq_ring);
+
+       ipoib_cm_free_rx_ring(dev, priv->cm.srq_ring);
        priv->cm.srq_ring = NULL;
 }
index 44c174182a829b39a53d80d72c3f38791f398bbc..8b882bbd1d051ff5fc6673abcad8f927afb24025 100644 (file)
@@ -124,7 +124,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
        return 0;
 }
 
-static struct seq_operations ipoib_mcg_seq_ops = {
+static const struct seq_operations ipoib_mcg_seq_ops = {
        .start = ipoib_mcg_seq_start,
        .next  = ipoib_mcg_seq_next,
        .stop  = ipoib_mcg_seq_stop,
@@ -230,7 +230,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
        return 0;
 }
 
-static struct seq_operations ipoib_path_seq_ops = {
+static const struct seq_operations ipoib_path_seq_ops = {
        .start = ipoib_path_seq_start,
        .next  = ipoib_path_seq_next,
        .stop  = ipoib_path_seq_stop,
index 5063dd509ad2338077c0b2fae061f8d6f68754be..52bc2bd5799ae227a66046bfd2d79e3f4b1028b2 100644 (file)
@@ -345,12 +345,12 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 {
        struct ib_send_wr *bad_wr;
 
-       priv->tx_sge.addr             = addr;
-       priv->tx_sge.length           = len;
+       priv->tx_sge.addr             = addr;
+       priv->tx_sge.length           = len;
 
-       priv->tx_wr.wr_id             = wr_id;
+       priv->tx_wr.wr_id             = wr_id;
        priv->tx_wr.wr.ud.remote_qpn  = qpn;
-       priv->tx_wr.wr.ud.ah          = address;
+       priv->tx_wr.wr.ud.ah          = address;
 
        return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
 }
index c9f6077b615eb62db39dae44f385976c50018865..a082466f4a83d58858120addcd7dbb77c73fb47f 100644 (file)
@@ -182,17 +182,20 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
        /* dev->mtu > 2K ==> connected mode */
-       if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) {
+       if (ipoib_cm_admin_enabled(dev)) {
+               if (new_mtu > ipoib_cm_max_mtu(dev))
+                       return -EINVAL;
+
                if (new_mtu > priv->mcast_mtu)
                        ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n",
                                   priv->mcast_mtu);
+
                dev->mtu = new_mtu;
                return 0;
        }
 
-       if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) {
+       if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN)
                return -EINVAL;
-       }
 
        priv->admin_mtu = new_mtu;
 
@@ -474,8 +477,8 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
        INIT_LIST_HEAD(&path->neigh_list);
 
        memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
-       path->pathrec.sgid          = priv->local_gid;
-       path->pathrec.pkey          = cpu_to_be16(priv->pkey);
+       path->pathrec.sgid          = priv->local_gid;
+       path->pathrec.pkey          = cpu_to_be16(priv->pkey);
        path->pathrec.numb_path     = 1;
        path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
 
@@ -669,16 +672,6 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
                return NETDEV_TX_LOCKED;
 
-       /*
-        * Check if our queue is stopped.  Since we have the LLTX bit
-        * set, we can't rely on netif_stop_queue() preventing our
-        * xmit function from being called with a full queue.
-        */
-       if (unlikely(netif_queue_stopped(dev))) {
-               spin_unlock_irqrestore(&priv->tx_lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-
        if (likely(skb->dst && skb->dst->neighbour)) {
                if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
                        ipoib_path_lookup(skb, dev);
@@ -950,34 +943,34 @@ static void ipoib_setup(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-       dev->open                = ipoib_open;
-       dev->stop                = ipoib_stop;
-       dev->change_mtu          = ipoib_change_mtu;
-       dev->hard_start_xmit     = ipoib_start_xmit;
-       dev->tx_timeout          = ipoib_timeout;
-       dev->header_ops          = &ipoib_header_ops;
-       dev->set_multicast_list  = ipoib_set_mcast_list;
-       dev->neigh_setup         = ipoib_neigh_setup_dev;
+       dev->open                = ipoib_open;
+       dev->stop                = ipoib_stop;
+       dev->change_mtu          = ipoib_change_mtu;
+       dev->hard_start_xmit     = ipoib_start_xmit;
+       dev->tx_timeout          = ipoib_timeout;
+       dev->header_ops          = &ipoib_header_ops;
+       dev->set_multicast_list  = ipoib_set_mcast_list;
+       dev->neigh_setup         = ipoib_neigh_setup_dev;
 
        netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
 
-       dev->watchdog_timeo      = HZ;
+       dev->watchdog_timeo      = HZ;
 
-       dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
+       dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
 
        /*
         * We add in INFINIBAND_ALEN to allow for the destination
         * address "pseudoheader" for skbs without neighbour struct.
         */
-       dev->hard_header_len     = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
-       dev->addr_len            = INFINIBAND_ALEN;
-       dev->type                = ARPHRD_INFINIBAND;
-       dev->tx_queue_len        = ipoib_sendq_size * 2;
-       dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
+       dev->hard_header_len     = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
+       dev->addr_len            = INFINIBAND_ALEN;
+       dev->type                = ARPHRD_INFINIBAND;
+       dev->tx_queue_len        = ipoib_sendq_size * 2;
+       dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
 
        /* MTU will be reset when mcast join happens */
-       dev->mtu                 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
-       priv->mcast_mtu          = priv->admin_mtu = dev->mtu;
+       dev->mtu                 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
+       priv->mcast_mtu          = priv->admin_mtu = dev->mtu;
 
        memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
 
@@ -1268,6 +1261,9 @@ static int __init ipoib_init_module(void)
        ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
        ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
        ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
+#ifdef CONFIG_INFINIBAND_IPOIB_CM
+       ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
+#endif
 
        ret = ipoib_register_debugfs();
        if (ret)
index 9bcfc7ad6aa646af94cdc9ab97ea4d4175583821..2628339e3a9973b01402250f8e6bf73be5d37c04 100644 (file)
@@ -702,7 +702,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
 
 out:
        if (mcast && mcast->ah) {
-               if (skb->dst            &&
+               if (skb->dst            &&
                    skb->dst->neighbour &&
                    !*to_ipoib_neigh(skb->dst->neighbour)) {
                        struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
@@ -710,7 +710,7 @@ out:
 
                        if (neigh) {
                                kref_get(&mcast->ah->ref);
-                               neigh->ah       = mcast->ah;
+                               neigh->ah       = mcast->ah;
                                list_add_tail(&neigh->list, &mcast->neigh_list);
                        }
                }
@@ -788,10 +788,6 @@ void ipoib_mcast_restart_task(struct work_struct *work)
 
                memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid);
 
-               /* Add in the P_Key */
-               mgid.raw[4] = (priv->pkey >> 8) & 0xff;
-               mgid.raw[5] = priv->pkey & 0xff;
-
                mcast = __ipoib_mcast_find(dev, &mgid);
                if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
                        struct ipoib_mcast *nmcast;
index 3c6e45db0ab5079b3c36c39ec0bb34ce597a6055..433e99ac227b85a2bd6e8594c69fe47f3dc6e274 100644 (file)
@@ -172,8 +172,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
 
        size = ipoib_sendq_size + ipoib_recvq_size + 1;
        ret = ipoib_cm_dev_init(dev);
-       if (!ret)
-               size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */;
+       if (!ret) {
+               if (ipoib_cm_has_srq(dev))
+                       size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
+               else
+                       size += ipoib_recvq_size * ipoib_max_conn_qp;
+       }
 
        priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
        if (IS_ERR(priv->cq)) {
@@ -197,12 +201,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
        priv->dev->dev_addr[2] = (priv->qp->qp_num >>  8) & 0xff;
        priv->dev->dev_addr[3] = (priv->qp->qp_num      ) & 0xff;
 
-       priv->tx_sge.lkey       = priv->mr->lkey;
+       priv->tx_sge.lkey       = priv->mr->lkey;
 
-       priv->tx_wr.opcode      = IB_WR_SEND;
-       priv->tx_wr.sg_list     = &priv->tx_sge;
-       priv->tx_wr.num_sge     = 1;
-       priv->tx_wr.send_flags  = IB_SEND_SIGNALED;
+       priv->tx_wr.opcode      = IB_WR_SEND;
+       priv->tx_wr.sg_list     = &priv->tx_sge;
+       priv->tx_wr.num_sge     = 1;
+       priv->tx_wr.send_flags  = IB_SEND_SIGNALED;
 
        return 0;
 
index fe604c8d299621b9dad04d8e4a9d85672b9ab326..77dedba829e6c5549ab495b8c2f23f2a0c782839 100644 (file)
@@ -8,5 +8,5 @@ config INFINIBAND_ISER
           that speak iSCSI over iSER over InfiniBand.
 
          The iSER protocol is defined by IETF.
-         See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
-         and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
+         See <http://www.ietf.org/rfc/rfc5046.txt>
+         and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF>
index bad8dacafd108e5c2c9fd0f4826e2a59630337e9..be1b9fbd416d9cf2a2c70dad4542278704448058 100644 (file)
@@ -129,7 +129,7 @@ error:
  * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
  *
  **/
-static void
+static int
 iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
 {
        struct iscsi_iser_conn     *iser_conn  = ctask->conn->dd_data;
@@ -138,6 +138,7 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
        iser_ctask->command_sent = 0;
        iser_ctask->iser_conn    = iser_conn;
        iser_ctask_rdma_init(iser_ctask);
+       return 0;
 }
 
 /**
@@ -220,12 +221,6 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
        debug_scsi("ctask deq [cid %d itt 0x%x]\n",
                   conn->id, ctask->itt);
 
-       /*
-        * serialize with TMF AbortTask
-        */
-       if (ctask->mtask)
-               return error;
-
        /* Send the cmd PDU */
        if (!iser_ctask->command_sent) {
                error = iser_send_command(conn, ctask);
@@ -406,6 +401,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit,
                ctask      = session->cmds[i];
                iser_ctask = ctask->dd_data;
                ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
+               ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header);
        }
 
        for (i = 0; i < session->mgmtpool_max; i++) {
@@ -551,11 +547,13 @@ static struct scsi_host_template iscsi_iser_sht = {
        .module                 = THIS_MODULE,
        .name                   = "iSCSI Initiator over iSER, v." DRV_VER,
        .queuecommand           = iscsi_queuecommand,
+       .change_queue_depth     = iscsi_change_queue_depth,
        .can_queue              = ISCSI_DEF_XMIT_CMDS_MAX - 1,
        .sg_tablesize           = ISCSI_ISER_SG_TABLESIZE,
        .max_sectors            = 1024,
        .cmd_per_lun            = ISCSI_MAX_CMD_PER_LUN,
        .eh_abort_handler       = iscsi_eh_abort,
+       .eh_device_reset_handler= iscsi_eh_device_reset,
        .eh_host_reset_handler  = iscsi_eh_host_reset,
        .use_clustering         = DISABLE_CLUSTERING,
        .proc_name              = "iscsi_iser",
@@ -582,7 +580,9 @@ static struct iscsi_transport iscsi_iser_transport = {
                                  ISCSI_PERSISTENT_ADDRESS |
                                  ISCSI_TARGET_NAME | ISCSI_TPGT |
                                  ISCSI_USERNAME | ISCSI_PASSWORD |
-                                 ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+                                 ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+                                 ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+                                 ISCSI_PING_TMO | ISCSI_RECV_TMO,
        .host_param_mask        = ISCSI_HOST_HWADDRESS |
                                  ISCSI_HOST_NETDEV_NAME |
                                  ISCSI_HOST_INITIATOR_NAME,
index a6f2303ed14a40016fe09bd1e13757fe6b49467b..83247f1fdf7280fe5b7caa7ffc7de4f46fb6c699 100644 (file)
@@ -561,7 +561,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
        if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
                itt = get_itt(hdr->itt); /* mask out cid and age bits */
                if (!(itt < session->cmds_max))
-                       iser_err("itt can't be matched to task!!!"
+                       iser_err("itt can't be matched to task!!! "
                                 "conn %p opcode %d cmds_max %d itt %d\n",
                                 conn->iscsi_conn,opcode,session->cmds_max,itt);
                /* use the mapping given with the cmds array indexed by itt */
@@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
                        struct iscsi_session *session = conn->session;
 
                        spin_lock(&conn->session->lock);
-                       list_del(&mtask->running);
-                       __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
-                                   sizeof(void*));
+                       iscsi_free_mgmt_task(conn, mtask);
                        spin_unlock(&session->lock);
                }
        }
index 654a4dce0236ac8dfd65ceacb946c0d684891e88..714b8db02b297b48c37abd37f1fc13891c2cbcaa 100644 (file)
@@ -105,7 +105,7 @@ pd_err:
 }
 
 /**
- * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR,
+ * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR,
  * CQ and PD created with the device associated with the adapator.
  */
 static void iser_free_device_ib_res(struct iser_device *device)
@@ -475,13 +475,11 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve
                iser_disconnected_handler(cma_id);
                break;
        case RDMA_CM_EVENT_DEVICE_REMOVAL:
+               iser_err("Device removal is currently unsupported\n");
                BUG();
                break;
-       case RDMA_CM_EVENT_CONNECT_RESPONSE:
-               BUG();
-               break;
-       case RDMA_CM_EVENT_CONNECT_REQUEST:
        default:
+               iser_err("Unexpected RDMA CM event (%d)\n", event->event);
                break;
        }
        return ret;
index 950228fb009f29c1ccebd3f9453ee2c731a9a4c9..f2d2c7e2c76b9cd1b778da992a481b65e575bf7a 100644 (file)
@@ -272,7 +272,8 @@ static void srp_path_rec_completion(int status,
 
        target->status = status;
        if (status)
-               printk(KERN_ERR PFX "Got failed path rec status %d\n", status);
+               shost_printk(KERN_ERR, target->scsi_host,
+                            PFX "Got failed path rec status %d\n", status);
        else
                target->path = *pathrec;
        complete(&target->done);
@@ -303,7 +304,8 @@ static int srp_lookup_path(struct srp_target_port *target)
        wait_for_completion(&target->done);
 
        if (target->status < 0)
-               printk(KERN_WARNING PFX "Path record query failed\n");
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "Path record query failed\n");
 
        return target->status;
 }
@@ -379,9 +381,10 @@ static int srp_send_req(struct srp_target_port *target)
         * the second 8 bytes to the local node GUID.
         */
        if (srp_target_is_topspin(target)) {
-               printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
-                      "activated for target GUID %016llx\n",
-                      (unsigned long long) be64_to_cpu(target->ioc_guid));
+               shost_printk(KERN_DEBUG, target->scsi_host,
+                            PFX "Topspin/Cisco initiator port ID workaround "
+                            "activated for target GUID %016llx\n",
+                            (unsigned long long) be64_to_cpu(target->ioc_guid));
                memset(req->priv.initiator_port_id, 0, 8);
                memcpy(req->priv.initiator_port_id + 8,
                       &target->srp_host->dev->dev->node_guid, 8);
@@ -400,7 +403,8 @@ static void srp_disconnect_target(struct srp_target_port *target)
 
        init_completion(&target->done);
        if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
-               printk(KERN_DEBUG PFX "Sending CM DREQ failed\n");
+               shost_printk(KERN_DEBUG, target->scsi_host,
+                            PFX "Sending CM DREQ failed\n");
                return;
        }
        wait_for_completion(&target->done);
@@ -568,7 +572,8 @@ static int srp_reconnect_target(struct srp_target_port *target)
        return ret;
 
 err:
-       printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret);
+       shost_printk(KERN_ERR, target->scsi_host,
+                    PFX "reconnect failed (%d), removing target port.\n", ret);
 
        /*
         * We couldn't reconnect, so kill our target port off.
@@ -683,8 +688,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
 
        if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
            scmnd->sc_data_direction != DMA_TO_DEVICE) {
-               printk(KERN_WARNING PFX "Unhandled data direction %d\n",
-                      scmnd->sc_data_direction);
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "Unhandled data direction %d\n",
+                            scmnd->sc_data_direction);
                return -EINVAL;
        }
 
@@ -786,8 +792,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
        } else {
                scmnd = req->scmnd;
                if (!scmnd)
-                       printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n",
-                              (unsigned long long) rsp->tag);
+                       shost_printk(KERN_ERR, target->scsi_host,
+                                    "Null scmnd for RSP w/tag %016llx\n",
+                                    (unsigned long long) rsp->tag);
                scmnd->result = rsp->status;
 
                if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
@@ -831,7 +838,8 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
        if (0) {
                int i;
 
-               printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode);
+               shost_printk(KERN_ERR, target->scsi_host,
+                            PFX "recv completion, opcode 0x%02x\n", opcode);
 
                for (i = 0; i < wc->byte_len; ++i) {
                        if (i % 8 == 0)
@@ -852,11 +860,13 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
 
        case SRP_T_LOGOUT:
                /* XXX Handle target logout */
-               printk(KERN_WARNING PFX "Got target logout request\n");
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "Got target logout request\n");
                break;
 
        default:
-               printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode);
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "Unhandled SRP opcode 0x%02x\n", opcode);
                break;
        }
 
@@ -872,9 +882,10 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
        ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
        while (ib_poll_cq(cq, 1, &wc) > 0) {
                if (wc.status) {
-                       printk(KERN_ERR PFX "failed %s status %d\n",
-                              wc.wr_id & SRP_OP_RECV ? "receive" : "send",
-                              wc.status);
+                       shost_printk(KERN_ERR, target->scsi_host,
+                                    PFX "failed %s status %d\n",
+                                    wc.wr_id & SRP_OP_RECV ? "receive" : "send",
+                                    wc.status);
                        target->qp_in_error = 1;
                        break;
                }
@@ -930,13 +941,18 @@ static int srp_post_recv(struct srp_target_port *target)
  * req_lim and tx_head.  Lock cannot be dropped between call here and
  * call to __srp_post_send().
  */
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+                                       enum srp_request_type req_type)
 {
+       s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
+
        if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
                return NULL;
 
-       if (unlikely(target->req_lim < 1))
+       if (target->req_lim < min) {
                ++target->zero_req_lim;
+               return NULL;
+       }
 
        return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
 }
@@ -993,7 +1009,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                return 0;
        }
 
-       iu = __srp_get_tx_iu(target);
+       iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
        if (!iu)
                goto err;
 
@@ -1022,12 +1038,13 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
 
        len = srp_map_data(scmnd, target, req);
        if (len < 0) {
-               printk(KERN_ERR PFX "Failed to map data\n");
+               shost_printk(KERN_ERR, target->scsi_host,
+                            PFX "Failed to map data\n");
                goto err;
        }
 
        if (__srp_post_recv(target)) {
-               printk(KERN_ERR PFX "Recv failed\n");
+               shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n");
                goto err_unmap;
        }
 
@@ -1035,7 +1052,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                                      DMA_TO_DEVICE);
 
        if (__srp_post_send(target, iu, len)) {
-               printk(KERN_ERR PFX "Send failed\n");
+               shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
                goto err_unmap;
        }
 
@@ -1090,6 +1107,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
                               struct ib_cm_event *event,
                               struct srp_target_port *target)
 {
+       struct Scsi_Host *shost = target->scsi_host;
        struct ib_class_port_info *cpi;
        int opcode;
 
@@ -1115,19 +1133,22 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
                        memcpy(target->path.dgid.raw,
                               event->param.rej_rcvd.ari, 16);
 
-                       printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
-                              (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
-                              (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
+                       shost_printk(KERN_DEBUG, shost,
+                                    PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
+                                    (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
+                                    (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
 
                        target->status = SRP_PORT_REDIRECT;
                } else {
-                       printk(KERN_WARNING "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
+                       shost_printk(KERN_WARNING, shost,
+                                    "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
                        target->status = -ECONNRESET;
                }
                break;
 
        case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
-               printk(KERN_WARNING "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
+               shost_printk(KERN_WARNING, shost,
+                           "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
                target->status = -ECONNRESET;
                break;
 
@@ -1138,20 +1159,21 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
                        u32 reason = be32_to_cpu(rej->reason);
 
                        if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
-                               printk(KERN_WARNING PFX
-                                      "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
+                               shost_printk(KERN_WARNING, shost,
+                                            PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
                        else
-                               printk(KERN_WARNING PFX
-                                      "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
+                               shost_printk(KERN_WARNING, shost,
+                                           PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
                } else
-                       printk(KERN_WARNING "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
-                              " opcode 0x%02x\n", opcode);
+                       shost_printk(KERN_WARNING, shost,
+                                    "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
+                                    " opcode 0x%02x\n", opcode);
                target->status = -ECONNRESET;
                break;
 
        default:
-               printk(KERN_WARNING "  REJ reason 0x%x\n",
-                      event->param.rej_rcvd.reason);
+               shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
+                            event->param.rej_rcvd.reason);
                target->status = -ECONNRESET;
        }
 }
@@ -1166,7 +1188,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 
        switch (event->event) {
        case IB_CM_REQ_ERROR:
-               printk(KERN_DEBUG PFX "Sending CM REQ failed\n");
+               shost_printk(KERN_DEBUG, target->scsi_host,
+                            PFX "Sending CM REQ failed\n");
                comp = 1;
                target->status = -ECONNRESET;
                break;
@@ -1184,7 +1207,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                        target->scsi_host->can_queue = min(target->req_lim,
                                                           target->scsi_host->can_queue);
                } else {
-                       printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode);
+                       shost_printk(KERN_WARNING, target->scsi_host,
+                                   PFX "Unhandled RSP opcode %#x\n", opcode);
                        target->status = -ECONNRESET;
                        break;
                }
@@ -1230,20 +1254,23 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                break;
 
        case IB_CM_REJ_RECEIVED:
-               printk(KERN_DEBUG PFX "REJ received\n");
+               shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
                comp = 1;
 
                srp_cm_rej_handler(cm_id, event, target);
                break;
 
        case IB_CM_DREQ_RECEIVED:
-               printk(KERN_WARNING PFX "DREQ received - connection closed\n");
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "DREQ received - connection closed\n");
                if (ib_send_cm_drep(cm_id, NULL, 0))
-                       printk(KERN_ERR PFX "Sending CM DREP failed\n");
+                       shost_printk(KERN_ERR, target->scsi_host,
+                                    PFX "Sending CM DREP failed\n");
                break;
 
        case IB_CM_TIMEWAIT_EXIT:
-               printk(KERN_ERR PFX "connection closed\n");
+               shost_printk(KERN_ERR, target->scsi_host,
+                            PFX "connection closed\n");
 
                comp = 1;
                target->status = 0;
@@ -1255,7 +1282,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                break;
 
        default:
-               printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "Unhandled CM event %d\n", event->event);
                break;
        }
 
@@ -1283,7 +1311,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
 
        init_completion(&req->done);
 
-       iu = __srp_get_tx_iu(target);
+       iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
        if (!iu)
                goto out;
 
@@ -1332,7 +1360,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
        struct srp_request *req;
        int ret = SUCCESS;
 
-       printk(KERN_ERR "SRP abort called\n");
+       shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
        if (target->qp_in_error)
                return FAILED;
@@ -1362,7 +1390,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
        struct srp_target_port *target = host_to_target(scmnd->device->host);
        struct srp_request *req, *tmp;
 
-       printk(KERN_ERR "SRP reset_device called\n");
+       shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
 
        if (target->qp_in_error)
                return FAILED;
@@ -1389,7 +1417,7 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
        struct srp_target_port *target = host_to_target(scmnd->device->host);
        int ret = FAILED;
 
-       printk(KERN_ERR PFX "SRP reset_host called\n");
+       shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n");
 
        if (!srp_reconnect_target(target))
                ret = SUCCESS;
@@ -1543,6 +1571,7 @@ static struct scsi_host_template srp_template = {
        .this_id                        = -1,
        .cmd_per_lun                    = SRP_SQ_SIZE,
        .use_clustering                 = ENABLE_CLUSTERING,
+       .use_sg_chaining                = ENABLE_SG_CHAINING,
        .shost_attrs                    = srp_host_attrs
 };
 
@@ -1814,8 +1843,9 @@ static ssize_t srp_create_target(struct class_device *class_dev,
 
        ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid);
 
-       printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
-              "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+       shost_printk(KERN_DEBUG, target->scsi_host, PFX
+                    "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
+                    "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
               (unsigned long long) be64_to_cpu(target->id_ext),
               (unsigned long long) be64_to_cpu(target->ioc_guid),
               be16_to_cpu(target->path.pkey),
@@ -1842,7 +1872,8 @@ static ssize_t srp_create_target(struct class_device *class_dev,
        target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret) {
-               printk(KERN_ERR PFX "Connection failed\n");
+               shost_printk(KERN_ERR, target->scsi_host,
+                            PFX "Connection failed\n");
                goto err_cm_id;
        }
 
@@ -2053,6 +2084,7 @@ static void srp_remove_one(struct ib_device *device)
 
                list_for_each_entry_safe(target, tmp_target,
                                         &host->target_list, list) {
+                       srp_remove_host(target->scsi_host);
                        scsi_remove_host(target->scsi_host);
                        srp_disconnect_target(target);
                        ib_destroy_cm_id(target->cm_id);
index e3573e7038c4ea7089f5e257964d75c3f0dbf043..4a3c1f37e4c206bea4674e76576596ac5a851bca 100644 (file)
@@ -79,6 +79,11 @@ enum srp_target_state {
        SRP_TARGET_REMOVED
 };
 
+enum srp_request_type {
+       SRP_REQ_NORMAL,
+       SRP_REQ_TASK_MGMT,
+};
+
 struct srp_device {
        struct list_head        dev_list;
        struct ib_device       *dev;
index bfc6061f1554fdf72c20d0e9d22631921f6fc052..1dc2ac9f3d1cce12d1516c07b567c4656b28ee54 100644 (file)
@@ -38,8 +38,6 @@ EXPORT_SYMBOL(gameport_unregister_driver);
 EXPORT_SYMBOL(gameport_open);
 EXPORT_SYMBOL(gameport_close);
 EXPORT_SYMBOL(gameport_rescan);
-EXPORT_SYMBOL(gameport_cooked_read);
-EXPORT_SYMBOL(gameport_set_name);
 EXPORT_SYMBOL(gameport_set_phys);
 EXPORT_SYMBOL(gameport_start_polling);
 EXPORT_SYMBOL(gameport_stop_polling);
index 307c7b5c2b33a59fa33825523cca639af4f4ccd2..a0be978501ff1c1679374adcde4d13ad84102aa6 100644 (file)
@@ -235,6 +235,10 @@ static void input_handle_event(struct input_dev *dev,
                if (value >= 0)
                        disposition = INPUT_PASS_TO_ALL;
                break;
+
+       case EV_PWR:
+               disposition = INPUT_PASS_TO_ALL;
+               break;
        }
 
        if (type != EV_SYN)
@@ -1266,6 +1270,10 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
                __set_bit(code, dev->ffbit);
                break;
 
+       case EV_PWR:
+               /* do nothing */
+               break;
+
        default:
                printk(KERN_ERR
                        "input_set_capability: unknown type %u (code %u)\n",
index dfa6592c10f646bb66465b173813e325feaa7860..086d58c0ccbe0ef2d800df377df2593af13cfb46 100644 (file)
@@ -209,22 +209,22 @@ config KEYBOARD_HIL
          to your machine, so normally you should say Y here.
 
 config KEYBOARD_HP6XX
-       tristate "HP Jornada 6XX Keyboard support"
+       tristate "HP Jornada 6xx keyboard"
        depends on SH_HP6XX
        select INPUT_POLLDEV
        help
-         This adds support for the onboard keyboard found on
-         HP Jornada 620/660/680/690.
+         Say Y here if you have a HP Jornada 620/660/680/690 and want to
+         support the built-in keyboard.
 
          To compile this driver as a module, choose M here: the
          module will be called jornada680_kbd.
 
 config KEYBOARD_HP7XX
-       tristate "HP Jornada 7XX Keyboard Driver"
+       tristate "HP Jornada 7xx keyboard"
        depends on SA1100_JORNADA720_SSP && SA1100_SSP
        help
-         Say Y here to add support for the HP Jornada 7xx (710/720/728)
-         onboard keyboard.
+         Say Y here if you have a HP Jornada 710/720/728 and want to
+         support the built-in keyboard.
 
          To compile this driver as a module, choose M here: the
          module will be called jornada720_kbd.
index bec1cf483723ef18d58a9e99472d5619931647f1..a23633a2e1b46654979633556ef8564d1e160aa3 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/input.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
+#include <linux/input.h>
 #include <linux/input-polldev.h>
+#include <linux/interrupt.h>
 #include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/interrupt.h>
 
 #include <asm/delay.h>
 #include <asm/io.h>
 #define PLDR 0xa4000134
 
 static const unsigned short jornada_scancodes[] = {
-/* PTD1 */     KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0,     /*  1  -> 8   */
-               KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5, /*  9  -> 16  */
-/* PTD5 */     KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,        /*  17 -> 24  */
-               KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,   /*  25 -> 32  */
-/* PTD7 */     KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0,                             /*  33 -> 40  */
-               0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA,                 /*  41 -> 48  */
-/* PTE0 */     0, 0, 0, 0, KEY_FINANCE, 0, 0, 0,                               /*  49 -> 56  */
-               KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /*  57 -> 64  */
-/* PTE1 */     KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/*  65 -> 72  */
-               KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,         /*  73 -> 80  */
-/* PTE3 */     KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0,      /*  81 -> 88  */
-               0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,                             /*  89 -> 96  */
-/* PTE6 */     KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,         /*  97 -> 104 */
-               KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,         /* 105 -> 112 */
-/* PTE7 */     KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0,                 /* 113 -> 120 */
-               KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6,         /* 121 -> 128 */
+/* PTD1 */     KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, KEY_KP5, 0, 0,                       /*  1  -> 8   */
+               KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F6, KEY_F4, KEY_F5,                         /*  9  -> 16  */
+/* PTD5 */     KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,                                /*  17 -> 24  */
+               KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,                           /*  25 -> 32  */
+/* PTD7 */     KEY_KP2, KEY_KP6, KEY_KP3, 0, 0, 0, 0, 0,                                               /*  33 -> 40  */
+               KEY_F10, KEY_RO, KEY_F9, KEY_KP4, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_LEFTALT, KEY_HANJA,  /*  41 -> 48  */
+/* PTE0 */     KEY_KATAKANA, KEY_KP0, KEY_GRAVE, 0, KEY_FINANCE, 0, 0, 0,                              /*  49 -> 56  */
+               KEY_KPMINUS, KEY_HIRAGANA, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0,               /*  57 -> 64  */
+/* PTE1 */     KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,                        /*  65 -> 72  */
+               KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,                                 /*  73 -> 80  */
+/* PTE3 */     KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0, 0,                             /*  81 -> 88  */
+               0, KEY_LEFTSHIFT, KEY_KP7, KEY_KP9, KEY_KP1, KEY_F11, KEY_KPPLUS, KEY_KPASTERISK,       /*  89 -> 96  */
+/* PTE6 */     KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,                                 /*  97 -> 104 */
+               KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_Y,                                 /* 105 -> 112 */
+/* PTE7 */     KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0,                                         /* 113 -> 120 */
+               KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6,                                 /* 121 -> 128 */
 /* **** */     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0
 };
index 410d78a774d03c2eab0ce95a1fd608f73df09436..1d59a2dc3c17c57a6a18110e73a6128bceb28073 100644 (file)
@@ -391,6 +391,7 @@ static int __init spitzkbd_probe(struct platform_device *dev)
        for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++)
                set_bit(spitzkbd->keycode[i], input_dev->keybit);
        clear_bit(0, input_dev->keybit);
+       set_bit(KEY_SUSPEND, input_dev->keybit);
        set_bit(SW_LID, input_dev->swbit);
        set_bit(SW_TABLET_MODE, input_dev->swbit);
        set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
index a3637d870880a22a8d92befb7e75aa9272096c1d..fed3c375ccf39ff34ecb2a23fb720da5538fa153 100644 (file)
@@ -195,7 +195,7 @@ static struct of_platform_driver ebus_beep_driver = {
        .name           = "beep",
        .match_table    = ebus_beep_match,
        .probe          = ebus_beep_probe,
-       .remove         = sparcspkr_remove,
+       .remove         = __devexit_p(sparcspkr_remove),
        .shutdown       = sparcspkr_shutdown,
 };
 
@@ -236,7 +236,7 @@ static struct of_platform_driver isa_beep_driver = {
        .name           = "beep",
        .match_table    = isa_beep_match,
        .probe          = isa_beep_probe,
-       .remove         = sparcspkr_remove,
+       .remove         = __devexit_p(sparcspkr_remove),
        .shutdown       = sparcspkr_shutdown,
 };
 
index 2b5ed119c9a90e9b5d66245eebfe9fcc1e11a197..b346a3b418ea78d60d4a129b911d7fe7a37035cb 100644 (file)
@@ -54,7 +54,7 @@ static const struct alps_model_info alps_model_data[] = {
        { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
        { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
        { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
-       { { 0x73, 0x02, 0x50 }, 0xcf, 0xff, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
+       { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
 };
 
 /*
index 9ec57d80186e43b7f776ec3b9aed0c7c385ce625..df81b0aaa9f88911fa335d506f284161c5e24d70 100644 (file)
@@ -225,8 +225,13 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu
 
 static void lifebook_disconnect(struct psmouse *psmouse)
 {
+       struct lifebook_data *priv = psmouse->private;
+
        psmouse_reset(psmouse);
-       kfree(psmouse->private);
+       if (priv) {
+               input_unregister_device(priv->dev2);
+               kfree(priv);
+       }
        psmouse->private = NULL;
 }
 
index 21a9c0b69a1f461befa62691f0a35baaa99641a6..b8628252e10c5832c0f61c88244200064f5de169 100644 (file)
@@ -1247,6 +1247,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
  err_pt_deactivate:
        if (parent && parent->pt_deactivate)
                parent->pt_deactivate(parent);
+       input_unregister_device(psmouse->dev);
+       input_dev = NULL; /* so we don't try to free it below */
  err_protocol_disconnect:
        if (psmouse->disconnect)
                psmouse->disconnect(psmouse);
index 78c3ea75da2a056b2799045c6c2329f5834a8705..be83516c776c8566b832c842ee40b7048129e6f1 100644 (file)
@@ -1029,6 +1029,15 @@ static const struct input_device_id mousedev_ids[] = {
                                BIT_MASK(ABS_PRESSURE) |
                                BIT_MASK(ABS_TOOL_WIDTH) },
        },      /* A touchpad */
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+                       INPUT_DEVICE_ID_MATCH_KEYBIT |
+                       INPUT_DEVICE_ID_MATCH_ABSBIT,
+               .evbit = { BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_SYN) },
+               .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
+               .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+       },      /* Mouse-like device with absolute X and Y but ordinary
+                  clicks, like hp ILO2 High Performance mouse */
 
        { },    /* Terminating entry */
 };
index fa8442b6241c11a343b7fe1413b8e2202c0c60c4..90e8e92dfe4792ca662e60bb94cdf30c2ee62c0d 100644 (file)
@@ -115,19 +115,17 @@ config TOUCHSCREEN_MK712
          module will be called mk712.
 
 config TOUCHSCREEN_HP600
-       tristate "HP Jornada 680/690 touchscreen"
+       tristate "HP Jornada 6xx touchscreen"
        depends on SH_HP6XX && SH_ADC
        help
-         Say Y here if you have a HP Jornada 680 or 690 and want to
+         Say Y here if you have a HP Jornada 620/660/680/690 and want to
           support the built-in touchscreen.
 
-         If unsure, say N.
-
          To compile this driver as a module, choose M here: the
          module will be called hp680_ts_input.
 
 config TOUCHSCREEN_HP7XX
-       tristate "HP Jornada 710/720/728 touchscreen"
+       tristate "HP Jornada 7xx touchscreen"
        depends on SA1100_JORNADA720_SSP
        help
          Say Y here if you have a HP Jornada 710/720/728 and want
index 19055e7381f8423b52e14763c43281b7672ccb09..63f9664a066f8465398f4526ca07ee4fbbbf4684 100644 (file)
@@ -11,6 +11,7 @@
  *  - DMC TSC-10/25
  *  - IRTOUCHSYSTEMS/UNITOP
  *  - IdealTEK URTC1000
+ *  - General Touch
  *  - GoTop Super_Q2/GogoPen/PenPower tablets
  *
  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
@@ -50,7 +51,7 @@
 #include <linux/usb/input.h>
 
 
-#define DRIVER_VERSION         "v0.5"
+#define DRIVER_VERSION         "v0.6"
 #define DRIVER_AUTHOR          "Daniel Ritz <daniel.ritz@gmx.ch>"
 #define DRIVER_DESC            "USB Touchscreen Driver"
 
@@ -65,17 +66,21 @@ struct usbtouch_device_info {
        int min_yc, max_yc;
        int min_press, max_press;
        int rept_size;
-       int flags;
 
        void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
+
+       /*
+        * used to get the packet len. possible return values:
+        * > 0: packet len
+        * = 0: skip one byte
+        * < 0: -return value more bytes needed
+        */
        int  (*get_pkt_len) (unsigned char *pkt, int len);
+
        int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
        int  (*init)        (struct usbtouch_usb *usbtouch);
 };
 
-#define USBTOUCH_FLG_BUFFER    0x01
-
-
 /* a usbtouch device */
 struct usbtouch_usb {
        unsigned char *data;
@@ -94,15 +99,6 @@ struct usbtouch_usb {
 };
 
 
-#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK)
-#define MULTI_PACKET
-#endif
-
-#ifdef MULTI_PACKET
-static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
-                                   unsigned char *pkt, int len);
-#endif
-
 /* device types */
 enum {
        DEVTPYE_DUMMY = -1,
@@ -186,6 +182,10 @@ static struct usb_device_id usbtouch_devices[] = {
 
 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
 
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+
 #define EGALAX_PKT_TYPE_MASK           0xFE
 #define EGALAX_PKT_TYPE_REPT           0x80
 #define EGALAX_PKT_TYPE_DIAG           0x0A
@@ -323,6 +323,9 @@ static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
  * eTurboTouch part
  */
 #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
 static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
        unsigned int shift;
@@ -461,6 +464,9 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
  * IdealTEK URTC1000 Part
  */
 #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
 static int idealtek_get_pkt_len(unsigned char *buf, int len)
 {
        if (buf[0] & 0x80)
@@ -525,6 +531,11 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 /*****************************************************************************
  * the different device descriptors
  */
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+                                  unsigned char *pkt, int len);
+#endif
+
 static struct usbtouch_device_info usbtouch_dev_info[] = {
 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
        [DEVTYPE_EGALAX] = {
@@ -533,7 +544,6 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .min_yc         = 0x0,
                .max_yc         = 0x07ff,
                .rept_size      = 16,
-               .flags          = USBTOUCH_FLG_BUFFER,
                .process_pkt    = usbtouch_process_multi,
                .get_pkt_len    = egalax_get_pkt_len,
                .read_data      = egalax_read_data,
@@ -582,7 +592,6 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .min_yc         = 0x0,
                .max_yc         = 0x07ff,
                .rept_size      = 8,
-               .flags          = USBTOUCH_FLG_BUFFER,
                .process_pkt    = usbtouch_process_multi,
                .get_pkt_len    = eturbo_get_pkt_len,
                .read_data      = eturbo_read_data,
@@ -630,7 +639,6 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .min_yc         = 0x0,
                .max_yc         = 0x0fff,
                .rept_size      = 8,
-               .flags          = USBTOUCH_FLG_BUFFER,
                .process_pkt    = usbtouch_process_multi,
                .get_pkt_len    = idealtek_get_pkt_len,
                .read_data      = idealtek_read_data,
@@ -738,11 +746,14 @@ static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
        pos = 0;
        while (pos < buf_len) {
                /* get packet len */
-               pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len);
+               pkt_len = usbtouch->type->get_pkt_len(buffer + pos,
+                                                       buf_len - pos);
 
-               /* unknown packet: drop everything */
-               if (unlikely(!pkt_len))
-                       goto out_flush_buf;
+               /* unknown packet: skip one byte */
+               if (unlikely(!pkt_len)) {
+                       pos++;
+                       continue;
+               }
 
                /* full packet: process */
                if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
@@ -857,7 +868,7 @@ static int usbtouch_probe(struct usb_interface *intf,
        if (!usbtouch->data)
                goto out_free;
 
-       if (type->flags & USBTOUCH_FLG_BUFFER) {
+       if (type->get_pkt_len) {
                usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
                if (!usbtouch->buffer)
                        goto out_free_buffers;
index f449daef3eedd4d0ce37200e979f3e6f4affb90d..23ae66c76d47f2698f5daeabdf548bab5c03ddbe 100644 (file)
@@ -1544,11 +1544,11 @@ static int __init capi_init(void)
                return PTR_ERR(capi_class);
        }
 
-       class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
+       device_create(capi_class, NULL, MKDEV(capi_major, 0), "capi");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
        if (capinc_tty_init() < 0) {
-               class_device_destroy(capi_class, MKDEV(capi_major, 0));
+               device_destroy(capi_class, MKDEV(capi_major, 0));
                class_destroy(capi_class);
                unregister_chrdev(capi_major, "capi20");
                return -ENOMEM;
@@ -1576,7 +1576,7 @@ static void __exit capi_exit(void)
 {
        proc_exit();
 
-       class_device_destroy(capi_class, MKDEV(capi_major, 0));
+       device_destroy(capi_class, MKDEV(capi_major, 0));
        class_destroy(capi_class);
        unregister_chrdev(capi_major, "capi20");
 
index 48c1775ef5b3de68404f90649b3ea9ede2d30d8a..cb42b690b45ee221b3f77a3ab967ced3864ba619 100644 (file)
@@ -2332,13 +2332,14 @@ static int __init capidrv_init(void)
 
 static void __exit capidrv_exit(void)
 {
-       char rev[10];
+       char rev[32];
        char *p;
 
        if ((p = strchr(revision, ':')) != 0) {
-               strcpy(rev, p + 1);
-               p = strchr(rev, '$');
-               *p = 0;
+               strncpy(rev, p + 1, sizeof(rev));
+               rev[sizeof(rev)-1] = 0;
+               if ((p = strchr(rev, '$')) != 0)
+                       *p = 0;
        } else {
                strcpy(rev, " ??? ");
        }
index a0317abaeb111fc9ced966f62c11afbd3491bc35..02bdaf22d7ea10b28cbe779dd6097ce52b318b17 100644 (file)
@@ -106,12 +106,6 @@ enum debuglevel {
                                         activated */
 };
 
-/* missing from linux/device.h ... */
-#ifndef dev_notice
-#define dev_notice(dev, format, arg...)                \
-       dev_printk(KERN_NOTICE , dev , format , ## arg)
-#endif
-
 /* Kernel message macros for situations where dev_printk and friends cannot be
  * used for lack of reliable access to a device structure.
  * linux/usb.h already contains these but in an obsolete form which clutters
index d6952959d72afc643be51248cadd523e2a0ebcf7..9cef6fcf587b6baaef9df48c3616779262d6d3a9 100644 (file)
@@ -914,6 +914,9 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
                        dflag = 0;
                        count_pull = count_put = 0;
                        while ((count_pull < skb->len) && (len > 0)) {
+                               /* push every character but the last to the tty buffer directly */
+                               if ( count_put )
+                                       tty_insert_flip_char(tty, last, TTY_NORMAL);
                                len--;
                                if (dev->drv[di]->DLEflag & DLEmask) {
                                        last = DLE;
index 4e5f87c1e71413bb3d15d65e5edf3ae011746b20..9cb6e5021adb93af85012396cf857b2fb82242f2 100644 (file)
@@ -85,6 +85,8 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
                                                                tty_insert_flip_char(tty, DLE, 0);
                                                        tty_insert_flip_char(tty, *dp++, 0);
                                                }
+                                               if (*dp == DLE)
+                                                       tty_insert_flip_char(tty, DLE, 0);
                                                last = *dp;
                                        } else {
 #endif
@@ -2645,7 +2647,12 @@ isdn_tty_modem_result(int code, modem_info * info)
                if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
                        return;
                }
+#ifdef CONFIG_ISDN_AUDIO
+               if ( !info->vonline )
+                       tty_ldisc_flush(info->tty);
+#else
                tty_ldisc_flush(info->tty);
+#endif
                if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
                    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
                       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
index 47c10b8f89b3f00a16674fec744e334590f523d7..c0f372f1d761312bc648d9deccd8e74609fbc513 100644 (file)
@@ -3451,7 +3451,7 @@ static int kvm_resume(struct sys_device *dev)
 }
 
 static struct sysdev_class kvm_sysdev_class = {
-       set_kset_name("kvm"),
+       .name = "kvm",
        .suspend = kvm_suspend,
        .resume = kvm_resume,
 };
index ba8b04b03b9f2799eacba45927595553ce4141df..64c66b3769c99edf05af6ae8d104a70a8240f2e1 100644 (file)
@@ -106,9 +106,9 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
                goto err_out;
 
        /* add to the list of leds */
-       write_lock(&leds_list_lock);
+       down_write(&leds_list_lock);
        list_add_tail(&led_cdev->node, &leds_list);
-       write_unlock(&leds_list_lock);
+       up_write(&leds_list_lock);
 
 #ifdef CONFIG_LEDS_TRIGGERS
        init_rwsem(&led_cdev->trigger_lock);
@@ -155,9 +155,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 
        device_unregister(led_cdev->dev);
 
-       write_lock(&leds_list_lock);
+       down_write(&leds_list_lock);
        list_del(&led_cdev->node);
-       write_unlock(&leds_list_lock);
+       up_write(&leds_list_lock);
 }
 EXPORT_SYMBOL_GPL(led_classdev_unregister);
 
index 9b015f9af351e49526eb52ec0f0c09b4acb21e56..5d1ca10524b6933bc216fb282815ac6f348cc9d0 100644 (file)
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/rwsem.h>
 #include <linux/leds.h>
 #include "leds.h"
 
-DEFINE_RWLOCK(leds_list_lock);
+DECLARE_RWSEM(leds_list_lock);
 LIST_HEAD(leds_list);
 
 EXPORT_SYMBOL_GPL(leds_list);
index 0bdb786210b1885bee8e6f194ccdcab09e5bdd18..13c9026d68af0af90e246824df1429496afe6814 100644 (file)
@@ -169,7 +169,7 @@ int led_trigger_register(struct led_trigger *trigger)
        up_write(&triggers_list_lock);
 
        /* Register with any LEDs that have this as a default trigger */
-       read_lock(&leds_list_lock);
+       down_read(&leds_list_lock);
        list_for_each_entry(led_cdev, &leds_list, node) {
                down_write(&led_cdev->trigger_lock);
                if (!led_cdev->trigger && led_cdev->default_trigger &&
@@ -177,7 +177,7 @@ int led_trigger_register(struct led_trigger *trigger)
                        led_trigger_set(led_cdev, trigger);
                up_write(&led_cdev->trigger_lock);
        }
-       read_unlock(&leds_list_lock);
+       up_read(&leds_list_lock);
 
        return 0;
 }
@@ -212,14 +212,14 @@ void led_trigger_unregister(struct led_trigger *trigger)
        up_write(&triggers_list_lock);
 
        /* Remove anyone actively using this trigger */
-       read_lock(&leds_list_lock);
+       down_read(&leds_list_lock);
        list_for_each_entry(led_cdev, &leds_list, node) {
                down_write(&led_cdev->trigger_lock);
                if (led_cdev->trigger == trigger)
                        led_trigger_set(led_cdev, NULL);
                up_write(&led_cdev->trigger_lock);
        }
-       read_unlock(&leds_list_lock);
+       up_read(&leds_list_lock);
 }
 
 void led_trigger_unregister_simple(struct led_trigger *trigger)
index bfac499f3258f74fd2c96267c7e9b9a5361a72bf..2207335e9212e97b64a05bdd290819ceee83a89d 100644 (file)
@@ -19,7 +19,7 @@
 static void locomoled_brightness_set(struct led_classdev *led_cdev,
                                enum led_brightness value, int offset)
 {
-       struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
+       struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev->parent);
        unsigned long flags;
 
        local_irq_save(flags);
index f2f3884fe06314b01a3bb647821c6b4e0ea88e89..12b6fe93b1356b980241ef2f7dae3fd325c30090 100644 (file)
@@ -14,6 +14,7 @@
 #define __LEDS_H_INCLUDED
 
 #include <linux/device.h>
+#include <linux/rwsem.h>
 #include <linux/leds.h>
 
 static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -26,7 +27,7 @@ static inline void led_set_brightness(struct led_classdev *led_cdev,
                led_cdev->brightness_set(led_cdev, value);
 }
 
-extern rwlock_t leds_list_lock;
+extern struct rw_semaphore leds_list_lock;
 extern struct list_head leds_list;
 
 #ifdef CONFIG_LEDS_TRIGGERS
index 7eb9ecff8f4a9e4ae1a73a5904048419860aa5f3..6b8dbb9ba73bbedf67aa06d756dfc94d2a66d663 100644 (file)
@@ -10,10 +10,3 @@ config LGUEST
          not "rustyvisor".  See Documentation/lguest/lguest.txt.
 
          If unsure, say N.  If curious, say M.  If masochistic, say Y.
-
-config LGUEST_GUEST
-       bool
-       help
-         The guest needs code built-in, even if the host has lguest
-         support as a module.  The drivers are tiny, so we build them
-         in too.
index 482aec2a96318e854aede3a385cf34eedc1da95f..96d0fd07c57d5702fe9666a587df05a2ced29c51 100644 (file)
@@ -459,7 +459,7 @@ void __init lguest_arch_host_init(void)
 
        /* We don't need the complexity of CPUs coming and going while we're
         * doing this. */
-       lock_cpu_hotplug();
+       get_online_cpus();
        if (cpu_has_pge) { /* We have a broader idea of "global". */
                /* Remember that this was originally set (for cleanup). */
                cpu_had_pge = 1;
@@ -469,20 +469,20 @@ void __init lguest_arch_host_init(void)
                /* Turn off the feature in the global feature set. */
                clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
        }
-       unlock_cpu_hotplug();
+       put_online_cpus();
 };
 /*:*/
 
 void __exit lguest_arch_host_fini(void)
 {
        /* If we had PGE before we started, turn it back on now. */
-       lock_cpu_hotplug();
+       get_online_cpus();
        if (cpu_had_pge) {
                set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
                /* adjust_pge's argument "1" means set PGE. */
                on_each_cpu(adjust_pge, (void *)1, 0, 1);
        }
-       unlock_cpu_hotplug();
+       put_online_cpus();
 }
 
 
index 5c742a526082484f41dbb1592d982a7d010c725f..b7adde4324e498d6bcea193a9bf88cf9db29d1dc 100644 (file)
@@ -875,5 +875,5 @@ adbdev_init(void)
        adb_dev_class = class_create(THIS_MODULE, "adb");
        if (IS_ERR(adb_dev_class))
                return;
-       class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb");
+       device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb");
 }
index 883da72b5368d236d6c0246da16509b9a97bc42f..ef4c117ea35fde801a43eeea0d1dbf8aebc14190 100644 (file)
@@ -322,8 +322,9 @@ adbhid_input_keycode(int id, int scancode, int repeat)
                        input_sync(ahid->input);
                        input_report_key(ahid->input, KEY_CAPSLOCK, 0);
                        input_sync(ahid->input);
+                       return;
                }
-               return;
+               break;
 #ifdef CONFIG_PPC_PMAC
        case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
                switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO,
index 48d647abea460ce914168072012208690c4c57d5..eaba4a9b231e5479a5b61be9b05f5085e6f20e5b 100644 (file)
@@ -563,7 +563,8 @@ static void media_bay_step(int i)
                                ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
                                hw.irq = bay->cd_irq;
                                hw.chipset = ide_pmac;
-                               bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL);
+                               bay->cd_index =
+                                       ide_register_hw(&hw, NULL, NULL);
                                pmu_resume();
                        }
                        if (bay->cd_index == -1) {
index 6123c70153d3d7db8504cc5eef67ecdc4a14d3a3..ac420b17e16fdbc90c5d3ed2f1c35425c8bcb20f 100644 (file)
@@ -2796,7 +2796,7 @@ static int pmu_sys_resume(struct sys_device *sysdev)
 #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
 
 static struct sysdev_class pmu_sysclass = {
-       set_kset_name("pmu"),
+       .name = "pmu",
 };
 
 static struct sys_device device_pmu = {
index 88c0fd657825fb88aab0eb07611050b2546c3514..f2d24eb3208c97e79bdf33b9d8c396f855f55566 100644 (file)
@@ -1109,7 +1109,7 @@ static void event_callback(void *context)
        list_splice_init(&md->uevent_list, &uevents);
        spin_unlock_irqrestore(&md->uevent_lock, flags);
 
-       dm_send_uevents(&uevents, &md->disk->kobj);
+       dm_send_uevents(&uevents, &md->disk->dev.kobj);
 
        atomic_inc(&md->event_nr);
        wake_up(&md->eventq);
@@ -1530,7 +1530,7 @@ out:
  *---------------------------------------------------------------*/
 void dm_kobject_uevent(struct mapped_device *md)
 {
-       kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
+       kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
 }
 
 uint32_t dm_next_uevent_seq(struct mapped_device *md)
index cef9ebd5a04652d4c3e9f293448c45425531d775..c28a120b4161ea7324eae5160ed2a4c2fc7e0ab6 100644 (file)
@@ -231,7 +231,7 @@ static void mddev_put(mddev_t *mddev)
                list_del(&mddev->all_mddevs);
                spin_unlock(&all_mddevs_lock);
                blk_cleanup_queue(mddev->queue);
-               kobject_unregister(&mddev->kobj);
+               kobject_put(&mddev->kobj);
        } else
                spin_unlock(&all_mddevs_lock);
 }
@@ -1383,22 +1383,19 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                        return -EBUSY;
        }
        bdevname(rdev->bdev,b);
-       if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
-               return -ENOMEM;
-       while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL)
+       while ( (s=strchr(b, '/')) != NULL)
                *s = '!';
-                       
+
        rdev->mddev = mddev;
        printk(KERN_INFO "md: bind<%s>\n", b);
 
-       rdev->kobj.parent = &mddev->kobj;
-       if ((err = kobject_add(&rdev->kobj)))
+       if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
                goto fail;
 
        if (rdev->bdev->bd_part)
-               ko = &rdev->bdev->bd_part->kobj;
+               ko = &rdev->bdev->bd_part->dev.kobj;
        else
-               ko = &rdev->bdev->bd_disk->kobj;
+               ko = &rdev->bdev->bd_disk->dev.kobj;
        if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
                kobject_del(&rdev->kobj);
                goto fail;
@@ -2036,9 +2033,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
        if (err)
                goto abort_free;
 
-       rdev->kobj.parent = NULL;
-       rdev->kobj.ktype = &rdev_ktype;
-       kobject_init(&rdev->kobj);
+       kobject_init(&rdev->kobj, &rdev_ktype);
 
        rdev->desc_nr = -1;
        rdev->saved_raid_disk = -1;
@@ -3054,6 +3049,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
        int partitioned = (MAJOR(dev) != MD_MAJOR);
        int shift = partitioned ? MdpMinorShift : 0;
        int unit = MINOR(dev) >> shift;
+       int error;
 
        if (!mddev)
                return NULL;
@@ -3082,12 +3078,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
        add_disk(disk);
        mddev->gendisk = disk;
        mutex_unlock(&disks_mutex);
-       mddev->kobj.parent = &disk->kobj;
-       kobject_set_name(&mddev->kobj, "%s", "md");
-       mddev->kobj.ktype = &md_ktype;
-       if (kobject_register(&mddev->kobj))
+       error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj,
+                                    "%s", "md");
+       if (error)
                printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
                       disk->disk_name);
+       else
+               kobject_uevent(&mddev->kobj, KOBJ_ADD);
        return NULL;
 }
 
@@ -3359,7 +3356,7 @@ static int do_md_run(mddev_t * mddev)
 
        mddev->changed = 1;
        md_new_event(mddev);
-       kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE);
+       kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE);
        return 0;
 }
 
index a5aad8cad84332a138e741d56ed49bbcf58e1c6c..e8c8157b02fcb5e99a09786b977e30226e56ed95 100644 (file)
@@ -2865,7 +2865,8 @@ static void handle_stripe5(struct stripe_head *sh)
                md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
        }
 
-       if (s.expanding && s.locked == 0)
+       if (s.expanding && s.locked == 0 &&
+           !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
                handle_stripe_expansion(conf, sh, NULL);
 
        if (sh->ops.count)
@@ -3067,7 +3068,8 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
                md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
        }
 
-       if (s.expanding && s.locked == 0)
+       if (s.expanding && s.locked == 0 &&
+           !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
                handle_stripe_expansion(conf, sh, &r6s);
 
        spin_unlock(&sh->lock);
index 1604f049040494dff638038665dd61c1de9586f3..8f4a45346de7e1432491151ff269c6f8e3a1a35a 100644 (file)
@@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig"
 config VIDEO_TUNER
        tristate
        depends on I2C
+       select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
        select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
        select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
        select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
        select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
        select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
+       select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
 
 menuconfig VIDEO_TUNER_CUSTOMIZE
        bool "Customize analog tuner modules to build"
@@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE
 
 if VIDEO_TUNER_CUSTOMIZE
 
+config TUNER_XC2028
+       tristate "XCeive xc2028/xc3028 tuners"
+       depends on I2C
+       default m if VIDEO_TUNER_CUSTOMIZE
+       help
+         Say Y here to include support for the xc2028/xc3028 tuners.
+
 config TUNER_MT20XX
        tristate "Microtune 2032 / 2050 tuners"
        depends on I2C
@@ -97,8 +106,10 @@ config TUNER_MT20XX
          Say Y here to include support for the MT2032 / MT2050 tuner.
 
 config TUNER_TDA8290
-       tristate "TDA 8290+8275(a) tuner combo"
+       tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
        depends on I2C
+       select DVB_TDA827X
+       select DVB_TDA18271
        default m if VIDEO_TUNER_CUSTOMIZE
        help
          Say Y here to include support for Philips TDA8290+8275(a) tuner.
@@ -120,10 +131,19 @@ config TUNER_TEA5767
 config TUNER_SIMPLE
        tristate "Simple tuner support"
        depends on I2C
+       select TUNER_TDA9887
        default m if VIDEO_TUNER_CUSTOMIZE
        help
          Say Y here to include support for various simple tuners.
 
+config TUNER_TDA9887
+       tristate "TDA 9885/6/7 analog IF demodulator"
+       depends on I2C
+       default m if VIDEO_TUNER_CUSTOMIZE
+       help
+         Say Y here to include support for Philips TDA9885/6/7
+         analog IF demodulator.
+
 endif # VIDEO_TUNER_CUSTOMIZE
 
 config VIDEOBUF_GEN
index c5092ef1082f1436d4fe6f4ef8f5e8bc7d8f6791..06ca75911b7f07aebb1bdeb362c04e6969f22bb6 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_SAA7146
        tristate
-       depends on I2C
+       depends on I2C && PCI
 
 config VIDEO_SAA7146_VV
        tristate
index e7c3ab951a44a25e9b37e06ea7eba22226e80725..bb2a027b94837d40740503ad50a94dbb71dc2b74 100644 (file)
@@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
  * saa7134 */
 
 /* decode raw bit pattern to RC5 code */
-u32 ir_rc5_decode(unsigned int code)
+static u32 ir_rc5_decode(unsigned int code)
 {
        unsigned int org_code = code;
        unsigned int pair;
@@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
 EXPORT_SYMBOL_GPL(ir_decode_biphase);
 EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
 
-EXPORT_SYMBOL_GPL(ir_rc5_decode);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
 
index 185e8a860c1a256c9ca211b12511142efee1e53c..a4a937c9053419d7788ee9f447a066a4db51d0f2 100644 (file)
@@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
        [ 0x35 ] = KEY_FASTFORWARD,
        [ 0x36 ] = KEY_TV,
        [ 0x37 ] = KEY_RADIO,         /* FM */
-       [ 0x38 ] = KEY_DVD
+       [ 0x38 ] = KEY_DVD,
+
+       [ 0x3e ] = KEY_F21,           /* MCE +VOL, on Y04G0033 */
+       [ 0x3a ] = KEY_F22,           /* MCE -VOL, on Y04G0033 */
+       [ 0x3b ] = KEY_F23,           /* MCE +CH,  on Y04G0033 */
+       [ 0x3f ] = KEY_F24            /* MCE -CH,  on Y04G0033 */
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
@@ -1843,3 +1848,142 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
+
+/* Pinnacle PCTV HD 800i mini remote */
+IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
+
+       [0x0f] = KEY_1,
+       [0x15] = KEY_2,
+       [0x10] = KEY_3,
+       [0x18] = KEY_4,
+       [0x1b] = KEY_5,
+       [0x1e] = KEY_6,
+       [0x11] = KEY_7,
+       [0x21] = KEY_8,
+       [0x12] = KEY_9,
+       [0x27] = KEY_0,
+
+       [0x24] = KEY_ZOOM,
+       [0x2a] = KEY_SUBTITLE,
+
+       [0x00] = KEY_MUTE,
+       [0x01] = KEY_ENTER,     /* Pinnacle Logo */
+       [0x39] = KEY_POWER,
+
+       [0x03] = KEY_VOLUMEUP,
+       [0x09] = KEY_VOLUMEDOWN,
+       [0x06] = KEY_CHANNELUP,
+       [0x0c] = KEY_CHANNELDOWN,
+
+       [0x2d] = KEY_REWIND,
+       [0x30] = KEY_PLAYPAUSE,
+       [0x33] = KEY_FASTFORWARD,
+       [0x3c] = KEY_STOP,
+       [0x36] = KEY_RECORD,
+       [0x3f] = KEY_EPG,       /* Labeled "?" */
+};
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
+
+/*
+ * Igor Kuznetsov <igk72@ya.ru>
+ * Andrey J. Melnikov <temnota@kmv.ru>
+ *
+ * Keytable is used by BeholdTV 60x series, M6 series at
+ * least, and probably other cards too.
+ * The "ascii-art picture" below (in comments, first row
+ * is the keycode in hex, and subsequent row(s) shows
+ * the button labels (several variants when appropriate)
+ * helps to descide which keycodes to assign to the buttons.
+ */
+IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
+
+       /*  0x1c            0x12  *
+        *  TV/FM          POWER  *
+        *                        */
+       [ 0x1c ] = KEY_TUNER,   /*XXX KEY_TV KEY_RADIO */
+       [ 0x12 ] = KEY_POWER,
+
+       /*  0x01    0x02    0x03  *
+        *   1       2       3    *
+        *                        *
+        *  0x04    0x05    0x06  *
+        *   4       5       6    *
+        *                        *
+        *  0x07    0x08    0x09  *
+        *   7       8       9    *
+        *                        */
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       /*  0x0a    0x00    0x17  *
+        * RECALL    0      MODE  *
+        *                        */
+       [ 0x0a ] = KEY_AGAIN,
+       [ 0x00 ] = KEY_0,
+       [ 0x17 ] = KEY_MODE,
+
+       /*  0x14          0x10    *
+        * ASPECT      FULLSCREEN *
+        *                        */
+       [ 0x14 ] = KEY_SCREEN,
+       [ 0x10 ] = KEY_ZOOM,
+
+       /*          0x0b          *
+        *           Up           *
+        *                        *
+        *  0x18    0x16    0x0c  *
+        *  Left     Ok     Right *
+        *                        *
+        *         0x015          *
+        *         Down           *
+        *                        */
+       [ 0x0b ] = KEY_CHANNELUP,       /*XXX KEY_UP */
+       [ 0x18 ] = KEY_VOLUMEDOWN,      /*XXX KEY_LEFT */
+       [ 0x16 ] = KEY_OK,              /*XXX KEY_ENTER */
+       [ 0x0c ] = KEY_VOLUMEUP,        /*XXX KEY_RIGHT */
+       [ 0x15 ] = KEY_CHANNELDOWN,     /*XXX KEY_DOWN */
+
+       /*  0x11            0x0d  *
+        *  MUTE            INFO  *
+        *                        */
+       [ 0x11 ] = KEY_MUTE,
+       [ 0x0d ] = KEY_INFO,
+
+       /*  0x0f    0x1b    0x1a  *
+        * RECORD PLAY/PAUSE STOP *
+        *                        *
+        *  0x0e    0x1f    0x1e  *
+        *TELETEXT  AUDIO  SOURCE *
+        *           RED   YELLOW *
+        *                        */
+       [ 0x0f ] = KEY_RECORD,
+       [ 0x1b ] = KEY_PLAYPAUSE,
+       [ 0x1a ] = KEY_STOP,
+       [ 0x0e ] = KEY_TEXT,
+       [ 0x1f ] = KEY_RED,     /*XXX KEY_AUDIO */
+       [ 0x1e ] = KEY_YELLOW,  /*XXX KEY_SOURCE */
+
+       /*  0x1d   0x13     0x19  *
+        * SLEEP  PREVIEW   DVB   *
+        *         GREEN    BLUE  *
+        *                        */
+       [ 0x1d ] = KEY_SLEEP,
+       [ 0x13 ] = KEY_GREEN,
+       [ 0x19 ] = KEY_BLUE,    /*XXX KEY_SAT */
+
+       /*  0x58           0x5c   *
+        * FREEZE        SNAPSHOT *
+        *                        */
+       [ 0x58 ] = KEY_SLOW,
+       [ 0x5c ] = KEY_SAVE,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_behold);
index 67d1b1b1b25420245ca5e28de9e45cf4dd65e95b..f0703d8bc3e8d9492e47382330db3f021dbb93e8 100644 (file)
@@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_unmap(q, dma);
        videobuf_dma_free(dma);
-       buf->vb.state = STATE_NEEDS_INIT;
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 
@@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
                buf->activate(dev,buf,NULL);
        } else {
                list_add_tail(&buf->vb.queue,&q->queue);
-               buf->vb.state = STATE_QUEUED;
+               buf->vb.state = VIDEOBUF_QUEUED;
                DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
        }
        return 0;
@@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data)
        spin_lock_irqsave(&dev->slock,flags);
        if (q->curr) {
                DEB_D(("timeout on %p\n", q->curr));
-               saa7146_buffer_finish(dev,q,STATE_ERROR);
+               saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
        }
 
        /* we don't restart the transfer here like other drivers do. when
@@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
        }
 
        poll_wait(file, &buf->done, wait);
-       if (buf->state == STATE_DONE || buf->state == STATE_ERROR) {
+       if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
                DEB_D(("poll succeeded!\n"));
                return POLLIN|POLLRDNORM;
        }
@@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
        if (video_register_device(vfd, type, -1) < 0) {
                ERR(("cannot register v4l2 device. skipping.\n"));
+               video_device_release(vfd);
                return -1;
        }
 
index 6103484e4442bb4564809ddb33be6a3a838e2c2c..c32dda973e928db5ed4fe3d1cf865b4e1cf7f235 100644 (file)
@@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev,
                           struct saa7146_buf *next)
 {
        struct saa7146_vv *vv = dev->vv_data;
-       buf->vb.state = STATE_ACTIVE;
+       buf->vb.state = VIDEOBUF_ACTIVE;
 
        DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
        saa7146_set_vbi_capture(dev,buf,next);
@@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
        if (buf->vb.size != size)
                saa7146_dma_free(dev,q,buf);
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
                buf->vb.width  = llength;
@@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
                if (0 != err)
                        return err;
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
 
        return 0;
@@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
        saa7146_write(dev, MC1, MASK_20);
 
        if (vv->vbi_q.curr) {
-               saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
+               saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
        }
 
        videobuf_queue_cancel(&fh->vbi_q);
@@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
                /* this must be += 2, one count for each field */
                vv->vbi_fieldcount+=2;
                vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
-               saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
+               saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
        } else {
                DEB_VBI(("dev:%p\n",dev));
        }
index ae36d101006b6d0600898b76af319b95d90c1c31..c31ab480d8e1c8884bd8245dedcde72021a660aa 100644 (file)
@@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev,
 {
        struct saa7146_vv *vv = dev->vv_data;
 
-       buf->vb.state = STATE_ACTIVE;
+       buf->vb.state = VIDEOBUF_ACTIVE;
        saa7146_set_capture(dev,buf,next);
 
        mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
@@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                saa7146_dma_free(dev,q,buf);
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct saa7146_format *sfmt;
 
                buf->vb.bytesperline  = fh->video_fmt.bytesperline;
@@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                if (err)
                        goto oops;
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
 
        return 0;
@@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
 
        /* only finish the buffer if we have one... */
        if( NULL != q->curr ) {
-               saa7146_buffer_finish(dev,q,STATE_DONE);
+               saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
        }
        saa7146_buffer_next(dev,q,0);
 
index 29ec4183118e80f744aed424dc1d1715b1b9aeef..2ddafd071c9776ddf02946f6ce018f86504e1fa0 100644 (file)
@@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
 
        fc->write_ibi_reg(fc,ctrl_208,v208_save);
 }
-EXPORT_SYMBOL(flexcop_reset_block_300);
 
 struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
 {
index 85e36a1d6d782d4c8c4581014e9944c9ec9e43dc..c7bbb40223f5ba6ecfc3ad1cfbd8b242300faf54 100644 (file)
@@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
 
 EXPORT_SYMBOL(bt878_device_control);
 
+#define BROOKTREE_878_DEVICE(vend, dev, name) \
+       { \
+               .vendor = PCI_VENDOR_ID_BROOKTREE, \
+               .device = PCI_DEVICE_ID_BROOKTREE_878, \
+               .subvendor = (vend), .subdevice = (dev), \
+               .driver_data = (unsigned long) name \
+       }
 
-static struct cards card_list[] __devinitdata = {
-
-       { 0x01010071, BTTV_BOARD_NEBULA_DIGITV,                 "Nebula Electronics DigiTV" },
-       { 0x07611461, BTTV_BOARD_AVDVBT_761,                    "AverMedia AverTV DVB-T 761" },
-       { 0x001c11bd, BTTV_BOARD_PINNACLESAT,                   "Pinnacle PCTV Sat" },
-       { 0x002611bd, BTTV_BOARD_TWINHAN_DST,                   "Pinnacle PCTV SAT CI" },
-       { 0x00011822, BTTV_BOARD_TWINHAN_DST,                   "Twinhan VisionPlus DVB" },
-       { 0xfc00270f, BTTV_BOARD_TWINHAN_DST,                   "ChainTech digitop DST-1000 DVB-S" },
-       { 0x07711461, BTTV_BOARD_AVDVBT_771,                    "AVermedia AverTV DVB-T 771" },
-       { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,               "DViCO FusionHDTV DVB-T Lite" },
-       { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,               "Ultraview DVB-T Lite" },
-       { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,       "DViCO FusionHDTV 5 Lite" },
-       { 0x20007063, BTTV_BOARD_PC_HDTV,                       "pcHDTV HD-2000 TV" },
-       { 0x00261822, BTTV_BOARD_TWINHAN_DST,                   "DNTV Live! Mini" }
+static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
+       BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
+       BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
+       BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
+       BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
+       BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
+       BROOKTREE_878_DEVICE(0x270f, 0xfc00,
+                               "ChainTech digitop DST-1000 DVB-S"),
+       BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
+       BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
+       BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
+       BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
+       BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
+       BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
+       { }
 };
 
+MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
+
+static const char * __devinit card_name(const struct pci_device_id *id)
+{
+       return id->driver_data ? (const char *)id->driver_data : "Unknown";
+}
 
 /***********************/
 /* PCI device handling */
@@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = {
 static int __devinit bt878_probe(struct pci_dev *dev,
                                 const struct pci_device_id *pci_id)
 {
-       int result = 0, has_dvb = 0, i;
+       int result = 0;
        unsigned char lat;
        struct bt878 *bt;
 #if defined(__powerpc__)
        unsigned int cmd;
 #endif
        unsigned int cardid;
-       unsigned short id;
-       struct cards *dvb_cards;
 
        printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
               bt878_num);
@@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
        if (pci_enable_device(dev))
                return -EIO;
 
-       pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id);
-       cardid = id << 16;
-       pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id);
-       cardid |= id;
-
-       for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) {
-               if (cardid == dvb_cards->pci_id) {
-                       printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n",
-                               __func__, cardid, dvb_cards->name);
-                       has_dvb = 1;
-               }
-       }
+       cardid = dev->subsystem_device << 16;
+       cardid |= dev->subsystem_vendor;
 
-       if (!has_dvb) {
-               printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid);
-               result = -EINVAL;
-
-               goto fail0;
-       }
+       printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
+                               __func__, cardid, card_name(pci_id));
 
        bt = &bt878[bt878_num];
        bt->dev = dev;
@@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
        return;
 }
 
-static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
-       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
-
 static struct pci_driver bt878_pci_driver = {
       .name    = "bt878",
       .id_table = bt878_pci_tbl,
index d593bc145628e3f0311875132dea279900a47f8d..375fd2892a11098bd01ec2253436e4a53affabfc 100644 (file)
 #define BTTV_BOARD_DVICO_DVBT_LITE         0x80
 #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
 
-struct cards {
-       __u32 pci_id;
-       __u16 card_id;
-       char  *name;
-};
-
 extern int bt878_num;
 
 struct bt878 {
index b7a17e69ca4dd796bab6ea615540f41232972f48..307ff35bdf13a6226e6413c104ae7279d176f50d 100644 (file)
@@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
        }                                                               \
 } while(0)
 
+static int dst_command(struct dst_state *state, u8 *data, u8 len);
 
 static void dst_packsize(struct dst_state *state, int psize)
 {
@@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize)
        bt878_device_control(state->bt, DST_IG_TS, &bits);
 }
 
-int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay)
+static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
+                        u32 outhigh, int delay)
 {
        union dst_gpio_packet enb;
        union dst_gpio_packet bits;
@@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int
 
        return 0;
 }
-EXPORT_SYMBOL(dst_gpio_outb);
 
-int dst_gpio_inb(struct dst_state *state, u8 *result)
+static int dst_gpio_inb(struct dst_state *state, u8 *result)
 {
        union dst_gpio_packet rd_packet;
        int err;
@@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
 
        return 0;
 }
-EXPORT_SYMBOL(dst_gpio_inb);
 
 int rdc_reset_state(struct dst_state *state)
 {
@@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state)
 }
 EXPORT_SYMBOL(rdc_reset_state);
 
-int rdc_8820_reset(struct dst_state *state)
+static int rdc_8820_reset(struct dst_state *state)
 {
        dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
        if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
@@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state)
 
        return 0;
 }
-EXPORT_SYMBOL(rdc_8820_reset);
 
-int dst_pio_enable(struct dst_state *state)
+static int dst_pio_enable(struct dst_state *state)
 {
        if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
                dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
@@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state)
 
        return 0;
 }
-EXPORT_SYMBOL(dst_pio_enable);
 
 int dst_pio_disable(struct dst_state *state)
 {
@@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type)
        return 0;
 }
 
-struct tuner_types tuner_list[] = {
+static struct tuner_types tuner_list[] = {
        {
                .tuner_type = TUNER_TYPE_L64724,
                .tuner_name = "L 64724",
@@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state)
        return 0;
 }
 
-int dst_command(struct dst_state *state, u8 *data, u8 len)
+static int dst_command(struct dst_state *state, u8 *data, u8 len)
 {
        u8 reply;
 
@@ -1287,7 +1285,6 @@ error:
        return -EIO;
 
 }
-EXPORT_SYMBOL(dst_command);
 
 static int dst_get_signal(struct dst_state *state)
 {
index 87623d203a89ab70546576276a6db8e8f56a71cf..d88cf2add82b6b20010b6b1c92c7f8d6d139b784 100644 (file)
@@ -165,10 +165,8 @@ struct dst_config
 };
 
 int rdc_reset_state(struct dst_state *state);
-int rdc_8820_reset(struct dst_state *state);
 
 int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
-int dst_pio_enable(struct dst_state *state);
 int dst_pio_disable(struct dst_state *state);
 int dst_error_recovery(struct dst_state* state);
 int dst_error_bailout(struct dst_state *state);
@@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len);
 u8 dst_check_sum(u8 * buf, u32 len);
 struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
 struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
-int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
-
-int dst_command(struct dst_state* state, u8 * data, u8 len);
 
 
 #endif // DST_COMMON_H
index 445f0266557754f739b5b406abf8f5e5f55a63a0..925cfa6221ad09d73e2831a6cadb2435a3747290 100644 (file)
@@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
                fe->ops.tuner_ops.release(fe);
                symbol_put_addr(fe->ops.tuner_ops.release);
        }
+       if (fe->ops.analog_ops.release) {
+               fe->ops.analog_ops.release(fe);
+               symbol_put_addr(fe->ops.analog_ops.release);
+       }
        ptr = (void*)fe->ops.release;
        if (ptr) {
                fe->ops.release(fe);
@@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
                fe->ops.release_sec(fe);
        if (fe->ops.tuner_ops.release)
                fe->ops.tuner_ops.release(fe);
+       if (fe->ops.analog_ops.release)
+               fe->ops.analog_ops.release(fe);
        if (fe->ops.release)
                fe->ops.release(fe);
 }
index a5262e852c822bd0d280cb0d52100a9d5cd22c3d..aa4133f0bd1911d093b4e386aba4ab0c965f6ba8 100644 (file)
@@ -84,6 +84,9 @@ struct dvb_tuner_ops {
        /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
        int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
 
+       /** This is to allow setting tuner-specific configs */
+       int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+
        int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
        int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
 
@@ -98,6 +101,28 @@ struct dvb_tuner_ops {
        int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
 };
 
+struct analog_demod_info {
+       char *name;
+};
+
+struct analog_demod_ops {
+
+       struct analog_demod_info info;
+
+       void (*set_params)(struct dvb_frontend *fe,
+                          struct analog_parameters *params);
+       int  (*has_signal)(struct dvb_frontend *fe);
+       int  (*is_stereo)(struct dvb_frontend *fe);
+       int  (*get_afc)(struct dvb_frontend *fe);
+       void (*tuner_status)(struct dvb_frontend *fe);
+       void (*standby)(struct dvb_frontend *fe);
+       void (*release)(struct dvb_frontend *fe);
+       int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
+
+       /** This is to allow setting tuner-specific configuration */
+       int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+};
+
 struct dvb_frontend_ops {
 
        struct dvb_frontend_info info;
@@ -143,6 +168,7 @@ struct dvb_frontend_ops {
        int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
 
        struct dvb_tuner_ops tuner_ops;
+       struct analog_demod_ops analog_ops;
 };
 
 #define MAX_EVENT 8
@@ -159,18 +185,19 @@ struct dvb_fe_events {
 struct dvb_frontend {
        struct dvb_frontend_ops ops;
        struct dvb_adapter *dvb;
-       void* demodulator_priv;
-       void* tuner_priv;
-       void* frontend_priv;
-       void* sec_priv;
+       void *demodulator_priv;
+       void *tuner_priv;
+       void *frontend_priv;
+       void *sec_priv;
+       void *analog_demod_priv;
 };
 
-extern int dvb_register_frontend(struct dvb_adapterdvb,
-                                struct dvb_frontendfe);
+extern int dvb_register_frontend(struct dvb_adapter *dvb,
+                                struct dvb_frontend *fe);
 
-extern int dvb_unregister_frontend(struct dvb_frontendfe);
+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
 
-extern void dvb_frontend_detach(struct dvb_frontendfe);
+extern void dvb_frontend_detach(struct dvb_frontend *fe);
 
 extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
 
index 9878183ba3f0d8cc751cfbd968b3c7c9aa5d5d3b..ac9d93cf83c6c898d48a6dd17622ce40e6d42094 100644 (file)
@@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init);
 EXPORT_SYMBOL(dvb_ringbuffer_empty);
 EXPORT_SYMBOL(dvb_ringbuffer_free);
 EXPORT_SYMBOL(dvb_ringbuffer_avail);
-EXPORT_SYMBOL(dvb_ringbuffer_flush);
 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
index 7db6eee50e39f04978ad1272348156490b5534a8..e7f76f515b4f6bbe293832596daf20c78dc0d0b4 100644 (file)
@@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
 static struct usb_device_id af9005_usb_table[] = {
        {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
        {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+       {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
        {0},
 };
 
@@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = {
        .rc_key_map_size = 0,
        .rc_query = af9005_rc_query,
 
-       .num_device_descs = 2,
+       .num_device_descs = 3,
        .devices = {
                    {.name = "Afatech DVB-T USB1.1 stick",
                     .cold_ids = {&af9005_usb_table[0], NULL},
@@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = {
                     .cold_ids = {&af9005_usb_table[1], NULL},
                     .warm_ids = {NULL},
                     },
+                   {.name = "Ansonic DVB-T USB1.1 stick",
+                    .cold_ids = {&af9005_usb_table[2], NULL},
+                    .warm_ids = {NULL},
+                    },
                    {NULL},
                    }
 };
index 18e0b16fb2a9ce012109809c0ae8bc15545f9e94..f3ff8131469607422e2599b88492521bac9e3f78 100644 (file)
@@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i;
 
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-               return -EAGAIN;
-
        if (num > 2)
                return -EINVAL;
 
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
        for (i = 0; i < num; i++) {
                /* write/read request */
                if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
index 04e31cf7d53030613aaab9269c4a29ee5232c26d..c58365005ac1cb32e0f7739918f6e3b3f8a37a97 100644 (file)
@@ -15,7 +15,7 @@
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
  * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
- * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
+ * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
  *
  *   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
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "zl10353.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
 
 /* debug */
-int dvb_usb_cxusb_debug;
+static int dvb_usb_cxusb_debug;
 module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
+                               dprintk(dvb_usb_cxusb_debug,0x01,args)
 
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
                          u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
@@ -46,11 +51,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
        sndbuf[0] = cmd;
        memcpy(&sndbuf[1], wbuf, wlen);
        if (wo)
-               dvb_usb_generic_write(d, sndbuf, 1+wlen);
+               return dvb_usb_generic_write(d, sndbuf, 1+wlen);
        else
-               dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
-
-       return 0;
+               return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
 }
 
 /* GPIO */
@@ -72,6 +75,34 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
        st->gpio_write_state[GPIO_TUNER] = onoff;
 }
 
+static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
+                                u8 newval)
+{
+       u8 o[2], gpio_state;
+       int rc;
+
+       o[0] = 0xff & ~changemask;      /* mask of bits to keep */
+       o[1] = newval & changemask;     /* new values for bits  */
+
+       rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
+       if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
+               deb_info("bluebird_gpio_write failed.\n");
+
+       return rc < 0 ? rc : gpio_state;
+}
+
+static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
+{
+       cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
+       msleep(5);
+       cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
+}
+
+static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
+{
+       cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
+}
+
 /* I2C */
 static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                          int num)
@@ -82,9 +113,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
 
-       if (num > 2)
-               warn("more than two i2c messages at a time is not handled yet. TODO.");
-
        for (i = 0; i < num; i++) {
 
                if (d->udev->descriptor.idVendor == USB_VID_MEDION)
@@ -97,8 +125,22 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                break;
                        }
 
-               /* read request */
-               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+               if (msg[i].flags & I2C_M_RD) {
+                       /* read only */
+                       u8 obuf[3], ibuf[1+msg[i].len];
+                       obuf[0] = 0;
+                       obuf[1] = msg[i].len;
+                       obuf[2] = msg[i].addr;
+                       if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+                                          obuf, 3,
+                                          ibuf, 1+msg[i].len) < 0) {
+                               warn("i2c read failed");
+                               break;
+                       }
+                       memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+               } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
+                          msg[i].addr == msg[i+1].addr) {
+                       /* write to then read from same address */
                        u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
                        obuf[0] = msg[i].len;
                        obuf[1] = msg[i+1].len;
@@ -116,7 +158,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
 
                        i++;
-               } else { /* write */
+               } else {
+                       /* write only */
                        u8 obuf[2+msg[i].len], ibuf;
                        obuf[0] = msg[i].addr;
                        obuf[1] = msg[i].len;
@@ -131,7 +174,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        }
 
        mutex_unlock(&d->i2c_mutex);
-       return i;
+       return i == num ? num : -EREMOTEIO;
 }
 
 static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
@@ -162,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
                return 0;
 }
 
+static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       int rc = 0;
+
+       rc = cxusb_power_ctrl(d, onoff);
+       if (!onoff)
+               cxusb_nano2_led(d, 0);
+
+       return rc;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        u8 buf[2] = { 0x03, 0x00 };
@@ -197,6 +251,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        return 0;
 }
 
+static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
+                                   int *state)
+{
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       u8 ircode[4];
+       int i;
+       struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+                              .buf = ircode, .len = 4 };
+
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
+               return 0;
+
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (keymap[i].custom == ircode[1] &&
+                   keymap[i].data == ircode[2]) {
+                       *event = keymap[i].event;
+                       *state = REMOTE_KEY_PRESSED;
+
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
 static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
        { 0xfe, 0x02, KEY_TV },
        { 0xfe, 0x0e, KEY_MP3 },
@@ -351,6 +433,20 @@ static struct mt352_config cxusb_mt352_config = {
        .demod_init    = cxusb_mt352_demod_init,
 };
 
+static struct zl10353_config cxusb_zl10353_xc3028_config = {
+       .demod_address = 0x0f,
+       .if2 = 45600,
+       .no_tuner = 1,
+       .parallel_ts = 1,
+};
+
+static struct mt352_config cxusb_mt352_xc3028_config = {
+       .demod_address = 0x0f,
+       .if2 = 4560,
+       .no_tuner = 1,
+       .demod_init = cxusb_mt352_demod_init,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -386,6 +482,51 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
+{
+       struct dvb_usb_device *d = ptr;
+
+       switch (command) {
+       case XC2028_TUNER_RESET:
+               deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+               cxusb_bluebird_gpio_pulse(d, 0x01, 1);
+               break;
+       case XC2028_RESET_CLK:
+               deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+               break;
+       default:
+               deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__,
+                        command, arg);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_frontend      *fe;
+       struct xc2028_config      cfg = {
+               .i2c_adap  = &adap->dev->i2c_adap,
+               .i2c_addr  = 0x61,
+               .video_dev = adap->dev,
+               .callback  = dvico_bluebird_xc2028_callback,
+       };
+       static struct xc2028_ctrl ctl = {
+               .fname       = "xc3028-dvico-au-01.fw",
+               .max_len     = 64,
+               .scode_table = ZARLINK456,
+       };
+
+       fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
+       if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
+               return -EIO;
+
+       fe->ops.tuner_ops.set_config(fe, &ctl);
+
+       return 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
        u8 b;
@@ -447,27 +588,120 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
        return -EIO;
 }
 
+static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       u8 ircode[4];
+       int i;
+       struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+                              .buf = ircode, .len = 4 };
+
+       if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       /* reset the tuner and demodulator */
+       cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+       cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+       cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+       if ((adap->fe = dvb_attach(zl10353_attach,
+                                  &cxusb_zl10353_xc3028_config,
+                                  &adap->dev->i2c_adap)) == NULL)
+               return -EIO;
+
+       /* try to determine if there is no IR decoder on the I2C bus */
+       for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+               msleep(20);
+               if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
+                       goto no_IR;
+               if (ircode[0] == 0 && ircode[1] == 0)
+                       continue;
+               if (ircode[2] + ircode[3] != 0xff) {
+no_IR:
+                       adap->dev->props.rc_key_map = NULL;
+                       info("No IR receiver detected on this device.");
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       /* reset the tuner and demodulator */
+       cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+       cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+       cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+       if ((adap->fe = dvb_attach(zl10353_attach,
+                                  &cxusb_zl10353_xc3028_config,
+                                  &adap->dev->i2c_adap)) != NULL)
+               return 0;
+
+       if ((adap->fe = dvb_attach(mt352_attach,
+                                  &cxusb_mt352_xc3028_config,
+                                  &adap->dev->i2c_adap)) != NULL)
+               return 0;
+
+       return -EIO;
+}
+
+/*
+ * DViCO has shipped two devices with the same USB ID, but only one of them
+ * needs a firmware download.  Check the device class details to see if they
+ * have non-default values to decide whether the device is actually cold or
+ * not, and forget a match if it turns out we selected the wrong device.
+ */
+static int bluebird_fx2_identify_state(struct usb_device *udev,
+                                      struct dvb_usb_device_properties *props,
+                                      struct dvb_usb_device_description **desc,
+                                      int *cold)
+{
+       int wascold = *cold;
+
+       *cold = udev->descriptor.bDeviceClass == 0xff &&
+               udev->descriptor.bDeviceSubClass == 0xff &&
+               udev->descriptor.bDeviceProtocol == 0xff;
+
+       if (*cold && !wascold)
+               *desc = NULL;
+
+       return 0;
+}
+
 /*
  * DViCO bluebird firmware needs the "warm" product ID to be patched into the
  * firmware file before download.
  */
 
-#define BLUEBIRD_01_ID_OFFSET 6638
+static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
 static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
                                                  const struct firmware *fw)
 {
-       if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
-               return -EINVAL;
+       int pos;
+
+       for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
+               int idoff = dvico_firmware_id_offsets[pos];
 
-       if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
-           fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+               if (fw->size < idoff + 4)
+                       continue;
 
-               fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
-                       le16_to_cpu(udev->descriptor.idProduct) + 1;
-               fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
-                       le16_to_cpu(udev->descriptor.idProduct) >> 8;
+               if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
+                   fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
+                       fw->data[idoff + 2] =
+                               le16_to_cpu(udev->descriptor.idProduct) + 1;
+                       fw->data[idoff + 3] =
+                               le16_to_cpu(udev->descriptor.idProduct) >> 8;
 
-               return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
+                       return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
+               }
        }
 
        return -EINVAL;
@@ -479,6 +713,9 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
@@ -487,7 +724,10 @@ static int cxusb_probe(struct usb_interface *intf,
                dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
                dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
                dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
-               dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) {
+               dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) {
                return 0;
        }
 
@@ -508,6 +748,9 @@ static struct usb_device_id cxusb_table [] = {
        { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
        { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
        { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
        {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -766,6 +1009,151 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
        }
 };
 
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl         = CYPRESS_FX2,
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_dualdig4_frontend_attach,
+                       .tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
+               },
+       },
+
+       .power_ctrl       = cxusb_power_ctrl,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .rc_interval      = 100,
+       .rc_key_map       = dvico_mce_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+       .rc_query         = cxusb_bluebird2_rc_query,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV DVB-T Dual Digital 4",
+                       { NULL },
+                       { &cxusb_table[13], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl         = CYPRESS_FX2,
+       .identify_state   = bluebird_fx2_identify_state,
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_nano2_frontend_attach,
+                       .tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
+               },
+       },
+
+       .power_ctrl       = cxusb_nano2_power_ctrl,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .rc_interval      = 100,
+       .rc_key_map       = dvico_portable_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+       .rc_query         = cxusb_bluebird2_rc_query,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV DVB-T NANO2",
+                       { NULL },
+                       { &cxusb_table[14], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl          = DEVICE_SPECIFIC,
+       .firmware          = "dvb-usb-bluebird-02.fw",
+       .download_firmware = bluebird_patch_dvico_firmware_download,
+       .identify_state    = bluebird_fx2_identify_state,
+
+       .size_of_priv      = sizeof(struct cxusb_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_nano2_frontend_attach,
+                       .tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
+               },
+       },
+
+       .power_ctrl       = cxusb_nano2_power_ctrl,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .rc_interval      = 100,
+       .rc_key_map       = dvico_portable_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+       .rc_query         = cxusb_rc_query,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
+                       { &cxusb_table[14], NULL },
+                       { &cxusb_table[15], NULL },
+               },
+       }
+};
+
 static struct usb_driver cxusb_driver = {
        .name           = "dvb_usb_cxusb",
        .probe          = cxusb_probe,
index c8ef77554b00a1cbff09faedd858ef898317a170..4768a2c355172b9be95a7e07dd0b2f0dfa6861c7 100644 (file)
@@ -4,12 +4,9 @@
 #define DVB_USB_LOG_PREFIX "cxusb"
 #include "dvb-usb.h"
 
-extern int dvb_usb_cxusb_debug;
-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
-#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
-                               dprintk(dvb_usb_cxusb_debug,0x01,args)
-
 /* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_BLUEBIRD_GPIO_RW 0x05
+
 #define CMD_I2C_WRITE     0x08
 #define CMD_I2C_READ      0x09
 
index 3ea294eb96bdedc4a7b6e12dfa3af42143cedb6c..c9857d5c69829e68bbc9e82af68026ebc4d4288c 100644 (file)
@@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        u8 b[4];
 
        b[0] = REQUEST_ENABLE_VIDEO;
-       b[1] = 0x00;
+       b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
        b[2] = (0x01 << 4); /* Master mode */
        b[3] = 0x00;
 
@@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
        b[2] |= st->channel_state;
 
-       if (st->channel_state) /* if at least one channel is active */
-               b[1] = (0x01 << 4) | 0x00;
-
        deb_info("data for streaming: %x %x\n",b[1],b[2]);
 
        return dib0700_ctrl_wr(adap->dev, b, 4);
index 58452b52002c7f9535e37f341f4ea18cd65bc637..e7093826e975896f31153621f08edf7aef219bf7 100644 (file)
@@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
                (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
 }
 
+static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
+{
+       struct i2c_msg msg[2] = {
+               { .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
+               { .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
+       };
+       if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
+       return 0;
+}
+
 static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       struct dib0700_state *st = adap->dev->priv;
+       struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
        struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
-       return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
-               st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
+       s8 a;
+       int if1=1220;
+       if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
+               adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) {
+               if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
+       }
+       return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
+               if1) == NULL ? -ENODEV : 0;
 }
 
 /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
@@ -230,6 +246,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = {
        }
 };
 
+static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       if (adap->id == 0) {
+               dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+               msleep(10);
+               dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+               dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+               dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+               dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+               msleep(10);
+               dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+               msleep(10);
+               dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
+       }
+
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+                               &stk7700d_dib7000p_mt2266_config[adap->id]);
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
 static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
 {
        if (adap->id == 0) {
@@ -415,6 +452,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
        { 0x1e, 0x38, KEY_YELLOW },
        { 0x1e, 0x3b, KEY_GOTO },
        { 0x1e, 0x3d, KEY_POWER },
+
+       /* Key codes for the Leadtek Winfast DTV Dongle */
+       { 0x00, 0x42, KEY_POWER },
+       { 0x07, 0x7c, KEY_TUNER },
+       { 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
+       { 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
+       { 0x0f, 0x71, KEY_DOT }, /* frequency */
+       { 0x07, 0x43, KEY_0 },
+       { 0x0c, 0x41, KEY_1 },
+       { 0x04, 0x43, KEY_2 },
+       { 0x0b, 0x7f, KEY_3 },
+       { 0x0e, 0x41, KEY_4 },
+       { 0x06, 0x43, KEY_5 },
+       { 0x09, 0x7f, KEY_6 },
+       { 0x0d, 0x7e, KEY_7 },
+       { 0x05, 0x7c, KEY_8 },
+       { 0x0a, 0x40, KEY_9 },
+       { 0x0e, 0x4e, KEY_CLEAR },
+       { 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
+       { 0x0f, 0x41, KEY_LAST }, /* recall */
+       { 0x03, 0x42, KEY_MUTE },
+       { 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
+       { 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
+       { 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+       { 0x0b, 0x70, KEY_RECORD },
+       { 0x03, 0x7d, KEY_VOLUMEUP },
+       { 0x01, 0x7d, KEY_VOLUMEDOWN },
+       { 0x02, 0x42, KEY_CHANNELUP },
+       { 0x00, 0x7d, KEY_CHANNELDOWN },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -578,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = {
 
 static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 {
+       struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
        struct dib0700_state *st = adap->dev->priv;
        struct i2c_adapter *tun_i2c;
-
+       s8 a;
+       int if1=1220;
+       if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
+               adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) {
+               if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
+       }
        if (st->is_dib7000pc)
                tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
        else
                tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 
        return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
-               st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
+               if1) == NULL ? -ENODEV : 0;
 }
 
 /* DIB7070 generic */
@@ -709,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
        .agc_config_count = 1,
        .agc = &dib7070_agc_config,
        .bw  = &dib7070_bw_config_12_mhz,
+       .tuner_is_baseband = 1,
+       .spur_protect = 1,
 
        .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
        .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -748,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
                .agc_config_count = 1,
                .agc = &dib7070_agc_config,
                .bw  = &dib7070_bw_config_12_mhz,
+               .tuner_is_baseband = 1,
+               .spur_protect = 1,
 
                .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
                .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -760,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
                .agc_config_count = 1,
                .agc = &dib7070_agc_config,
                .bw  = &dib7070_bw_config_12_mhz,
+               .tuner_is_baseband = 1,
+               .spur_protect = 1,
 
                .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
                .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -821,6 +899,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
                { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
                { USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
 /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+               { USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
+               { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
+               { USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
+               { USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
+/* 25 */       { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
+               { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
                { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -862,7 +946,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 7,
+               .num_device_descs = 8,
                .devices = {
                        {   "DiBcom STK7700P reference design",
                                { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -891,6 +975,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        {   "AVerMedia AVerTV DVB-T Express",
                                { &dib0700_usb_id_table[20] },
                                { NULL },
+                       },
+                       {   "Gigabyte U7000",
+                               { &dib0700_usb_id_table[21], NULL },
+                               { NULL },
                        }
                },
 
@@ -961,7 +1049,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        {   "DiBcom STK7700D reference design",
                                { &dib0700_usb_id_table[14], NULL },
                                { NULL },
-                       },
+                       }
                },
 
                .rc_interval      = DEFAULT_RC_INTERVAL,
@@ -969,6 +1057,25 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
                .rc_query         = dib0700_rc_query
 
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .frontend_attach  = stk7700P2_frontend_attach,
+                               .tuner_attach     = stk7700d_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "ASUS My Cinema U3000 Mini DVBT Tuner",
+                               { &dib0700_usb_id_table[23], NULL },
+                               { NULL },
+                       },
+               }
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -983,7 +1090,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 2,
+               .num_device_descs = 6,
                .devices = {
                        {   "DiBcom STK7070P reference design",
                                { &dib0700_usb_id_table[15], NULL },
@@ -993,7 +1100,29 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[16], NULL },
                                { NULL },
                        },
-               }
+                       {   "Artec T14BR DVB-T",
+                               { &dib0700_usb_id_table[22], NULL },
+                               { NULL },
+                       },
+                       {   "ASUS My Cinema U3100 Mini DVBT Tuner",
+                               { &dib0700_usb_id_table[24], NULL },
+                               { NULL },
+                       },
+                       {   "Hauppauge Nova-T Stick",
+                               { &dib0700_usb_id_table[25], NULL },
+                               { NULL },
+                       },
+                       {   "Hauppauge Nova-T MyTV.t",
+                               { &dib0700_usb_id_table[26], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = dib0700_rc_keys,
+               .rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+               .rc_query         = dib0700_rc_query
+
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 2,
@@ -1024,7 +1153,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        {   "Pinnacle PCTV Dual DVB-T Diversity Stick",
                                { &dib0700_usb_id_table[18], NULL },
                                { NULL },
-                       },
+                       }
                }
        },
 };
index bca1e09057395898478182fcc4cd4a909009f11a..3acbda4aa27e1e550cb548e4f2972c050c8d4ada 100644 (file)
 #include "nxt6000.h"
 
 /* debug */
-int dvb_usb_digitv_debug;
+static int dvb_usb_digitv_debug;
 module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
 static int digitv_ctrl_msg(struct dvb_usb_device *d,
                u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
index 8b43e3db869171f8b0ea78569383d8aaf76a9242..908c09f4966b89b8923569b35a5a2cbc3b8a6727 100644 (file)
@@ -8,9 +8,6 @@ struct digitv_state {
     int is_nxt6000;
 };
 
-extern int dvb_usb_digitv_debug;
-#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
-
 /* protocol (from usblogging and the SDK:
  *
  * Always 7 bytes bulk message(s) for controlling
index 4fa3e895028a0596c7a792cb5e451aadceddc634..aa4844ef875e02798c6f761423a0f33d9aeffd79 100644 (file)
@@ -15,7 +15,9 @@
 #define USB_VID_ALCOR_MICRO                    0x058f
 #define USB_VID_ALINK                          0x05e3
 #define USB_VID_ANCHOR                         0x0547
+#define USB_VID_ANSONIC                                0x10b9
 #define USB_VID_ANUBIS_ELECTRONIC              0x10fd
+#define USB_VID_ASUS                           0x0b05
 #define USB_VID_AVERMEDIA                      0x07ca
 #define USB_VID_COMPRO                         0x185b
 #define USB_VID_COMPRO_UNK                     0x145f
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
 #define USB_VID_UNIWILL                                0x1584
 #define USB_VID_WIDEVIEW                       0x14aa
+/* dom : pour gigabyte u7000 */
+#define USB_VID_GIGABYTE                       0x1044
+
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_ADSTECH_USB2_WARM                      0xa334
 #define USB_PID_AFATECH_AF9005                         0x9020
 #define USB_VID_ALINK_DTU                              0xf170
+#define USB_PID_ANSONIC_DVBT_USB                       0x6000
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
@@ -69,6 +75,7 @@
 #define USB_PID_DIBCOM_STK7700P                                0x1e14
 #define USB_PID_DIBCOM_STK7700P_PC                     0x1e78
 #define USB_PID_DIBCOM_STK7700D                                0x1ef0
+#define USB_PID_DIBCOM_STK7700_U7000                   0x7001
 #define USB_PID_DIBCOM_STK7070P                                0x1ebc
 #define USB_PID_DIBCOM_STK7070PD                       0x1ebe
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
 #define USB_PID_ULTIMA_TVBOX_USB2_WARM                 0x810a
 #define USB_PID_ARTEC_T14_COLD                         0x810b
 #define USB_PID_ARTEC_T14_WARM                         0x810c
+#define USB_PID_ARTEC_T14BR                            0x810f
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD              0x8613
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM              0x1002
 #define USB_PID_UNK_HYPER_PALTEK_COLD                  0x005e
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2                 0x9950
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK                 0x7050
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2               0x7060
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3               0x7070
+#define USB_PID_HAUPPAUGE_MYTV_T                       0x7080
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK                        0x9580
 #define USB_PID_AVERMEDIA_EXPRESS                      0xb568
 #define USB_PID_AVERMEDIA_VOLAR                                0xa807
 #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM             0xdb51
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD             0xdb58
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM             0xdb59
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4                  0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2            0xdb70
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM   0xdb71
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD                0xdb54
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM                0xdb55
 #define USB_PID_MEDION_MD95700                         0x0932
 #define USB_PID_OPERA1_WARM                            0x3829
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD           0x0514
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM           0x0513
-
+/* dom pour gigabyte u7000 */
+#define USB_PID_GIGABYTE_U7000                         0x7001
+#define USB_PID_ASUS_U3000                             0x171f
+#define USB_PID_ASUS_U3100                             0x173f
 
 #endif
index f01d99c1c43c12ebef10a3729c1c5ff15b9a23ec..6b99d9f4d5b35846892f023998d903aafdc8caa5 100644 (file)
@@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i;
 
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-               return -EAGAIN;
-
        if (num > 2)
                return -EINVAL;
 
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
        for (i = 0; i < num; i++) {
                /* write/read request */
                if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
index 92147ee3e14ffe69a134f5bfea59df244a951c51..83e8535014c6d092fc08f5c91e0963f31408dca2 100644 (file)
@@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
        return 0;
 }
 
-int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
-{
-       u8 buf;
-       int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
-       /* Turn off 8psk power */
-       if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
-               return -EINVAL;
-       /* Turn On 8psk power */
-       if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
-               return -EINVAL;
-       /* load BCM4500 firmware */
-       if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-               if (gp8psk_load_bcm4500fw(d))
-                       return EINVAL;
-       return 0;
-}
 
 static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
index e83a57506cfa945b2f97d16fb8fc9808221f981d..e5cd8149c23dc3ea37bf6dcc5d2cea82ea97962e 100644 (file)
@@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
 extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
 extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
                             u16 index, u8 *b, int blen);
-extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
 
 #endif
index d7c04951ceab38a20cef7b548b21af912cc58157..21935bf7059ee34f976914d82aaf22cd88fadb5d 100644 (file)
@@ -10,7 +10,9 @@
 * see Documentation/dvb/README.dvb-usb for more information
 */
 
-#include "opera1.h"
+#define DVB_USB_LOG_PREFIX "opera"
+
+#include "dvb-usb.h"
 #include "stv0299.h"
 
 #define OPERA_READ_MSG 0
@@ -38,7 +40,7 @@ struct opera_rc_keys {
        u32 event;
 };
 
-int dvb_usb_opera1_debug;
+static int dvb_usb_opera1_debug;
 module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
 MODULE_PARM_DESC(debug,
                 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h
deleted file mode 100644 (file)
index 5317442..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _OPERA1_H_
-#define _OPERA1_H_
-
-#define DVB_USB_LOG_PREFIX "opera"
-#include "dvb-usb.h"
-
-extern int dvb_usb_opera1_debug;
-#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
-#endif
index 16533b31a82dd6a10c7b10fc672dd53eaf0e0f6a..e553c139ac44947abbc4ad010564ec4ec8bdcb6d 100644 (file)
@@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
        return ret;
 }
 
-int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
                             u16 index, u8 *b, int blen)
 {
        int ret;
@@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        return 0;
 }
 
-int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-       struct vp702x_device_state *st = d->priv;
-
-       if (st->power_state == 0 && onoff)
-               vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
-       else if (st->power_state == 1 && onoff == 0)
-               vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
-
-       st->power_state = onoff;
-
-       return 0;
-}
 
 static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 {
index 25a9dee4c824328fc6c27be4fd4730f1c2632efe..c2f97f96c21fc1feae79ac7caa455cb641d1e8f0 100644 (file)
@@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
 
 extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
 extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
 
 #endif
index 5bbd2d5192f0a4130cd47a28808b3ff94c707040..c172babf59bbf5d850c41dcb2eacd083887ce4ce 100644 (file)
 #include "vp7045.h"
 
 /* debug */
-int dvb_usb_vp7045_debug;
+static int dvb_usb_vp7045_debug;
 module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
 
 int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
 {
index 9ce21a20fa86cc5ea3155ff62fdbaf9a79c277b2..969688f8526750c8c9b8ea74d535ef1371885a49 100644 (file)
 #define DVB_USB_LOG_PREFIX "vp7045"
 #include "dvb-usb.h"
 
-extern int dvb_usb_vp7045_debug;
-#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
-
 /* vp7045 commands */
 
 /* Twinhan Vendor requests */
index 59b9ed1f1aec6b5f8769d17bc11389d195577e7f..9ad86ce4a4e5b783e0d8627e2b30b0f816ef8245 100644 (file)
@@ -316,6 +316,13 @@ config DVB_TDA827X
        help
          A DVB-T silicon tuner module. Say Y when you want to support this tuner.
 
+config DVB_TDA18271
+       tristate "NXP TDA18271 silicon tuner"
+       depends on I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_TUNER_QT1010
        tristate "Quantek QT1010 silicon tuner"
        depends on DVB_CORE && I2C
@@ -353,6 +360,15 @@ config DVB_TUNER_DIB0070
          This device is only used inside a SiP called togther with a
          demodulator for now.
 
+config DVB_TUNER_XC5000
+       tristate "Xceive XC5000 silicon tuner"
+       depends on I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A driver for the silicon tuner XC5000 from Xceive.
+         This device is only used inside a SiP called togther with a
+         demodulator for now.
+
 comment "Miscellaneous devices"
        depends on DVB_CORE
 
index 4b8ad1f132aa380a656940070b5a80e520cf3ff4..16bd107ebd32d83a2c64da419a367f0351e37820 100644 (file)
@@ -3,6 +3,9 @@
 #
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/video/
+
+tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -39,6 +42,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TDA827X) += tda827x.o
+obj-$(CONFIG_DVB_TDA18271) += tda18271.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
@@ -46,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
+obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
index 481eaa684157773ae7cff688bdf5d0becdbf83bc..fe895bf7b18fbc686a7d4114d2e506bbf3b9bbe6 100644 (file)
@@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] =
        0,
 };
 
-static void dib0070_wbd_calibration(struct dib0070_state *state)
+static void dib0070_wbd_calibration(struct dvb_frontend *fe)
 {
        u16 wbd_offs;
+       struct dib0070_state *state = fe->tuner_priv;
+
+       if (state->cfg->sleep)
+               state->cfg->sleep(fe, 0);
+
        dib0070_write_reg(state, 0x0f, 0x6d81);
        dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
        msleep(9);
@@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state)
        dib0070_write_reg(state, 0x20, 0);
        state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
        dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+
+       if (state->cfg->sleep)
+               state->cfg->sleep(fe, 1);
+
 }
 
 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
@@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
        if (dib0070_reset(state) != 0)
                goto free_mem;
 
-       dib0070_wbd_calibration(state);
+       dib0070_wbd_calibration(fe);
 
        printk(KERN_INFO "DiB0070: successfully identified\n");
        memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
index edae0be063f5819f73e63e6ffb238ddbba8961a4..fa851601e7d4af1baae5312cce3819380df2a523 100644 (file)
@@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
                                struct dvb_frontend_parameters *fep)
 {
        struct dib3000mc_state *state = fe->demodulator_priv;
+    int ret;
+
+       dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
 
        state->current_bandwidth = fep->u.ofdm.bandwidth;
        dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
@@ -700,7 +703,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
                fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
                fep->u.ofdm.constellation     == QAM_AUTO ||
                fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
-               int i = 100, found;
+               int i = 1000, found;
 
                dib3000mc_autosearch_start(fe, fep);
                do {
@@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
                dib3000mc_get_frontend(fe, fep);
        }
 
+    ret = dib3000mc_tune(fe, fep);
+
        /* make this a config parameter */
        dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-       return dib3000mc_tune(fe, fep);
+    return ret;
 }
 
 static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
index fb18441a8c57493eb05e99bdd673c8a74df4a8de..5f1375e30dfc25e3bff127b8bf6ebbf4ef2e420e 100644 (file)
@@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
                                struct dvb_frontend_parameters *fep)
 {
        struct dib7000m_state *state = fe->demodulator_priv;
-       int time;
+       int time, ret;
+
+    dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
 
        state->current_bandwidth = fep->u.ofdm.bandwidth;
        dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
@@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
                dib7000m_get_frontend(fe, fep);
        }
 
+       ret = dib7000m_tune(fe, fep);
+
        /* make this a config parameter */
        dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-       return dib7000m_tune(fe, fep);
+       return ret;
 }
 
 static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
index f45bcfc51cf8ba13ead921436b83b50f8b61e74f..47c23e29753e6dc20dd32ae2d550e8d832d7204c 100644 (file)
@@ -35,8 +35,8 @@ struct dib7000p_state {
 
        u16 wbd_ref;
 
-       u8 current_band;
-       fe_bandwidth_t current_bandwidth;
+       u8  current_band;
+       u32 current_bandwidth;
        struct dibx000_agc_config *current_agc;
        u32 timf;
 
@@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
 
        fep->inversion = INVERSION_AUTO;
 
-       fep->u.ofdm.bandwidth = state->current_bandwidth;
+       fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
 
        switch ((tps >> 8) & 0x3) {
                case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
@@ -1128,12 +1128,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
                                struct dvb_frontend_parameters *fep)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
-       int time;
+       int time, ret;
 
-       state->current_bandwidth = fep->u.ofdm.bandwidth;
-       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+       dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
 
-       /* maybe the parameter has been changed */
+    /* maybe the parameter has been changed */
        state->sfn_workaround_active = buggy_sfn_workaround;
 
        if (fe->ops.tuner_ops.set_params)
@@ -1166,10 +1165,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
                dib7000p_get_frontend(fe, fep);
        }
 
+       ret = dib7000p_tune(fe, fep);
+
        /* make this a config parameter */
        dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-       return dib7000p_tune(fe, fep);
+    return ret;
 }
 
 static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
index 5e17275afd256c732716c853164a2dcc29dd3c0c..84e4d536292221752d1629f3e79359ed06eda90e 100644 (file)
@@ -128,6 +128,11 @@ enum dibx000_adc_states {
                             (v) == BANDWIDTH_7_MHZ  ? 7000 : \
                             (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
 
+#define BANDWIDTH_TO_INDEX(v) ( \
+       (v) == 8000 ? BANDWIDTH_8_MHZ : \
+               (v) == 7000 ? BANDWIDTH_7_MHZ : \
+               (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
+
 /* Chip output mode. */
 #define OUTMODE_HIGH_Z              0
 #define OUTMODE_MPEG2_PAR_GATED_CLK 1
index 03fe8265745f34cb175cc8653e4f003f77b28379..54b18f94b14bc427511a69fd9a116d3197bc98bb 100644 (file)
@@ -38,8 +38,12 @@ struct mt2266_priv {
 
        u32 frequency;
        u32 bandwidth;
+       u8 band;
 };
 
+#define MT2266_VHF 1
+#define MT2266_UHF 0
+
 /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
 
 static int debug;
@@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
 }
 
 // Initialisation sequences
-static u8 mt2266_init1[] = {
-       REG_TUNE,
-       0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
+static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
+                                0x00, 0x52, 0x99, 0x3f };
 
 static u8 mt2266_init2[] = {
-       0x17,                                     0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
-       0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
-       0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
+    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
+    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
+    0xff, 0x00, 0x77, 0x0f, 0x2d
+};
+
+static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
+                                               0x22, 0x22, 0x22, 0x22 };
 
-static u8 mt2266_init_8mhz[] = {
-       REG_BANDWIDTH,
-       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
+static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
+                                               0x32, 0x32, 0x32, 0x32 };
 
-static u8 mt2266_init_7mhz[] = {
-       REG_BANDWIDTH,
-       0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
+                                               0xa7, 0xa7, 0xa7, 0xa7 };
 
-static u8 mt2266_init_6mhz[] = {
-       REG_BANDWIDTH,
-       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
+                          0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
+
+static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
+                          0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
 
 #define FREF 30000       // Quartz oscillator 30 MHz
 
@@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
        u8  lnaband;
        u8  b[10];
        int i;
+       u8 band;
 
        priv = fe->tuner_priv;
 
-       mt2266_writereg(priv,0x17,0x6d);
-       mt2266_writereg(priv,0x1c,0xff);
-
        freq = params->frequency / 1000; // Hz -> kHz
+       if (freq < 470000 && freq > 230000)
+               return -EINVAL; /* Gap between VHF and UHF bands */
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
        priv->frequency = freq * 1000;
-       tune=2 * freq * (8192/16) / (FREF/16);
-
-       if (freq <= 495000) lnaband = 0xEE; else
-       if (freq <= 525000) lnaband = 0xDD; else
-       if (freq <= 550000) lnaband = 0xCC; else
-       if (freq <= 580000) lnaband = 0xBB; else
-       if (freq <= 605000) lnaband = 0xAA; else
-       if (freq <= 630000) lnaband = 0x99; else
-       if (freq <= 655000) lnaband = 0x88; else
-       if (freq <= 685000) lnaband = 0x77; else
-       if (freq <= 710000) lnaband = 0x66; else
-       if (freq <= 735000) lnaband = 0x55; else
-       if (freq <= 765000) lnaband = 0x44; else
-       if (freq <= 802000) lnaband = 0x33; else
-       if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
-
-       msleep(100);
-       mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
-                               (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
-                               mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+       tune = 2 * freq * (8192/16) / (FREF/16);
+       band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
+       if (band == MT2266_VHF)
+               tune *= 2;
+
+       switch (params->u.ofdm.bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               mt2266_writeregs(priv, mt2266_init_6mhz,
+                                sizeof(mt2266_init_6mhz));
+               break;
+       case BANDWIDTH_7_MHZ:
+               mt2266_writeregs(priv, mt2266_init_7mhz,
+                                sizeof(mt2266_init_7mhz));
+               break;
+       case BANDWIDTH_8_MHZ:
+       default:
+               mt2266_writeregs(priv, mt2266_init_8mhz,
+                                sizeof(mt2266_init_8mhz));
+               break;
+       }
+
+       if (band == MT2266_VHF && priv->band == MT2266_UHF) {
+               dprintk("Switch from UHF to VHF");
+               mt2266_writereg(priv, 0x05, 0x04);
+               mt2266_writereg(priv, 0x19, 0x61);
+               mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
+       } else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
+               dprintk("Switch from VHF to UHF");
+               mt2266_writereg(priv, 0x05, 0x52);
+               mt2266_writereg(priv, 0x19, 0x61);
+               mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
+       }
+       msleep(10);
+
+       if (freq <= 495000)
+               lnaband = 0xEE;
+       else if (freq <= 525000)
+               lnaband = 0xDD;
+       else if (freq <= 550000)
+               lnaband = 0xCC;
+       else if (freq <= 580000)
+               lnaband = 0xBB;
+       else if (freq <= 605000)
+               lnaband = 0xAA;
+       else if (freq <= 630000)
+               lnaband = 0x99;
+       else if (freq <= 655000)
+               lnaband = 0x88;
+       else if (freq <= 685000)
+               lnaband = 0x77;
+       else if (freq <= 710000)
+               lnaband = 0x66;
+       else if (freq <= 735000)
+               lnaband = 0x55;
+       else if (freq <= 765000)
+               lnaband = 0x44;
+       else if (freq <= 802000)
+               lnaband = 0x33;
+       else if (freq <= 840000)
+               lnaband = 0x22;
+       else
+               lnaband = 0x11;
 
        b[0] = REG_TUNE;
        b[1] = (tune >> 8) & 0x1F;
@@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
        b[3] = tune >> 13;
        mt2266_writeregs(priv,b,4);
 
-       dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
-       dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
-
-       b[0] = 0x05;
-       b[1] = 0x62;
-       b[2] = lnaband;
-       mt2266_writeregs(priv,b,3);
+       dprintk("set_parms: tune=%d band=%d %s",
+               (int) tune, (int) lnaband,
+               (band == MT2266_UHF) ? "UHF" : "VHF");
+       dprintk("set_parms: [1..3]: %2x %2x %2x",
+               (int) b[1], (int) b[2], (int)b[3]);
+
+       if (band == MT2266_UHF) {
+               b[0] = 0x05;
+               b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
+               b[2] = lnaband;
+               mt2266_writeregs(priv, b, 3);
+       }
 
-       //Waits for pll lock or timeout
+       /* Wait for pll lock or timeout */
        i = 0;
        do {
                mt2266_readreg(priv,REG_LOCK,b);
-               if ((b[0] & 0x40)==0x40)
+               if (b[0] & 0x40)
                        break;
                msleep(10);
                i++;
        } while (i<10);
        dprintk("Lock when i=%i",(int)i);
+
+       if (band == MT2266_UHF && priv->band == MT2266_VHF)
+               mt2266_writereg(priv, 0x05, 0x62);
+
+       priv->band = band;
+
        return ret;
 }
 
 static void mt2266_calibrate(struct mt2266_priv *priv)
 {
-       mt2266_writereg(priv,0x11,0x03);
-       mt2266_writereg(priv,0x11,0x01);
-
-       mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
-       mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
-
-       mt2266_writereg(priv,0x33,0x5e);
-       mt2266_writereg(priv,0x10,0x10);
-       mt2266_writereg(priv,0x10,0x00);
-
-       mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
-
+       mt2266_writereg(priv, 0x11, 0x03);
+       mt2266_writereg(priv, 0x11, 0x01);
+       mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
+       mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
+       mt2266_writereg(priv, 0x33, 0x5e);
+       mt2266_writereg(priv, 0x10, 0x10);
+       mt2266_writereg(priv, 0x10, 0x00);
+       mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
        msleep(25);
-       mt2266_writereg(priv,0x17,0x6d);
-       mt2266_writereg(priv,0x1c,0x00);
+       mt2266_writereg(priv, 0x17, 0x6d);
+       mt2266_writereg(priv, 0x1c, 0x00);
        msleep(75);
-       mt2266_writereg(priv,0x17,0x6d);
-       mt2266_writereg(priv,0x1c,0xff);
+       mt2266_writereg(priv, 0x17, 0x6d);
+       mt2266_writereg(priv, 0x1c, 0xff);
 }
 
 static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
@@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 
 static int mt2266_init(struct dvb_frontend *fe)
 {
+       int ret;
        struct mt2266_priv *priv = fe->tuner_priv;
-       mt2266_writereg(priv,0x17,0x6d);
-       mt2266_writereg(priv,0x1c,0xff);
+       ret = mt2266_writereg(priv, 0x17, 0x6d);
+       if (ret < 0)
+               return ret;
+       ret = mt2266_writereg(priv, 0x1c, 0xff);
+       if (ret < 0)
+               return ret;
        return 0;
 }
 
 static int mt2266_sleep(struct dvb_frontend *fe)
 {
        struct mt2266_priv *priv = fe->tuner_priv;
-       mt2266_writereg(priv,0x17,0x6d);
-       mt2266_writereg(priv,0x1c,0x00);
+       mt2266_writereg(priv, 0x17, 0x6d);
+       mt2266_writereg(priv, 0x1c, 0x00);
        return 0;
 }
 
@@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe)
 static const struct dvb_tuner_ops mt2266_tuner_ops = {
        .info = {
                .name           = "Microtune MT2266",
-               .frequency_min  = 470000000,
-               .frequency_max  = 860000000,
+               .frequency_min  = 174000000,
+               .frequency_max  = 862000000,
                .frequency_step =     50000,
        },
        .release       = mt2266_release,
@@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter
 
        priv->cfg      = cfg;
        priv->i2c      = i2c;
+       priv->band     = MT2266_UHF;
 
-       if (mt2266_readreg(priv,0,&id) != 0) {
+       if (mt2266_readreg(priv, 0, &id)) {
                kfree(priv);
                return NULL;
        }
index 0606b9a5b616fff9558848c7aa5a2bc6e1e112b9..1638301fbd6e71268812f48beddc1cea1b0cb127 100644 (file)
@@ -37,9 +37,9 @@
 
 
 struct mt312_state {
-       struct i2c_adapteri2c;
+       struct i2c_adapter *i2c;
        /* configuration settings */
-       const struct mt312_configconfig;
+       const struct mt312_config *config;
        struct dvb_frontend frontend;
 
        u8 id;
@@ -49,14 +49,15 @@ struct mt312_state {
 static int debug;
 #define dprintk(args...) \
        do { \
-               if (debug) printk(KERN_DEBUG "mt312: " args); \
+               if (debug) \
+                       printk(KERN_DEBUG "mt312: " args); \
        } while (0)
 
 #define MT312_SYS_CLK          90000000UL      /* 90 MHz */
 #define MT312_LPOWER_SYS_CLK   60000000UL      /* 60 MHz */
 #define MT312_PLL_CLK          10000000UL      /* 10 MHz */
 
-static int mt312_read(struct mt312_statestate, const enum mt312_reg_addr reg,
+static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
                      void *buf, const size_t count)
 {
        int ret;
@@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
                return -EREMOTEIO;
        }
 
-       if(debug) {
+       if (debug) {
                int i;
                dprintk("R(%d):", reg & 0x7f);
                for (i = 0; i < count; i++)
@@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
        return 0;
 }
 
-static int mt312_write(struct mt312_statestate, const enum mt312_reg_addr reg,
+static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
                       const void *src, const size_t count)
 {
        int ret;
        u8 buf[count + 1];
        struct i2c_msg msg;
 
-       if(debug) {
+       if (debug) {
                int i;
                dprintk("W(%d):", reg & 0x7f);
                for (i = 0; i < count; i++)
@@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
        return 0;
 }
 
-static inline int mt312_readreg(struct mt312_statestate,
+static inline int mt312_readreg(struct mt312_state *state,
                                const enum mt312_reg_addr reg, u8 *val)
 {
        return mt312_read(state, reg, val, 1);
 }
 
-static inline int mt312_writereg(struct mt312_statestate,
+static inline int mt312_writereg(struct mt312_state *state,
                                 const enum mt312_reg_addr reg, const u8 val)
 {
        return mt312_write(state, reg, &val, 1);
@@ -140,18 +141,19 @@ static inline u32 mt312_div(u32 a, u32 b)
        return (a + (b / 2)) / b;
 }
 
-static int mt312_reset(struct mt312_statestate, const u8 full)
+static int mt312_reset(struct mt312_state *state, const u8 full)
 {
        return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
 }
 
-static int mt312_get_inversion(struct mt312_statestate,
+static int mt312_get_inversion(struct mt312_state *state,
                               fe_spectral_inversion_t *i)
 {
        int ret;
        u8 vit_mode;
 
-       if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
+       ret = mt312_readreg(state, VIT_MODE, &vit_mode);
+       if (ret < 0)
                return ret;
 
        if (vit_mode & 0x80)    /* auto inversion was used */
@@ -160,7 +162,7 @@ static int mt312_get_inversion(struct mt312_state* state,
        return 0;
 }
 
-static int mt312_get_symbol_rate(struct mt312_statestate, u32 *sr)
+static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
 {
        int ret;
        u8 sym_rate_h;
@@ -169,37 +171,44 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
        u16 monitor;
        u8 buf[2];
 
-       if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
+       ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
+       if (ret < 0)
                return ret;
 
-       if (sym_rate_h & 0x80) {        /* symbol rate search was used */
-               if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
+       if (sym_rate_h & 0x80) {
+               /* symbol rate search was used */
+               ret = mt312_writereg(state, MON_CTRL, 0x03);
+               if (ret < 0)
                        return ret;
 
-               if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+               ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+               if (ret < 0)
                        return ret;
 
                monitor = (buf[0] << 8) | buf[1];
 
-               dprintk(KERN_DEBUG "sr(auto) = %u\n",
+               dprintk("sr(auto) = %u\n",
                       mt312_div(monitor * 15625, 4));
        } else {
-               if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
+               ret = mt312_writereg(state, MON_CTRL, 0x05);
+               if (ret < 0)
                        return ret;
 
-               if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+               ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+               if (ret < 0)
                        return ret;
 
                dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
 
-               if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
+               ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
+               if (ret < 0)
                        return ret;
 
                sym_rat_op = (buf[0] << 8) | buf[1];
 
-               dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
+               dprintk("sym_rat_op=%d dec_ratio=%d\n",
                       sym_rat_op, dec_ratio);
-               dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
+               dprintk("*sr(manual) = %lu\n",
                       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
                        2) - dec_ratio);
        }
@@ -207,7 +216,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
        return 0;
 }
 
-static int mt312_get_code_rate(struct mt312_statestate, fe_code_rate_t *cr)
+static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
 {
        const fe_code_rate_t fec_tab[8] =
            { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
@@ -216,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
        int ret;
        u8 fec_status;
 
-       if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
+       ret = mt312_readreg(state, FEC_STATUS, &fec_status);
+       if (ret < 0)
                return ret;
 
        *cr = fec_tab[(fec_status >> 4) & 0x07];
@@ -224,61 +234,72 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
        return 0;
 }
 
-static int mt312_initfe(struct dvb_frontendfe)
+static int mt312_initfe(struct dvb_frontend *fe)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
        u8 buf[2];
 
        /* wake up */
-       if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
+       ret = mt312_writereg(state, CONFIG,
+                       (state->frequency == 60 ? 0x88 : 0x8c));
+       if (ret < 0)
                return ret;
 
        /* wait at least 150 usec */
        udelay(150);
 
        /* full reset */
-       if ((ret = mt312_reset(state, 1)) < 0)
+       ret = mt312_reset(state, 1);
+       if (ret < 0)
                return ret;
 
-// Per datasheet, write correct values. 09/28/03 ACCJr.
-// If we don't do this, we won't get FE_HAS_VITERBI in the VP310.
+/* Per datasheet, write correct values. 09/28/03 ACCJr.
+ * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
        {
-               u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
+               u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
+                                 0x01, 0x00, 0x00, 0x00 };
 
-               if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
+               ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
+               if (ret < 0)
                        return ret;
        }
 
        /* SYS_CLK */
-       buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
+       buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
+                               MT312_SYS_CLK) * 2, 1000000);
 
        /* DISEQC_RATIO */
        buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
 
-       if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
+       ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
+       if (ret < 0)
                return ret;
 
-       if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
+       ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
+       if (ret < 0)
                return ret;
 
-       if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
+       ret = mt312_writereg(state, OP_CTRL, 0x53);
+       if (ret < 0)
                return ret;
 
        /* TS_SW_LIM */
        buf[0] = 0x8c;
        buf[1] = 0x98;
 
-       if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
+       ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
+       if (ret < 0)
                return ret;
 
-       if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
+       ret = mt312_writereg(state, CS_SW_LIM, 0x69);
+       if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_send_master_cmd(struct dvb_frontendfe,
+static int mt312_send_master_cmd(struct dvb_frontend *fe,
                                 struct dvb_diseqc_master_cmd *c)
 {
        struct mt312_state *state = fe->demodulator_priv;
@@ -288,29 +309,31 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe,
        if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
                return -EINVAL;
 
-       if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+       ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+       if (ret < 0)
                return ret;
 
-       if ((ret =
-            mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
+       ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
+       if (ret < 0)
                return ret;
 
-       if ((ret =
-            mt312_writereg(state, DISEQC_MODE,
-                           (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
-                           | 0x04)) < 0)
+       ret = mt312_writereg(state, DISEQC_MODE,
+                            (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
+                            | 0x04);
+       if (ret < 0)
                return ret;
 
        /* set DISEQC_MODE[2:0] to zero if a return message is expected */
-       if (c->msg[0] & 0x02)
-               if ((ret =
-                    mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
+       if (c->msg[0] & 0x02) {
+               ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
+               if (ret < 0)
                        return ret;
+       }
 
        return 0;
 }
 
-static int mt312_send_burst(struct dvb_frontendfe, const fe_sec_mini_cmd_t c)
+static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
 {
        struct mt312_state *state = fe->demodulator_priv;
        const u8 mini_tab[2] = { 0x02, 0x03 };
@@ -321,18 +344,19 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
        if (c > SEC_MINI_B)
                return -EINVAL;
 
-       if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+       ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+       if (ret < 0)
                return ret;
 
-       if ((ret =
-            mt312_writereg(state, DISEQC_MODE,
-                           (diseqc_mode & 0x40) | mini_tab[c])) < 0)
+       ret = mt312_writereg(state, DISEQC_MODE,
+                            (diseqc_mode & 0x40) | mini_tab[c]);
+       if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_set_tone(struct dvb_frontendfe, const fe_sec_tone_mode_t t)
+static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
 {
        struct mt312_state *state = fe->demodulator_priv;
        const u8 tone_tab[2] = { 0x01, 0x00 };
@@ -343,18 +367,19 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
        if (t > SEC_TONE_OFF)
                return -EINVAL;
 
-       if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+       ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+       if (ret < 0)
                return ret;
 
-       if ((ret =
-            mt312_writereg(state, DISEQC_MODE,
-                           (diseqc_mode & 0x40) | tone_tab[t])) < 0)
+       ret = mt312_writereg(state, DISEQC_MODE,
+                            (diseqc_mode & 0x40) | tone_tab[t]);
+       if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_set_voltage(struct dvb_frontendfe, const fe_sec_voltage_t v)
+static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
 {
        struct mt312_state *state = fe->demodulator_priv;
        const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
@@ -365,7 +390,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
        return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
 }
 
-static int mt312_read_status(struct dvb_frontendfe, fe_status_t *s)
+static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
@@ -373,10 +398,12 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 
        *s = 0;
 
-       if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
+       ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
+       if (ret < 0)
                return ret;
 
-       dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
+       dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
+               " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
 
        if (status[0] & 0xc0)
                *s |= FE_HAS_SIGNAL;    /* signal noise ratio */
@@ -392,13 +419,14 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
        return 0;
 }
 
-static int mt312_read_ber(struct dvb_frontendfe, u32 *ber)
+static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
        u8 buf[3];
 
-       if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
+       ret = mt312_read(state, RS_BERCNT_H, buf, 3);
+       if (ret < 0)
                return ret;
 
        *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
@@ -406,7 +434,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
        return 0;
 }
 
-static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
+static int mt312_read_signal_strength(struct dvb_frontend *fe,
+                                     u16 *signal_strength)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
@@ -414,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
        u16 agc;
        s16 err_db;
 
-       if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
+       ret = mt312_read(state, AGC_H, buf, sizeof(buf));
+       if (ret < 0)
                return ret;
 
        agc = (buf[0] << 6) | (buf[1] >> 2);
@@ -422,18 +452,19 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
 
        *signal_strength = agc;
 
-       dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db);
+       dprintk("agc=%08x err_db=%hd\n", agc, err_db);
 
        return 0;
 }
 
-static int mt312_read_snr(struct dvb_frontendfe, u16 *snr)
+static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
        u8 buf[2];
 
-       if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
+       ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
+       if (ret < 0)
                return ret;
 
        *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
@@ -441,13 +472,14 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
        return 0;
 }
 
-static int mt312_read_ucblocks(struct dvb_frontendfe, u32 *ubc)
+static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
        u8 buf[2];
 
-       if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
+       ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
+       if (ret < 0)
                return ret;
 
        *ubc = (buf[0] << 8) | buf[1];
@@ -455,7 +487,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
        return 0;
 }
 
-static int mt312_set_frontend(struct dvb_frontendfe,
+static int mt312_set_frontend(struct dvb_frontend *fe,
                              struct dvb_frontend_parameters *p)
 {
        struct mt312_state *state = fe->demodulator_priv;
@@ -491,24 +523,28 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
        switch (state->id) {
        case ID_VP310:
-       // For now we will do this only for the VP310.
-       // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
+       /* For now we will do this only for the VP310.
+        * It should be better for the mt312 as well,
+        * but tuning will be slower. ACCJr 09/29/03
+        */
                ret = mt312_readreg(state, CONFIG, &config_val);
                if (ret < 0)
                        return ret;
-               if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
-               {
-                       if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
+               if (p->u.qpsk.symbol_rate >= 30000000) {
+                       /* Note that 30MS/s should use 90MHz */
+                       if ((config_val & 0x0c) == 0x08) {
+                               /* We are running 60MHz */
                                state->frequency = 90;
-                               if ((ret = mt312_initfe(fe)) < 0)
+                               ret = mt312_initfe(fe);
+                               if (ret < 0)
                                        return ret;
                        }
-               }
-               else
-               {
-                       if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
+               } else {
+                       if ((config_val & 0x0c) == 0x0C) {
+                               /* We are running 90MHz */
                                state->frequency = 60;
-                               if ((ret = mt312_initfe(fe)) < 0)
+                               ret = mt312_initfe(fe);
+                               if (ret < 0)
                                        return ret;
                        }
                }
@@ -523,7 +559,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
        if (fe->ops.tuner_ops.set_params) {
                fe->ops.tuner_ops.set_params(fe, p);
-               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        /* sr = (u16)(sr * 256.0 / 1000000.0) */
@@ -545,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
        /* GO */
        buf[4] = 0x01;
 
-       if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
+       ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
+       if (ret < 0)
                return ret;
 
        mt312_reset(state, 0);
@@ -553,27 +591,30 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int mt312_get_frontend(struct dvb_frontendfe,
+static int mt312_get_frontend(struct dvb_frontend *fe,
                              struct dvb_frontend_parameters *p)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
 
-       if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
+       ret = mt312_get_inversion(state, &p->inversion);
+       if (ret < 0)
                return ret;
 
-       if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
+       ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+       if (ret < 0)
                return ret;
 
-       if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
+       ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
+       if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_i2c_gate_ctrl(struct dvb_frontendfe, int enable)
+static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-       struct mt312_statestate = fe->demodulator_priv;
+       struct mt312_state *state = fe->demodulator_priv;
 
        if (enable) {
                return mt312_writereg(state, GPP_CTRL, 0x40);
@@ -582,27 +623,31 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
        }
 }
 
-static int mt312_sleep(struct dvb_frontendfe)
+static int mt312_sleep(struct dvb_frontend *fe)
 {
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
        u8 config;
 
        /* reset all registers to defaults */
-       if ((ret = mt312_reset(state, 1)) < 0)
+       ret = mt312_reset(state, 1);
+       if (ret < 0)
                return ret;
 
-       if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
+       ret = mt312_readreg(state, CONFIG, &config);
+       if (ret < 0)
                return ret;
 
        /* enter standby */
-       if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
+       ret = mt312_writereg(state, CONFIG, config & 0x7f);
+       if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int mt312_get_tune_settings(struct dvb_frontend *fe,
+               struct dvb_frontend_tune_settings *fesettings)
 {
        fesettings->min_delay_ms = 50;
        fesettings->step_size = 0;
@@ -610,9 +655,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_
        return 0;
 }
 
-static void mt312_release(struct dvb_frontendfe)
+static void mt312_release(struct dvb_frontend *fe)
 {
-       struct mt312_statestate = fe->demodulator_priv;
+       struct mt312_state *state = fe->demodulator_priv;
        kfree(state);
 }
 
@@ -655,10 +700,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
        .set_voltage = mt312_set_voltage,
 };
 
-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-                                       struct i2c_adapteri2c)
+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+                                       struct i2c_adapter *i2c)
 {
-       struct mt312_statestate = NULL;
+       struct mt312_state *state = NULL;
 
        /* allocate memory for the internal state */
        state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
@@ -674,7 +719,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
                goto error;
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+       memcpy(&state->frontend.ops, &vp310_mt312_ops,
+               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
        switch (state->id) {
@@ -687,7 +733,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
                state->frequency = 60;
                break;
        default:
-               printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n");
+               printk(KERN_WARNING "Only Zarlink VP310/MT312"
+                       " are supported chips.\n");
                goto error;
        }
 
@@ -697,6 +744,7 @@ error:
        kfree(state);
        return NULL;
 }
+EXPORT_SYMBOL(vp310_mt312_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -705,4 +753,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(vp310_mt312_attach);
index cf9a1505ad4bff097e5d5c17fdfff269396d7a86..f17cb93ba9ba068e8a486cd804176b3e96a02a1d 100644 (file)
 
 #include <linux/dvb/frontend.h>
 
-struct mt312_config
-{
+struct mt312_config {
        /* the demodulator's i2c address */
        u8 demod_address;
 };
 
 #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-                                       struct i2c_adapteri2c);
+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+                                       struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-                                       struct i2c_adapter* i2c)
+static inline struct dvb_frontend *vp310_mt312_attach(
+       const struct mt312_config *config, struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
        return NULL;
 }
-#endif // CONFIG_DVB_MT312
+#endif /* CONFIG_DVB_MT312 */
 
-#endif // MT312_H
+#endif /* MT312_H */
index 5dd9b731f6f29bdb10eee01122e2959613e4adde..7cd190b6f01573919e7939948b8f922e8f5622b2 100644 (file)
@@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state,
        if (state->config.if2)
                if2 = state->config.if2;
 
-       ife = (2*adc_clock - if2);
+       if (adc_clock >= if2 * 2)
+               ife = if2;
+       else {
+               ife = adc_clock - (if2 % adc_clock);
+               if (ife > adc_clock / 2)
+                       ife = adc_clock - ife;
+       }
        value = -16374 * ife / adc_clock;
        dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
                __FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);
index b314a1f2deed4ed12e16390aea097f039bcbd966..1d2d28ce823d4058a593cb7270a4cb4d277695a1 100644 (file)
@@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
        /* Allocate memory for the internal state */
        state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL);
        if (state == NULL)
-               goto error;
+               return NULL;
 
        /* Setup the state */
        state->config = config;
@@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
        memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
-
-error:
-       kfree(state);
-       return NULL;
 }
 
 static struct dvb_frontend_ops or51132_ops = {
index f02bd94459556a6874a5d23d83afb28a6bfebc87..6a6b0d727c6fc53ece47c2816086e8cf9025cf3f 100644 (file)
@@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
        /* Allocate memory for the internal state */
        state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
        if (state == NULL)
-               goto error;
+               return NULL;
 
        /* Setup the state */
        state->config = config;
@@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
        memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
-
-error:
-       kfree(state);
-       return NULL;
 }
 
 static struct dvb_frontend_ops or51211_ops = {
index 562d9208857ab25290c5f7fdd0f4b7c6b0e86380..819433485d3b27a3dda97c621419573d0cb1cf1f 100644 (file)
@@ -42,6 +42,7 @@ struct s5h1409_state {
        fe_modulation_t current_modulation;
 
        u32 current_frequency;
+       int if_freq;
 
        u32 is_qam_locked;
        u32 qam_state;
@@ -97,7 +98,7 @@ static struct init_tab {
        { 0xac, 0x1003, },
        { 0xad, 0x103f, },
        { 0xe2, 0x0100, },
-       { 0xe3, 0x0000, },
+       { 0xe3, 0x1000, },
        { 0x28, 0x1010, },
        { 0xb1, 0x000e, },
 };
@@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
        return 0;
 }
 
+#define S5H1409_VSB_IF_FREQ 5380
+#define S5H1409_QAM_IF_FREQ state->config->qam_if
+
 static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
 {
        struct s5h1409_state* state = fe->demodulator_priv;
-       int ret = 0;
 
        dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
 
-       if( (KHz == 44000) || (KHz == 5380) ) {
-               s5h1409_writereg(state, 0x87, 0x01be);
-               s5h1409_writereg(state, 0x88, 0x0436);
-               s5h1409_writereg(state, 0x89, 0x054d);
-       } else
-       if (KHz == 4000) {
+       switch (KHz) {
+       case 4000:
                s5h1409_writereg(state, 0x87, 0x014b);
                s5h1409_writereg(state, 0x88, 0x0cb5);
                s5h1409_writereg(state, 0x89, 0x03e2);
-       } else {
-               printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
-               ret = -1;
+               break;
+       case 5380:
+       case 44000:
+       default:
+               s5h1409_writereg(state, 0x87, 0x01be);
+               s5h1409_writereg(state, 0x88, 0x0436);
+               s5h1409_writereg(state, 0x89, 0x054d);
+               break;
        }
+       state->if_freq = KHz;
 
-       return ret;
+       return 0;
 }
 
 static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
@@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
        switch(m) {
        case VSB_8:
                dprintk("%s() VSB_8\n", __FUNCTION__);
+               if (state->if_freq != S5H1409_VSB_IF_FREQ)
+                       s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
                s5h1409_writereg(state, 0xf4, 0);
                break;
        case QAM_64:
        case QAM_256:
                dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
+               if (state->if_freq != S5H1409_QAM_IF_FREQ)
+                       s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
                s5h1409_writereg(state, 0xf4, 1);
                s5h1409_writereg(state, 0x85, 0x110);
                break;
@@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
        dprintk("%s(%d)\n", __FUNCTION__, enable);
 
        if (enable)
-               return s5h1409_writereg(state, 0xe3, 0x1100);
+               return s5h1409_writereg(state, 0xe3,
+                       s5h1409_readreg(state, 0xe3) | 0x1100);
        else
-               return s5h1409_writereg(state, 0xe3, 0x1000);
+               return s5h1409_writereg(state, 0xe3,
+                       s5h1409_readreg(state, 0xe3) & 0xeeff);
 }
 
 static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
@@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
                        s5h1409_writereg(state, 0x96, 0x20);
                        s5h1409_writereg(state, 0xad,
                                ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
-                       s5h1409_writereg(state, 0xab, 0x1100);
+                       s5h1409_writereg(state, 0xab,
+                               s5h1409_readreg(state, 0xab) & 0xeffe);
                }
        } else {
                if (state->qam_state != 1) {
                        state->qam_state = 1;
                        s5h1409_writereg(state, 0x96, 0x08);
-                       s5h1409_writereg(state, 0xab, 0x1101);
+                       s5h1409_writereg(state, 0xab,
+                               s5h1409_readreg(state, 0xab) | 0x1001);
                }
        }
 }
@@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
        return 0;
 }
 
+static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+       struct s5h1409_state *state = fe->demodulator_priv;
+       u16 val;
+
+       dprintk("%s(%d)\n", __FUNCTION__, mode);
+
+       val = s5h1409_readreg(state, 0xac) & 0xcfff;
+       switch (mode) {
+       case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+               val |= 0x0000;
+               break;
+       case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+               dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode);
+               val |= 0x1000;
+               break;
+       case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+               val |= 0x2000;
+               break;
+       case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+               val |= 0x3000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Configure MPEG Signal Timing charactistics */
+       return s5h1409_writereg(state, 0xac, val);
+}
+
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
 static int s5h1409_init (struct dvb_frontend* fe)
@@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe)
        state->current_modulation = VSB_8;
 
        if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
-               s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+               s5h1409_writereg(state, 0xab,
+                       s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
        else
-               s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+               s5h1409_writereg(state, 0xab,
+                       s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
 
        s5h1409_set_spectralinversion(fe, state->config->inversion);
-       s5h1409_set_if_freq(fe, state->config->if_freq);
+       s5h1409_set_if_freq(fe, state->if_freq);
        s5h1409_set_gpio(fe, state->config->gpio);
+       s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
        s5h1409_softreset(fe);
 
        /* Note: Leaving the I2C gate closed. */
@@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
                                    struct i2c_adapter* i2c)
 {
        struct s5h1409_state* state = NULL;
+       u16 reg;
 
        /* allocate memory for the internal state */
        state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
@@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
        state->config = config;
        state->i2c = i2c;
        state->current_modulation = 0;
+       state->if_freq = S5H1409_VSB_IF_FREQ;
 
        /* check if the demod exists */
-       if (s5h1409_readreg(state, 0x04) != 0x0066)
+       reg = s5h1409_readreg(state, 0x04);
+       if ((reg != 0x0066) && (reg != 0x007f))
                goto error;
 
        /* create dvb_frontend */
@@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       if (s5h1409_init(&state->frontend) != 0) {
+               printk(KERN_ERR "%s: Failed to initialize correctly\n",
+                       __FUNCTION__);
+               goto error;
+       }
+
        /* Note: Leaving the I2C gate open here. */
-       s5h1409_writereg(state, 0xf3, 1);
+       s5h1409_i2c_gate_ctrl(&state->frontend, 1);
 
        return &state->frontend;
 
index 20f9af1af445c2f49304ab6979aa28e7c5eb7894..f0bb13fe808b99053333be93699d7eefb74c118a 100644 (file)
@@ -39,8 +39,8 @@ struct s5h1409_config
 #define S5H1409_GPIO_ON  1
        u8 gpio;
 
-       /* IF Freq in KHz */
-       u16 if_freq;
+       /* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
+       u16 qam_if;
 
        /* Spectral Inversion */
 #define S5H1409_INVERSION_OFF 0
@@ -51,6 +51,13 @@ struct s5h1409_config
 #define S5H1409_TUNERLOCKING 0
 #define S5H1409_DEMODLOCKING 1
        u8 status_mode;
+
+       /* MPEG signal timing */
+#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+       u16 mpeg_timing;
 };
 
 #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
new file mode 100644 (file)
index 0000000..cebb6b9
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tda18271-priv.h"
+
+static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       enum tda18271_i2c_gate gate;
+       int ret = 0;
+
+       switch (priv->gate) {
+       case TDA18271_GATE_DIGITAL:
+       case TDA18271_GATE_ANALOG:
+               gate = priv->gate;
+               break;
+       case TDA18271_GATE_AUTO:
+       default:
+               switch (priv->mode) {
+               case TDA18271_DIGITAL:
+                       gate = TDA18271_GATE_DIGITAL;
+                       break;
+               case TDA18271_ANALOG:
+               default:
+                       gate = TDA18271_GATE_ANALOG;
+                       break;
+               }
+       }
+
+       switch (gate) {
+       case TDA18271_GATE_ANALOG:
+               if (fe->ops.analog_ops.i2c_gate_ctrl)
+                       ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
+               break;
+       case TDA18271_GATE_DIGITAL:
+               if (fe->ops.i2c_gate_ctrl)
+                       ret = fe->ops.i2c_gate_ctrl(fe, enable);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+};
+
+/*---------------------------------------------------------------------*/
+
+static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       tda_reg("=== TDA18271 REG DUMP ===\n");
+       tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
+       tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
+       tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
+       tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
+       tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
+       tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
+       tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
+       tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
+       tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
+       tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
+       tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
+       tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
+       tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
+       tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
+       tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
+       tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
+
+       /* only dump extended regs if DBG_ADV is set */
+       if (!(tda18271_debug & DBG_ADV))
+               return;
+
+       /* W indicates write-only registers.
+        * Register dump for write-only registers shows last value written. */
+
+       tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
+       tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
+       tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
+       tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
+       tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
+       tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
+       tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
+       tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
+       tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
+       tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
+       tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
+       tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
+       tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
+       tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
+       tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
+       tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
+       tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
+       tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
+       tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
+       tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
+       tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
+       tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
+       tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
+}
+
+int tda18271_read_regs(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       unsigned char buf = 0x00;
+       int ret;
+       struct i2c_msg msg[] = {
+               { .addr = priv->i2c_addr, .flags = 0,
+                 .buf = &buf, .len = 1 },
+               { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+                 .buf = regs, .len = 16 }
+       };
+
+       tda18271_i2c_gate_ctrl(fe, 1);
+
+       /* read all registers */
+       ret = i2c_transfer(priv->i2c_adap, msg, 2);
+
+       tda18271_i2c_gate_ctrl(fe, 0);
+
+       if (ret != 2)
+               tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+       if (tda18271_debug & DBG_REG)
+               tda18271_dump_regs(fe, 0);
+
+       return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_read_extended(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       unsigned char regdump[TDA18271_NUM_REGS];
+       unsigned char buf = 0x00;
+       int ret, i;
+       struct i2c_msg msg[] = {
+               { .addr = priv->i2c_addr, .flags = 0,
+                 .buf = &buf, .len = 1 },
+               { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+                 .buf = regdump, .len = TDA18271_NUM_REGS }
+       };
+
+       tda18271_i2c_gate_ctrl(fe, 1);
+
+       /* read all registers */
+       ret = i2c_transfer(priv->i2c_adap, msg, 2);
+
+       tda18271_i2c_gate_ctrl(fe, 0);
+
+       if (ret != 2)
+               tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+       for (i = 0; i <= TDA18271_NUM_REGS; i++) {
+               /* don't update write-only registers */
+               if ((i != R_EB9)  &&
+                   (i != R_EB16) &&
+                   (i != R_EB17) &&
+                   (i != R_EB19) &&
+                   (i != R_EB20))
+               regs[i] = regdump[i];
+       }
+
+       if (tda18271_debug & DBG_REG)
+               tda18271_dump_regs(fe, 1);
+
+       return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       unsigned char buf[TDA18271_NUM_REGS + 1];
+       struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+                              .buf = buf, .len = len + 1 };
+       int i, ret;
+
+       BUG_ON((len == 0) || (idx + len > sizeof(buf)));
+
+       buf[0] = idx;
+       for (i = 1; i <= len; i++)
+               buf[i] = regs[idx - 1 + i];
+
+       tda18271_i2c_gate_ctrl(fe, 1);
+
+       /* write registers */
+       ret = i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tda18271_i2c_gate_ctrl(fe, 0);
+
+       if (ret != 1)
+               tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+       return (ret == 1 ? 0 : ret);
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_init_regs(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       tda_dbg("initializing registers for device @ %d-%04x\n",
+               i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
+
+       /* initialize registers */
+       switch (priv->id) {
+       case TDA18271HDC1:
+               regs[R_ID]   = 0x83;
+               break;
+       case TDA18271HDC2:
+               regs[R_ID]   = 0x84;
+               break;
+       };
+
+       regs[R_TM]   = 0x08;
+       regs[R_PL]   = 0x80;
+       regs[R_EP1]  = 0xc6;
+       regs[R_EP2]  = 0xdf;
+       regs[R_EP3]  = 0x16;
+       regs[R_EP4]  = 0x60;
+       regs[R_EP5]  = 0x80;
+       regs[R_CPD]  = 0x80;
+       regs[R_CD1]  = 0x00;
+       regs[R_CD2]  = 0x00;
+       regs[R_CD3]  = 0x00;
+       regs[R_MPD]  = 0x00;
+       regs[R_MD1]  = 0x00;
+       regs[R_MD2]  = 0x00;
+       regs[R_MD3]  = 0x00;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               regs[R_EB1]  = 0xff;
+               break;
+       case TDA18271HDC2:
+               regs[R_EB1]  = 0xfc;
+               break;
+       };
+
+       regs[R_EB2]  = 0x01;
+       regs[R_EB3]  = 0x84;
+       regs[R_EB4]  = 0x41;
+       regs[R_EB5]  = 0x01;
+       regs[R_EB6]  = 0x84;
+       regs[R_EB7]  = 0x40;
+       regs[R_EB8]  = 0x07;
+       regs[R_EB9]  = 0x00;
+       regs[R_EB10] = 0x00;
+       regs[R_EB11] = 0x96;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               regs[R_EB12] = 0x0f;
+               break;
+       case TDA18271HDC2:
+               regs[R_EB12] = 0x33;
+               break;
+       };
+
+       regs[R_EB13] = 0xc1;
+       regs[R_EB14] = 0x00;
+       regs[R_EB15] = 0x8f;
+       regs[R_EB16] = 0x00;
+       regs[R_EB17] = 0x00;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               regs[R_EB18] = 0x00;
+               break;
+       case TDA18271HDC2:
+               regs[R_EB18] = 0x8c;
+               break;
+       };
+
+       regs[R_EB19] = 0x00;
+       regs[R_EB20] = 0x20;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               regs[R_EB21] = 0x33;
+               break;
+       case TDA18271HDC2:
+               regs[R_EB21] = 0xb3;
+               break;
+       };
+
+       regs[R_EB22] = 0x48;
+       regs[R_EB23] = 0xb0;
+
+       tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+
+       /* setup agc1 gain */
+       regs[R_EB17] = 0x00;
+       tda18271_write_regs(fe, R_EB17, 1);
+       regs[R_EB17] = 0x03;
+       tda18271_write_regs(fe, R_EB17, 1);
+       regs[R_EB17] = 0x43;
+       tda18271_write_regs(fe, R_EB17, 1);
+       regs[R_EB17] = 0x4c;
+       tda18271_write_regs(fe, R_EB17, 1);
+
+       /* setup agc2 gain */
+       if ((priv->id) == TDA18271HDC1) {
+               regs[R_EB20] = 0xa0;
+               tda18271_write_regs(fe, R_EB20, 1);
+               regs[R_EB20] = 0xa7;
+               tda18271_write_regs(fe, R_EB20, 1);
+               regs[R_EB20] = 0xe7;
+               tda18271_write_regs(fe, R_EB20, 1);
+               regs[R_EB20] = 0xec;
+               tda18271_write_regs(fe, R_EB20, 1);
+       }
+
+       /* image rejection calibration */
+
+       /* low-band */
+       regs[R_EP3] = 0x1f;
+       regs[R_EP4] = 0x66;
+       regs[R_EP5] = 0x81;
+       regs[R_CPD] = 0xcc;
+       regs[R_CD1] = 0x6c;
+       regs[R_CD2] = 0x00;
+       regs[R_CD3] = 0x00;
+       regs[R_MPD] = 0xcd;
+       regs[R_MD1] = 0x77;
+       regs[R_MD2] = 0x08;
+       regs[R_MD3] = 0x00;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               tda18271_write_regs(fe, R_EP3, 11);
+               break;
+       case TDA18271HDC2:
+               tda18271_write_regs(fe, R_EP3, 12);
+               break;
+       };
+
+       if ((priv->id) == TDA18271HDC2) {
+               /* main pll cp source on */
+               regs[R_EB4] = 0x61;
+               tda18271_write_regs(fe, R_EB4, 1);
+               msleep(1);
+
+               /* main pll cp source off */
+               regs[R_EB4] = 0x41;
+               tda18271_write_regs(fe, R_EB4, 1);
+       }
+
+       msleep(5); /* pll locking */
+
+       /* launch detector */
+       tda18271_write_regs(fe, R_EP1, 1);
+       msleep(5); /* wanted low measurement */
+
+       regs[R_EP5] = 0x85;
+       regs[R_CPD] = 0xcb;
+       regs[R_CD1] = 0x66;
+       regs[R_CD2] = 0x70;
+
+       tda18271_write_regs(fe, R_EP3, 7);
+       msleep(5); /* pll locking */
+
+       /* launch optimization algorithm */
+       tda18271_write_regs(fe, R_EP2, 1);
+       msleep(30); /* image low optimization completion */
+
+       /* mid-band */
+       regs[R_EP5] = 0x82;
+       regs[R_CPD] = 0xa8;
+       regs[R_CD2] = 0x00;
+       regs[R_MPD] = 0xa9;
+       regs[R_MD1] = 0x73;
+       regs[R_MD2] = 0x1a;
+
+       tda18271_write_regs(fe, R_EP3, 11);
+       msleep(5); /* pll locking */
+
+       tda18271_write_regs(fe, R_EP1, 1);
+       msleep(5); /* wanted mid measurement */
+
+       regs[R_EP5] = 0x86;
+       regs[R_CPD] = 0xa8;
+       regs[R_CD1] = 0x66;
+       regs[R_CD2] = 0xa0;
+
+       tda18271_write_regs(fe, R_EP3, 7);
+       msleep(5); /* pll locking */
+
+       /* launch optimization algorithm */
+       tda18271_write_regs(fe, R_EP2, 1);
+       msleep(30); /* image mid optimization completion */
+
+       /* high-band */
+       regs[R_EP5] = 0x83;
+       regs[R_CPD] = 0x98;
+       regs[R_CD1] = 0x65;
+       regs[R_CD2] = 0x00;
+       regs[R_MPD] = 0x99;
+       regs[R_MD1] = 0x71;
+       regs[R_MD2] = 0xcd;
+
+       tda18271_write_regs(fe, R_EP3, 11);
+       msleep(5); /* pll locking */
+
+       /* launch detector */
+       tda18271_write_regs(fe, R_EP1, 1);
+       msleep(5); /* wanted high measurement */
+
+       regs[R_EP5] = 0x87;
+       regs[R_CD1] = 0x65;
+       regs[R_CD2] = 0x50;
+
+       tda18271_write_regs(fe, R_EP3, 7);
+       msleep(5); /* pll locking */
+
+       /* launch optimization algorithm */
+       tda18271_write_regs(fe, R_EP2, 1);
+       msleep(30); /* image high optimization completion */
+
+       /* return to normal mode */
+       regs[R_EP4] = 0x64;
+       tda18271_write_regs(fe, R_EP4, 1);
+
+       /* synchronize */
+       tda18271_write_regs(fe, R_EP1, 1);
+
+       return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+/*
+ *  Standby modes, EP3 [7:5]
+ *
+ *  | SM  || SM_LT || SM_XT || mode description
+ *  |=====\\=======\\=======\\===================================
+ *  |  0  ||   0   ||   0   || normal mode
+ *  |-----||-------||-------||-----------------------------------
+ *  |     ||       ||       || standby mode w/ slave tuner output
+ *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   1   || power off
+ *
+ */
+
+int tda18271_set_standby_mode(struct dvb_frontend *fe,
+                             int sm, int sm_lt, int sm_xt)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+
+       regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
+       regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
+                       sm_lt ? (1 << 6) : 0 |
+                       sm_xt ? (1 << 5) : 0;
+
+       tda18271_write_regs(fe, R_EP3, 1);
+
+       return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
+{
+       /* sets main post divider & divider bytes, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 d, pd;
+       u32 div;
+
+       int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_MPD]   = (0x77 & pd);
+
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               regs[R_MPD]  &= ~0x08;
+               break;
+       case TDA18271_DIGITAL:
+               regs[R_MPD]  |=  0x08;
+               break;
+       }
+
+       div =  ((d * (freq / 1000)) << 7) / 125;
+
+       regs[R_MD1]   = 0x7f & (div >> 16);
+       regs[R_MD2]   = 0xff & (div >> 8);
+       regs[R_MD3]   = 0xff & div;
+fail:
+       return ret;
+}
+
+int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
+{
+       /* sets cal post divider & divider bytes, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 d, pd;
+       u32 div;
+
+       int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_CPD]   = pd;
+
+       div =  ((d * (freq / 1000)) << 7) / 125;
+
+       regs[R_CD1]   = 0x7f & (div >> 16);
+       regs[R_CD2]   = 0xff & (div >> 8);
+       regs[R_CD3]   = 0xff & div;
+fail:
+       return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
+{
+       /* sets bp filter bits, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 val;
+
+       int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
+       regs[R_EP1]  |= (0x07 & val);
+fail:
+       return ret;
+}
+
+int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
+{
+       /* sets K & M bits, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 val;
+
+       int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_EB13] &= ~0x7c; /* clear k & m bits */
+       regs[R_EB13] |= (0x7c & val);
+fail:
+       return ret;
+}
+
+int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
+{
+       /* sets rf band bits, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 val;
+
+       int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
+       regs[R_EP2]  |= (0xe0 & (val << 5));
+fail:
+       return ret;
+}
+
+int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
+{
+       /* sets gain taper bits, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 val;
+
+       int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
+       regs[R_EP2]  |= (0x1f & val);
+fail:
+       return ret;
+}
+
+int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
+{
+       /* sets IR Meas bits, but does not write them */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 val;
+
+       int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
+       if (ret < 0)
+               goto fail;
+
+       regs[R_EP5] &= ~0x07;
+       regs[R_EP5] |= (0x07 & val);
+fail:
+       return ret;
+}
+
+int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
+{
+       /* sets rf cal byte (RFC_Cprog), but does not write it */
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u8 val;
+
+       tda18271_lookup_map(fe, RF_CAL, freq, &val);
+
+       regs[R_EB14] = val;
+
+       return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c
new file mode 100644 (file)
index 0000000..dfe72aa
--- /dev/null
@@ -0,0 +1,1225 @@
+/*
+    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include "tda18271-priv.h"
+
+int tda18271_debug;
+module_param_named(debug, tda18271_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level "
+                "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
+
+static int tda18271_cal_on_startup;
+module_param_named(cal, tda18271_cal_on_startup, int, 0644);
+MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
+
+static LIST_HEAD(tda18271_list);
+static DEFINE_MUTEX(tda18271_list_mutex);
+
+/*---------------------------------------------------------------------*/
+
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       tda18271_read_regs(fe);
+
+       /* test IR_CAL_OK to see if we need init */
+       if ((regs[R_EP1] & 0x08) == 0)
+               tda18271_init_regs(fe);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_channel_configuration(struct dvb_frontend *fe,
+                                         u32 ifc, u32 freq, u32 bw, u8 std,
+                                         int radio)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u32 N;
+
+       /* update TV broadcast parameters */
+
+       /* set standard */
+       regs[R_EP3]  &= ~0x1f; /* clear std bits */
+       regs[R_EP3]  |= std;
+
+       /* set cal mode to normal */
+       regs[R_EP4]  &= ~0x03;
+
+       /* update IF output level & IF notch frequency */
+       regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+               break;
+       case TDA18271_DIGITAL:
+               regs[R_EP4]  |= 0x04; /* IF level = 1 */
+               regs[R_MPD]  |= 0x80; /* IF notch = 1 */
+               break;
+       }
+
+       if (radio)
+               regs[R_EP4]  |=  0x80;
+       else
+               regs[R_EP4]  &= ~0x80;
+
+       /* update RF_TOP / IF_TOP */
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               regs[R_EB22]  = 0x2c;
+               break;
+       case TDA18271_DIGITAL:
+               regs[R_EB22]  = 0x37;
+               break;
+       }
+       tda18271_write_regs(fe, R_EB22, 1);
+
+       /* --------------------------------------------------------------- */
+
+       /* disable Power Level Indicator */
+       regs[R_EP1]  |= 0x40;
+
+       /* frequency dependent parameters */
+
+       tda18271_calc_ir_measure(fe, &freq);
+
+       tda18271_calc_bp_filter(fe, &freq);
+
+       tda18271_calc_rf_band(fe, &freq);
+
+       tda18271_calc_gain_taper(fe, &freq);
+
+       /* --------------------------------------------------------------- */
+
+       /* dual tuner and agc1 extra configuration */
+
+       /* main vco when Master, cal vco when slave */
+       regs[R_EB1]  |= 0x04; /* FIXME: assumes master */
+
+       /* agc1 always active */
+       regs[R_EB1]  &= ~0x02;
+
+       /* agc1 has priority on agc2 */
+       regs[R_EB1]  &= ~0x01;
+
+       tda18271_write_regs(fe, R_EB1, 1);
+
+       /* --------------------------------------------------------------- */
+
+       N = freq + ifc;
+
+       /* FIXME: assumes master */
+       tda18271_calc_main_pll(fe, N);
+       tda18271_write_regs(fe, R_MPD, 4);
+
+       tda18271_write_regs(fe, R_TM, 7);
+
+       /* main pll charge pump source */
+       regs[R_EB4] |= 0x20;
+       tda18271_write_regs(fe, R_EB4, 1);
+
+       msleep(1);
+
+       /* normal operation for the main pll */
+       regs[R_EB4] &= ~0x20;
+       tda18271_write_regs(fe, R_EB4, 1);
+
+       msleep(5);
+
+       return 0;
+}
+
+static int tda18271_read_thermometer(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       int tm;
+
+       /* switch thermometer on */
+       regs[R_TM]   |= 0x10;
+       tda18271_write_regs(fe, R_TM, 1);
+
+       /* read thermometer info */
+       tda18271_read_regs(fe);
+
+       if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
+           (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
+
+               if ((regs[R_TM] & 0x20) == 0x20)
+                       regs[R_TM] &= ~0x20;
+               else
+                       regs[R_TM] |= 0x20;
+
+               tda18271_write_regs(fe, R_TM, 1);
+
+               msleep(10); /* temperature sensing */
+
+               /* read thermometer info */
+               tda18271_read_regs(fe);
+       }
+
+       tm = tda18271_lookup_thermometer(fe);
+
+       /* switch thermometer off */
+       regs[R_TM]   &= ~0x10;
+       tda18271_write_regs(fe, R_TM, 1);
+
+       /* set CAL mode to normal */
+       regs[R_EP4]  &= ~0x03;
+       tda18271_write_regs(fe, R_EP4, 1);
+
+       return tm;
+}
+
+static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
+                                                  u32 freq)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+       unsigned char *regs = priv->tda18271_regs;
+       int tm_current, rfcal_comp, approx, i;
+       u8 dc_over_dt, rf_tab;
+
+       /* power up */
+       tda18271_set_standby_mode(fe, 0, 0, 0);
+
+       /* read die current temperature */
+       tm_current = tda18271_read_thermometer(fe);
+
+       /* frequency dependent parameters */
+
+       tda18271_calc_rf_cal(fe, &freq);
+       rf_tab = regs[R_EB14];
+
+       i = tda18271_lookup_rf_band(fe, &freq, NULL);
+       if (i < 0)
+               return -EINVAL;
+
+       if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
+               approx = map[i].rf_a1 *
+                       (freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
+       } else {
+               approx = map[i].rf_a2 *
+                       (freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
+       }
+
+       if (approx < 0)
+               approx = 0;
+       if (approx > 255)
+               approx = 255;
+
+       tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
+
+       /* calculate temperature compensation */
+       rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
+
+       regs[R_EB14] = approx + rfcal_comp;
+       tda18271_write_regs(fe, R_EB14, 1);
+
+       return 0;
+}
+
+static int tda18271_por(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       /* power up detector 1 */
+       regs[R_EB12] &= ~0x20;
+       tda18271_write_regs(fe, R_EB12, 1);
+
+       regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
+       regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+       tda18271_write_regs(fe, R_EB18, 1);
+
+       regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
+
+       /* POR mode */
+       tda18271_set_standby_mode(fe, 1, 0, 0);
+
+       /* disable 1.5 MHz low pass filter */
+       regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
+       regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
+       tda18271_write_regs(fe, R_EB21, 3);
+
+       return 0;
+}
+
+static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u32 N;
+
+       /* set CAL mode to normal */
+       regs[R_EP4]  &= ~0x03;
+       tda18271_write_regs(fe, R_EP4, 1);
+
+       /* switch off agc1 */
+       regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
+
+       regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
+       tda18271_write_regs(fe, R_EB18, 1);
+
+       /* frequency dependent parameters */
+
+       tda18271_calc_bp_filter(fe, &freq);
+       tda18271_calc_gain_taper(fe, &freq);
+       tda18271_calc_rf_band(fe, &freq);
+       tda18271_calc_km(fe, &freq);
+
+       tda18271_write_regs(fe, R_EP1, 3);
+       tda18271_write_regs(fe, R_EB13, 1);
+
+       /* main pll charge pump source */
+       regs[R_EB4]  |= 0x20;
+       tda18271_write_regs(fe, R_EB4, 1);
+
+       /* cal pll charge pump source */
+       regs[R_EB7]  |= 0x20;
+       tda18271_write_regs(fe, R_EB7, 1);
+
+       /* force dcdc converter to 0 V */
+       regs[R_EB14] = 0x00;
+       tda18271_write_regs(fe, R_EB14, 1);
+
+       /* disable plls lock */
+       regs[R_EB20] &= ~0x20;
+       tda18271_write_regs(fe, R_EB20, 1);
+
+       /* set CAL mode to RF tracking filter calibration */
+       regs[R_EP4]  |= 0x03;
+       tda18271_write_regs(fe, R_EP4, 2);
+
+       /* --------------------------------------------------------------- */
+
+       /* set the internal calibration signal */
+       N = freq;
+
+       tda18271_calc_main_pll(fe, N);
+       tda18271_write_regs(fe, R_MPD, 4);
+
+       /* downconvert internal calibration */
+       N += 1000000;
+
+       tda18271_calc_main_pll(fe, N);
+       tda18271_write_regs(fe, R_MPD, 4);
+
+       msleep(5);
+
+       tda18271_write_regs(fe, R_EP2, 1);
+       tda18271_write_regs(fe, R_EP1, 1);
+       tda18271_write_regs(fe, R_EP2, 1);
+       tda18271_write_regs(fe, R_EP1, 1);
+
+       /* --------------------------------------------------------------- */
+
+       /* normal operation for the main pll */
+       regs[R_EB4] &= ~0x20;
+       tda18271_write_regs(fe, R_EB4, 1);
+
+       /* normal operation for the cal pll  */
+       regs[R_EB7] &= ~0x20;
+       tda18271_write_regs(fe, R_EB7, 1);
+
+       msleep(5); /* plls locking */
+
+       /* launch the rf tracking filters calibration */
+       regs[R_EB20]  |= 0x20;
+       tda18271_write_regs(fe, R_EB20, 1);
+
+       msleep(60); /* calibration */
+
+       /* --------------------------------------------------------------- */
+
+       /* set CAL mode to normal */
+       regs[R_EP4]  &= ~0x03;
+
+       /* switch on agc1 */
+       regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
+
+       regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+       tda18271_write_regs(fe, R_EB18, 1);
+
+       tda18271_write_regs(fe, R_EP3, 2);
+
+       /* synchronization */
+       tda18271_write_regs(fe, R_EP1, 1);
+
+       /* get calibration result */
+       tda18271_read_extended(fe);
+
+       return regs[R_EB14];
+}
+
+static int tda18271_powerscan(struct dvb_frontend *fe,
+                             u32 *freq_in, u32 *freq_out)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       int sgn, bcal, count, wait;
+       u8 cid_target;
+       u16 count_limit;
+       u32 freq;
+
+       freq = *freq_in;
+
+       tda18271_calc_rf_band(fe, &freq);
+       tda18271_calc_rf_cal(fe, &freq);
+       tda18271_calc_gain_taper(fe, &freq);
+       tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
+
+       tda18271_write_regs(fe, R_EP2, 1);
+       tda18271_write_regs(fe, R_EB14, 1);
+
+       /* downconvert frequency */
+       freq += 1000000;
+
+       tda18271_calc_main_pll(fe, freq);
+       tda18271_write_regs(fe, R_MPD, 4);
+
+       msleep(5); /* pll locking */
+
+       /* detection mode */
+       regs[R_EP4]  &= ~0x03;
+       regs[R_EP4]  |= 0x01;
+       tda18271_write_regs(fe, R_EP4, 1);
+
+       /* launch power detection measurement */
+       tda18271_write_regs(fe, R_EP2, 1);
+
+       /* read power detection info, stored in EB10 */
+       tda18271_read_extended(fe);
+
+       /* algorithm initialization */
+       sgn = 1;
+       *freq_out = *freq_in;
+       bcal = 0;
+       count = 0;
+       wait = false;
+
+       while ((regs[R_EB10] & 0x3f) < cid_target) {
+               /* downconvert updated freq to 1 MHz */
+               freq = *freq_in + (sgn * count) + 1000000;
+
+               tda18271_calc_main_pll(fe, freq);
+               tda18271_write_regs(fe, R_MPD, 4);
+
+               if (wait) {
+                       msleep(5); /* pll locking */
+                       wait = false;
+               } else
+                       udelay(100); /* pll locking */
+
+               /* launch power detection measurement */
+               tda18271_write_regs(fe, R_EP2, 1);
+
+               /* read power detection info, stored in EB10 */
+               tda18271_read_extended(fe);
+
+               count += 200;
+
+               if (count < count_limit)
+                       continue;
+
+               if (sgn <= 0)
+                       break;
+
+               sgn = -1 * sgn;
+               count = 200;
+               wait = true;
+       }
+
+       if ((regs[R_EB10] & 0x3f) >= cid_target) {
+               bcal = 1;
+               *freq_out = freq - 1000000;
+       } else
+               bcal = 0;
+
+       tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
+               bcal, *freq_in, *freq_out, freq);
+
+       return bcal;
+}
+
+static int tda18271_powerscan_init(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       /* set standard to digital */
+       regs[R_EP3]  &= ~0x1f; /* clear std bits */
+       regs[R_EP3]  |= 0x12;
+
+       /* set cal mode to normal */
+       regs[R_EP4]  &= ~0x03;
+
+       /* update IF output level & IF notch frequency */
+       regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+       tda18271_write_regs(fe, R_EP3, 2);
+
+       regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
+       tda18271_write_regs(fe, R_EB18, 1);
+
+       regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
+
+       /* 1.5 MHz low pass filter */
+       regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
+       regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
+
+       tda18271_write_regs(fe, R_EB21, 3);
+
+       return 0;
+}
+
+static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+       unsigned char *regs = priv->tda18271_regs;
+       int bcal, rf, i;
+#define RF1 0
+#define RF2 1
+#define RF3 2
+       u32 rf_default[3];
+       u32 rf_freq[3];
+       u8 prog_cal[3];
+       u8 prog_tab[3];
+
+       i = tda18271_lookup_rf_band(fe, &freq, NULL);
+
+       if (i < 0)
+               return i;
+
+       rf_default[RF1] = 1000 * map[i].rf1_def;
+       rf_default[RF2] = 1000 * map[i].rf2_def;
+       rf_default[RF3] = 1000 * map[i].rf3_def;
+
+       for (rf = RF1; rf <= RF3; rf++) {
+               if (0 == rf_default[rf])
+                       return 0;
+               tda_cal("freq = %d, rf = %d\n", freq, rf);
+
+               /* look for optimized calibration frequency */
+               bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
+
+               tda18271_calc_rf_cal(fe, &rf_freq[rf]);
+               prog_tab[rf] = regs[R_EB14];
+
+               if (1 == bcal)
+                       prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]);
+               else
+                       prog_cal[rf] = prog_tab[rf];
+
+               switch (rf) {
+               case RF1:
+                       map[i].rf_a1 = 0;
+                       map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
+                       map[i].rf1   = rf_freq[RF1] / 1000;
+                       break;
+               case RF2:
+                       map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
+                                       prog_cal[RF1] + prog_tab[RF1]) /
+                               ((rf_freq[RF2] - rf_freq[RF1]) / 1000);
+                       map[i].rf2   = rf_freq[RF2] / 1000;
+                       break;
+               case RF3:
+                       map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
+                                       prog_cal[RF2] + prog_tab[RF2]) /
+                               ((rf_freq[RF3] - rf_freq[RF2]) / 1000);
+                       map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
+                       map[i].rf3   = rf_freq[RF3] / 1000;
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       return 0;
+}
+
+static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned int i;
+
+       tda_info("tda18271: performing RF tracking filter calibration\n");
+
+       /* wait for die temperature stabilization */
+       msleep(200);
+
+       tda18271_powerscan_init(fe);
+
+       /* rf band calibration */
+       for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
+               tda18271_rf_tracking_filters_init(fe, 1000 *
+                                                 priv->rf_cal_state[i].rfmax);
+
+       priv->tm_rfcal = tda18271_read_thermometer(fe);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_rf_cal_init(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+
+       /* test RF_CAL_OK to see if we need init */
+       if ((regs[R_EP1] & 0x10) == 0)
+               priv->cal_initialized = false;
+
+       if (priv->cal_initialized)
+               return 0;
+
+       tda18271_calc_rf_filter_curve(fe);
+
+       tda18271_por(fe);
+
+       tda_info("tda18271: RF tracking filter calibration complete\n");
+
+       priv->cal_initialized = true;
+
+       return 0;
+}
+
+static int tda18271_init(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+
+       mutex_lock(&priv->lock);
+
+       /* power up */
+       tda18271_set_standby_mode(fe, 0, 0, 0);
+
+       /* initialization */
+       tda18271_ir_cal_init(fe);
+
+       if (priv->id == TDA18271HDC2)
+               tda18271_rf_cal_init(fe);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int tda18271c2_tune(struct dvb_frontend *fe,
+                          u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+
+       tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
+
+       tda18271_init(fe);
+
+       mutex_lock(&priv->lock);
+
+       tda18271_rf_tracking_filters_correction(fe, freq);
+
+       tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271c1_tune(struct dvb_frontend *fe,
+                          u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       u32 N = 0;
+
+       tda18271_init(fe);
+
+       mutex_lock(&priv->lock);
+
+       tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
+
+       /* RF tracking filter calibration */
+
+       /* calculate bp filter */
+       tda18271_calc_bp_filter(fe, &freq);
+       tda18271_write_regs(fe, R_EP1, 1);
+
+       regs[R_EB4]  &= 0x07;
+       regs[R_EB4]  |= 0x60;
+       tda18271_write_regs(fe, R_EB4, 1);
+
+       regs[R_EB7]   = 0x60;
+       tda18271_write_regs(fe, R_EB7, 1);
+
+       regs[R_EB14]  = 0x00;
+       tda18271_write_regs(fe, R_EB14, 1);
+
+       regs[R_EB20]  = 0xcc;
+       tda18271_write_regs(fe, R_EB20, 1);
+
+       /* set cal mode to RF tracking filter calibration */
+       regs[R_EP4]  |= 0x03;
+
+       /* calculate cal pll */
+
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               N = freq - 1250000;
+               break;
+       case TDA18271_DIGITAL:
+               N = freq + bw / 2;
+               break;
+       }
+
+       tda18271_calc_cal_pll(fe, N);
+
+       /* calculate main pll */
+
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               N = freq - 250000;
+               break;
+       case TDA18271_DIGITAL:
+               N = freq + bw / 2 + 1000000;
+               break;
+       }
+
+       tda18271_calc_main_pll(fe, N);
+
+       tda18271_write_regs(fe, R_EP3, 11);
+       msleep(5); /* RF tracking filter calibration initialization */
+
+       /* search for K,M,CO for RF calibration */
+       tda18271_calc_km(fe, &freq);
+       tda18271_write_regs(fe, R_EB13, 1);
+
+       /* search for rf band */
+       tda18271_calc_rf_band(fe, &freq);
+
+       /* search for gain taper */
+       tda18271_calc_gain_taper(fe, &freq);
+
+       tda18271_write_regs(fe, R_EP2, 1);
+       tda18271_write_regs(fe, R_EP1, 1);
+       tda18271_write_regs(fe, R_EP2, 1);
+       tda18271_write_regs(fe, R_EP1, 1);
+
+       regs[R_EB4]  &= 0x07;
+       regs[R_EB4]  |= 0x40;
+       tda18271_write_regs(fe, R_EB4, 1);
+
+       regs[R_EB7]   = 0x40;
+       tda18271_write_regs(fe, R_EB7, 1);
+       msleep(10);
+
+       regs[R_EB20]  = 0xec;
+       tda18271_write_regs(fe, R_EB20, 1);
+       msleep(60); /* RF tracking filter calibration completion */
+
+       regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+       tda18271_write_regs(fe, R_EP4, 1);
+
+       tda18271_write_regs(fe, R_EP1, 1);
+
+       /* RF tracking filter correction for VHF_Low band */
+       if (0 == tda18271_calc_rf_cal(fe, &freq))
+               tda18271_write_regs(fe, R_EB14, 1);
+
+       /* Channel Configuration */
+
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               regs[R_EB22]  = 0x2c;
+               break;
+       case TDA18271_DIGITAL:
+               regs[R_EB22]  = 0x37;
+               break;
+       }
+       tda18271_write_regs(fe, R_EB22, 1);
+
+       regs[R_EP1]  |= 0x40; /* set dis power level on */
+
+       /* set standard */
+       regs[R_EP3]  &= ~0x1f; /* clear std bits */
+
+       /* see table 22 */
+       regs[R_EP3]  |= std;
+
+       regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+
+       regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+       switch (priv->mode) {
+       case TDA18271_ANALOG:
+               regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+               break;
+       case TDA18271_DIGITAL:
+               regs[R_EP4]  |= 0x04;
+               regs[R_MPD]  |= 0x80;
+               break;
+       }
+
+       if (radio)
+               regs[R_EP4]  |=  0x80;
+       else
+               regs[R_EP4]  &= ~0x80;
+
+       /* image rejection validity */
+       tda18271_calc_ir_measure(fe, &freq);
+
+       /* calculate MAIN PLL */
+       N = freq + ifc;
+
+       tda18271_calc_main_pll(fe, N);
+
+       tda18271_write_regs(fe, R_TM, 15);
+       msleep(5);
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static inline int tda18271_tune(struct dvb_frontend *fe,
+                               u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       int ret = -EINVAL;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
+               break;
+       case TDA18271HDC2:
+               ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
+               break;
+       }
+       return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_set_params(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *params)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_std_map *std_map = &priv->std;
+       int ret;
+       u8 std;
+       u16 sgIF;
+       u32 bw, freq = params->frequency;
+
+       priv->mode = TDA18271_DIGITAL;
+
+       if (fe->ops.info.type == FE_ATSC) {
+               switch (params->u.vsb.modulation) {
+               case VSB_8:
+               case VSB_16:
+                       std  = std_map->atsc_6.std_bits;
+                       sgIF = std_map->atsc_6.if_freq;
+                       break;
+               case QAM_64:
+               case QAM_256:
+                       std  = std_map->qam_6.std_bits;
+                       sgIF = std_map->qam_6.if_freq;
+                       break;
+               default:
+                       tda_warn("modulation not set!\n");
+                       return -EINVAL;
+               }
+#if 0
+               /* userspace request is already center adjusted */
+               freq += 1750000; /* Adjust to center (+1.75MHZ) */
+#endif
+               bw = 6000000;
+       } else if (fe->ops.info.type == FE_OFDM) {
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       bw = 6000000;
+                       std  = std_map->dvbt_6.std_bits;
+                       sgIF = std_map->dvbt_6.if_freq;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       bw = 7000000;
+                       std  = std_map->dvbt_7.std_bits;
+                       sgIF = std_map->dvbt_7.if_freq;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       bw = 8000000;
+                       std  = std_map->dvbt_8.std_bits;
+                       sgIF = std_map->dvbt_8.if_freq;
+                       break;
+               default:
+                       tda_warn("bandwidth not set!\n");
+                       return -EINVAL;
+               }
+       } else {
+               tda_warn("modulation type not supported!\n");
+               return -EINVAL;
+       }
+
+       /* When tuning digital, the analog demod must be tri-stated */
+       if (fe->ops.analog_ops.standby)
+               fe->ops.analog_ops.standby(fe);
+
+       ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
+
+       if (ret < 0)
+               goto fail;
+
+       priv->frequency = freq;
+       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+               params->u.ofdm.bandwidth : 0;
+fail:
+       return ret;
+}
+
+static int tda18271_set_analog_params(struct dvb_frontend *fe,
+                                     struct analog_parameters *params)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_std_map *std_map = &priv->std;
+       char *mode;
+       int ret, radio = 0;
+       u8 std;
+       u16 sgIF;
+       u32 freq = params->frequency * 62500;
+
+       priv->mode = TDA18271_ANALOG;
+
+       if (params->mode == V4L2_TUNER_RADIO) {
+               radio = 1;
+               freq = freq / 1000;
+               std  = std_map->fm_radio.std_bits;
+               sgIF = std_map->fm_radio.if_freq;
+               mode = "fm";
+       } else if (params->std & V4L2_STD_MN) {
+               std  = std_map->atv_mn.std_bits;
+               sgIF = std_map->atv_mn.if_freq;
+               mode = "MN";
+       } else if (params->std & V4L2_STD_B) {
+               std  = std_map->atv_b.std_bits;
+               sgIF = std_map->atv_b.if_freq;
+               mode = "B";
+       } else if (params->std & V4L2_STD_GH) {
+               std  = std_map->atv_gh.std_bits;
+               sgIF = std_map->atv_gh.if_freq;
+               mode = "GH";
+       } else if (params->std & V4L2_STD_PAL_I) {
+               std  = std_map->atv_i.std_bits;
+               sgIF = std_map->atv_i.if_freq;
+               mode = "I";
+       } else if (params->std & V4L2_STD_DK) {
+               std  = std_map->atv_dk.std_bits;
+               sgIF = std_map->atv_dk.if_freq;
+               mode = "DK";
+       } else if (params->std & V4L2_STD_SECAM_L) {
+               std  = std_map->atv_l.std_bits;
+               sgIF = std_map->atv_l.if_freq;
+               mode = "L";
+       } else if (params->std & V4L2_STD_SECAM_LC) {
+               std  = std_map->atv_lc.std_bits;
+               sgIF = std_map->atv_lc.if_freq;
+               mode = "L'";
+       } else {
+               std  = std_map->atv_i.std_bits;
+               sgIF = std_map->atv_i.if_freq;
+               mode = "xx";
+       }
+
+       tda_dbg("setting tda18271 to system %s\n", mode);
+
+       ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
+
+       if (ret < 0)
+               goto fail;
+
+       priv->frequency = freq;
+       priv->bandwidth = 0;
+fail:
+       return ret;
+}
+
+static int tda18271_sleep(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+
+       mutex_lock(&priv->lock);
+
+       /* standby mode w/ slave tuner output
+        * & loop thru & xtal oscillator on */
+       tda18271_set_standby_mode(fe, 1, 0, 0);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int tda18271_release(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+
+       mutex_lock(&tda18271_list_mutex);
+
+       priv->count--;
+
+       if (!priv->count) {
+               tda_dbg("destroying instance @ %d-%04x\n",
+                       i2c_adapter_id(priv->i2c_adap),
+                       priv->i2c_addr);
+               list_del(&priv->tda18271_list);
+
+               kfree(priv);
+       }
+       mutex_unlock(&tda18271_list_mutex);
+
+       fe->tuner_priv = NULL;
+
+       return 0;
+}
+
+static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       *bandwidth = priv->bandwidth;
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+#define tda18271_update_std(std_cfg, name) do {                                \
+       if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) {         \
+               tda_dbg("Using custom std config for %s\n", name);      \
+               memcpy(&std->std_cfg, &map->std_cfg,                    \
+                       sizeof(struct tda18271_std_map_item));          \
+       } } while (0)
+
+#define tda18271_dump_std_item(std_cfg, name) do {                     \
+       tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n",               \
+               name, std->std_cfg.if_freq, std->std_cfg.std_bits);     \
+       } while (0)
+
+static int tda18271_dump_std_map(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_std_map *std = &priv->std;
+
+       tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
+       tda18271_dump_std_item(fm_radio, "fm");
+       tda18271_dump_std_item(atv_b,  "pal b");
+       tda18271_dump_std_item(atv_dk, "pal dk");
+       tda18271_dump_std_item(atv_gh, "pal gh");
+       tda18271_dump_std_item(atv_i,  "pal i");
+       tda18271_dump_std_item(atv_l,  "pal l");
+       tda18271_dump_std_item(atv_lc, "pal l'");
+       tda18271_dump_std_item(atv_mn, "atv mn");
+       tda18271_dump_std_item(atsc_6, "atsc 6");
+       tda18271_dump_std_item(dvbt_6, "dvbt 6");
+       tda18271_dump_std_item(dvbt_7, "dvbt 7");
+       tda18271_dump_std_item(dvbt_8, "dvbt 8");
+       tda18271_dump_std_item(qam_6,  "qam 6");
+       tda18271_dump_std_item(qam_8,  "qam 8");
+
+       return 0;
+}
+
+static int tda18271_update_std_map(struct dvb_frontend *fe,
+                                  struct tda18271_std_map *map)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_std_map *std = &priv->std;
+
+       if (!map)
+               return -EINVAL;
+
+       tda18271_update_std(fm_radio, "fm");
+       tda18271_update_std(atv_b,  "atv b");
+       tda18271_update_std(atv_dk, "atv dk");
+       tda18271_update_std(atv_gh, "atv gh");
+       tda18271_update_std(atv_i,  "atv i");
+       tda18271_update_std(atv_l,  "atv l");
+       tda18271_update_std(atv_lc, "atv l'");
+       tda18271_update_std(atv_mn, "atv mn");
+       tda18271_update_std(atsc_6, "atsc 6");
+       tda18271_update_std(dvbt_6, "dvbt 6");
+       tda18271_update_std(dvbt_7, "dvbt 7");
+       tda18271_update_std(dvbt_8, "dvbt 8");
+       tda18271_update_std(qam_6,  "qam 6");
+       tda18271_update_std(qam_8,  "qam 8");
+
+       return 0;
+}
+
+static int tda18271_get_id(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       char *name;
+       int ret = 0;
+
+       mutex_lock(&priv->lock);
+       tda18271_read_regs(fe);
+       mutex_unlock(&priv->lock);
+
+       switch (regs[R_ID] & 0x7f) {
+       case 3:
+               name = "TDA18271HD/C1";
+               priv->id = TDA18271HDC1;
+               break;
+       case 4:
+               name = "TDA18271HD/C2";
+               priv->id = TDA18271HDC2;
+               break;
+       default:
+               name = "Unknown device";
+               ret = -EINVAL;
+               break;
+       }
+
+       tda_info("%s detected @ %d-%04x%s\n", name,
+                i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
+                (0 == ret) ? "" : ", device not supported.");
+
+       return ret;
+}
+
+static struct dvb_tuner_ops tda18271_tuner_ops = {
+       .info = {
+               .name = "NXP TDA18271HD",
+               .frequency_min  =  45000000,
+               .frequency_max  = 864000000,
+               .frequency_step =     62500
+       },
+       .init              = tda18271_init,
+       .sleep             = tda18271_sleep,
+       .set_params        = tda18271_set_params,
+       .set_analog_params = tda18271_set_analog_params,
+       .release           = tda18271_release,
+       .get_frequency     = tda18271_get_frequency,
+       .get_bandwidth     = tda18271_get_bandwidth,
+};
+
+struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+                                    struct i2c_adapter *i2c,
+                                    struct tda18271_config *cfg)
+{
+       struct tda18271_priv *priv = NULL;
+       int state_found = 0;
+
+       mutex_lock(&tda18271_list_mutex);
+
+       list_for_each_entry(priv, &tda18271_list, tda18271_list) {
+               if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
+                   (priv->i2c_addr == addr)) {
+                       tda_dbg("attaching existing tuner @ %d-%04x\n",
+                               i2c_adapter_id(priv->i2c_adap),
+                               priv->i2c_addr);
+                       priv->count++;
+                       fe->tuner_priv = priv;
+                       state_found = 1;
+                       /* allow dvb driver to override i2c gate setting */
+                       if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+                               priv->gate = cfg->gate;
+                       break;
+               }
+       }
+       if (state_found == 0) {
+               tda_dbg("creating new tuner instance @ %d-%04x\n",
+                       i2c_adapter_id(i2c), addr);
+
+               priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
+               if (priv == NULL) {
+                       mutex_unlock(&tda18271_list_mutex);
+                       return NULL;
+               }
+
+               priv->i2c_addr = addr;
+               priv->i2c_adap = i2c;
+               priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+               priv->cal_initialized = false;
+               mutex_init(&priv->lock);
+               priv->count++;
+
+               fe->tuner_priv = priv;
+
+               list_add_tail(&priv->tda18271_list, &tda18271_list);
+
+               if (tda18271_get_id(fe) < 0)
+                       goto fail;
+
+               if (tda18271_assign_map_layout(fe) < 0)
+                       goto fail;
+
+               mutex_lock(&priv->lock);
+               tda18271_init_regs(fe);
+
+               if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
+                       tda18271_rf_cal_init(fe);
+
+               mutex_unlock(&priv->lock);
+       }
+
+       /* override default std map with values in config struct */
+       if ((cfg) && (cfg->std_map))
+               tda18271_update_std_map(fe, cfg->std_map);
+
+       mutex_unlock(&tda18271_list_mutex);
+
+       memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
+       if (tda18271_debug & DBG_MAP)
+               tda18271_dump_std_map(fe);
+
+       return fe;
+fail:
+       mutex_unlock(&tda18271_list_mutex);
+
+       tda18271_release(fe);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(tda18271_attach);
+MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h
new file mode 100644 (file)
index 0000000..7b939a5
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA18271_PRIV_H__
+#define __TDA18271_PRIV_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include "tda18271.h"
+
+#define R_ID     0x00  /* ID byte                */
+#define R_TM     0x01  /* Thermo byte            */
+#define R_PL     0x02  /* Power level byte       */
+#define R_EP1    0x03  /* Easy Prog byte 1       */
+#define R_EP2    0x04  /* Easy Prog byte 2       */
+#define R_EP3    0x05  /* Easy Prog byte 3       */
+#define R_EP4    0x06  /* Easy Prog byte 4       */
+#define R_EP5    0x07  /* Easy Prog byte 5       */
+#define R_CPD    0x08  /* Cal Post-Divider byte  */
+#define R_CD1    0x09  /* Cal Divider byte 1     */
+#define R_CD2    0x0a  /* Cal Divider byte 2     */
+#define R_CD3    0x0b  /* Cal Divider byte 3     */
+#define R_MPD    0x0c  /* Main Post-Divider byte */
+#define R_MD1    0x0d  /* Main Divider byte 1    */
+#define R_MD2    0x0e  /* Main Divider byte 2    */
+#define R_MD3    0x0f  /* Main Divider byte 3    */
+#define R_EB1    0x10  /* Extended byte 1        */
+#define R_EB2    0x11  /* Extended byte 2        */
+#define R_EB3    0x12  /* Extended byte 3        */
+#define R_EB4    0x13  /* Extended byte 4        */
+#define R_EB5    0x14  /* Extended byte 5        */
+#define R_EB6    0x15  /* Extended byte 6        */
+#define R_EB7    0x16  /* Extended byte 7        */
+#define R_EB8    0x17  /* Extended byte 8        */
+#define R_EB9    0x18  /* Extended byte 9        */
+#define R_EB10   0x19  /* Extended byte 10       */
+#define R_EB11   0x1a  /* Extended byte 11       */
+#define R_EB12   0x1b  /* Extended byte 12       */
+#define R_EB13   0x1c  /* Extended byte 13       */
+#define R_EB14   0x1d  /* Extended byte 14       */
+#define R_EB15   0x1e  /* Extended byte 15       */
+#define R_EB16   0x1f  /* Extended byte 16       */
+#define R_EB17   0x20  /* Extended byte 17       */
+#define R_EB18   0x21  /* Extended byte 18       */
+#define R_EB19   0x22  /* Extended byte 19       */
+#define R_EB20   0x23  /* Extended byte 20       */
+#define R_EB21   0x24  /* Extended byte 21       */
+#define R_EB22   0x25  /* Extended byte 22       */
+#define R_EB23   0x26  /* Extended byte 23       */
+
+#define TDA18271_NUM_REGS 39
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_rf_tracking_filter_cal {
+       u32 rfmax;
+       u8  rfband;
+       u32 rf1_def;
+       u32 rf2_def;
+       u32 rf3_def;
+       u32 rf1;
+       u32 rf2;
+       u32 rf3;
+       int rf_a1;
+       int rf_b1;
+       int rf_a2;
+       int rf_b2;
+};
+
+enum tda18271_mode {
+       TDA18271_ANALOG,
+       TDA18271_DIGITAL,
+};
+
+struct tda18271_map_layout;
+
+enum tda18271_ver {
+       TDA18271HDC1,
+       TDA18271HDC2,
+};
+
+struct tda18271_priv {
+       u8 i2c_addr;
+       struct i2c_adapter *i2c_adap;
+       unsigned char tda18271_regs[TDA18271_NUM_REGS];
+
+       struct list_head tda18271_list;
+
+       enum tda18271_mode mode;
+       enum tda18271_i2c_gate gate;
+       enum tda18271_ver id;
+
+       unsigned int count;
+       unsigned int tm_rfcal;
+       unsigned int cal_initialized:1;
+
+       struct tda18271_map_layout *maps;
+       struct tda18271_std_map std;
+       struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
+
+       struct mutex lock;
+
+       u32 frequency;
+       u32 bandwidth;
+};
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_debug;
+
+#define DBG_INFO 1
+#define DBG_MAP  2
+#define DBG_REG  4
+#define DBG_ADV  8
+#define DBG_CAL  16
+
+#define tda_printk(kern, fmt, arg...) \
+       printk(kern "%s: " fmt, __FUNCTION__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+       if (tda18271_debug & lvl) \
+               tda_printk(kern, fmt, ##arg); } while (0)
+
+#define tda_info(fmt, arg...) printk(KERN_INFO              fmt, ##arg)
+#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING,      fmt, ##arg)
+#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,          fmt, ##arg)
+#define tda_dbg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
+#define tda_map(fmt, arg...)  dprintk(KERN_DEBUG, DBG_MAP,  fmt, ##arg)
+#define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
+#define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
+
+/*---------------------------------------------------------------------*/
+
+enum tda18271_map_type {
+       /* tda18271_pll_map */
+       MAIN_PLL,
+       CAL_PLL,
+       /* tda18271_map */
+       RF_CAL,
+       RF_CAL_KMCO,
+       RF_CAL_DC_OVER_DT,
+       BP_FILTER,
+       RF_BAND,
+       GAIN_TAPER,
+       IR_MEASURE,
+};
+
+extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+                                  enum tda18271_map_type map_type,
+                                  u32 *freq, u8 *post_div, u8 *div);
+extern int tda18271_lookup_map(struct dvb_frontend *fe,
+                              enum tda18271_map_type map_type,
+                              u32 *freq, u8 *val);
+
+extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
+
+extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
+                                  u32 *freq, u8 *rf_band);
+
+extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+                                     u32 *freq, u8 *cid_target,
+                                     u16 *count_limit);
+
+extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_read_regs(struct dvb_frontend *fe);
+extern int tda18271_read_extended(struct dvb_frontend *fe);
+extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
+extern int tda18271_init_regs(struct dvb_frontend *fe);
+
+extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
+                                    int sm, int sm_lt, int sm_xt);
+
+extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
+extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
+
+extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
+
+#endif /* __TDA18271_PRIV_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c
new file mode 100644 (file)
index 0000000..e94afcf
--- /dev/null
@@ -0,0 +1,1285 @@
+/*
+    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tda18271-priv.h"
+
+struct tda18271_pll_map {
+       u32 lomax;
+       u8 pd; /* post div */
+       u8 d;  /*      div */
+};
+
+struct tda18271_map {
+       u32 rfmax;
+       u8  val;
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_pll_map tda18271c1_main_pll[] = {
+       { .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
+       { .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
+       { .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
+       { .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
+       { .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
+       { .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
+       { .lomax =  54000, .pd = 0x59, .d = 0x90 },
+       { .lomax =  61000, .pd = 0x58, .d = 0x80 },
+       { .lomax =  65000, .pd = 0x4f, .d = 0x78 },
+       { .lomax =  70000, .pd = 0x4e, .d = 0x70 },
+       { .lomax =  75000, .pd = 0x4d, .d = 0x68 },
+       { .lomax =  82000, .pd = 0x4c, .d = 0x60 },
+       { .lomax =  89000, .pd = 0x4b, .d = 0x58 },
+       { .lomax =  98000, .pd = 0x4a, .d = 0x50 },
+       { .lomax = 109000, .pd = 0x49, .d = 0x48 },
+       { .lomax = 123000, .pd = 0x48, .d = 0x40 },
+       { .lomax = 131000, .pd = 0x3f, .d = 0x3c },
+       { .lomax = 141000, .pd = 0x3e, .d = 0x38 },
+       { .lomax = 151000, .pd = 0x3d, .d = 0x34 },
+       { .lomax = 164000, .pd = 0x3c, .d = 0x30 },
+       { .lomax = 179000, .pd = 0x3b, .d = 0x2c },
+       { .lomax = 197000, .pd = 0x3a, .d = 0x28 },
+       { .lomax = 219000, .pd = 0x39, .d = 0x24 },
+       { .lomax = 246000, .pd = 0x38, .d = 0x20 },
+       { .lomax = 263000, .pd = 0x2f, .d = 0x1e },
+       { .lomax = 282000, .pd = 0x2e, .d = 0x1c },
+       { .lomax = 303000, .pd = 0x2d, .d = 0x1a },
+       { .lomax = 329000, .pd = 0x2c, .d = 0x18 },
+       { .lomax = 359000, .pd = 0x2b, .d = 0x16 },
+       { .lomax = 395000, .pd = 0x2a, .d = 0x14 },
+       { .lomax = 438000, .pd = 0x29, .d = 0x12 },
+       { .lomax = 493000, .pd = 0x28, .d = 0x10 },
+       { .lomax = 526000, .pd = 0x1f, .d = 0x0f },
+       { .lomax = 564000, .pd = 0x1e, .d = 0x0e },
+       { .lomax = 607000, .pd = 0x1d, .d = 0x0d },
+       { .lomax = 658000, .pd = 0x1c, .d = 0x0c },
+       { .lomax = 718000, .pd = 0x1b, .d = 0x0b },
+       { .lomax = 790000, .pd = 0x1a, .d = 0x0a },
+       { .lomax = 877000, .pd = 0x19, .d = 0x09 },
+       { .lomax = 987000, .pd = 0x18, .d = 0x08 },
+       { .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_main_pll[] = {
+       { .lomax =  33125, .pd = 0x57, .d = 0xf0 },
+       { .lomax =  35500, .pd = 0x56, .d = 0xe0 },
+       { .lomax =  38188, .pd = 0x55, .d = 0xd0 },
+       { .lomax =  41375, .pd = 0x54, .d = 0xc0 },
+       { .lomax =  45125, .pd = 0x53, .d = 0xb0 },
+       { .lomax =  49688, .pd = 0x52, .d = 0xa0 },
+       { .lomax =  55188, .pd = 0x51, .d = 0x90 },
+       { .lomax =  62125, .pd = 0x50, .d = 0x80 },
+       { .lomax =  66250, .pd = 0x47, .d = 0x78 },
+       { .lomax =  71000, .pd = 0x46, .d = 0x70 },
+       { .lomax =  76375, .pd = 0x45, .d = 0x68 },
+       { .lomax =  82750, .pd = 0x44, .d = 0x60 },
+       { .lomax =  90250, .pd = 0x43, .d = 0x58 },
+       { .lomax =  99375, .pd = 0x42, .d = 0x50 },
+       { .lomax = 110375, .pd = 0x41, .d = 0x48 },
+       { .lomax = 124250, .pd = 0x40, .d = 0x40 },
+       { .lomax = 132500, .pd = 0x37, .d = 0x3c },
+       { .lomax = 142000, .pd = 0x36, .d = 0x38 },
+       { .lomax = 152750, .pd = 0x35, .d = 0x34 },
+       { .lomax = 165500, .pd = 0x34, .d = 0x30 },
+       { .lomax = 180500, .pd = 0x33, .d = 0x2c },
+       { .lomax = 198750, .pd = 0x32, .d = 0x28 },
+       { .lomax = 220750, .pd = 0x31, .d = 0x24 },
+       { .lomax = 248500, .pd = 0x30, .d = 0x20 },
+       { .lomax = 265000, .pd = 0x27, .d = 0x1e },
+       { .lomax = 284000, .pd = 0x26, .d = 0x1c },
+       { .lomax = 305500, .pd = 0x25, .d = 0x1a },
+       { .lomax = 331000, .pd = 0x24, .d = 0x18 },
+       { .lomax = 361000, .pd = 0x23, .d = 0x16 },
+       { .lomax = 397500, .pd = 0x22, .d = 0x14 },
+       { .lomax = 441500, .pd = 0x21, .d = 0x12 },
+       { .lomax = 497000, .pd = 0x20, .d = 0x10 },
+       { .lomax = 530000, .pd = 0x17, .d = 0x0f },
+       { .lomax = 568000, .pd = 0x16, .d = 0x0e },
+       { .lomax = 611000, .pd = 0x15, .d = 0x0d },
+       { .lomax = 662000, .pd = 0x14, .d = 0x0c },
+       { .lomax = 722000, .pd = 0x13, .d = 0x0b },
+       { .lomax = 795000, .pd = 0x12, .d = 0x0a },
+       { .lomax = 883000, .pd = 0x11, .d = 0x09 },
+       { .lomax = 994000, .pd = 0x10, .d = 0x08 },
+       { .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c1_cal_pll[] = {
+       { .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
+       { .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
+       { .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
+       { .lomax =   44000, .pd = 0xda, .d = 0xa0 },
+       { .lomax =   49000, .pd = 0xd9, .d = 0x90 },
+       { .lomax =   55000, .pd = 0xd8, .d = 0x80 },
+       { .lomax =   63000, .pd = 0xd3, .d = 0x70 },
+       { .lomax =   67000, .pd = 0xcd, .d = 0x68 },
+       { .lomax =   73000, .pd = 0xcc, .d = 0x60 },
+       { .lomax =   80000, .pd = 0xcb, .d = 0x58 },
+       { .lomax =   88000, .pd = 0xca, .d = 0x50 },
+       { .lomax =   98000, .pd = 0xc9, .d = 0x48 },
+       { .lomax =  110000, .pd = 0xc8, .d = 0x40 },
+       { .lomax =  126000, .pd = 0xc3, .d = 0x38 },
+       { .lomax =  135000, .pd = 0xbd, .d = 0x34 },
+       { .lomax =  147000, .pd = 0xbc, .d = 0x30 },
+       { .lomax =  160000, .pd = 0xbb, .d = 0x2c },
+       { .lomax =  176000, .pd = 0xba, .d = 0x28 },
+       { .lomax =  196000, .pd = 0xb9, .d = 0x24 },
+       { .lomax =  220000, .pd = 0xb8, .d = 0x20 },
+       { .lomax =  252000, .pd = 0xb3, .d = 0x1c },
+       { .lomax =  271000, .pd = 0xad, .d = 0x1a },
+       { .lomax =  294000, .pd = 0xac, .d = 0x18 },
+       { .lomax =  321000, .pd = 0xab, .d = 0x16 },
+       { .lomax =  353000, .pd = 0xaa, .d = 0x14 },
+       { .lomax =  392000, .pd = 0xa9, .d = 0x12 },
+       { .lomax =  441000, .pd = 0xa8, .d = 0x10 },
+       { .lomax =  505000, .pd = 0xa3, .d = 0x0e },
+       { .lomax =  543000, .pd = 0x9d, .d = 0x0d },
+       { .lomax =  589000, .pd = 0x9c, .d = 0x0c },
+       { .lomax =  642000, .pd = 0x9b, .d = 0x0b },
+       { .lomax =  707000, .pd = 0x9a, .d = 0x0a },
+       { .lomax =  785000, .pd = 0x99, .d = 0x09 },
+       { .lomax =  883000, .pd = 0x98, .d = 0x08 },
+       { .lomax = 1010000, .pd = 0x93, .d = 0x07 },
+       { .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_cal_pll[] = {
+       { .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
+       { .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
+       { .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
+       { .lomax =   43938, .pd = 0xda, .d = 0xa0 },
+       { .lomax =   48813, .pd = 0xd9, .d = 0x90 },
+       { .lomax =   54938, .pd = 0xd8, .d = 0x80 },
+       { .lomax =   62813, .pd = 0xd3, .d = 0x70 },
+       { .lomax =   67625, .pd = 0xcd, .d = 0x68 },
+       { .lomax =   73250, .pd = 0xcc, .d = 0x60 },
+       { .lomax =   79875, .pd = 0xcb, .d = 0x58 },
+       { .lomax =   87875, .pd = 0xca, .d = 0x50 },
+       { .lomax =   97625, .pd = 0xc9, .d = 0x48 },
+       { .lomax =  109875, .pd = 0xc8, .d = 0x40 },
+       { .lomax =  125625, .pd = 0xc3, .d = 0x38 },
+       { .lomax =  135250, .pd = 0xbd, .d = 0x34 },
+       { .lomax =  146500, .pd = 0xbc, .d = 0x30 },
+       { .lomax =  159750, .pd = 0xbb, .d = 0x2c },
+       { .lomax =  175750, .pd = 0xba, .d = 0x28 },
+       { .lomax =  195250, .pd = 0xb9, .d = 0x24 },
+       { .lomax =  219750, .pd = 0xb8, .d = 0x20 },
+       { .lomax =  251250, .pd = 0xb3, .d = 0x1c },
+       { .lomax =  270500, .pd = 0xad, .d = 0x1a },
+       { .lomax =  293000, .pd = 0xac, .d = 0x18 },
+       { .lomax =  319500, .pd = 0xab, .d = 0x16 },
+       { .lomax =  351500, .pd = 0xaa, .d = 0x14 },
+       { .lomax =  390500, .pd = 0xa9, .d = 0x12 },
+       { .lomax =  439500, .pd = 0xa8, .d = 0x10 },
+       { .lomax =  502500, .pd = 0xa3, .d = 0x0e },
+       { .lomax =  541000, .pd = 0x9d, .d = 0x0d },
+       { .lomax =  586000, .pd = 0x9c, .d = 0x0c },
+       { .lomax =  639000, .pd = 0x9b, .d = 0x0b },
+       { .lomax =  703000, .pd = 0x9a, .d = 0x0a },
+       { .lomax =  781000, .pd = 0x99, .d = 0x09 },
+       { .lomax =  879000, .pd = 0x98, .d = 0x08 },
+       { .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_bp_filter[] = {
+       { .rfmax =  62000, .val = 0x00 },
+       { .rfmax =  84000, .val = 0x01 },
+       { .rfmax = 100000, .val = 0x02 },
+       { .rfmax = 140000, .val = 0x03 },
+       { .rfmax = 170000, .val = 0x04 },
+       { .rfmax = 180000, .val = 0x05 },
+       { .rfmax = 865000, .val = 0x06 },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_km[] = {
+       { .rfmax =  61100, .val = 0x74 },
+       { .rfmax = 350000, .val = 0x40 },
+       { .rfmax = 720000, .val = 0x30 },
+       { .rfmax = 865000, .val = 0x40 },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_km[] = {
+       { .rfmax =  47900, .val = 0x38 },
+       { .rfmax =  61100, .val = 0x44 },
+       { .rfmax = 350000, .val = 0x30 },
+       { .rfmax = 720000, .val = 0x24 },
+       { .rfmax = 865000, .val = 0x3c },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_band[] = {
+       { .rfmax =  47900, .val = 0x00 },
+       { .rfmax =  61100, .val = 0x01 },
+/*     { .rfmax = 152600, .val = 0x02 }, */
+       { .rfmax = 121200, .val = 0x02 },
+       { .rfmax = 164700, .val = 0x03 },
+       { .rfmax = 203500, .val = 0x04 },
+       { .rfmax = 457800, .val = 0x05 },
+       { .rfmax = 865000, .val = 0x06 },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_gain_taper[] = {
+       { .rfmax =  45400, .val = 0x1f },
+       { .rfmax =  45800, .val = 0x1e },
+       { .rfmax =  46200, .val = 0x1d },
+       { .rfmax =  46700, .val = 0x1c },
+       { .rfmax =  47100, .val = 0x1b },
+       { .rfmax =  47500, .val = 0x1a },
+       { .rfmax =  47900, .val = 0x19 },
+       { .rfmax =  49600, .val = 0x17 },
+       { .rfmax =  51200, .val = 0x16 },
+       { .rfmax =  52900, .val = 0x15 },
+       { .rfmax =  54500, .val = 0x14 },
+       { .rfmax =  56200, .val = 0x13 },
+       { .rfmax =  57800, .val = 0x12 },
+       { .rfmax =  59500, .val = 0x11 },
+       { .rfmax =  61100, .val = 0x10 },
+       { .rfmax =  67600, .val = 0x0d },
+       { .rfmax =  74200, .val = 0x0c },
+       { .rfmax =  80700, .val = 0x0b },
+       { .rfmax =  87200, .val = 0x0a },
+       { .rfmax =  93800, .val = 0x09 },
+       { .rfmax = 100300, .val = 0x08 },
+       { .rfmax = 106900, .val = 0x07 },
+       { .rfmax = 113400, .val = 0x06 },
+       { .rfmax = 119900, .val = 0x05 },
+       { .rfmax = 126500, .val = 0x04 },
+       { .rfmax = 133000, .val = 0x03 },
+       { .rfmax = 139500, .val = 0x02 },
+       { .rfmax = 146100, .val = 0x01 },
+       { .rfmax = 152600, .val = 0x00 },
+       { .rfmax = 154300, .val = 0x1f },
+       { .rfmax = 156100, .val = 0x1e },
+       { .rfmax = 157800, .val = 0x1d },
+       { .rfmax = 159500, .val = 0x1c },
+       { .rfmax = 161200, .val = 0x1b },
+       { .rfmax = 163000, .val = 0x1a },
+       { .rfmax = 164700, .val = 0x19 },
+       { .rfmax = 170200, .val = 0x17 },
+       { .rfmax = 175800, .val = 0x16 },
+       { .rfmax = 181300, .val = 0x15 },
+       { .rfmax = 186900, .val = 0x14 },
+       { .rfmax = 192400, .val = 0x13 },
+       { .rfmax = 198000, .val = 0x12 },
+       { .rfmax = 203500, .val = 0x11 },
+       { .rfmax = 216200, .val = 0x14 },
+       { .rfmax = 228900, .val = 0x13 },
+       { .rfmax = 241600, .val = 0x12 },
+       { .rfmax = 254400, .val = 0x11 },
+       { .rfmax = 267100, .val = 0x10 },
+       { .rfmax = 279800, .val = 0x0f },
+       { .rfmax = 292500, .val = 0x0e },
+       { .rfmax = 305200, .val = 0x0d },
+       { .rfmax = 317900, .val = 0x0c },
+       { .rfmax = 330700, .val = 0x0b },
+       { .rfmax = 343400, .val = 0x0a },
+       { .rfmax = 356100, .val = 0x09 },
+       { .rfmax = 368800, .val = 0x08 },
+       { .rfmax = 381500, .val = 0x07 },
+       { .rfmax = 394200, .val = 0x06 },
+       { .rfmax = 406900, .val = 0x05 },
+       { .rfmax = 419700, .val = 0x04 },
+       { .rfmax = 432400, .val = 0x03 },
+       { .rfmax = 445100, .val = 0x02 },
+       { .rfmax = 457800, .val = 0x01 },
+       { .rfmax = 476300, .val = 0x19 },
+       { .rfmax = 494800, .val = 0x18 },
+       { .rfmax = 513300, .val = 0x17 },
+       { .rfmax = 531800, .val = 0x16 },
+       { .rfmax = 550300, .val = 0x15 },
+       { .rfmax = 568900, .val = 0x14 },
+       { .rfmax = 587400, .val = 0x13 },
+       { .rfmax = 605900, .val = 0x12 },
+       { .rfmax = 624400, .val = 0x11 },
+       { .rfmax = 642900, .val = 0x10 },
+       { .rfmax = 661400, .val = 0x0f },
+       { .rfmax = 679900, .val = 0x0e },
+       { .rfmax = 698400, .val = 0x0d },
+       { .rfmax = 716900, .val = 0x0c },
+       { .rfmax = 735400, .val = 0x0b },
+       { .rfmax = 753900, .val = 0x0a },
+       { .rfmax = 772500, .val = 0x09 },
+       { .rfmax = 791000, .val = 0x08 },
+       { .rfmax = 809500, .val = 0x07 },
+       { .rfmax = 828000, .val = 0x06 },
+       { .rfmax = 846500, .val = 0x05 },
+       { .rfmax = 865000, .val = 0x04 },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_rf_cal[] = {
+       { .rfmax = 41000, .val = 0x1e },
+       { .rfmax = 43000, .val = 0x30 },
+       { .rfmax = 45000, .val = 0x43 },
+       { .rfmax = 46000, .val = 0x4d },
+       { .rfmax = 47000, .val = 0x54 },
+       { .rfmax = 47900, .val = 0x64 },
+       { .rfmax = 49100, .val = 0x20 },
+       { .rfmax = 50000, .val = 0x22 },
+       { .rfmax = 51000, .val = 0x2a },
+       { .rfmax = 53000, .val = 0x32 },
+       { .rfmax = 55000, .val = 0x35 },
+       { .rfmax = 56000, .val = 0x3c },
+       { .rfmax = 57000, .val = 0x3f },
+       { .rfmax = 58000, .val = 0x48 },
+       { .rfmax = 59000, .val = 0x4d },
+       { .rfmax = 60000, .val = 0x58 },
+       { .rfmax = 61100, .val = 0x5f },
+       { .rfmax =     0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_rf_cal[] = {
+       { .rfmax =  41000, .val = 0x0f },
+       { .rfmax =  43000, .val = 0x1c },
+       { .rfmax =  45000, .val = 0x2f },
+       { .rfmax =  46000, .val = 0x39 },
+       { .rfmax =  47000, .val = 0x40 },
+       { .rfmax =  47900, .val = 0x50 },
+       { .rfmax =  49100, .val = 0x16 },
+       { .rfmax =  50000, .val = 0x18 },
+       { .rfmax =  51000, .val = 0x20 },
+       { .rfmax =  53000, .val = 0x28 },
+       { .rfmax =  55000, .val = 0x2b },
+       { .rfmax =  56000, .val = 0x32 },
+       { .rfmax =  57000, .val = 0x35 },
+       { .rfmax =  58000, .val = 0x3e },
+       { .rfmax =  59000, .val = 0x43 },
+       { .rfmax =  60000, .val = 0x4e },
+       { .rfmax =  61100, .val = 0x55 },
+       { .rfmax =  63000, .val = 0x0f },
+       { .rfmax =  64000, .val = 0x11 },
+       { .rfmax =  65000, .val = 0x12 },
+       { .rfmax =  66000, .val = 0x15 },
+       { .rfmax =  67000, .val = 0x16 },
+       { .rfmax =  68000, .val = 0x17 },
+       { .rfmax =  70000, .val = 0x19 },
+       { .rfmax =  71000, .val = 0x1c },
+       { .rfmax =  72000, .val = 0x1d },
+       { .rfmax =  73000, .val = 0x1f },
+       { .rfmax =  74000, .val = 0x20 },
+       { .rfmax =  75000, .val = 0x21 },
+       { .rfmax =  76000, .val = 0x24 },
+       { .rfmax =  77000, .val = 0x25 },
+       { .rfmax =  78000, .val = 0x27 },
+       { .rfmax =  80000, .val = 0x28 },
+       { .rfmax =  81000, .val = 0x29 },
+       { .rfmax =  82000, .val = 0x2d },
+       { .rfmax =  83000, .val = 0x2e },
+       { .rfmax =  84000, .val = 0x2f },
+       { .rfmax =  85000, .val = 0x31 },
+       { .rfmax =  86000, .val = 0x33 },
+       { .rfmax =  87000, .val = 0x34 },
+       { .rfmax =  88000, .val = 0x35 },
+       { .rfmax =  89000, .val = 0x37 },
+       { .rfmax =  90000, .val = 0x38 },
+       { .rfmax =  91000, .val = 0x39 },
+       { .rfmax =  93000, .val = 0x3c },
+       { .rfmax =  94000, .val = 0x3e },
+       { .rfmax =  95000, .val = 0x3f },
+       { .rfmax =  96000, .val = 0x40 },
+       { .rfmax =  97000, .val = 0x42 },
+       { .rfmax =  99000, .val = 0x45 },
+       { .rfmax = 100000, .val = 0x46 },
+       { .rfmax = 102000, .val = 0x48 },
+       { .rfmax = 103000, .val = 0x4a },
+       { .rfmax = 105000, .val = 0x4d },
+       { .rfmax = 106000, .val = 0x4e },
+       { .rfmax = 107000, .val = 0x50 },
+       { .rfmax = 108000, .val = 0x51 },
+       { .rfmax = 110000, .val = 0x54 },
+       { .rfmax = 111000, .val = 0x56 },
+       { .rfmax = 112000, .val = 0x57 },
+       { .rfmax = 113000, .val = 0x58 },
+       { .rfmax = 114000, .val = 0x59 },
+       { .rfmax = 115000, .val = 0x5c },
+       { .rfmax = 116000, .val = 0x5d },
+       { .rfmax = 117000, .val = 0x5f },
+       { .rfmax = 119000, .val = 0x60 },
+       { .rfmax = 120000, .val = 0x64 },
+       { .rfmax = 121000, .val = 0x65 },
+       { .rfmax = 122000, .val = 0x66 },
+       { .rfmax = 123000, .val = 0x68 },
+       { .rfmax = 124000, .val = 0x69 },
+       { .rfmax = 125000, .val = 0x6c },
+       { .rfmax = 126000, .val = 0x6d },
+       { .rfmax = 127000, .val = 0x6e },
+       { .rfmax = 128000, .val = 0x70 },
+       { .rfmax = 129000, .val = 0x71 },
+       { .rfmax = 130000, .val = 0x75 },
+       { .rfmax = 131000, .val = 0x77 },
+       { .rfmax = 132000, .val = 0x78 },
+       { .rfmax = 133000, .val = 0x7b },
+       { .rfmax = 134000, .val = 0x7e },
+       { .rfmax = 135000, .val = 0x81 },
+       { .rfmax = 136000, .val = 0x82 },
+       { .rfmax = 137000, .val = 0x87 },
+       { .rfmax = 138000, .val = 0x88 },
+       { .rfmax = 139000, .val = 0x8d },
+       { .rfmax = 140000, .val = 0x8e },
+       { .rfmax = 141000, .val = 0x91 },
+       { .rfmax = 142000, .val = 0x95 },
+       { .rfmax = 143000, .val = 0x9a },
+       { .rfmax = 144000, .val = 0x9d },
+       { .rfmax = 145000, .val = 0xa1 },
+       { .rfmax = 146000, .val = 0xa2 },
+       { .rfmax = 147000, .val = 0xa4 },
+       { .rfmax = 148000, .val = 0xa9 },
+       { .rfmax = 149000, .val = 0xae },
+       { .rfmax = 150000, .val = 0xb0 },
+       { .rfmax = 151000, .val = 0xb1 },
+       { .rfmax = 152000, .val = 0xb7 },
+       { .rfmax = 153000, .val = 0xbd },
+       { .rfmax = 154000, .val = 0x20 },
+       { .rfmax = 155000, .val = 0x22 },
+       { .rfmax = 156000, .val = 0x24 },
+       { .rfmax = 157000, .val = 0x25 },
+       { .rfmax = 158000, .val = 0x27 },
+       { .rfmax = 159000, .val = 0x29 },
+       { .rfmax = 160000, .val = 0x2c },
+       { .rfmax = 161000, .val = 0x2d },
+       { .rfmax = 163000, .val = 0x2e },
+       { .rfmax = 164000, .val = 0x2f },
+       { .rfmax = 165000, .val = 0x30 },
+       { .rfmax = 166000, .val = 0x11 },
+       { .rfmax = 167000, .val = 0x12 },
+       { .rfmax = 168000, .val = 0x13 },
+       { .rfmax = 169000, .val = 0x14 },
+       { .rfmax = 170000, .val = 0x15 },
+       { .rfmax = 172000, .val = 0x16 },
+       { .rfmax = 173000, .val = 0x17 },
+       { .rfmax = 174000, .val = 0x18 },
+       { .rfmax = 175000, .val = 0x1a },
+       { .rfmax = 176000, .val = 0x1b },
+       { .rfmax = 178000, .val = 0x1d },
+       { .rfmax = 179000, .val = 0x1e },
+       { .rfmax = 180000, .val = 0x1f },
+       { .rfmax = 181000, .val = 0x20 },
+       { .rfmax = 182000, .val = 0x21 },
+       { .rfmax = 183000, .val = 0x22 },
+       { .rfmax = 184000, .val = 0x24 },
+       { .rfmax = 185000, .val = 0x25 },
+       { .rfmax = 186000, .val = 0x26 },
+       { .rfmax = 187000, .val = 0x27 },
+       { .rfmax = 188000, .val = 0x29 },
+       { .rfmax = 189000, .val = 0x2a },
+       { .rfmax = 190000, .val = 0x2c },
+       { .rfmax = 191000, .val = 0x2d },
+       { .rfmax = 192000, .val = 0x2e },
+       { .rfmax = 193000, .val = 0x2f },
+       { .rfmax = 194000, .val = 0x30 },
+       { .rfmax = 195000, .val = 0x33 },
+       { .rfmax = 196000, .val = 0x35 },
+       { .rfmax = 198000, .val = 0x36 },
+       { .rfmax = 200000, .val = 0x38 },
+       { .rfmax = 201000, .val = 0x3c },
+       { .rfmax = 202000, .val = 0x3d },
+       { .rfmax = 203500, .val = 0x3e },
+       { .rfmax = 206000, .val = 0x0e },
+       { .rfmax = 208000, .val = 0x0f },
+       { .rfmax = 212000, .val = 0x10 },
+       { .rfmax = 216000, .val = 0x11 },
+       { .rfmax = 217000, .val = 0x12 },
+       { .rfmax = 218000, .val = 0x13 },
+       { .rfmax = 220000, .val = 0x14 },
+       { .rfmax = 222000, .val = 0x15 },
+       { .rfmax = 225000, .val = 0x16 },
+       { .rfmax = 228000, .val = 0x17 },
+       { .rfmax = 231000, .val = 0x18 },
+       { .rfmax = 234000, .val = 0x19 },
+       { .rfmax = 235000, .val = 0x1a },
+       { .rfmax = 236000, .val = 0x1b },
+       { .rfmax = 237000, .val = 0x1c },
+       { .rfmax = 240000, .val = 0x1d },
+       { .rfmax = 242000, .val = 0x1f },
+       { .rfmax = 247000, .val = 0x20 },
+       { .rfmax = 249000, .val = 0x21 },
+       { .rfmax = 252000, .val = 0x22 },
+       { .rfmax = 253000, .val = 0x23 },
+       { .rfmax = 254000, .val = 0x24 },
+       { .rfmax = 256000, .val = 0x25 },
+       { .rfmax = 259000, .val = 0x26 },
+       { .rfmax = 262000, .val = 0x27 },
+       { .rfmax = 264000, .val = 0x28 },
+       { .rfmax = 267000, .val = 0x29 },
+       { .rfmax = 269000, .val = 0x2a },
+       { .rfmax = 271000, .val = 0x2b },
+       { .rfmax = 273000, .val = 0x2c },
+       { .rfmax = 275000, .val = 0x2d },
+       { .rfmax = 277000, .val = 0x2e },
+       { .rfmax = 279000, .val = 0x2f },
+       { .rfmax = 282000, .val = 0x30 },
+       { .rfmax = 284000, .val = 0x31 },
+       { .rfmax = 286000, .val = 0x32 },
+       { .rfmax = 287000, .val = 0x33 },
+       { .rfmax = 290000, .val = 0x34 },
+       { .rfmax = 293000, .val = 0x35 },
+       { .rfmax = 295000, .val = 0x36 },
+       { .rfmax = 297000, .val = 0x37 },
+       { .rfmax = 300000, .val = 0x38 },
+       { .rfmax = 303000, .val = 0x39 },
+       { .rfmax = 305000, .val = 0x3a },
+       { .rfmax = 306000, .val = 0x3b },
+       { .rfmax = 307000, .val = 0x3c },
+       { .rfmax = 310000, .val = 0x3d },
+       { .rfmax = 312000, .val = 0x3e },
+       { .rfmax = 315000, .val = 0x3f },
+       { .rfmax = 318000, .val = 0x40 },
+       { .rfmax = 320000, .val = 0x41 },
+       { .rfmax = 323000, .val = 0x42 },
+       { .rfmax = 324000, .val = 0x43 },
+       { .rfmax = 325000, .val = 0x44 },
+       { .rfmax = 327000, .val = 0x45 },
+       { .rfmax = 331000, .val = 0x46 },
+       { .rfmax = 334000, .val = 0x47 },
+       { .rfmax = 337000, .val = 0x48 },
+       { .rfmax = 339000, .val = 0x49 },
+       { .rfmax = 340000, .val = 0x4a },
+       { .rfmax = 341000, .val = 0x4b },
+       { .rfmax = 343000, .val = 0x4c },
+       { .rfmax = 345000, .val = 0x4d },
+       { .rfmax = 349000, .val = 0x4e },
+       { .rfmax = 352000, .val = 0x4f },
+       { .rfmax = 353000, .val = 0x50 },
+       { .rfmax = 355000, .val = 0x51 },
+       { .rfmax = 357000, .val = 0x52 },
+       { .rfmax = 359000, .val = 0x53 },
+       { .rfmax = 361000, .val = 0x54 },
+       { .rfmax = 362000, .val = 0x55 },
+       { .rfmax = 364000, .val = 0x56 },
+       { .rfmax = 368000, .val = 0x57 },
+       { .rfmax = 370000, .val = 0x58 },
+       { .rfmax = 372000, .val = 0x59 },
+       { .rfmax = 375000, .val = 0x5a },
+       { .rfmax = 376000, .val = 0x5b },
+       { .rfmax = 377000, .val = 0x5c },
+       { .rfmax = 379000, .val = 0x5d },
+       { .rfmax = 382000, .val = 0x5e },
+       { .rfmax = 384000, .val = 0x5f },
+       { .rfmax = 385000, .val = 0x60 },
+       { .rfmax = 386000, .val = 0x61 },
+       { .rfmax = 388000, .val = 0x62 },
+       { .rfmax = 390000, .val = 0x63 },
+       { .rfmax = 393000, .val = 0x64 },
+       { .rfmax = 394000, .val = 0x65 },
+       { .rfmax = 396000, .val = 0x66 },
+       { .rfmax = 397000, .val = 0x67 },
+       { .rfmax = 398000, .val = 0x68 },
+       { .rfmax = 400000, .val = 0x69 },
+       { .rfmax = 402000, .val = 0x6a },
+       { .rfmax = 403000, .val = 0x6b },
+       { .rfmax = 407000, .val = 0x6c },
+       { .rfmax = 408000, .val = 0x6d },
+       { .rfmax = 409000, .val = 0x6e },
+       { .rfmax = 410000, .val = 0x6f },
+       { .rfmax = 411000, .val = 0x70 },
+       { .rfmax = 412000, .val = 0x71 },
+       { .rfmax = 413000, .val = 0x72 },
+       { .rfmax = 414000, .val = 0x73 },
+       { .rfmax = 417000, .val = 0x74 },
+       { .rfmax = 418000, .val = 0x75 },
+       { .rfmax = 420000, .val = 0x76 },
+       { .rfmax = 422000, .val = 0x77 },
+       { .rfmax = 423000, .val = 0x78 },
+       { .rfmax = 424000, .val = 0x79 },
+       { .rfmax = 427000, .val = 0x7a },
+       { .rfmax = 428000, .val = 0x7b },
+       { .rfmax = 429000, .val = 0x7d },
+       { .rfmax = 432000, .val = 0x7f },
+       { .rfmax = 434000, .val = 0x80 },
+       { .rfmax = 435000, .val = 0x81 },
+       { .rfmax = 436000, .val = 0x83 },
+       { .rfmax = 437000, .val = 0x84 },
+       { .rfmax = 438000, .val = 0x85 },
+       { .rfmax = 439000, .val = 0x86 },
+       { .rfmax = 440000, .val = 0x87 },
+       { .rfmax = 441000, .val = 0x88 },
+       { .rfmax = 442000, .val = 0x89 },
+       { .rfmax = 445000, .val = 0x8a },
+       { .rfmax = 446000, .val = 0x8b },
+       { .rfmax = 447000, .val = 0x8c },
+       { .rfmax = 448000, .val = 0x8e },
+       { .rfmax = 449000, .val = 0x8f },
+       { .rfmax = 450000, .val = 0x90 },
+       { .rfmax = 452000, .val = 0x91 },
+       { .rfmax = 453000, .val = 0x93 },
+       { .rfmax = 454000, .val = 0x94 },
+       { .rfmax = 456000, .val = 0x96 },
+       { .rfmax = 457000, .val = 0x98 },
+       { .rfmax = 461000, .val = 0x11 },
+       { .rfmax = 468000, .val = 0x12 },
+       { .rfmax = 472000, .val = 0x13 },
+       { .rfmax = 473000, .val = 0x14 },
+       { .rfmax = 474000, .val = 0x15 },
+       { .rfmax = 481000, .val = 0x16 },
+       { .rfmax = 486000, .val = 0x17 },
+       { .rfmax = 491000, .val = 0x18 },
+       { .rfmax = 498000, .val = 0x19 },
+       { .rfmax = 499000, .val = 0x1a },
+       { .rfmax = 501000, .val = 0x1b },
+       { .rfmax = 506000, .val = 0x1c },
+       { .rfmax = 511000, .val = 0x1d },
+       { .rfmax = 516000, .val = 0x1e },
+       { .rfmax = 520000, .val = 0x1f },
+       { .rfmax = 521000, .val = 0x20 },
+       { .rfmax = 525000, .val = 0x21 },
+       { .rfmax = 529000, .val = 0x22 },
+       { .rfmax = 533000, .val = 0x23 },
+       { .rfmax = 539000, .val = 0x24 },
+       { .rfmax = 541000, .val = 0x25 },
+       { .rfmax = 547000, .val = 0x26 },
+       { .rfmax = 549000, .val = 0x27 },
+       { .rfmax = 551000, .val = 0x28 },
+       { .rfmax = 556000, .val = 0x29 },
+       { .rfmax = 561000, .val = 0x2a },
+       { .rfmax = 563000, .val = 0x2b },
+       { .rfmax = 565000, .val = 0x2c },
+       { .rfmax = 569000, .val = 0x2d },
+       { .rfmax = 571000, .val = 0x2e },
+       { .rfmax = 577000, .val = 0x2f },
+       { .rfmax = 580000, .val = 0x30 },
+       { .rfmax = 582000, .val = 0x31 },
+       { .rfmax = 584000, .val = 0x32 },
+       { .rfmax = 588000, .val = 0x33 },
+       { .rfmax = 591000, .val = 0x34 },
+       { .rfmax = 596000, .val = 0x35 },
+       { .rfmax = 598000, .val = 0x36 },
+       { .rfmax = 603000, .val = 0x37 },
+       { .rfmax = 604000, .val = 0x38 },
+       { .rfmax = 606000, .val = 0x39 },
+       { .rfmax = 612000, .val = 0x3a },
+       { .rfmax = 615000, .val = 0x3b },
+       { .rfmax = 617000, .val = 0x3c },
+       { .rfmax = 621000, .val = 0x3d },
+       { .rfmax = 622000, .val = 0x3e },
+       { .rfmax = 625000, .val = 0x3f },
+       { .rfmax = 632000, .val = 0x40 },
+       { .rfmax = 633000, .val = 0x41 },
+       { .rfmax = 634000, .val = 0x42 },
+       { .rfmax = 642000, .val = 0x43 },
+       { .rfmax = 643000, .val = 0x44 },
+       { .rfmax = 647000, .val = 0x45 },
+       { .rfmax = 650000, .val = 0x46 },
+       { .rfmax = 652000, .val = 0x47 },
+       { .rfmax = 657000, .val = 0x48 },
+       { .rfmax = 661000, .val = 0x49 },
+       { .rfmax = 662000, .val = 0x4a },
+       { .rfmax = 665000, .val = 0x4b },
+       { .rfmax = 667000, .val = 0x4c },
+       { .rfmax = 670000, .val = 0x4d },
+       { .rfmax = 673000, .val = 0x4e },
+       { .rfmax = 676000, .val = 0x4f },
+       { .rfmax = 677000, .val = 0x50 },
+       { .rfmax = 681000, .val = 0x51 },
+       { .rfmax = 683000, .val = 0x52 },
+       { .rfmax = 686000, .val = 0x53 },
+       { .rfmax = 688000, .val = 0x54 },
+       { .rfmax = 689000, .val = 0x55 },
+       { .rfmax = 691000, .val = 0x56 },
+       { .rfmax = 695000, .val = 0x57 },
+       { .rfmax = 698000, .val = 0x58 },
+       { .rfmax = 703000, .val = 0x59 },
+       { .rfmax = 704000, .val = 0x5a },
+       { .rfmax = 705000, .val = 0x5b },
+       { .rfmax = 707000, .val = 0x5c },
+       { .rfmax = 710000, .val = 0x5d },
+       { .rfmax = 712000, .val = 0x5e },
+       { .rfmax = 717000, .val = 0x5f },
+       { .rfmax = 718000, .val = 0x60 },
+       { .rfmax = 721000, .val = 0x61 },
+       { .rfmax = 722000, .val = 0x62 },
+       { .rfmax = 723000, .val = 0x63 },
+       { .rfmax = 725000, .val = 0x64 },
+       { .rfmax = 727000, .val = 0x65 },
+       { .rfmax = 730000, .val = 0x66 },
+       { .rfmax = 732000, .val = 0x67 },
+       { .rfmax = 735000, .val = 0x68 },
+       { .rfmax = 740000, .val = 0x69 },
+       { .rfmax = 741000, .val = 0x6a },
+       { .rfmax = 742000, .val = 0x6b },
+       { .rfmax = 743000, .val = 0x6c },
+       { .rfmax = 745000, .val = 0x6d },
+       { .rfmax = 747000, .val = 0x6e },
+       { .rfmax = 748000, .val = 0x6f },
+       { .rfmax = 750000, .val = 0x70 },
+       { .rfmax = 752000, .val = 0x71 },
+       { .rfmax = 754000, .val = 0x72 },
+       { .rfmax = 757000, .val = 0x73 },
+       { .rfmax = 758000, .val = 0x74 },
+       { .rfmax = 760000, .val = 0x75 },
+       { .rfmax = 763000, .val = 0x76 },
+       { .rfmax = 764000, .val = 0x77 },
+       { .rfmax = 766000, .val = 0x78 },
+       { .rfmax = 767000, .val = 0x79 },
+       { .rfmax = 768000, .val = 0x7a },
+       { .rfmax = 773000, .val = 0x7b },
+       { .rfmax = 774000, .val = 0x7c },
+       { .rfmax = 776000, .val = 0x7d },
+       { .rfmax = 777000, .val = 0x7e },
+       { .rfmax = 778000, .val = 0x7f },
+       { .rfmax = 779000, .val = 0x80 },
+       { .rfmax = 781000, .val = 0x81 },
+       { .rfmax = 783000, .val = 0x82 },
+       { .rfmax = 784000, .val = 0x83 },
+       { .rfmax = 785000, .val = 0x84 },
+       { .rfmax = 786000, .val = 0x85 },
+       { .rfmax = 793000, .val = 0x86 },
+       { .rfmax = 794000, .val = 0x87 },
+       { .rfmax = 795000, .val = 0x88 },
+       { .rfmax = 797000, .val = 0x89 },
+       { .rfmax = 799000, .val = 0x8a },
+       { .rfmax = 801000, .val = 0x8b },
+       { .rfmax = 802000, .val = 0x8c },
+       { .rfmax = 803000, .val = 0x8d },
+       { .rfmax = 804000, .val = 0x8e },
+       { .rfmax = 810000, .val = 0x90 },
+       { .rfmax = 811000, .val = 0x91 },
+       { .rfmax = 812000, .val = 0x92 },
+       { .rfmax = 814000, .val = 0x93 },
+       { .rfmax = 816000, .val = 0x94 },
+       { .rfmax = 817000, .val = 0x96 },
+       { .rfmax = 818000, .val = 0x97 },
+       { .rfmax = 820000, .val = 0x98 },
+       { .rfmax = 821000, .val = 0x99 },
+       { .rfmax = 822000, .val = 0x9a },
+       { .rfmax = 828000, .val = 0x9b },
+       { .rfmax = 829000, .val = 0x9d },
+       { .rfmax = 830000, .val = 0x9f },
+       { .rfmax = 831000, .val = 0xa0 },
+       { .rfmax = 833000, .val = 0xa1 },
+       { .rfmax = 835000, .val = 0xa2 },
+       { .rfmax = 836000, .val = 0xa3 },
+       { .rfmax = 837000, .val = 0xa4 },
+       { .rfmax = 838000, .val = 0xa6 },
+       { .rfmax = 840000, .val = 0xa8 },
+       { .rfmax = 842000, .val = 0xa9 },
+       { .rfmax = 845000, .val = 0xaa },
+       { .rfmax = 846000, .val = 0xab },
+       { .rfmax = 847000, .val = 0xad },
+       { .rfmax = 848000, .val = 0xae },
+       { .rfmax = 852000, .val = 0xaf },
+       { .rfmax = 853000, .val = 0xb0 },
+       { .rfmax = 858000, .val = 0xb1 },
+       { .rfmax = 860000, .val = 0xb2 },
+       { .rfmax = 861000, .val = 0xb3 },
+       { .rfmax = 862000, .val = 0xb4 },
+       { .rfmax = 863000, .val = 0xb6 },
+       { .rfmax = 864000, .val = 0xb8 },
+       { .rfmax = 865000, .val = 0xb9 },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_ir_measure[] = {
+       { .rfmax =  30000, .val = 4 },
+       { .rfmax = 200000, .val = 5 },
+       { .rfmax = 600000, .val = 6 },
+       { .rfmax = 865000, .val = 7 },
+       { .rfmax =      0, .val = 0 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
+       { .rfmax =  47900, .val = 0x00 },
+       { .rfmax =  55000, .val = 0x00 },
+       { .rfmax =  61100, .val = 0x0a },
+       { .rfmax =  64000, .val = 0x0a },
+       { .rfmax =  82000, .val = 0x14 },
+       { .rfmax =  84000, .val = 0x19 },
+       { .rfmax = 119000, .val = 0x1c },
+       { .rfmax = 124000, .val = 0x20 },
+       { .rfmax = 129000, .val = 0x2a },
+       { .rfmax = 134000, .val = 0x32 },
+       { .rfmax = 139000, .val = 0x39 },
+       { .rfmax = 144000, .val = 0x3e },
+       { .rfmax = 149000, .val = 0x3f },
+       { .rfmax = 152600, .val = 0x40 },
+       { .rfmax = 154000, .val = 0x40 },
+       { .rfmax = 164700, .val = 0x41 },
+       { .rfmax = 203500, .val = 0x32 },
+       { .rfmax = 353000, .val = 0x19 },
+       { .rfmax = 356000, .val = 0x1a },
+       { .rfmax = 359000, .val = 0x1b },
+       { .rfmax = 363000, .val = 0x1c },
+       { .rfmax = 366000, .val = 0x1d },
+       { .rfmax = 369000, .val = 0x1e },
+       { .rfmax = 373000, .val = 0x1f },
+       { .rfmax = 376000, .val = 0x20 },
+       { .rfmax = 379000, .val = 0x21 },
+       { .rfmax = 383000, .val = 0x22 },
+       { .rfmax = 386000, .val = 0x23 },
+       { .rfmax = 389000, .val = 0x24 },
+       { .rfmax = 393000, .val = 0x25 },
+       { .rfmax = 396000, .val = 0x26 },
+       { .rfmax = 399000, .val = 0x27 },
+       { .rfmax = 402000, .val = 0x28 },
+       { .rfmax = 404000, .val = 0x29 },
+       { .rfmax = 407000, .val = 0x2a },
+       { .rfmax = 409000, .val = 0x2b },
+       { .rfmax = 412000, .val = 0x2c },
+       { .rfmax = 414000, .val = 0x2d },
+       { .rfmax = 417000, .val = 0x2e },
+       { .rfmax = 419000, .val = 0x2f },
+       { .rfmax = 422000, .val = 0x30 },
+       { .rfmax = 424000, .val = 0x31 },
+       { .rfmax = 427000, .val = 0x32 },
+       { .rfmax = 429000, .val = 0x33 },
+       { .rfmax = 432000, .val = 0x34 },
+       { .rfmax = 434000, .val = 0x35 },
+       { .rfmax = 437000, .val = 0x36 },
+       { .rfmax = 439000, .val = 0x37 },
+       { .rfmax = 442000, .val = 0x38 },
+       { .rfmax = 444000, .val = 0x39 },
+       { .rfmax = 447000, .val = 0x3a },
+       { .rfmax = 449000, .val = 0x3b },
+       { .rfmax = 457800, .val = 0x3c },
+       { .rfmax = 465000, .val = 0x0f },
+       { .rfmax = 477000, .val = 0x12 },
+       { .rfmax = 483000, .val = 0x14 },
+       { .rfmax = 502000, .val = 0x19 },
+       { .rfmax = 508000, .val = 0x1b },
+       { .rfmax = 519000, .val = 0x1c },
+       { .rfmax = 522000, .val = 0x1d },
+       { .rfmax = 524000, .val = 0x1e },
+       { .rfmax = 534000, .val = 0x1f },
+       { .rfmax = 549000, .val = 0x20 },
+       { .rfmax = 554000, .val = 0x22 },
+       { .rfmax = 584000, .val = 0x24 },
+       { .rfmax = 589000, .val = 0x26 },
+       { .rfmax = 658000, .val = 0x27 },
+       { .rfmax = 664000, .val = 0x2c },
+       { .rfmax = 669000, .val = 0x2d },
+       { .rfmax = 699000, .val = 0x2e },
+       { .rfmax = 704000, .val = 0x30 },
+       { .rfmax = 709000, .val = 0x31 },
+       { .rfmax = 714000, .val = 0x32 },
+       { .rfmax = 724000, .val = 0x33 },
+       { .rfmax = 729000, .val = 0x36 },
+       { .rfmax = 739000, .val = 0x38 },
+       { .rfmax = 744000, .val = 0x39 },
+       { .rfmax = 749000, .val = 0x3b },
+       { .rfmax = 754000, .val = 0x3c },
+       { .rfmax = 759000, .val = 0x3d },
+       { .rfmax = 764000, .val = 0x3e },
+       { .rfmax = 769000, .val = 0x3f },
+       { .rfmax = 774000, .val = 0x40 },
+       { .rfmax = 779000, .val = 0x41 },
+       { .rfmax = 784000, .val = 0x43 },
+       { .rfmax = 789000, .val = 0x46 },
+       { .rfmax = 794000, .val = 0x48 },
+       { .rfmax = 799000, .val = 0x4b },
+       { .rfmax = 804000, .val = 0x4f },
+       { .rfmax = 809000, .val = 0x54 },
+       { .rfmax = 814000, .val = 0x59 },
+       { .rfmax = 819000, .val = 0x5d },
+       { .rfmax = 824000, .val = 0x61 },
+       { .rfmax = 829000, .val = 0x68 },
+       { .rfmax = 834000, .val = 0x6e },
+       { .rfmax = 839000, .val = 0x75 },
+       { .rfmax = 844000, .val = 0x7e },
+       { .rfmax = 849000, .val = 0x82 },
+       { .rfmax = 854000, .val = 0x84 },
+       { .rfmax = 859000, .val = 0x8f },
+       { .rfmax = 865000, .val = 0x9a },
+       { .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_thermo_map {
+       u8 d;
+       u8 r0;
+       u8 r1;
+};
+
+static struct tda18271_thermo_map tda18271_thermometer[] = {
+       { .d = 0x00, .r0 = 60, .r1 =  92 },
+       { .d = 0x01, .r0 = 62, .r1 =  94 },
+       { .d = 0x02, .r0 = 66, .r1 =  98 },
+       { .d = 0x03, .r0 = 64, .r1 =  96 },
+       { .d = 0x04, .r0 = 74, .r1 = 106 },
+       { .d = 0x05, .r0 = 72, .r1 = 104 },
+       { .d = 0x06, .r0 = 68, .r1 = 100 },
+       { .d = 0x07, .r0 = 70, .r1 = 102 },
+       { .d = 0x08, .r0 = 90, .r1 = 122 },
+       { .d = 0x09, .r0 = 88, .r1 = 120 },
+       { .d = 0x0a, .r0 = 84, .r1 = 116 },
+       { .d = 0x0b, .r0 = 86, .r1 = 118 },
+       { .d = 0x0c, .r0 = 76, .r1 = 108 },
+       { .d = 0x0d, .r0 = 78, .r1 = 110 },
+       { .d = 0x0e, .r0 = 82, .r1 = 114 },
+       { .d = 0x0f, .r0 = 80, .r1 = 112 },
+       { .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
+};
+
+int tda18271_lookup_thermometer(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       unsigned char *regs = priv->tda18271_regs;
+       int val, i = 0;
+
+       while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
+               if (tda18271_thermometer[i + 1].d == 0)
+                       break;
+               i++;
+       }
+
+       if ((regs[R_TM] & 0x20) == 0x20)
+               val = tda18271_thermometer[i].r1;
+       else
+               val = tda18271_thermometer[i].r0;
+
+       tda_map("(%d) tm = %d\n", i, val);
+
+       return val;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_cid_target_map {
+       u32 rfmax;
+       u8  target;
+       u16 limit;
+};
+
+static struct tda18271_cid_target_map tda18271_cid_target[] = {
+       { .rfmax =  46000, .target = 0x04, .limit =  1800 },
+       { .rfmax =  52200, .target = 0x0a, .limit =  1500 },
+       { .rfmax =  79100, .target = 0x01, .limit =  4000 },
+       { .rfmax = 136800, .target = 0x18, .limit =  4000 },
+       { .rfmax = 156700, .target = 0x18, .limit =  4000 },
+       { .rfmax = 156700, .target = 0x18, .limit =  4000 },
+       { .rfmax = 186250, .target = 0x0a, .limit =  4000 },
+       { .rfmax = 230000, .target = 0x0a, .limit =  4000 },
+       { .rfmax = 345000, .target = 0x18, .limit =  4000 },
+       { .rfmax = 426000, .target = 0x0e, .limit =  4000 },
+       { .rfmax = 489500, .target = 0x1e, .limit =  4000 },
+       { .rfmax = 697500, .target = 0x32, .limit =  4000 },
+       { .rfmax = 842000, .target = 0x3a, .limit =  4000 },
+       { .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
+};
+
+int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+                              u32 *freq, u8 *cid_target, u16 *count_limit)
+{
+       int i = 0;
+
+       while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
+               if (tda18271_cid_target[i + 1].rfmax == 0)
+                       break;
+               i++;
+       }
+       *cid_target  = tda18271_cid_target[i].target;
+       *count_limit = tda18271_cid_target[i].limit;
+
+       tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
+               tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
+
+       return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
+       { .rfmax =  47900, .rfband = 0x00,
+         .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
+       { .rfmax =  61100, .rfband = 0x01,
+         .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
+       { .rfmax = 152600, .rfband = 0x02,
+         .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
+       { .rfmax = 164700, .rfband = 0x03,
+         .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
+       { .rfmax = 203500, .rfband = 0x04,
+         .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
+       { .rfmax = 457800, .rfband = 0x05,
+         .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
+       { .rfmax = 865000, .rfband = 0x06,
+         .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
+       { .rfmax =      0, .rfband = 0x00,
+         .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
+};
+
+int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+       int i = 0;
+
+       while ((map[i].rfmax * 1000) < *freq) {
+               if (tda18271_debug & DBG_ADV)
+                       tda_map("(%d) rfmax = %d < freq = %d, "
+                               "rf1_def = %d, rf2_def = %d, rf3_def = %d, "
+                               "rf1 = %d, rf2 = %d, rf3 = %d, "
+                               "rf_a1 = %d, rf_a2 = %d, "
+                               "rf_b1 = %d, rf_b2 = %d\n",
+                               i, map[i].rfmax * 1000, *freq,
+                               map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
+                               map[i].rf1, map[i].rf2, map[i].rf3,
+                               map[i].rf_a1, map[i].rf_a2,
+                               map[i].rf_b1, map[i].rf_b2);
+               if (map[i].rfmax == 0)
+                       return -EINVAL;
+               i++;
+       }
+       if (rf_band)
+               *rf_band = map[i].rfband;
+
+       tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
+
+       return i;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_map_layout {
+       struct tda18271_pll_map *main_pll;
+       struct tda18271_pll_map *cal_pll;
+
+       struct tda18271_map *rf_cal;
+       struct tda18271_map *rf_cal_kmco;
+       struct tda18271_map *rf_cal_dc_over_dt;
+
+       struct tda18271_map *bp_filter;
+       struct tda18271_map *rf_band;
+       struct tda18271_map *gain_taper;
+       struct tda18271_map *ir_measure;
+};
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+                           enum tda18271_map_type map_type,
+                           u32 *freq, u8 *post_div, u8 *div)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_pll_map *map = NULL;
+       unsigned int i = 0;
+       char *map_name;
+       int ret = 0;
+
+       BUG_ON(!priv->maps);
+
+       switch (map_type) {
+       case MAIN_PLL:
+               map = priv->maps->main_pll;
+               map_name = "main_pll";
+               break;
+       case CAL_PLL:
+               map = priv->maps->cal_pll;
+               map_name = "cal_pll";
+               break;
+       default:
+               /* we should never get here */
+               map_name = "undefined";
+               break;
+       }
+
+       if (!map) {
+               tda_warn("%s map is not set!\n", map_name);
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       while ((map[i].lomax * 1000) < *freq) {
+               if (map[i + 1].lomax == 0) {
+                       tda_map("%s: frequency (%d) out of range\n",
+                               map_name, *freq);
+                       ret = -ERANGE;
+                       break;
+               }
+               i++;
+       }
+       *post_div = map[i].pd;
+       *div      = map[i].d;
+
+       tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
+               i, map_name, *post_div, *div);
+fail:
+       return ret;
+}
+
+int tda18271_lookup_map(struct dvb_frontend *fe,
+                       enum tda18271_map_type map_type,
+                       u32 *freq, u8 *val)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       struct tda18271_map *map = NULL;
+       unsigned int i = 0;
+       char *map_name;
+       int ret = 0;
+
+       BUG_ON(!priv->maps);
+
+       switch (map_type) {
+       case BP_FILTER:
+               map = priv->maps->bp_filter;
+               map_name = "bp_filter";
+               break;
+       case RF_CAL_KMCO:
+               map = priv->maps->rf_cal_kmco;
+               map_name = "km";
+               break;
+       case RF_BAND:
+               map = priv->maps->rf_band;
+               map_name = "rf_band";
+               break;
+       case GAIN_TAPER:
+               map = priv->maps->gain_taper;
+               map_name = "gain_taper";
+               break;
+       case RF_CAL:
+               map = priv->maps->rf_cal;
+               map_name = "rf_cal";
+               break;
+       case IR_MEASURE:
+               map = priv->maps->ir_measure;
+               map_name = "ir_measure";
+               break;
+       case RF_CAL_DC_OVER_DT:
+               map = priv->maps->rf_cal_dc_over_dt;
+               map_name = "rf_cal_dc_over_dt";
+               break;
+       default:
+               /* we should never get here */
+               map_name = "undefined";
+               break;
+       }
+
+       if (!map) {
+               tda_warn("%s map is not set!\n", map_name);
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       while ((map[i].rfmax * 1000) < *freq) {
+               if (map[i + 1].rfmax == 0) {
+                       tda_map("%s: frequency (%d) out of range\n",
+                               map_name, *freq);
+                       ret = -ERANGE;
+                       break;
+               }
+               i++;
+       }
+       *val = map[i].val;
+
+       tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
+fail:
+       return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_std_map tda18271c1_std_map = {
+       .fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
+       .atv_b    = { .if_freq = 6750, .std_bits = 0x0e },
+       .atv_dk   = { .if_freq = 7750, .std_bits = 0x0f },
+       .atv_gh   = { .if_freq = 7750, .std_bits = 0x0f },
+       .atv_i    = { .if_freq = 7750, .std_bits = 0x0f },
+       .atv_l    = { .if_freq = 7750, .std_bits = 0x0f },
+       .atv_lc   = { .if_freq = 1250, .std_bits = 0x0f },
+       .atv_mn   = { .if_freq = 5750, .std_bits = 0x0d },
+       .atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
+       .dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
+       .dvbt_7   = { .if_freq = 3800, .std_bits = 0x1d },
+       .dvbt_8   = { .if_freq = 4300, .std_bits = 0x1e },
+       .qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
+       .qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+};
+
+static struct tda18271_std_map tda18271c2_std_map = {
+       .fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
+       .atv_b    = { .if_freq = 6000, .std_bits = 0x0d },
+       .atv_dk   = { .if_freq = 6900, .std_bits = 0x0e },
+       .atv_gh   = { .if_freq = 7100, .std_bits = 0x0e },
+       .atv_i    = { .if_freq = 7250, .std_bits = 0x0e },
+       .atv_l    = { .if_freq = 6900, .std_bits = 0x0e },
+       .atv_lc   = { .if_freq = 1250, .std_bits = 0x0e },
+       .atv_mn   = { .if_freq = 5400, .std_bits = 0x0c },
+       .atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
+       .dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
+       .dvbt_7   = { .if_freq = 3500, .std_bits = 0x1c },
+       .dvbt_8   = { .if_freq = 4000, .std_bits = 0x1d },
+       .qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
+       .qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_map_layout tda18271c1_map_layout = {
+       .main_pll          = tda18271c1_main_pll,
+       .cal_pll           = tda18271c1_cal_pll,
+
+       .rf_cal            = tda18271c1_rf_cal,
+       .rf_cal_kmco       = tda18271c1_km,
+
+       .bp_filter         = tda18271_bp_filter,
+       .rf_band           = tda18271_rf_band,
+       .gain_taper        = tda18271_gain_taper,
+       .ir_measure        = tda18271_ir_measure,
+};
+
+static struct tda18271_map_layout tda18271c2_map_layout = {
+       .main_pll          = tda18271c2_main_pll,
+       .cal_pll           = tda18271c2_cal_pll,
+
+       .rf_cal            = tda18271c2_rf_cal,
+       .rf_cal_kmco       = tda18271c2_km,
+
+       .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
+
+       .bp_filter         = tda18271_bp_filter,
+       .rf_band           = tda18271_rf_band,
+       .gain_taper        = tda18271_gain_taper,
+       .ir_measure        = tda18271_ir_measure,
+};
+
+int tda18271_assign_map_layout(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       int ret = 0;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               priv->maps = &tda18271c1_map_layout;
+               memcpy(&priv->std, &tda18271c1_std_map,
+                      sizeof(struct tda18271_std_map));
+               break;
+       case TDA18271HDC2:
+               priv->maps = &tda18271c2_map_layout;
+               memcpy(&priv->std, &tda18271c2_std_map,
+                      sizeof(struct tda18271_std_map));
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
+              sizeof(tda18271_rf_band_template));
+
+       return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h
new file mode 100644 (file)
index 0000000..24b0e35
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA18271_H__
+#define __TDA18271_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda18271_std_map_item {
+       u16 if_freq;
+       u8 std_bits;
+};
+
+struct tda18271_std_map {
+       struct tda18271_std_map_item fm_radio;
+       struct tda18271_std_map_item atv_b;
+       struct tda18271_std_map_item atv_dk;
+       struct tda18271_std_map_item atv_gh;
+       struct tda18271_std_map_item atv_i;
+       struct tda18271_std_map_item atv_l;
+       struct tda18271_std_map_item atv_lc;
+       struct tda18271_std_map_item atv_mn;
+       struct tda18271_std_map_item atsc_6;
+       struct tda18271_std_map_item dvbt_6;
+       struct tda18271_std_map_item dvbt_7;
+       struct tda18271_std_map_item dvbt_8;
+       struct tda18271_std_map_item qam_6;
+       struct tda18271_std_map_item qam_8;
+};
+
+enum tda18271_i2c_gate {
+       TDA18271_GATE_AUTO = 0,
+       TDA18271_GATE_ANALOG,
+       TDA18271_GATE_DIGITAL,
+};
+
+struct tda18271_config {
+       /* override default if freq / std settings (optional) */
+       struct tda18271_std_map *std_map;
+
+       /* use i2c gate provided by analog or digital demod */
+       enum tda18271_i2c_gate gate;
+};
+
+#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+                                           struct i2c_adapter *i2c,
+                                           struct tda18271_config *cfg);
+#else
+static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
+                                                  u8 addr,
+                                                  struct i2c_adapter *i2c,
+                                                  struct tda18271_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       return NULL;
+}
+#endif
+
+#endif /* __TDA18271_H__ */
index 256fc4bf500b17f44fe368f0ffcfa0623fb5a340..229b11987a589fed652c00934c91101f59867eeb 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/dvb/frontend.h>
 #include <asm/types.h>
+#include <linux/dvb/frontend.h>
+#include <linux/videodev2.h>
 
 #include "tda827x.h"
 
 static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
 #define dprintk(args...) \
        do {                                        \
                if (debug) printk(KERN_DEBUG "tda827x: " args); \
@@ -34,10 +38,57 @@ struct tda827x_priv {
        int i2c_addr;
        struct i2c_adapter *i2c_adap;
        struct tda827x_config *cfg;
+
+       unsigned int sgIF;
+       unsigned char lpsel;
+
        u32 frequency;
        u32 bandwidth;
 };
 
+static void tda827x_set_std(struct dvb_frontend *fe,
+                           struct analog_parameters *params)
+{
+       struct tda827x_priv *priv = fe->tuner_priv;
+       char *mode;
+
+       priv->lpsel = 0;
+       if (params->std & V4L2_STD_MN) {
+               priv->sgIF = 92;
+               priv->lpsel = 1;
+               mode = "MN";
+       } else if (params->std & V4L2_STD_B) {
+               priv->sgIF = 108;
+               mode = "B";
+       } else if (params->std & V4L2_STD_GH) {
+               priv->sgIF = 124;
+               mode = "GH";
+       } else if (params->std & V4L2_STD_PAL_I) {
+               priv->sgIF = 124;
+               mode = "I";
+       } else if (params->std & V4L2_STD_DK) {
+               priv->sgIF = 124;
+               mode = "DK";
+       } else if (params->std & V4L2_STD_SECAM_L) {
+               priv->sgIF = 124;
+               mode = "L";
+       } else if (params->std & V4L2_STD_SECAM_LC) {
+               priv->sgIF = 20;
+               mode = "LC";
+       } else {
+               priv->sgIF = 124;
+               mode = "xx";
+       }
+
+       if (params->mode == V4L2_TUNER_RADIO)
+               priv->sgIF = 88; /* if frequency is 5.5 MHz */
+
+       dprintk("setting tda827x to system %s\n", mode);
+}
+
+
+/* ------------------------------------------------------------------ */
+
 struct tda827x_data {
        u32 lomax;
        u8  spd;
@@ -48,7 +99,7 @@ struct tda827x_data {
        u8 div1p5;
 };
 
-static const struct tda827x_data tda827x_dvbt[] = {
+static const struct tda827x_data tda827x_table[] = {
        { .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
        { .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
        { .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
@@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
        tuner_freq = params->frequency + if_freq;
 
        i = 0;
-       while (tda827x_dvbt[i].lomax < tuner_freq) {
-               if(tda827x_dvbt[i + 1].lomax == 0)
+       while (tda827x_table[i].lomax < tuner_freq) {
+               if (tda827x_table[i + 1].lomax == 0)
                        break;
                i++;
        }
 
-       N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
+       N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
        buf[0] = 0;
        buf[1] = (N>>8) | 0x40;
        buf[2] = N & 0xff;
        buf[3] = 0;
        buf[4] = 0x52;
-       buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
-                               (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
-       buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
+       buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
+                               (tda827x_table[i].bs << 3) +
+                               tda827x_table[i].bp;
+       buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
        buf[7] = 0xbf;
        buf[8] = 0x2a;
        buf[9] = 0x05;
@@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
        msleep(500);
        /* correct CP value */
        buf[0] = 0x30;
-       buf[1] = 0x50 + tda827x_dvbt[i].cp;
+       buf[1] = 0x50 + tda827x_table[i].cp;
        msg.len = 2;
 
        if (fe->ops.i2c_gate_ctrl)
@@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
 
 /* ------------------------------------------------------------------ */
 
+static int tda827xo_set_analog_params(struct dvb_frontend *fe,
+                                     struct analog_parameters *params)
+{
+       unsigned char tuner_reg[8];
+       unsigned char reg2[2];
+       u32 N;
+       int i;
+       struct tda827x_priv *priv = fe->tuner_priv;
+       struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
+       unsigned int freq = params->frequency;
+
+       tda827x_set_std(fe, params);
+
+       if (params->mode == V4L2_TUNER_RADIO)
+               freq = freq / 1000;
+
+       N = freq + priv->sgIF;
+
+       i = 0;
+       while (tda827x_table[i].lomax < N * 62500) {
+               if (tda827x_table[i + 1].lomax == 0)
+                       break;
+               i++;
+       }
+
+       N = N << tda827x_table[i].spd;
+
+       tuner_reg[0] = 0;
+       tuner_reg[1] = (unsigned char)(N>>8);
+       tuner_reg[2] = (unsigned char) N;
+       tuner_reg[3] = 0x40;
+       tuner_reg[4] = 0x52 + (priv->lpsel << 5);
+       tuner_reg[5] = (tda827x_table[i].spd    << 6) +
+                      (tda827x_table[i].div1p5 << 5) +
+                      (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
+       tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
+       tuner_reg[7] = 0x8f;
+
+       msg.buf = tuner_reg;
+       msg.len = 8;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       msg.buf = reg2;
+       msg.len = 2;
+       reg2[0] = 0x80;
+       reg2[1] = 0;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       reg2[0] = 0x60;
+       reg2[1] = 0xbf;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       reg2[0] = 0x30;
+       reg2[1] = tuner_reg[4] + 0x80;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       msleep(1);
+       reg2[0] = 0x30;
+       reg2[1] = tuner_reg[4] + 4;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       msleep(1);
+       reg2[0] = 0x30;
+       reg2[1] = tuner_reg[4];
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       msleep(550);
+       reg2[0] = 0x30;
+       reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       reg2[0] = 0x60;
+       reg2[1] = 0x3f;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       reg2[0] = 0x80;
+       reg2[1] = 0x08;   /* Vsync en */
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       priv->frequency = freq * 62500;
+
+       return 0;
+}
+
+static void tda827xo_agcf(struct dvb_frontend *fe)
+{
+       struct tda827x_priv *priv = fe->tuner_priv;
+       unsigned char data[] = { 0x80, 0x0c };
+       struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+                              .buf = data, .len = 2};
+
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
 struct tda827xa_data {
        u32 lomax;
        u8  svco;
@@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
        { .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
 };
 
+static struct tda827xa_data tda827xa_analog[] = {
+       { .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
+       { .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+       { .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+       { .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+       { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+       { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
+       { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
+       { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+       { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+       { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+       { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+       { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+       { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+       { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+       { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+       { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+       { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+       { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+       { .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
 static int tda827xa_set_params(struct dvb_frontend *fe,
                               struct dvb_frontend_parameters *params)
 {
@@ -368,6 +545,163 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
+/* ------------------------------------------------------------------ */
+
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+                             struct analog_parameters *params)
+{
+       struct tda827x_priv *priv = fe->tuner_priv;
+       unsigned char buf[] = {0x22, 0x01};
+       int arg;
+       struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+                              .buf = buf, .len = sizeof(buf) };
+
+       if (NULL == priv->cfg) {
+               dprintk("tda827x_config not defined, cannot set LNA gain!\n");
+               return;
+       }
+
+       if (priv->cfg->config) {
+               if (high)
+                       dprintk("setting LNA to high gain\n");
+               else
+                       dprintk("setting LNA to low gain\n");
+       }
+       switch (*priv->cfg->config) {
+       case 0: /* no LNA */
+               break;
+       case 1: /* switch is GPIO 0 of tda8290 */
+       case 2:
+               /* turn Vsync on */
+               if (params->std & V4L2_STD_MN)
+                       arg = 1;
+               else
+                       arg = 0;
+               if (priv->cfg->tuner_callback)
+                       priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+                                                 1, arg);
+               buf[1] = high ? 0 : 1;
+               if (*priv->cfg->config == 2)
+                       buf[1] = high ? 1 : 0;
+               i2c_transfer(priv->i2c_adap, &msg, 1);
+               break;
+       case 3: /* switch with GPIO of saa713x */
+               if (priv->cfg->tuner_callback)
+                       priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+                                                 0, high);
+               break;
+       }
+}
+
+static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+                                     struct analog_parameters *params)
+{
+       unsigned char tuner_reg[11];
+       u32 N;
+       int i;
+       struct tda827x_priv *priv = fe->tuner_priv;
+       struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+                              .buf = tuner_reg, .len = sizeof(tuner_reg) };
+       unsigned int freq = params->frequency;
+
+       tda827x_set_std(fe, params);
+
+       tda827xa_lna_gain(fe, 1, params);
+       msleep(10);
+
+       if (params->mode == V4L2_TUNER_RADIO)
+               freq = freq / 1000;
+
+       N = freq + priv->sgIF;
+
+       i = 0;
+       while (tda827xa_analog[i].lomax < N * 62500) {
+               if (tda827xa_analog[i + 1].lomax == 0)
+                       break;
+               i++;
+       }
+
+       N = N << tda827xa_analog[i].spd;
+
+       tuner_reg[0] = 0;
+       tuner_reg[1] = (unsigned char)(N>>8);
+       tuner_reg[2] = (unsigned char) N;
+       tuner_reg[3] = 0;
+       tuner_reg[4] = 0x16;
+       tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
+                      (tda827xa_analog[i].svco << 3) +
+                       tda827xa_analog[i].sbs;
+       tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+       tuner_reg[7] = 0x1c;
+       tuner_reg[8] = 4;
+       tuner_reg[9] = 0x20;
+       tuner_reg[10] = 0x00;
+       msg.len = 11;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tuner_reg[0] = 0x90;
+       tuner_reg[1] = 0xff;
+       tuner_reg[2] = 0xe0;
+       tuner_reg[3] = 0;
+       tuner_reg[4] = 0x99 + (priv->lpsel << 1);
+       msg.len = 5;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tuner_reg[0] = 0xa0;
+       tuner_reg[1] = 0xc0;
+       msg.len = 2;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tuner_reg[0] = 0x30;
+       tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       msg.flags = I2C_M_RD;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+       msg.flags = 0;
+       tuner_reg[1] >>= 4;
+       dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
+       if (tuner_reg[1] < 1)
+               tda827xa_lna_gain(fe, 0, params);
+
+       msleep(100);
+       tuner_reg[0] = 0x60;
+       tuner_reg[1] = 0x3c;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       msleep(163);
+       tuner_reg[0] = 0x50;
+       tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tuner_reg[0] = 0x80;
+       tuner_reg[1] = 0x28;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tuner_reg[0] = 0xb0;
+       tuner_reg[1] = 0x01;
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       tuner_reg[0] = 0xc0;
+       tuner_reg[1] = 0x19 + (priv->lpsel << 1);
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+
+       priv->frequency = freq * 62500;
+
+       return 0;
+}
+
+static void tda827xa_agcf(struct dvb_frontend *fe)
+{
+       struct tda827x_priv *priv = fe->tuner_priv;
+       unsigned char data[] = {0x80, 0x2c};
+       struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
+                             .buf = data, .len = 2};
+       i2c_transfer(priv->i2c_adap, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
 static int tda827x_release(struct dvb_frontend *fe)
 {
        kfree(fe->tuner_priv);
@@ -430,6 +764,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = {
        .init = tda827x_initial_init,
        .sleep = tda827x_initial_sleep,
        .set_params = tda827xo_set_params,
+       .set_analog_params = tda827xo_set_analog_params,
        .get_frequency = tda827x_get_frequency,
        .get_bandwidth = tda827x_get_bandwidth,
 };
@@ -445,6 +780,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
        .init = tda827x_init,
        .sleep = tda827xa_sleep,
        .set_params = tda827xa_set_params,
+       .set_analog_params = tda827xa_set_analog_params,
        .get_frequency = tda827x_get_frequency,
        .get_bandwidth = tda827x_get_bandwidth,
 };
@@ -465,9 +801,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe)
                dprintk("tda827x tuner found\n");
                fe->ops.tuner_ops.init  = tda827x_init;
                fe->ops.tuner_ops.sleep = tda827xo_sleep;
+               if (priv->cfg)
+                       priv->cfg->agcf = tda827xo_agcf;
        } else {
                dprintk("tda827xa tuner found\n");
                memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
+               if (priv->cfg)
+                       priv->cfg->agcf = tda827xa_agcf;
        }
        return 0;
 }
@@ -487,16 +827,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
        priv->i2c_adap = i2c;
        priv->cfg = cfg;
        memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
-
        fe->tuner_priv = priv;
 
+       dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
+
        return fe;
 }
-
-EXPORT_SYMBOL(tda827x_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+EXPORT_SYMBOL_GPL(tda827x_attach);
 
 MODULE_DESCRIPTION("DVB TDA827x driver");
 MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
index 69e8263d6d594ad9f75968e7bacb3d89635ef52e..92eb65b4012b37dcb28abb204f132ac34d8b1c29 100644 (file)
 
 struct tda827x_config
 {
+       /* saa7134 - provided callbacks */
        void (*lna_gain) (struct dvb_frontend *fe, int high);
        int (*init) (struct dvb_frontend *fe);
        int (*sleep) (struct dvb_frontend *fe);
+
+       /* interface to tda829x driver */
+       unsigned int *config;
+       int (*tuner_callback) (void *dev, int command, int arg);
+
+       void (*agcf)(struct dvb_frontend *fe);
 };
 
 
index 60433b5011fde27e1ddaadc6279a40165352e379..8791701c8f25c8a9288d842ae865c4ba6bd656aa 100644 (file)
@@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
        ret = i2c_transfer(state->i2c, &msg, 1);
 
        if (ret != 1)
-               printk("ves1820: %s(): writereg error (reg == 0x%02x,"
+               printk("ves1820: %s(): writereg error (reg == 0x%02x, "
                        "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
 
        return (ret != 1) ? -EREMOTEIO : 0;
@@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
        ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2)
-               printk("ves1820: %s(): readreg error (reg == 0x%02x,"
+               printk("ves1820: %s(): readreg error (reg == 0x%02x, "
                "ret == %i)\n", __FUNCTION__, reg, ret);
 
        return b1[0];
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c
new file mode 100644 (file)
index 0000000..f642ca2
--- /dev/null
@@ -0,0 +1,964 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "xc5000.h"
+#include "xc5000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+       printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
+
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+
+/* Misc Defines */
+#define MAX_TV_STANDARD                        23
+#define XC_MAX_I2C_WRITE_LENGTH                64
+
+/* Signal Types */
+#define XC_RF_MODE_AIR                 0
+#define XC_RF_MODE_CABLE               1
+
+/* Result codes */
+#define XC_RESULT_SUCCESS              0
+#define XC_RESULT_RESET_FAILURE                1
+#define XC_RESULT_I2C_WRITE_FAILURE    2
+#define XC_RESULT_I2C_READ_FAILURE     3
+#define XC_RESULT_OUT_OF_RANGE         5
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED    0x2000
+#define XC_PRODUCT_ID_FW_LOADED        0x1388
+
+/* Registers */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_IF_OUT       0x05
+#define XREG_SEEK_MODE    0x07
+#define XREG_POWER_DOWN   0x0A
+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_XTALFREQ     0x0F
+#define XREG_FINERFFREQ   0x10
+#define XREG_DDIMODE      0x11
+
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+#define XREG_BUSY         0x09
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+
+*/
+typedef struct {
+       char *Name;
+       u16 AudioMode;
+       u16 VideoMode;
+} XC_TV_STANDARD;
+
+/* Tuner standards */
+#define MN_NTSC_PAL_BTSC       0
+#define MN_NTSC_PAL_A2         1
+#define MN_NTSC_PAL_EIAJ       2
+#define MN_NTSC_PAL_Mono       3
+#define BG_PAL_A2              4
+#define BG_PAL_NICAM           5
+#define BG_PAL_MONO            6
+#define I_PAL_NICAM            7
+#define I_PAL_NICAM_MONO       8
+#define DK_PAL_A2              9
+#define DK_PAL_NICAM           10
+#define DK_PAL_MONO            11
+#define DK_SECAM_A2DK1         12
+#define DK_SECAM_A2LDK3        13
+#define DK_SECAM_A2MONO        14
+#define L_SECAM_NICAM          15
+#define LC_SECAM_NICAM         16
+#define DTV6                   17
+#define DTV8                   18
+#define DTV7_8                 19
+#define DTV7                   20
+#define FM_Radio_INPUT2        21
+#define FM_Radio_INPUT1        22
+
+XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+       {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
+       {"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
+       {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
+       {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
+       {"B/G-PAL-A2",        0x0A00, 0x8049},
+       {"B/G-PAL-NICAM",     0x0C04, 0x8049},
+       {"B/G-PAL-MONO",      0x0878, 0x8059},
+       {"I-PAL-NICAM",       0x1080, 0x8009},
+       {"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
+       {"D/K-PAL-A2",        0x1600, 0x8009},
+       {"D/K-PAL-NICAM",     0x0E80, 0x8009},
+       {"D/K-PAL-MONO",      0x1478, 0x8009},
+       {"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
+       {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+       {"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
+       {"L-SECAM-NICAM",     0x8E82, 0x0009},
+       {"L'-SECAM-NICAM",    0x8E82, 0x4009},
+       {"DTV6",              0x00C0, 0x8002},
+       {"DTV8",              0x00C0, 0x800B},
+       {"DTV7/8",            0x00C0, 0x801B},
+       {"DTV7",              0x00C0, 0x8007},
+       {"FM Radio-INPUT2",   0x9802, 0x9002},
+       {"FM Radio-INPUT1",   0x0208, 0x9002}
+};
+
+static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static void xc5000_TunerReset(struct dvb_frontend *fe);
+
+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+       return xc5000_writeregs(priv, buf, len)
+               ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+       return xc5000_readregs(priv, buf, len)
+               ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_reset(struct dvb_frontend *fe)
+{
+       xc5000_TunerReset(fe);
+       return XC_RESULT_SUCCESS;
+}
+
+static void xc_wait(int wait_ms)
+{
+       msleep(wait_ms);
+}
+
+static void xc5000_TunerReset(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       if (priv->cfg->tuner_callback) {
+               ret = priv->cfg->tuner_callback(priv->cfg->priv,
+                                               XC5000_TUNER_RESET, 0);
+               if (ret)
+                       printk(KERN_ERR "xc5000: reset failed\n");
+       } else
+               printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+}
+
+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+{
+       u8 buf[4];
+       int WatchDogTimer = 5;
+       int result;
+
+       buf[0] = (regAddr >> 8) & 0xFF;
+       buf[1] = regAddr & 0xFF;
+       buf[2] = (i2cData >> 8) & 0xFF;
+       buf[3] = i2cData & 0xFF;
+       result = xc_send_i2c_data(priv, buf, 4);
+       if (result == XC_RESULT_SUCCESS) {
+               /* wait for busy flag to clear */
+               while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+                       buf[0] = 0;
+                       buf[1] = XREG_BUSY;
+
+                       result = xc_send_i2c_data(priv, buf, 2);
+                       if (result == XC_RESULT_SUCCESS) {
+                               result = xc_read_i2c_data(priv, buf, 2);
+                               if (result == XC_RESULT_SUCCESS) {
+                                       if ((buf[0] == 0) && (buf[1] == 0)) {
+                                               /* busy flag cleared */
+                                       break;
+                                       } else {
+                                               xc_wait(100); /* wait 5 ms */
+                                               WatchDogTimer--;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (WatchDogTimer < 0)
+               result = XC_RESULT_I2C_WRITE_FAILURE;
+
+       return result;
+}
+
+static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
+{
+       u8 buf[2];
+       int result;
+
+       buf[0] = (regAddr >> 8) & 0xFF;
+       buf[1] = regAddr & 0xFF;
+       result = xc_send_i2c_data(priv, buf, 2);
+       if (result != XC_RESULT_SUCCESS)
+               return result;
+
+       result = xc_read_i2c_data(priv, buf, 2);
+       if (result != XC_RESULT_SUCCESS)
+               return result;
+
+       *i2cData = buf[0] * 256 + buf[1];
+       return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[])
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+
+       int i, nbytes_to_send, result;
+       unsigned int len, pos, index;
+       u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+       index=0;
+       while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
+               len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+               if (len == 0x0000) {
+                       /* RESET command */
+                       result = xc_reset(fe);
+                       index += 2;
+                       if (result != XC_RESULT_SUCCESS)
+                               return result;
+               } else if (len & 0x8000) {
+                       /* WAIT command */
+                       xc_wait(len & 0x7FFF);
+                       index += 2;
+               } else {
+                       /* Send i2c data whilst ensuring individual transactions
+                        * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+                        */
+                       index += 2;
+                       buf[0] = i2c_sequence[index];
+                       buf[1] = i2c_sequence[index + 1];
+                       pos = 2;
+                       while (pos < len) {
+                               if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
+                                       nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
+                               } else {
+                                       nbytes_to_send = (len - pos + 2);
+                               }
+                               for (i=2; i<nbytes_to_send; i++) {
+                                       buf[i] = i2c_sequence[index + pos + i - 2];
+                               }
+                               result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+
+                               if (result != XC_RESULT_SUCCESS)
+                                       return result;
+
+                               pos += nbytes_to_send - 2;
+                       }
+                       index += len;
+               }
+       }
+       return XC_RESULT_SUCCESS;
+}
+
+static int xc_initialize(struct xc5000_priv *priv)
+{
+       dprintk(1, "%s()\n", __FUNCTION__);
+       return xc_write_reg(priv, XREG_INIT, 0);
+}
+
+static int xc_SetTVStandard(struct xc5000_priv *priv,
+       u16 VideoMode, u16 AudioMode)
+{
+       int ret;
+       dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode);
+       dprintk(1, "%s() Standard = %s\n",
+               __FUNCTION__,
+               XC5000_Standard[priv->video_standard].Name);
+
+       ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
+       if (ret == XC_RESULT_SUCCESS)
+               ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+
+       return ret;
+}
+
+static int xc_shutdown(struct xc5000_priv *priv)
+{
+       return 0;
+       /* Fixme: cannot bring tuner back alive once shutdown
+        *        without reloading the driver modules.
+        *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
+        */
+}
+
+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+{
+       dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode,
+               rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+       if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
+       {
+               rf_mode = XC_RF_MODE_CABLE;
+               printk(KERN_ERR
+                       "%s(), Invalid mode, defaulting to CABLE",
+                       __FUNCTION__);
+       }
+       return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops;
+
+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+       u16 freq_code;
+
+       dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+
+       if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+               (freq_hz < xc5000_tuner_ops.info.frequency_min))
+               return XC_RESULT_OUT_OF_RANGE;
+
+       freq_code = (u16)(freq_hz / 15625);
+
+       return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+
+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
+{
+       u32 freq_code = (freq_khz * 1024)/1000;
+       dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
+               __FUNCTION__, freq_khz, freq_code);
+
+       return xc_write_reg(priv, XREG_IF_OUT, freq_code);
+}
+
+
+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+{
+       return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
+{
+       int result;
+       u16 regData;
+       u32 tmp;
+
+       result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
+       if (result)
+               return result;
+
+       tmp = (u32)regData;
+       (*freq_error_hz) = (tmp * 15625) / 1000;
+       return result;
+}
+
+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
+{
+       return xc_read_reg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc5000_priv *priv,
+       u8 *hw_majorversion, u8 *hw_minorversion,
+       u8 *fw_majorversion, u8 *fw_minorversion)
+{
+       u16 data;
+       int result;
+
+       result = xc_read_reg(priv, XREG_VERSION, &data);
+       if (result)
+               return result;
+
+       (*hw_majorversion) = (data >> 12) & 0x0F;
+       (*hw_minorversion) = (data >>  8) & 0x0F;
+       (*fw_majorversion) = (data >>  4) & 0x0F;
+       (*fw_minorversion) = data & 0x0F;
+
+       return 0;
+}
+
+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
+{
+       u16 regData;
+       int result;
+
+       result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
+       if (result)
+               return result;
+
+       (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+       return result;
+}
+
+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
+{
+       return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
+{
+       return xc_read_reg(priv, XREG_QUALITY, quality);
+}
+
+static u16 WaitForLock(struct xc5000_priv *priv)
+{
+       u16 lockState = 0;
+       int watchDogCount = 40;
+
+       while ((lockState == 0) && (watchDogCount > 0)) {
+               xc_get_lock_status(priv, &lockState);
+               if (lockState != 1) {
+                       xc_wait(5);
+                       watchDogCount--;
+               }
+       }
+       return lockState;
+}
+
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+{
+       int found = 0;
+
+       dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+
+       if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+               return 0;
+
+       if (WaitForLock(priv) == 1)
+               found = 1;
+
+       return found;
+}
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+       u8 buf[2] = { reg >> 8, reg & 0xff };
+       u8 bval[2] = { 0, 0 };
+       struct i2c_msg msg[2] = {
+               { .addr = priv->cfg->i2c_address,
+                       .flags = 0, .buf = &buf[0], .len = 2 },
+               { .addr = priv->cfg->i2c_address,
+                       .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+       };
+
+       if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+               printk(KERN_WARNING "xc5000: I2C read failed\n");
+               return -EREMOTEIO;
+       }
+
+       *val = (bval[0] << 8) | bval[1];
+       return 0;
+}
+
+static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+               .flags = 0, .buf = buf, .len = len };
+
+       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+               printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
+                       (int)len);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+               .flags = I2C_M_RD, .buf = buf, .len = len };
+
+       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int xc5000_fwupload(struct dvb_frontend* fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       const struct firmware *fw;
+       int ret;
+
+       /* request the firmware, this will block and timeout */
+       printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
+               XC5000_DEFAULT_FIRMWARE);
+
+       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+       if (ret) {
+               printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
+               ret = XC_RESULT_RESET_FAILURE;
+               goto out;
+       } else {
+               printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+                      fw->size);
+               ret = XC_RESULT_SUCCESS;
+       }
+
+       if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+               printk(KERN_ERR "xc5000: firmware incorrect size\n");
+               ret = XC_RESULT_RESET_FAILURE;
+       } else {
+               printk(KERN_INFO "xc5000: firmware upload\n");
+               ret = xc_load_i2c_sequence(fe,  fw->data );
+       }
+
+out:
+       release_firmware(fw);
+       return ret;
+}
+
+static void xc_debug_dump(struct xc5000_priv *priv)
+{
+       u16 adc_envelope;
+       u32 freq_error_hz = 0;
+       u16 lock_status;
+       u32 hsync_freq_hz = 0;
+       u16 frame_lines;
+       u16 quality;
+       u8 hw_majorversion = 0, hw_minorversion = 0;
+       u8 fw_majorversion = 0, fw_minorversion = 0;
+
+       /* Wait for stats to stabilize.
+        * Frame Lines needs two frame times after initial lock
+        * before it is valid.
+        */
+       xc_wait(100);
+
+       xc_get_ADC_Envelope(priv,  &adc_envelope);
+       dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+       xc_get_frequency_error(priv, &freq_error_hz);
+       dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+       xc_get_lock_status(priv,  &lock_status);
+       dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+               lock_status);
+
+       xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
+               &fw_majorversion, &fw_minorversion);
+       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+               hw_majorversion, hw_minorversion,
+               fw_majorversion, fw_minorversion);
+
+       xc_get_hsync_freq(priv,  &hsync_freq_hz);
+       dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
+
+       xc_get_frame_lines(priv,  &frame_lines);
+       dprintk(1, "*** Frame lines = %d\n", frame_lines);
+
+       xc_get_quality(priv,  &quality);
+       dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+}
+
+static int xc5000_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency);
+
+       switch(params->u.vsb.modulation) {
+       case VSB_8:
+       case VSB_16:
+               dprintk(1, "%s() VSB modulation\n", __FUNCTION__);
+               priv->rf_mode = XC_RF_MODE_AIR;
+               priv->freq_hz = params->frequency - 1750000;
+               priv->bandwidth = BANDWIDTH_6_MHZ;
+               priv->video_standard = DTV6;
+               break;
+       case QAM_64:
+       case QAM_256:
+       case QAM_AUTO:
+               dprintk(1, "%s() QAM modulation\n", __FUNCTION__);
+               priv->rf_mode = XC_RF_MODE_CABLE;
+               priv->freq_hz = params->frequency - 1750000;
+               priv->bandwidth = BANDWIDTH_6_MHZ;
+               priv->video_standard = DTV6;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dprintk(1, "%s() frequency=%d (compensated)\n",
+               __FUNCTION__, priv->freq_hz);
+
+       ret = xc_SetSignalSource(priv, priv->rf_mode);
+       if (ret != XC_RESULT_SUCCESS) {
+               printk(KERN_ERR
+                       "xc5000: xc_SetSignalSource(%d) failed\n",
+                       priv->rf_mode);
+               return -EREMOTEIO;
+       }
+
+       ret = xc_SetTVStandard(priv,
+               XC5000_Standard[priv->video_standard].VideoMode,
+               XC5000_Standard[priv->video_standard].AudioMode);
+       if (ret != XC_RESULT_SUCCESS) {
+               printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+               return -EREMOTEIO;
+       }
+
+       ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+       if (ret != XC_RESULT_SUCCESS) {
+               printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+                       priv->cfg->if_khz);
+               return -EIO;
+       }
+
+       xc_tune_channel(priv, priv->freq_hz);
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+       struct analog_parameters *params)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       if(priv->fwloaded == 0)
+               xc_load_fw_and_init_tuner(fe);
+
+       dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+               __FUNCTION__, params->frequency);
+
+       priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
+
+       /* params->frequency is in units of 62.5khz */
+       priv->freq_hz = params->frequency * 62500;
+
+       /* FIX ME: Some video standards may have several possible audio
+                  standards. We simply default to one of them here.
+        */
+       if(params->std & V4L2_STD_MN) {
+               /* default to BTSC audio standard */
+               priv->video_standard = MN_NTSC_PAL_BTSC;
+               goto tune_channel;
+       }
+
+       if(params->std & V4L2_STD_PAL_BG) {
+               /* default to NICAM audio standard */
+               priv->video_standard = BG_PAL_NICAM;
+               goto tune_channel;
+       }
+
+       if(params->std & V4L2_STD_PAL_I) {
+               /* default to NICAM audio standard */
+               priv->video_standard = I_PAL_NICAM;
+               goto tune_channel;
+       }
+
+       if(params->std & V4L2_STD_PAL_DK) {
+               /* default to NICAM audio standard */
+               priv->video_standard = DK_PAL_NICAM;
+               goto tune_channel;
+       }
+
+       if(params->std & V4L2_STD_SECAM_DK) {
+               /* default to A2 DK1 audio standard */
+               priv->video_standard = DK_SECAM_A2DK1;
+               goto tune_channel;
+       }
+
+       if(params->std & V4L2_STD_SECAM_L) {
+               priv->video_standard = L_SECAM_NICAM;
+               goto tune_channel;
+       }
+
+       if(params->std & V4L2_STD_SECAM_LC) {
+               priv->video_standard = LC_SECAM_NICAM;
+               goto tune_channel;
+       }
+
+tune_channel:
+       ret = xc_SetSignalSource(priv, priv->rf_mode);
+       if (ret != XC_RESULT_SUCCESS) {
+       printk(KERN_ERR
+                       "xc5000: xc_SetSignalSource(%d) failed\n",
+                       priv->rf_mode);
+               return -EREMOTEIO;
+       }
+
+       ret = xc_SetTVStandard(priv,
+               XC5000_Standard[priv->video_standard].VideoMode,
+               XC5000_Standard[priv->video_standard].AudioMode);
+       if (ret != XC_RESULT_SUCCESS) {
+               printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+               return -EREMOTEIO;
+       }
+
+       xc_tune_channel(priv, priv->freq_hz);
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       return 0;
+}
+
+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __FUNCTION__);
+       *freq = priv->freq_hz;
+       return 0;
+}
+
+static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       *bw = priv->bandwidth;
+       return 0;
+}
+
+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       u16 lock_status = 0;
+
+       xc_get_lock_status(priv, &lock_status);
+
+       dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status);
+
+       *status = lock_status;
+
+       return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret = 0;
+
+       if (priv->fwloaded == 0) {
+               ret = xc5000_fwupload(fe);
+               if (ret != XC_RESULT_SUCCESS)
+                       return ret;
+               priv->fwloaded = 1;
+       }
+
+       /* Start the tuner self-calibration process */
+       ret |= xc_initialize(priv);
+
+       /* Wait for calibration to complete.
+        * We could continue but XC5000 will clock stretch subsequent
+        * I2C transactions until calibration is complete.  This way we
+        * don't have to rely on clock stretching working.
+        */
+       xc_wait( 100 );
+
+       /* Default to "CABLE" mode */
+       ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+
+       return ret;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
+        * once shutdown without reloading the driver. Maybe I am not
+        * doing something right.
+        *
+        */
+
+       ret = xc_shutdown(priv);
+       if(ret != XC_RESULT_SUCCESS) {
+               printk(KERN_ERR
+                       "xc5000: %s() unable to shutdown tuner\n",
+                       __FUNCTION__);
+               return -EREMOTEIO;
+       }
+       else {
+               /* priv->fwloaded = 0; */
+               return XC_RESULT_SUCCESS;
+       }
+}
+
+static int xc5000_init(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+               printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
+               return -EREMOTEIO;
+       }
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       return 0;
+}
+
+static int xc5000_release(struct dvb_frontend *fe)
+{
+       dprintk(1, "%s()\n", __FUNCTION__);
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops = {
+       .info = {
+               .name           = "Xceive XC5000",
+               .frequency_min  =    1000000,
+               .frequency_max  = 1023000000,
+               .frequency_step =      50000,
+       },
+
+       .release           = xc5000_release,
+       .init              = xc5000_init,
+       .sleep             = xc5000_sleep,
+
+       .set_params        = xc5000_set_params,
+       .set_analog_params = xc5000_set_analog_params,
+       .get_frequency     = xc5000_get_frequency,
+       .get_bandwidth     = xc5000_get_bandwidth,
+       .get_status        = xc5000_get_status
+};
+
+struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c,
+       struct xc5000_config *cfg)
+{
+       struct xc5000_priv *priv = NULL;
+       u16 id = 0;
+
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->cfg = cfg;
+       priv->bandwidth = BANDWIDTH_6_MHZ;
+       priv->i2c = i2c;
+
+       /* Check if firmware has been loaded. It is possible that another
+          instance of the driver has loaded the firmware.
+        */
+       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
+               kfree(priv);
+               return NULL;
+       }
+
+       switch(id) {
+       case XC_PRODUCT_ID_FW_LOADED:
+               printk(KERN_INFO
+                       "xc5000: Successfully identified at address 0x%02x\n",
+                       cfg->i2c_address);
+               printk(KERN_INFO
+                       "xc5000: Firmware has been loaded previously\n");
+               priv->fwloaded = 1;
+               break;
+       case XC_PRODUCT_ID_FW_NOT_LOADED:
+               printk(KERN_INFO
+                       "xc5000: Successfully identified at address 0x%02x\n",
+                       cfg->i2c_address);
+               printk(KERN_INFO
+                       "xc5000: Firmware has not been loaded previously\n");
+               priv->fwloaded = 0;
+               break;
+       default:
+               printk(KERN_ERR
+                       "xc5000: Device not found at addr 0x%02x (0x%x)\n",
+                       cfg->i2c_address, id);
+               kfree(priv);
+               return NULL;
+       }
+
+       memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+
+       fe->tuner_priv = priv;
+
+       return fe;
+}
+EXPORT_SYMBOL(xc5000_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h
new file mode 100644 (file)
index 0000000..e0e8456
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XC5000_H__
+#define __XC5000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc5000_config {
+       u8   i2c_address;
+       u32  if_khz;
+
+       /* For each bridge framework, when it attaches either analog or digital,
+        * it has to store a reference back to its _core equivalent structure,
+        * so that it can service the hardware by steering gpio's etc.
+        * Each bridge implementation is different so cast priv accordingly.
+        * The xc5000 driver cares not for this value, other than ensuring
+        * it's passed back to a bridge during tuner_callback().
+        */
+       void *priv;
+       int  (*tuner_callback) (void *priv, int command, int arg);
+};
+
+/* xc5000 callback command */
+#define XC5000_TUNER_RESET             0
+
+#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE)
+extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+                                         struct i2c_adapter *i2c,
+                                         struct xc5000_config *cfg);
+#else
+static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+                                                struct i2c_adapter *i2c,
+                                                struct xc5000_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       return NULL;
+}
+#endif // CONFIG_DVB_TUNER_XC5000
+
+#endif // __XC5000_H__
diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/dvb/frontends/xc5000_priv.h
new file mode 100644 (file)
index 0000000..13b2d19
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef XC5000_PRIV_H
+#define XC5000_PRIV_H
+
+struct xc5000_priv {
+       struct xc5000_config *cfg;
+       struct i2c_adapter   *i2c;
+
+       u32 freq_hz;
+       u32 bandwidth;
+       u8  video_standard;
+       u8  rf_mode;
+       u8  fwloaded;
+};
+
+#endif
index 0106df4c55e827da3410630463888b7bcecda789..276e3b631dc211eedaf9612af4d48a5b04a84a80 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for Zarlink DVB-T ZL10353 demodulator
  *
- * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
  *
  * 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
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <asm/div64.h>
 
 #include "dvb_frontend.h"
 #include "zl10353_priv.h"
@@ -35,6 +36,8 @@ struct zl10353_state {
        struct dvb_frontend frontend;
 
        struct zl10353_config config;
+
+       enum fe_bandwidth bandwidth;
 };
 
 static int debug;
@@ -122,9 +125,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
                                      enum fe_bandwidth bandwidth,
                                      u16 *nominal_rate)
 {
-       u32 adc_clock = 45056; /* 45.056 MHz */
-       u8 bw;
        struct zl10353_state *state = fe->demodulator_priv;
+       u32 adc_clock = 450560; /* 45.056 MHz */
+       u64 value;
+       u8 bw;
 
        if (state->config.adc_clock)
                adc_clock = state->config.adc_clock;
@@ -142,12 +146,44 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
                break;
        }
 
-       *nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock;
+       value = (u64)10 * (1 << 23) / 7 * 125;
+       value = (bw * value) + adc_clock / 2;
+       do_div(value, adc_clock);
+       *nominal_rate = value;
 
        dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
                __FUNCTION__, bw, adc_clock, *nominal_rate);
 }
 
+static void zl10353_calc_input_freq(struct dvb_frontend *fe,
+                                   u16 *input_freq)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       u32 adc_clock = 450560; /* 45.056  MHz */
+       int if2 = 361667;       /* 36.1667 MHz */
+       int ife;
+       u64 value;
+
+       if (state->config.adc_clock)
+               adc_clock = state->config.adc_clock;
+       if (state->config.if2)
+               if2 = state->config.if2;
+
+       if (adc_clock >= if2 * 2)
+               ife = if2;
+       else {
+               ife = adc_clock - (if2 % adc_clock);
+               if (ife > adc_clock / 2)
+                       ife = adc_clock - ife;
+       }
+       value = (u64)65536 * ife + adc_clock / 2;
+       do_div(value, adc_clock);
+       *input_freq = -value;
+
+       dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+               __FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq);
+}
+
 static int zl10353_sleep(struct dvb_frontend *fe)
 {
        static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
@@ -160,64 +196,276 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                                  struct dvb_frontend_parameters *param)
 {
        struct zl10353_state *state = fe->demodulator_priv;
-       u16 nominal_rate;
-       u8 pllbuf[6] = { 0x67 };
+       u16 nominal_rate, input_freq;
+       u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
+       u16 tps = 0;
+       struct dvb_ofdm_parameters *op = &param->u.ofdm;
 
-       /* These settings set "auto-everything" and start the FSM. */
-       zl10353_single_write(fe, 0x55, 0x80);
+       zl10353_single_write(fe, RESET, 0x80);
        udelay(200);
        zl10353_single_write(fe, 0xEA, 0x01);
        udelay(200);
        zl10353_single_write(fe, 0xEA, 0x00);
 
-       zl10353_single_write(fe, 0x56, 0x28);
-       zl10353_single_write(fe, 0x89, 0x20);
-       zl10353_single_write(fe, 0x5E, 0x00);
+       zl10353_single_write(fe, AGC_TARGET, 0x28);
+
+       if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
+               acq_ctl |= (1 << 0);
+       if (op->guard_interval != GUARD_INTERVAL_AUTO)
+               acq_ctl |= (1 << 1);
+       zl10353_single_write(fe, ACQ_CTL, acq_ctl);
 
-       zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+       switch (op->bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               /* These are extrapolated from the 7 and 8MHz values */
+               zl10353_single_write(fe, MCLK_RATIO, 0x97);
+               zl10353_single_write(fe, 0x64, 0x34);
+               break;
+       case BANDWIDTH_7_MHZ:
+               zl10353_single_write(fe, MCLK_RATIO, 0x86);
+               zl10353_single_write(fe, 0x64, 0x35);
+               break;
+       case BANDWIDTH_8_MHZ:
+       default:
+               zl10353_single_write(fe, MCLK_RATIO, 0x75);
+               zl10353_single_write(fe, 0x64, 0x36);
+       }
+
+       zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
        zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
        zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+       state->bandwidth = op->bandwidth;
+
+       zl10353_calc_input_freq(fe, &input_freq);
+       zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
+       zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
+
+       /* Hint at TPS settings */
+       switch (op->code_rate_HP) {
+       case FEC_2_3:
+               tps |= (1 << 7);
+               break;
+       case FEC_3_4:
+               tps |= (2 << 7);
+               break;
+       case FEC_5_6:
+               tps |= (3 << 7);
+               break;
+       case FEC_7_8:
+               tps |= (4 << 7);
+               break;
+       case FEC_1_2:
+       case FEC_AUTO:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (op->code_rate_LP) {
+       case FEC_2_3:
+               tps |= (1 << 4);
+               break;
+       case FEC_3_4:
+               tps |= (2 << 4);
+               break;
+       case FEC_5_6:
+               tps |= (3 << 4);
+               break;
+       case FEC_7_8:
+               tps |= (4 << 4);
+               break;
+       case FEC_1_2:
+       case FEC_AUTO:
+               break;
+       case FEC_NONE:
+               if (op->hierarchy_information == HIERARCHY_AUTO ||
+                   op->hierarchy_information == HIERARCHY_NONE)
+                       break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (op->constellation) {
+       case QPSK:
+               break;
+       case QAM_AUTO:
+       case QAM_16:
+               tps |= (1 << 13);
+               break;
+       case QAM_64:
+               tps |= (2 << 13);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (op->transmission_mode) {
+       case TRANSMISSION_MODE_2K:
+       case TRANSMISSION_MODE_AUTO:
+               break;
+       case TRANSMISSION_MODE_8K:
+               tps |= (1 << 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (op->guard_interval) {
+       case GUARD_INTERVAL_1_32:
+       case GUARD_INTERVAL_AUTO:
+               break;
+       case GUARD_INTERVAL_1_16:
+               tps |= (1 << 2);
+               break;
+       case GUARD_INTERVAL_1_8:
+               tps |= (2 << 2);
+               break;
+       case GUARD_INTERVAL_1_4:
+               tps |= (3 << 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (op->hierarchy_information) {
+       case HIERARCHY_AUTO:
+       case HIERARCHY_NONE:
+               break;
+       case HIERARCHY_1:
+               tps |= (1 << 10);
+               break;
+       case HIERARCHY_2:
+               tps |= (2 << 10);
+               break;
+       case HIERARCHY_4:
+               tps |= (3 << 10);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
+       zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
 
-       zl10353_single_write(fe, 0x6C, 0xCD);
-       zl10353_single_write(fe, 0x6D, 0x7E);
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
 
-       // if there is no attached secondary tuner, we call set_params to program
-       // a potential tuner attached somewhere else
+       /*
+        * If there is no tuner attached to the secondary I2C bus, we call
+        * set_params to program a potential tuner attached somewhere else.
+        * Otherwise, we update the PLL registers via calc_regs.
+        */
        if (state->config.no_tuner) {
                if (fe->ops.tuner_ops.set_params) {
                        fe->ops.tuner_ops.set_params(fe, param);
                        if (fe->ops.i2c_gate_ctrl)
                                fe->ops.i2c_gate_ctrl(fe, 0);
                }
+       } else if (fe->ops.tuner_ops.calc_regs) {
+               fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
+               pllbuf[1] <<= 1;
+               zl10353_write(fe, pllbuf, sizeof(pllbuf));
        }
 
-       // if pllbuf is defined, retrieve the settings
-       if (fe->ops.tuner_ops.calc_regs) {
-               fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
-               pllbuf[1] <<= 1;
-       } else {
-               // fake pllbuf settings
-               pllbuf[1] = 0x61 << 1;
-               pllbuf[2] = 0;
-               pllbuf[3] = 0;
-               pllbuf[3] = 0;
-               pllbuf[4] = 0;
+       zl10353_single_write(fe, 0x5F, 0x13);
+
+       /* If no attached tuner or invalid PLL registers, just start the FSM. */
+       if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
+               zl10353_single_write(fe, FSM_GO, 0x01);
+       else
+               zl10353_single_write(fe, TUNER_GO, 0x01);
+
+       return 0;
+}
+
+static int zl10353_get_parameters(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *param)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       struct dvb_ofdm_parameters *op = &param->u.ofdm;
+       int s6, s9;
+       u16 tps;
+       static const u8 tps_fec_to_api[8] = {
+               FEC_1_2,
+               FEC_2_3,
+               FEC_3_4,
+               FEC_5_6,
+               FEC_7_8,
+               FEC_AUTO,
+               FEC_AUTO,
+               FEC_AUTO
+       };
+
+       s6 = zl10353_read_register(state, STATUS_6);
+       s9 = zl10353_read_register(state, STATUS_9);
+       if (s6 < 0 || s9 < 0)
+               return -EREMOTEIO;
+       if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
+               return -EINVAL; /* no FE or TPS lock */
+
+       tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
+             zl10353_read_register(state, TPS_RECEIVED_0);
+
+       op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+       op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+       switch ((tps >> 13) & 3) {
+       case 0:
+               op->constellation = QPSK;
+               break;
+       case 1:
+               op->constellation = QAM_16;
+               break;
+       case 2:
+               op->constellation = QAM_64;
+               break;
+       default:
+               op->constellation = QAM_AUTO;
+               break;
        }
 
-       // there is no call to _just_ start decoding, so we send the pllbuf anyway
-       // even if there isn't a PLL attached to the secondary bus
-       zl10353_write(fe, pllbuf, sizeof(pllbuf));
+       op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
+                                              TRANSMISSION_MODE_2K;
 
-       zl10353_single_write(fe, 0x5F, 0x13);
-       zl10353_single_write(fe, 0x70, 0x01);
-       udelay(250);
-       zl10353_single_write(fe, 0xE4, 0x00);
-       zl10353_single_write(fe, 0xE5, 0x2A);
-       zl10353_single_write(fe, 0xE9, 0x02);
-       zl10353_single_write(fe, 0xE7, 0x40);
-       zl10353_single_write(fe, 0xE8, 0x10);
+       switch ((tps >> 2) & 3) {
+       case 0:
+               op->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               op->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               op->guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               op->guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       default:
+               op->guard_interval = GUARD_INTERVAL_AUTO;
+               break;
+       }
+
+       switch ((tps >> 10) & 7) {
+       case 0:
+               op->hierarchy_information = HIERARCHY_NONE;
+               break;
+       case 1:
+               op->hierarchy_information = HIERARCHY_1;
+               break;
+       case 2:
+               op->hierarchy_information = HIERARCHY_2;
+               break;
+       case 3:
+               op->hierarchy_information = HIERARCHY_4;
+               break;
+       default:
+               op->hierarchy_information = HIERARCHY_AUTO;
+               break;
+       }
+
+       param->frequency = 0;
+       op->bandwidth = state->bandwidth;
+       param->inversion = INVERSION_AUTO;
 
        return 0;
 }
@@ -406,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = {
        .write = zl10353_write,
 
        .set_frontend = zl10353_set_parameters,
+       .get_frontend = zl10353_get_parameters,
        .get_tune_settings = zl10353_get_tune_settings,
 
        .read_status = zl10353_read_status,
index 1c3d494a6da9e3bd04ba06ba646c2d4c7beb5c0d..fc734c22b5fa9d8231aa723698eb43746ba1d290 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Zarlink DVB-T ZL10353 demodulator
  *
- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -29,8 +29,9 @@ struct zl10353_config
        /* demodulator's I2C address */
        u8 demod_address;
 
-       /* frequencies in kHz */
-       int adc_clock;  /* default: 45056 */
+       /* frequencies in units of 0.1kHz */
+       int adc_clock;  /* default: 450560 (45.056  MHz) */
+       int if2;        /* default: 361667 (36.1667 MHz) */
 
        /* set if no pll is connected to the secondary i2c bus */
        int no_tuner;
@@ -49,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
        return NULL;
 }
-#endif // CONFIG_DVB_ZL10353
+#endif /* CONFIG_DVB_ZL10353 */
 
 #endif /* ZL10353_H */
index 4962434b35e751e94df246ea55548358e0d5b563..055ff1f7e34909f73470566cef7ae0a5eaf357e1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Zarlink DVB-T ZL10353 demodulator
  *
- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
  *
  *  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
@@ -16,7 +16,7 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _ZL10353_PRIV_
@@ -46,9 +46,28 @@ enum zl10353_reg_addr {
        RS_ERR_CNT_0       = 0x13,
        RS_UBC_1           = 0x14,
        RS_UBC_0           = 0x15,
+       TPS_RECEIVED_1     = 0x1D,
+       TPS_RECEIVED_0     = 0x1E,
+       TPS_CURRENT_1      = 0x1F,
+       TPS_CURRENT_0      = 0x20,
+       RESET              = 0x55,
+       AGC_TARGET         = 0x56,
+       MCLK_RATIO         = 0x5C,
+       ACQ_CTL            = 0x5E,
        TRL_NOMINAL_RATE_1 = 0x65,
        TRL_NOMINAL_RATE_0 = 0x66,
+       INPUT_FREQ_1       = 0x6C,
+       INPUT_FREQ_0       = 0x6D,
+       TPS_GIVEN_1        = 0x6E,
+       TPS_GIVEN_0        = 0x6F,
+       TUNER_GO           = 0x70,
+       FSM_GO             = 0x71,
        CHIP_ID            = 0x7F,
+       CHAN_STEP_1        = 0xE4,
+       CHAN_STEP_0        = 0xE5,
+       OFDM_LOCK_TIME     = 0xE7,
+       FEC_LOCK_TIME      = 0xE8,
+       ACQ_DELAY          = 0xE9,
 };
 
 #endif                          /* _ZL10353_PRIV_ */
index 54b91f26ca63a233515c04d16615be787c5e4b48..ae882432dd3d2b39179cc628260b723ac84a9798 100644 (file)
@@ -1,8 +1,14 @@
+config TTPCI_EEPROM
+       tristate
+       default n
+
 config DVB_AV7110
        tristate "AV7110 cards"
-       depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+       depends on DVB_CORE && PCI && I2C
        select FW_LOADER if !DVB_AV7110_FIRMWARE
+       select TTPCI_EEPROM
        select VIDEO_SAA7146_VV
+       depends on VIDEO_DEV    # dependencies of VIDEO_SAA7146_VV
        select DVB_VES1820 if !DVB_FE_CUSTOMISE
        select DVB_VES1X93 if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
@@ -57,10 +63,19 @@ config DVB_AV7110_OSD
 
          All other people say N.
 
+config DVB_BUDGET_CORE
+       tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
+       depends on DVB_CORE && PCI && I2C
+       select VIDEO_SAA7146
+       select TTPCI_EEPROM
+       help
+         Support for simple SAA7146 based DVB cards
+         (so called Budget- or Nova-PCI cards) without onboard
+         MPEG2 decoder.
+
 config DVB_BUDGET
        tristate "Budget cards"
-       depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
-       select VIDEO_SAA7146
+       depends on DVB_BUDGET_CORE && I2C
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_VES1X93 if !DVB_FE_CUSTOMISE
        select DVB_VES1820 if !DVB_FE_CUSTOMISE
@@ -73,9 +88,9 @@ config DVB_BUDGET
        select DVB_TDA826X if !DVB_FE_CUSTOMISE
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
        help
-         Support for simple SAA7146 based DVB cards
-         (so called Budget- or Nova-PCI cards) without onboard
-         MPEG2 decoder.
+         Support for simple SAA7146 based DVB cards (so called Budget-
+         or Nova-PCI cards) without onboard MPEG2 decoder, and without
+         analog inputs or an onboard Common Interface connector.
 
          Say Y if you own such a card and want to use it.
 
@@ -84,8 +99,7 @@ config DVB_BUDGET
 
 config DVB_BUDGET_CI
        tristate "Budget cards with onboard CI connector"
-       depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT
-       select VIDEO_SAA7146
+       depends on DVB_BUDGET_CORE && I2C
        select DVB_STV0297 if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -106,8 +120,9 @@ config DVB_BUDGET_CI
 
 config DVB_BUDGET_AV
        tristate "Budget cards with analog video inputs"
-       depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+       depends on DVB_BUDGET_CORE && I2C
        select VIDEO_SAA7146_VV
+       depends on VIDEO_DEV    # dependencies of VIDEO_SAA7146_VV
        select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -127,8 +142,8 @@ config DVB_BUDGET_AV
 
 config DVB_BUDGET_PATCH
        tristate "AV7110 cards with Budget Patch"
-       depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
-       select DVB_AV7110
+       depends on DVB_BUDGET_CORE && I2C
+       depends on DVB_AV7110
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_VES1X93 if !DVB_FE_CUSTOMISE
        select DVB_TDA8083 if !DVB_FE_CUSTOMISE
index 2c1145236ee634b8f8108d33a8481dab2a9afbde..d7483f1a9b3f9fa4f311fd266045a0feb000ea9f 100644 (file)
@@ -5,11 +5,13 @@
 
 dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
 
-obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
+obj-$(CONFIG_DVB_BUDGET) += budget.o
+obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
+obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
index 8b8144f77a739b7637ce5c9de526c199a3daf389..0e5701bdff19472bd08ec89a6b3219f9f634310e 100644 (file)
@@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
        mutex_init(&av7110->osd_mutex);
 
        /* TV standard */
-       av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
+       av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
+                                          : AV7110_VIDEO_MODE_PAL;
 
        /* ARM "watchdog" */
        init_waitqueue_head(&av7110->arm_wait);
@@ -2800,12 +2801,12 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
 }
 
 
-static struct saa7146_extension av7110_extension;
+static struct saa7146_extension av7110_extension_driver;
 
 #define MAKE_AV7110_INFO(x_var,x_name) \
 static struct saa7146_pci_extension_data x_var = { \
        .ext_priv = x_name, \
-       .ext = &av7110_extension }
+       .ext = &av7110_extension_driver }
 
 MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C");
 MAKE_AV7110_INFO(ttt_1_X,    "Technotrend/Hauppauge WinTV DVB-T rev1.X");
@@ -2843,7 +2844,7 @@ static struct pci_device_id pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 
-static struct saa7146_extension av7110_extension = {
+static struct saa7146_extension av7110_extension_driver = {
        .name           = "dvb",
        .flags          = SAA7146_USE_I2C_IRQ,
 
@@ -2860,14 +2861,14 @@ static struct saa7146_extension av7110_extension = {
 static int __init av7110_init(void)
 {
        int retval;
-       retval = saa7146_register_extension(&av7110_extension);
+       retval = saa7146_register_extension(&av7110_extension_driver);
        return retval;
 }
 
 
 static void __exit av7110_exit(void)
 {
-       saa7146_unregister_extension(&av7110_extension);
+       saa7146_unregister_extension(&av7110_extension_driver);
 }
 
 module_init(av7110_init);
index 0cb43952749891855ceefe5a7c6fd9c0fbffc0e1..39fbf7d5cffbca70e6abcada285ec0d176147783 100644 (file)
@@ -46,6 +46,11 @@ extern int av7110_debug;
 
 enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
 
+enum av7110_video_mode {
+       AV7110_VIDEO_MODE_PAL   = 0,
+       AV7110_VIDEO_MODE_NTSC  = 1
+};
+
 struct av7110_p2t {
        u8                pes[TS_SIZE];
        u8                counter;
@@ -170,7 +175,7 @@ struct av7110 {
 
        ca_slot_info_t          ci_slot[2];
 
-       int                     vidmode;
+       enum av7110_video_mode  vidmode;
        struct dmxdev           dmxdev;
        struct dvb_demux        demux;
 
index d75e7e48addcc821b0869a4b524bfb3265797c08..aef6e36d7c5c5e4467182b2660413e4607827554 100644 (file)
@@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
        return 0;
 }
 
-int av7110_set_vidmode(struct av7110 *av7110, int mode)
+int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
 {
        int ret;
        dprintk(2, "av7110:%p, \n", av7110);
@@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode)
 }
 
 
-static int sw2mode[16] = {
-       VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL,
-       VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
-       VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
-       VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
+static enum av7110_video_mode sw2mode[16] = {
+       AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+       AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
+       AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
+       AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+       AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+       AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+       AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+       AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
 };
 
 static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
index 45dc144b8b435c1425b52b26da8f639e4888fba6..5f02ef85e47deb28cd00fe5b5823d702a906528b 100644 (file)
@@ -3,7 +3,8 @@
 
 struct av7110;
 
-extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
+extern int av7110_set_vidmode(struct av7110 *av7110,
+                             enum av7110_video_mode mode);
 
 extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
 extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
index 76cca003252fdf6c69e5274651a0428aae4100fd..e2f066fb796727c1f0f7bf1c8196a562d25c1839 100644 (file)
@@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
        struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
 
        if (std->id & V4L2_STD_PAL) {
-               av7110->vidmode = VIDEO_MODE_PAL;
+               av7110->vidmode = AV7110_VIDEO_MODE_PAL;
                av7110_set_vidmode(av7110, av7110->vidmode);
        }
        else if (std->id & V4L2_STD_NTSC) {
-               av7110->vidmode = VIDEO_MODE_NTSC;
+               av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
                av7110_set_vidmode(av7110, av7110->vidmode);
        }
        else
index 11e962f1a97f955f9d6504fb4b88af522ac5a11a..8d5214f18cf0d488a36ec4fd66d80822d83466da 100644 (file)
@@ -351,4 +351,14 @@ config USB_DSBR
          To compile this driver as a module, choose M here: the
          module will be called dsbr100.
 
+config USB_SI470X
+       tristate "Silicon Labs Si470x FM Radio Receiver support"
+       depends on USB && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-silabs.
+
 endif # RADIO_ADAPTERS
index cf55a18e3ddf94bcd0c20a2d834db3a980f62d67..a30159f6fa428808ff88b76f497a5421b3fd71cc 100644 (file)
@@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
+obj-$(CONFIG_USB_SI470X) += radio-si470x.o
 
 EXTRA_CFLAGS += -Isound
index 3bd07f7e377489198ca539deee8e3401ffa5056a..36c0e365150241ebe1561c7aaa09d738cddbcf15 100644 (file)
@@ -33,6 +33,9 @@
 
  History:
 
+ Version 0.43:
+       Oliver Neukum: avoided DMA coherency issue
+
  Version 0.42:
        Converted dsbr100 to use video_ioctl2
        by Douglas Landgraf <dougsland@gmail.com>
@@ -135,7 +138,7 @@ module_param(radio_nr, int, 0);
 struct dsbr100_device {
        struct usb_device *usbdev;
        struct video_device *videodev;
-       unsigned char transfer_buffer[TB_LEN];
+       u8 *transfer_buffer;
        int curfreq;
        int stereo;
        int users;
@@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
 /* handle unplugging of the device, release data structures
 if nothing keeps us from doing it.  If something is still
 keeping us busy, the release callback of v4l will take care
-of releasing it.  stv680.c does not relase its private
-data, so I don't do this here either.  Checking out the
-code I'd expect I better did that, but if there's a memory
-leak here it's tiny (~50 bytes per disconnect) */
+of releasing it. */
 static void usb_dsbr100_disconnect(struct usb_interface *intf)
 {
        struct dsbr100_device *radio = usb_get_intfdata(intf);
@@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
                video_unregister_device(radio->videodev);
                radio->videodev = NULL;
                if (radio->users) {
+                       kfree(radio->transfer_buffer);
                        kfree(radio);
                } else {
                        radio->removed = 1;
@@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file)
                return -ENODEV;
        radio->users = 0;
        if (radio->removed) {
+               kfree(radio->transfer_buffer);
                kfree(radio);
        }
        return 0;
@@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 
        if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
                return -ENOMEM;
+       if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
+               kfree(radio);
+               return -ENOMEM;
+       }
        if (!(radio->videodev = video_device_alloc())) {
+               kfree(radio->transfer_buffer);
                kfree(radio);
                return -ENOMEM;
        }
@@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
        if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
                warn("Could not register video device");
                video_device_release(radio->videodev);
+               kfree(radio->transfer_buffer);
                kfree(radio);
                return -EIO;
        }
index 5e4b9ddb23c0a07e59998606acfe672f260e02df..246422b49267ca3bf1a6bd3efa425cd778de2c42 100644 (file)
@@ -58,10 +58,10 @@ static int initmute = 1;
 static int radio_nr    = -1;
 
 module_param(io, int, 0444);
-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
         "probing is disabled or fails. The most common I/O ports are: 0x20c "
         "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
-        " work for the combined sound/radiocard).");
+        "work for the combined sound/radiocard).");
 
 module_param(probe, bool, 0444);
 MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
@@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
        }
 };
 
-static struct file_operations gemtek_fops = {
+static const struct file_operations gemtek_fops = {
        .owner          = THIS_MODULE,
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
index 8e33a19a22a3134c16109d60ebd5bff971ec6056..bc51f4d23a5a176abbc61007d7d8dbfdec21e5e9 100644 (file)
@@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
 errunr:
        video_unregister_device(maestro_radio_inst);
 errfr1:
-       kfree(maestro_radio_inst);
+       video_device_release(maestro_radio_inst);
 errfr:
        kfree(radio_unit);
 err:
index 395165367f377c6dfb4541f061fa88430b880619..3118bdab3183d674b0b13e94176f1d97a4cb03c7 100644 (file)
@@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(isapnp, id_table);
 
-static int isapnp_fmi_probe(void)
+static int __init isapnp_fmi_probe(void)
 {
        int i = 0;
 
index c432c44bd634bf2144395dc0bfe902ba886b205f..f7c8b000404fffbe587b0d9ca2e96ed0c4aeadc8 100644 (file)
@@ -476,8 +476,7 @@ static int __init fmr2_init(void)
                return -EBUSY;
        }
 
-       if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-       {
+       if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 2);
                return -EINVAL;
        }
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
new file mode 100644 (file)
index 0000000..8e4bd47
--- /dev/null
@@ -0,0 +1,1432 @@
+/*
+ *  drivers/media/radio/radio-si470x.c
+ *
+ *  Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers:
+ *   - Silicon Labs USB FM Radio Reference Design
+ *   - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
+ *
+ *  Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+ *
+ * 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
+ */
+
+
+/*
+ * History:
+ * 2008-01-12  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.0
+ *             - First working version
+ * 2008-01-13   Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.1
+ *             - Improved error handling, every function now returns errno
+ *             - Improved multi user access (start/mute/stop)
+ *             - Channel doesn't get lost anymore after start/mute/stop
+ *             - RDS support added (polling mode via interrupt EP 1)
+ *             - marked default module parameters with *value*
+ *             - switched from bit structs to bit masks
+ *             - header file cleaned and integrated
+ * 2008-01-14  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.2
+ *             - hex values are now lower case
+ *             - commented USB ID for ADS/Tech moved on todo list
+ *             - blacklisted si470x in hid-quirks.c
+ *             - rds buffer handling functions integrated into *_work, *_read
+ *             - rds_command in si470x_poll exchanged against simple retval
+ *             - check for firmware version 15
+ *             - code order and prototypes still remain the same
+ *             - spacing and bottom of band codes remain the same
+ * 2008-01-16  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.3
+ *             - code reordered to avoid function prototypes
+ *             - switch/case defaults are now more user-friendly
+ *             - unified comment style
+ *             - applied all checkpatch.pl v1.12 suggestions
+ *               except the warning about the too long lines with bit comments
+ *             - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
+ * 2008-01-22  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.4
+ *             - avoid poss. locking when doing copy_to_user which may sleep
+ *             - RDS is automatically activated on read now
+ *             - code cleaned of unnecessary rds_commands
+ *             - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
+ *               (thanks to Guillaume RAMOUSSE)
+ *
+ * ToDo:
+ * - add seeking support
+ * - add firmware download/update support
+ * - RDS support: interrupt mode, instead of polling
+ * - add LED status output (check if that's not already done in firmware)
+ */
+
+
+/* driver definitions */
+#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
+#define DRIVER_NAME "radio-si470x"
+#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4)
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
+
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/rds.h>
+
+
+/* USB Device ID List */
+static struct usb_device_id si470x_usb_driver_id_table[] = {
+       /* Silicon Labs USB FM Radio Reference Design */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
+       /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
+       /* Terminating entry */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
+
+
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Radio Nr */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+/* Spacing (kHz) */
+/* 0: 200 kHz (USA, Australia) */
+/* 1: 100 kHz (Europe, Japan) */
+/* 2:  50 kHz */
+static int space = 2;
+module_param(space, int, 0);
+MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
+
+/* Bottom of Band (MHz) */
+/* 0: 87.5 - 108 MHz (USA, Europe)*/
+/* 1: 76   - 108 MHz (Japan wide band) */
+/* 2: 76   -  90 MHz (Japan) */
+static int band = 1;
+module_param(band, int, 0);
+MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
+
+/* De-emphasis */
+/* 0: 75 us (USA) */
+/* 1: 50 us (Europe, Australia, Japan) */
+static int de = 1;
+module_param(de, int, 0);
+MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
+
+/* USB timeout */
+static int usb_timeout = 500;
+module_param(usb_timeout, int, 0);
+MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
+
+/* Seek retries */
+static int seek_retries = 100;
+module_param(seek_retries, int, 0);
+MODULE_PARM_DESC(seek_retries, "Seek retries: *100*");
+
+/* RDS buffer blocks */
+static int rds_buf = 100;
+module_param(rds_buf, int, 0);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+
+/* RDS maximum block errors */
+static int max_rds_errors = 1;
+/* 0 means   0  errors requiring correction */
+/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
+/* 2 means 3-5  errors requiring correction */
+/* 3 means   6+ errors or errors in checkword, correction not possible */
+module_param(max_rds_errors, int, 0);
+MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
+
+/* RDS poll frequency */
+static int rds_poll_time = 40;
+/* 40 is used by the original USBRadio.exe */
+/* 50 is used by radio-cadet */
+/* 75 should be okay */
+/* 80 is the usual RDS receive interval */
+module_param(rds_poll_time, int, 0);
+MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+
+
+
+/**************************************************************************
+ * Register Definitions
+ **************************************************************************/
+#define RADIO_REGISTER_SIZE    2       /* 16 register bit width */
+#define RADIO_REGISTER_NUM     16      /* DEVICEID   ... RDSD */
+#define RDS_REGISTER_NUM       6       /* STATUSRSSI ... RDSD */
+
+#define DEVICEID               0       /* Device ID */
+#define DEVICEID_PN            0xf000  /* bits 15..12: Part Number */
+#define DEVICEID_MFGID         0x0fff  /* bits 11..00: Manufacturer ID */
+
+#define CHIPID                 1       /* Chip ID */
+#define CHIPID_REV             0xfc00  /* bits 15..10: Chip Version */
+#define CHIPID_DEV             0x0200  /* bits 09..09: Device */
+#define CHIPID_FIRMWARE                0x01ff  /* bits 08..00: Firmware Version */
+
+#define POWERCFG               2       /* Power Configuration */
+#define POWERCFG_DSMUTE                0x8000  /* bits 15..15: Softmute Disable */
+#define POWERCFG_DMUTE         0x4000  /* bits 14..14: Mute Disable */
+#define POWERCFG_MONO          0x2000  /* bits 13..13: Mono Select */
+#define POWERCFG_RDSM          0x0800  /* bits 11..11: RDS Mode (Si4701 only) */
+#define POWERCFG_SKMODE                0x0400  /* bits 10..10: Seek Mode */
+#define POWERCFG_SEEKUP                0x0200  /* bits 09..09: Seek Direction */
+#define POWERCFG_SEEK          0x0100  /* bits 08..08: Seek */
+#define POWERCFG_DISABLE       0x0040  /* bits 06..06: Powerup Disable */
+#define POWERCFG_ENABLE                0x0001  /* bits 00..00: Powerup Enable */
+
+#define CHANNEL                        3       /* Channel */
+#define CHANNEL_TUNE           0x8000  /* bits 15..15: Tune */
+#define CHANNEL_CHAN           0x03ff  /* bits 09..00: Channel Select */
+
+#define SYSCONFIG1             4       /* System Configuration 1 */
+#define SYSCONFIG1_RDSIEN      0x8000  /* bits 15..15: RDS Interrupt Enable (Si4701 only) */
+#define SYSCONFIG1_STCIEN      0x4000  /* bits 14..14: Seek/Tune Complete Interrupt Enable */
+#define SYSCONFIG1_RDS         0x1000  /* bits 12..12: RDS Enable (Si4701 only) */
+#define SYSCONFIG1_DE          0x0800  /* bits 11..11: De-emphasis (0=75us 1=50us) */
+#define SYSCONFIG1_AGCD                0x0400  /* bits 10..10: AGC Disable */
+#define SYSCONFIG1_BLNDADJ     0x00c0  /* bits 07..06: Stereo/Mono Blend Level Adjustment */
+#define SYSCONFIG1_GPIO3       0x0030  /* bits 05..04: General Purpose I/O 3 */
+#define SYSCONFIG1_GPIO2       0x000c  /* bits 03..02: General Purpose I/O 2 */
+#define SYSCONFIG1_GPIO1       0x0003  /* bits 01..00: General Purpose I/O 1 */
+
+#define SYSCONFIG2             5       /* System Configuration 2 */
+#define SYSCONFIG2_SEEKTH      0xff00  /* bits 15..08: RSSI Seek Threshold */
+#define SYSCONFIG2_BAND                0x0080  /* bits 07..06: Band Select */
+#define SYSCONFIG2_SPACE       0x0030  /* bits 05..04: Channel Spacing */
+#define SYSCONFIG2_VOLUME      0x000f  /* bits 03..00: Volume */
+
+#define SYSCONFIG3             6       /* System Configuration 3 */
+#define SYSCONFIG3_SMUTER      0xc000  /* bits 15..14: Softmute Attack/Recover Rate */
+#define SYSCONFIG3_SMUTEA      0x3000  /* bits 13..12: Softmute Attenuation */
+#define SYSCONFIG3_SKSNR       0x00f0  /* bits 07..04: Seek SNR Threshold */
+#define SYSCONFIG3_SKCNT       0x000f  /* bits 03..00: Seek FM Impulse Detection Threshold */
+
+#define TEST1                  7       /* Test 1 */
+#define TEST1_AHIZEN           0x4000  /* bits 14..14: Audio High-Z Enable */
+
+#define TEST2                  8       /* Test 2 */
+/* TEST2 only contains reserved bits */
+
+#define BOOTCONFIG             9       /* Boot Configuration */
+/* BOOTCONFIG only contains reserved bits */
+
+#define STATUSRSSI             10      /* Status RSSI */
+#define STATUSRSSI_RDSR                0x8000  /* bits 15..15: RDS Ready (Si4701 only) */
+#define STATUSRSSI_STC         0x4000  /* bits 14..14: Seek/Tune Complete */
+#define STATUSRSSI_SF          0x2000  /* bits 13..13: Seek Fail/Band Limit */
+#define STATUSRSSI_AFCRL       0x1000  /* bits 12..12: AFC Rail */
+#define STATUSRSSI_RDSS                0x0800  /* bits 11..11: RDS Synchronized (Si4701 only) */
+#define STATUSRSSI_BLERA       0x0600  /* bits 10..09: RDS Block A Errors (Si4701 only) */
+#define STATUSRSSI_ST          0x0100  /* bits 08..08: Stereo Indicator */
+#define STATUSRSSI_RSSI                0x00ff  /* bits 07..00: RSSI (Received Signal Strength Indicator) */
+
+#define READCHAN               11      /* Read Channel */
+#define READCHAN_BLERB         0xc000  /* bits 15..14: RDS Block D Errors (Si4701 only) */
+#define READCHAN_BLERC         0x3000  /* bits 13..12: RDS Block C Errors (Si4701 only) */
+#define READCHAN_BLERD         0x0c00  /* bits 11..10: RDS Block B Errors (Si4701 only) */
+#define READCHAN_READCHAN      0x03ff  /* bits 09..00: Read Channel */
+
+#define RDSA                   12      /* RDSA */
+#define RDSA_RDSA              0xffff  /* bits 15..00: RDS Block A Data (Si4701 only) */
+
+#define RDSB                   13      /* RDSB */
+#define RDSB_RDSB              0xffff  /* bits 15..00: RDS Block B Data (Si4701 only) */
+
+#define RDSC                   14      /* RDSC */
+#define RDSC_RDSC              0xffff  /* bits 15..00: RDS Block C Data (Si4701 only) */
+
+#define RDSD                   15      /* RDSD */
+#define RDSD_RDSD              0xffff  /* bits 15..00: RDS Block D Data (Si4701 only) */
+
+
+
+/**************************************************************************
+ * USB HID Reports
+ **************************************************************************/
+
+/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
+/* with the (REPORT_ID - 1) corresponding to the register address across USB */
+/* endpoint 0 using GET_REPORT and SET_REPORT */
+#define REGISTER_REPORT_SIZE   (RADIO_REGISTER_SIZE + 1)
+#define REGISTER_REPORT(reg)   ((reg) + 1)
+
+/* Report 17 gives direct read/write access to the entire Si470x register */
+/* map across endpoint 0 using GET_REPORT and SET_REPORT */
+#define ENTIRE_REPORT_SIZE     (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define ENTIRE_REPORT          17
+
+/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
+/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
+#define RDS_REPORT_SIZE                (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define RDS_REPORT             18
+
+/* Report 19: LED state */
+#define LED_REPORT_SIZE                3
+#define LED_REPORT             19
+
+/* Report 19: stream */
+#define STREAM_REPORT_SIZE     3
+#define        STREAM_REPORT           19
+
+/* Report 20: scratch */
+#define SCRATCH_PAGE_SIZE      63
+#define SCRATCH_REPORT_SIZE    (SCRATCH_PAGE_SIZE + 1)
+#define SCRATCH_REPORT         20
+
+/* Reports 19-22: flash upgrade of the C8051F321 */
+#define WRITE_REPORT           19
+#define FLASH_REPORT           20
+#define CRC_REPORT             21
+#define RESPONSE_REPORT                22
+
+/* Report 23: currently unused, but can accept 60 byte reports on the HID */
+/* interrupt out endpoint 2 every 1 millisecond */
+#define UNUSED_REPORT          23
+
+
+
+/**************************************************************************
+ * Software/Hardware Versions
+ **************************************************************************/
+#define RADIO_SW_VERSION_NOT_BOOTLOADABLE      6
+#define RADIO_SW_VERSION                       7
+#define RADIO_SW_VERSION_CURRENT               15
+#define RADIO_HW_VERSION                       1
+
+#define SCRATCH_PAGE_SW_VERSION        1
+#define SCRATCH_PAGE_HW_VERSION        2
+
+
+
+/**************************************************************************
+ * LED State Definitions
+ **************************************************************************/
+#define LED_COMMAND            0x35
+
+#define NO_CHANGE_LED          0x00
+#define ALL_COLOR_LED          0x01    /* streaming state */
+#define BLINK_GREEN_LED                0x02    /* connect state */
+#define BLINK_RED_LED          0x04
+#define BLINK_ORANGE_LED       0x10    /* disconnect state */
+#define SOLID_GREEN_LED                0x20    /* tuning/seeking state */
+#define SOLID_RED_LED          0x40    /* bootload state */
+#define SOLID_ORANGE_LED       0x80
+
+
+
+/**************************************************************************
+ * Stream State Definitions
+ **************************************************************************/
+#define STREAM_COMMAND 0x36
+#define STREAM_VIDPID  0x00
+#define STREAM_AUDIO   0xff
+
+
+
+/**************************************************************************
+ * Bootloader / Flash Commands
+ **************************************************************************/
+
+/* unique id sent to bootloader and required to put into a bootload state */
+#define UNIQUE_BL_ID           0x34
+
+/* mask for the flash data */
+#define FLASH_DATA_MASK                0x55
+
+/* bootloader commands */
+#define GET_SW_VERSION_COMMAND 0x00
+#define        SET_PAGE_COMMAND        0x01
+#define ERASE_PAGE_COMMAND     0x02
+#define WRITE_PAGE_COMMAND     0x03
+#define CRC_ON_PAGE_COMMAND    0x04
+#define READ_FLASH_BYTE_COMMAND        0x05
+#define RESET_DEVICE_COMMAND   0x06
+#define GET_HW_VERSION_COMMAND 0x07
+#define BLANK                  0xff
+
+/* bootloader command responses */
+#define COMMAND_OK             0x01
+#define COMMAND_FAILED         0x02
+#define COMMAND_PENDING                0x03
+
+/* buffer sizes */
+#define COMMAND_BUFFER_SIZE    4
+#define RESPONSE_BUFFER_SIZE   2
+#define FLASH_BUFFER_SIZE      64
+#define CRC_BUFFER_SIZE                3
+
+
+
+/**************************************************************************
+ * General Driver Definitions
+ **************************************************************************/
+
+/*
+ * si470x_device - private data
+ */
+struct si470x_device {
+       /* reference to USB and video device */
+       struct usb_device *usbdev;
+       struct video_device *videodev;
+
+       /* are these really necessary ? */
+       int users;
+
+       /* report buffer (maximum 64 bytes) */
+       unsigned char buf[64];
+
+       /* Silabs internal registers (0..15) */
+       unsigned short registers[RADIO_REGISTER_NUM];
+
+       /* RDS receive buffer */
+       struct work_struct work;
+       wait_queue_head_t read_queue;
+       struct timer_list timer;
+       spinlock_t lock;                /* buffer locking */
+       unsigned char *buffer;          /* size is always multiple of three */
+       unsigned int buf_size;
+       unsigned int rd_index;
+       unsigned int wr_index;
+};
+
+
+/*
+ * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
+ * 62.5 kHz otherwise.
+ * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
+ * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
+ * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
+ */
+#define FREQ_MUL (1000000 / 62.5)
+
+
+
+/**************************************************************************
+ * General Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_get_report - receive a HID report
+ */
+static int si470x_get_report(struct si470x_device *radio, int size)
+{
+       return usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               HID_REQ_GET_REPORT,
+               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+               radio->buf[0], 2,
+               radio->buf, size, usb_timeout);
+}
+
+
+/*
+ * si470x_set_report - send a HID report
+ */
+static int si470x_set_report(struct si470x_device *radio, int size)
+{
+       return usb_control_msg(radio->usbdev,
+               usb_sndctrlpipe(radio->usbdev, 0),
+               HID_REQ_SET_REPORT,
+               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+               radio->buf[0], 2,
+               radio->buf, size, usb_timeout);
+}
+
+
+/*
+ * si470x_get_register - read register
+ */
+static int si470x_get_register(struct si470x_device *radio, int regnr)
+{
+       int retval;
+
+       radio->buf[0] = REGISTER_REPORT(regnr);
+
+       retval = si470x_get_report(radio, REGISTER_REPORT_SIZE);
+       if (retval >= 0)
+               radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2];
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_register - write register
+ */
+static int si470x_set_register(struct si470x_device *radio, int regnr)
+{
+       int retval;
+
+       radio->buf[0] = REGISTER_REPORT(regnr);
+       radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8;
+       radio->buf[2] = (radio->registers[regnr] & 0x00ff);
+
+       retval = si470x_set_report(radio, REGISTER_REPORT_SIZE);
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_get_all_registers - read entire registers
+ */
+static int si470x_get_all_registers(struct si470x_device *radio)
+{
+       int retval;
+       int regnr;
+
+       radio->buf[0] = ENTIRE_REPORT;
+
+       retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE);
+
+       if (retval >= 0)
+               for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
+                       radio->registers[regnr] =
+                       (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
+                        radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_get_rds_registers - read rds registers
+ */
+static int si470x_get_rds_registers(struct si470x_device *radio)
+{
+       int retval;
+       int regnr;
+       int size;
+
+       radio->buf[0] = RDS_REPORT;
+
+       retval = usb_interrupt_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 1),
+               radio->buf, RDS_REPORT_SIZE, &size, usb_timeout);
+
+       if (retval >= 0)
+               for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+                       radio->registers[STATUSRSSI + regnr] =
+                       (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
+                        radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_chan - set the channel
+ */
+static int si470x_set_chan(struct si470x_device *radio, int chan)
+{
+       int retval, i;
+
+       /* start tuning */
+       radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
+       radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
+       retval = si470x_set_register(radio, CHANNEL);
+       if (retval < 0)
+               return retval;
+
+       /* wait till seek operation has completed */
+       i = 0;
+       do {
+               retval = si470x_get_register(radio, STATUSRSSI);
+               if (retval < 0)
+                       return retval;
+       } while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) &&
+               (++i < seek_retries));
+       if (i >= seek_retries)
+               printk(KERN_WARNING DRIVER_NAME
+                       ": seek does not finish after %d tries\n", i);
+
+       /* stop tuning */
+       radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
+       return si470x_set_register(radio, CHANNEL);
+}
+
+
+/*
+ * si470x_get_freq - get the frequency
+ */
+static int si470x_get_freq(struct si470x_device *radio)
+{
+       int spacing, band_bottom, chan, freq;
+       int retval;
+
+       /* Spacing (kHz) */
+       switch (space) {
+       /* 0: 200 kHz (USA, Australia) */
+       case 0 : spacing = 0.200 * FREQ_MUL; break;
+       /* 1: 100 kHz (Europe, Japan) */
+       case 1 : spacing = 0.100 * FREQ_MUL; break;
+       /* 2:  50 kHz */
+       default: spacing = 0.050 * FREQ_MUL; break;
+       };
+
+       /* Bottom of Band (MHz) */
+       switch (band) {
+       /* 0: 87.5 - 108 MHz (USA, Europe) */
+       case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+       /* 1: 76   - 108 MHz (Japan wide band) */
+       default: band_bottom = 76   * FREQ_MUL; break;
+       /* 2: 76   -  90 MHz (Japan) */
+       case 2 : band_bottom = 76   * FREQ_MUL; break;
+       };
+
+       /* read channel */
+       retval = si470x_get_register(radio, READCHAN);
+       if (retval < 0)
+               return retval;
+       chan = radio->registers[READCHAN] & READCHAN_READCHAN;
+
+       /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
+       freq = chan * spacing + band_bottom;
+
+       return freq;
+}
+
+
+/*
+ * si470x_set_freq - set the frequency
+ */
+static int si470x_set_freq(struct si470x_device *radio, int freq)
+{
+       int spacing, band_bottom, chan;
+
+       /* Spacing (kHz) */
+       switch (space) {
+       /* 0: 200 kHz (USA, Australia) */
+       case 0 : spacing = 0.200 * FREQ_MUL; break;
+       /* 1: 100 kHz (Europe, Japan) */
+       case 1 : spacing = 0.100 * FREQ_MUL; break;
+       /* 2:  50 kHz */
+       default: spacing = 0.050 * FREQ_MUL; break;
+       };
+
+       /* Bottom of Band (MHz) */
+       switch (band) {
+       /* 0: 87.5 - 108 MHz (USA, Europe) */
+       case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+       /* 1: 76   - 108 MHz (Japan wide band) */
+       default: band_bottom = 76   * FREQ_MUL; break;
+       /* 2: 76   -  90 MHz (Japan) */
+       case 2 : band_bottom = 76   * FREQ_MUL; break;
+       };
+
+       /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
+       chan = (freq - band_bottom) / spacing;
+
+       return si470x_set_chan(radio, chan);
+}
+
+
+/*
+ * si470x_start - switch on radio
+ */
+static int si470x_start(struct si470x_device *radio)
+{
+       int retval;
+
+       /* powercfg */
+       radio->registers[POWERCFG] =
+               POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
+       retval = si470x_set_register(radio, POWERCFG);
+       if (retval < 0)
+               return retval;
+
+       /* sysconfig 1 */
+       radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+       retval = si470x_set_register(radio, SYSCONFIG1);
+       if (retval < 0)
+               return retval;
+
+       /* sysconfig 2 */
+       radio->registers[SYSCONFIG2] =
+               (0x3f  << 8) |  /* SEEKTH */
+               (band  << 6) |  /* BAND */
+               (space << 4) |  /* SPACE */
+               15;             /* VOLUME (max) */
+       retval = si470x_set_register(radio, SYSCONFIG2);
+       if (retval < 0)
+               return retval;
+
+       /* reset last channel */
+       return si470x_set_chan(radio,
+               radio->registers[CHANNEL] & CHANNEL_CHAN);
+}
+
+
+/*
+ * si470x_stop - switch off radio
+ */
+static int si470x_stop(struct si470x_device *radio)
+{
+       int retval;
+
+       /* sysconfig 1 */
+       radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
+       retval = si470x_set_register(radio, SYSCONFIG1);
+       if (retval < 0)
+               return retval;
+
+       /* powercfg */
+       radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+       /* POWERCFG_ENABLE has to automatically go low */
+       radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
+       return si470x_set_register(radio, POWERCFG);
+}
+
+
+/*
+ * si470x_rds_on - switch on rds reception
+ */
+static int si470x_rds_on(struct si470x_device *radio)
+{
+       /* sysconfig 1 */
+       radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
+       return si470x_set_register(radio, SYSCONFIG1);
+}
+
+
+
+/**************************************************************************
+ * RDS Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_rds - rds processing function
+ */
+static void si470x_rds(struct si470x_device *radio)
+{
+       unsigned char tmpbuf[3];
+       unsigned char blocknum;
+       unsigned char bler; /* rds block errors */
+       unsigned short rds;
+       unsigned int i;
+
+       /* get rds blocks */
+       if (si470x_get_rds_registers(radio) < 0)
+               return;
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
+               /* No RDS group ready */
+               return;
+       }
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
+               /* RDS decoder not synchronized */
+               return;
+       }
+
+       /* copy four RDS blocks to internal buffer */
+       if (spin_trylock(&radio->lock)) {
+               /* process each rds block */
+               for (blocknum = 0; blocknum < 4; blocknum++) {
+                       switch (blocknum) {
+                       default:
+                               bler = (radio->registers[STATUSRSSI] &
+                                               STATUSRSSI_BLERA) >> 9;
+                               rds = radio->registers[RDSA];
+                               break;
+                       case 1:
+                               bler = (radio->registers[READCHAN] &
+                                               READCHAN_BLERB) >> 14;
+                               rds = radio->registers[RDSB];
+                               break;
+                       case 2:
+                               bler = (radio->registers[READCHAN] &
+                                               READCHAN_BLERC) >> 12;
+                               rds = radio->registers[RDSC];
+                               break;
+                       case 3:
+                               bler = (radio->registers[READCHAN] &
+                                               READCHAN_BLERD) >> 10;
+                               rds = radio->registers[RDSD];
+                               break;
+                       };
+
+                       /* Fill the V4L2 RDS buffer */
+                       tmpbuf[0] = rds & 0x00ff;       /* LSB */
+                       tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */
+                       tmpbuf[2] = blocknum;           /* offset name */
+                       tmpbuf[2] |= blocknum << 3;     /* received offset */
+                       if (bler > max_rds_errors)
+                               tmpbuf[2] |= 0x80; /* uncorrectable errors */
+                       else if (bler > 0)
+                               tmpbuf[2] |= 0x40; /* corrected error(s) */
+
+                       /* copy RDS block to internal buffer */
+                       for (i = 0; i < 3; i++) {
+                               radio->buffer[radio->wr_index] = tmpbuf[i];
+                               radio->wr_index++;
+                       }
+
+                       /* wrap write pointer */
+                       if (radio->wr_index >= radio->buf_size)
+                               radio->wr_index = 0;
+
+                       /* check for overflow */
+                       if (radio->wr_index == radio->rd_index) {
+                               /* increment and wrap read pointer */
+                               radio->rd_index += 3;
+                               if (radio->rd_index >= radio->buf_size)
+                                       radio->rd_index = 0;
+                       }
+               }
+               spin_unlock(&radio->lock);
+       }
+
+       /* wake up read queue */
+       if (radio->wr_index != radio->rd_index)
+               wake_up_interruptible(&radio->read_queue);
+}
+
+
+/*
+ * si470x_timer - rds timer function
+ */
+static void si470x_timer(unsigned long data)
+{
+       struct si470x_device *radio = (struct si470x_device *) data;
+
+       schedule_work(&radio->work);
+}
+
+
+/*
+ * si470x_work - rds work function
+ */
+static void si470x_work(struct work_struct *work)
+{
+       struct si470x_device *radio = container_of(work, struct si470x_device,
+               work);
+
+       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+               return;
+
+       si470x_rds(radio);
+       mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time));
+}
+
+
+
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si470x_fops_read - read RDS data
+ */
+static ssize_t si470x_fops_read(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       int retval = 0;
+       unsigned int block_count = 0;
+
+       /* switch on rds reception */
+       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
+               si470x_rds_on(radio);
+               schedule_work(&radio->work);
+       }
+
+       /* block if no new data available */
+       while (radio->wr_index == radio->rd_index) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               interruptible_sleep_on(&radio->read_queue);
+       }
+
+       /* calculate block count from byte count */
+       count /= 3;
+
+       /* copy RDS block out of internal buffer and to user buffer */
+       if (spin_trylock(&radio->lock)) {
+               while (block_count < count) {
+                       if (radio->rd_index == radio->wr_index)
+                               break;
+
+                       /* always transfer rds complete blocks */
+                       if (copy_to_user(buf,
+                                       &radio->buffer[radio->rd_index], 3))
+                               /* retval = -EFAULT; */
+                               break;
+
+                       /* increment and wrap read pointer */
+                       radio->rd_index += 3;
+                       if (radio->rd_index >= radio->buf_size)
+                               radio->rd_index = 0;
+
+                       /* increment counters */
+                       block_count++;
+                       buf += 3;
+                       retval += 3;
+               }
+
+               spin_unlock(&radio->lock);
+       }
+
+       return retval;
+}
+
+
+/*
+ * si470x_fops_poll - poll RDS data
+ */
+static unsigned int si470x_fops_poll(struct file *file,
+               struct poll_table_struct *pts)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       /* switch on rds reception */
+       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
+               si470x_rds_on(radio);
+               schedule_work(&radio->work);
+       }
+
+       poll_wait(file, &radio->read_queue, pts);
+
+       if (radio->rd_index != radio->wr_index)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+
+/*
+ * si470x_fops_open - file open
+ */
+static int si470x_fops_open(struct inode *inode, struct file *file)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       radio->users++;
+       if (radio->users == 1)
+               return si470x_start(radio);
+
+       return 0;
+}
+
+
+/*
+ * si470x_fops_release - file release
+ */
+static int si470x_fops_release(struct inode *inode, struct file *file)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       if (!radio)
+               return -ENODEV;
+
+       radio->users--;
+       if (radio->users == 0) {
+               /* stop rds reception */
+               del_timer_sync(&radio->timer);
+               flush_scheduled_work();
+
+               /* cancel read processes */
+               wake_up_interruptible(&radio->read_queue);
+
+               return si470x_stop(radio);
+       }
+
+       return 0;
+}
+
+
+/*
+ * si470x_fops - file operations interface
+ */
+static const struct file_operations si470x_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = si470x_fops_read,
+       .poll           = si470x_fops_poll,
+       .ioctl          = video_ioctl2,
+       .compat_ioctl   = v4l_compat_ioctl32,
+       .open           = si470x_fops_open,
+       .release        = si470x_fops_release,
+};
+
+
+
+/**************************************************************************
+ * Video4Linux Interface
+ **************************************************************************/
+
+/*
+ * si470x_v4l2_queryctrl - query control
+ */
+static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
+/* HINT: the disabled controls are only here to satify kradio and such apps */
+       {
+               .id             = V4L2_CID_AUDIO_VOLUME,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Volume",
+               .minimum        = 0,
+               .maximum        = 15,
+               .step           = 1,
+               .default_value  = 15,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BALANCE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BASS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_TREBLE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_MUTE,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Mute",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_LOUDNESS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+};
+
+
+/*
+ * si470x_vidioc_querycap - query device capabilities
+ */
+static int si470x_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *capability)
+{
+       strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+       strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+       sprintf(capability->bus_info, "USB");
+       capability->version = DRIVER_VERSION;
+       capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_input - get input
+ */
+static int si470x_vidioc_g_input(struct file *filp, void *priv,
+               unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_input - set input
+ */
+static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_queryctrl - enumerate control items
+ */
+static int si470x_vidioc_queryctrl(struct file *file, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
+               if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
+                       memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+
+/*
+ * si470x_vidioc_g_ctrl - get the value of a control
+ */
+static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = radio->registers[SYSCONFIG2] &
+                               SYSCONFIG2_VOLUME;
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = ((radio->registers[POWERCFG] &
+                               POWERCFG_DMUTE) == 0) ? 1 : 0;
+               break;
+       }
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_ctrl - set the value of a control
+ */
+static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
+               radio->registers[SYSCONFIG2] |= ctrl->value;
+               return si470x_set_register(radio, SYSCONFIG2);
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value == 1)
+                       radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+               else
+                       radio->registers[POWERCFG] |= POWERCFG_DMUTE;
+               return si470x_set_register(radio, POWERCFG);
+       }
+
+       return -EINVAL;
+}
+
+
+/*
+ * si470x_vidioc_g_audio - get audio attributes
+ */
+static int si470x_vidioc_g_audio(struct file *file, void *priv,
+               struct v4l2_audio *audio)
+{
+       if (audio->index > 1)
+               return -EINVAL;
+
+       strcpy(audio->name, "Radio");
+       audio->capability = V4L2_AUDCAP_STEREO;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_audio - set audio attributes
+ */
+static int si470x_vidioc_s_audio(struct file *file, void *priv,
+               struct v4l2_audio *audio)
+{
+       if (audio->index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_tuner - get tuner attributes
+ */
+static int si470x_vidioc_g_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       int retval;
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       if (tuner->index > 0)
+               return -EINVAL;
+
+       /* read status rssi */
+       retval = si470x_get_register(radio, STATUSRSSI);
+       if (retval < 0)
+               return retval;
+
+       strcpy(tuner->name, "FM");
+       tuner->type = V4L2_TUNER_RADIO;
+       switch (band) {
+       /* 0: 87.5 - 108 MHz (USA, Europe, default) */
+       default:
+               tuner->rangelow  =  87.5 * FREQ_MUL;
+               tuner->rangehigh = 108   * FREQ_MUL;
+               break;
+       /* 1: 76   - 108 MHz (Japan wide band) */
+       case 1 :
+               tuner->rangelow  =  76   * FREQ_MUL;
+               tuner->rangehigh = 108   * FREQ_MUL;
+               break;
+       /* 2: 76   -  90 MHz (Japan) */
+       case 2 :
+               tuner->rangelow  =  76   * FREQ_MUL;
+               tuner->rangehigh =  90   * FREQ_MUL;
+               break;
+       };
+       tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       tuner->capability = V4L2_TUNER_CAP_LOW;
+
+       /* Stereo indicator == Stereo (instead of Mono) */
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
+               tuner->audmode = V4L2_TUNER_MODE_STEREO;
+       else
+               tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+       /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
+       tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
+                               * 0x0101;
+
+       /* automatic frequency control: -1: freq to low, 1 freq to high */
+       tuner->afc = 0;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_tuner - set tuner attributes
+ */
+static int si470x_vidioc_s_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       if (tuner->index > 0)
+               return -EINVAL;
+
+       if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+               radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
+       else
+               radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
+
+       return si470x_set_register(radio, POWERCFG);
+}
+
+
+/*
+ * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
+ */
+static int si470x_vidioc_g_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       freq->type = V4L2_TUNER_RADIO;
+       freq->frequency = si470x_get_freq(radio);
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
+ */
+static int si470x_vidioc_s_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+       if (freq->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+
+       return si470x_set_freq(radio, freq->frequency);
+}
+
+
+/*
+ * si470x_viddev_tamples - video device interface
+ */
+static struct video_device si470x_viddev_template = {
+       .fops                   = &si470x_fops,
+       .name                   = DRIVER_NAME,
+       .type                   = VID_TYPE_TUNER,
+       .release                = video_device_release,
+       .vidioc_querycap        = si470x_vidioc_querycap,
+       .vidioc_g_input         = si470x_vidioc_g_input,
+       .vidioc_s_input         = si470x_vidioc_s_input,
+       .vidioc_queryctrl       = si470x_vidioc_queryctrl,
+       .vidioc_g_ctrl          = si470x_vidioc_g_ctrl,
+       .vidioc_s_ctrl          = si470x_vidioc_s_ctrl,
+       .vidioc_g_audio         = si470x_vidioc_g_audio,
+       .vidioc_s_audio         = si470x_vidioc_s_audio,
+       .vidioc_g_tuner         = si470x_vidioc_g_tuner,
+       .vidioc_s_tuner         = si470x_vidioc_s_tuner,
+       .vidioc_g_frequency     = si470x_vidioc_g_frequency,
+       .vidioc_s_frequency     = si470x_vidioc_s_frequency,
+       .owner                  = THIS_MODULE,
+};
+
+
+
+/**************************************************************************
+ * USB Interface
+ **************************************************************************/
+
+/*
+ * si470x_usb_driver_probe - probe for the device
+ */
+static int si470x_usb_driver_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct si470x_device *radio;
+
+       /* memory and interface allocations */
+       radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL);
+       if (!radio)
+               return -ENOMEM;
+       radio->videodev = video_device_alloc();
+       if (!radio->videodev) {
+               kfree(radio);
+               return -ENOMEM;
+       }
+       memcpy(radio->videodev, &si470x_viddev_template,
+                       sizeof(si470x_viddev_template));
+       radio->users = 0;
+       radio->usbdev = interface_to_usbdev(intf);
+       video_set_drvdata(radio->videodev, radio);
+       if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+               printk(KERN_WARNING DRIVER_NAME
+                               ": Could not register video device\n");
+               video_device_release(radio->videodev);
+               kfree(radio);
+               return -EIO;
+       }
+       usb_set_intfdata(intf, radio);
+
+       /* show some infos about the specific device */
+       if (si470x_get_all_registers(radio) < 0) {
+               video_device_release(radio->videodev);
+               kfree(radio);
+               return -EIO;
+       }
+       printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n",
+                       radio->registers[DEVICEID], radio->registers[CHIPID]);
+
+       /* check if firmware is current */
+       if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
+                       < RADIO_SW_VERSION_CURRENT)
+               printk(KERN_WARNING DRIVER_NAME
+                       ": This driver is known to work with chip version %d, "
+                       "but the device has firmware %d.\n"
+                       DRIVER_NAME
+                       "If you have some trouble using this driver, please "
+                       "report to V4L ML at video4linux-list@redhat.com\n",
+                       radio->registers[CHIPID] & CHIPID_FIRMWARE,
+                       RADIO_SW_VERSION_CURRENT);
+
+       /* set initial frequency */
+       si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
+
+       /* rds initialization */
+       radio->buf_size = rds_buf * 3;
+       radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+       if (!radio->buffer) {
+               video_device_release(radio->videodev);
+               kfree(radio);
+               return -ENOMEM;
+       }
+       radio->wr_index = 0;
+       radio->rd_index = 0;
+       init_waitqueue_head(&radio->read_queue);
+
+       /* prepare polling via eventd */
+       INIT_WORK(&radio->work, si470x_work);
+       init_timer(&radio->timer);
+       radio->timer.function = si470x_timer;
+       radio->timer.data = (unsigned long) radio;
+
+       return 0;
+}
+
+
+/*
+ * si470x_usb_driver_disconnect - disconnect the device
+ */
+static void si470x_usb_driver_disconnect(struct usb_interface *intf)
+{
+       struct si470x_device *radio = usb_get_intfdata(intf);
+
+       del_timer_sync(&radio->timer);
+       flush_scheduled_work();
+
+       usb_set_intfdata(intf, NULL);
+       if (radio) {
+               video_unregister_device(radio->videodev);
+               kfree(radio->buffer);
+               kfree(radio);
+       }
+}
+
+
+/*
+ * si470x_usb_driver - usb driver interface
+ */
+static struct usb_driver si470x_usb_driver = {
+       .name           = DRIVER_NAME,
+       .probe          = si470x_usb_driver_probe,
+       .disconnect     = si470x_usb_driver_disconnect,
+       .id_table       = si470x_usb_driver_id_table,
+};
+
+
+
+/**************************************************************************
+ * Module Interface
+ **************************************************************************/
+
+/*
+ * si470x_module_init - module init
+ */
+static int __init si470x_module_init(void)
+{
+       printk(KERN_INFO DRIVER_DESC "\n");
+       return usb_register(&si470x_usb_driver);
+}
+
+
+/*
+ * si470x_module_exit - module exit
+ */
+static void __exit si470x_module_exit(void)
+{
+       usb_deregister(&si470x_usb_driver);
+}
+
+
+module_init(si470x_module_init);
+module_exit(si470x_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION("1.0.4");
index c9f14bfc85441cf28ce522875ba9169a6b82f56e..a2e8987a61954acfa1c4c654933e1193e7daf2ab 100644 (file)
@@ -45,7 +45,7 @@ comment "Audio decoders"
 
 config VIDEO_TVAUDIO
        tristate "Simple audio decoder chips"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for several audio decoder chips found on some bt8xx boards:
          Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
@@ -57,7 +57,7 @@ config VIDEO_TVAUDIO
 
 config VIDEO_TDA7432
        tristate "Philips TDA7432 audio processor"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for tda7432 audio decoder chip found on some bt8xx boards.
 
@@ -75,7 +75,7 @@ config VIDEO_TDA9840
 
 config VIDEO_TDA9875
        tristate "Philips TDA9875 audio processor"
-       depends on VIDEO_V4L1 && I2C
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for tda9875 audio decoder chip found on some bt8xx boards.
 
@@ -109,9 +109,19 @@ config VIDEO_MSP3400
          To compile this driver as a module, choose M here: the
          module will be called msp3400.
 
+config VIDEO_CS5345
+       tristate "Cirrus Logic CS5345 audio ADC"
+       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       ---help---
+         Support for the Cirrus Logic CS5345 24-bit, 192 kHz
+         stereo A/D converter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cs5345.
+
 config VIDEO_CS53L32A
        tristate "Cirrus Logic CS53L32A audio ADC"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Cirrus Logic CS53L32A low voltage
          stereo A/D converter.
@@ -119,6 +129,15 @@ config VIDEO_CS53L32A
          To compile this driver as a module, choose M here: the
          module will be called cs53l32a.
 
+config VIDEO_M52790
+       tristate "Mitsubishi M52790 A/V switch"
+       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       ---help---
+        Support for the Mitsubishi M52790 A/V switch.
+
+        To compile this driver as a module, choose M here: the
+        module will be called m52790.
+
 config VIDEO_TLV320AIC23B
        tristate "Texas Instruments TLV320AIC23B audio codec"
        depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
@@ -130,7 +149,7 @@ config VIDEO_TLV320AIC23B
 
 config VIDEO_WM8775
        tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Wolfson Microelectronics WM8775 high
          performance stereo A/D Converter with a 4 channel input mixer.
@@ -140,7 +159,7 @@ config VIDEO_WM8775
 
 config VIDEO_WM8739
        tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Wolfson Microelectronics WM8739
          stereo A/D Converter.
@@ -244,7 +263,7 @@ config VIDEO_SAA7114
 
 config VIDEO_SAA711X
        tristate "Philips SAA7113/4/5 video decoders"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Philips SAA7113/4/5 video decoders.
 
@@ -300,7 +319,7 @@ comment "Video encoders"
 
 config VIDEO_SAA7127
        tristate "Philips SAA7127/9 digital video encoders"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Philips SAA7127/9 digital video encoders.
 
@@ -338,7 +357,7 @@ comment "Video improvement chips"
 
 config VIDEO_UPD64031A
        tristate "NEC Electronics uPD64031A Ghost Reduction"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the NEC Electronics uPD64031A Ghost Reduction
          video chip. It is most often found in NTSC TV cards made for
@@ -350,7 +369,7 @@ config VIDEO_UPD64031A
 
 config VIDEO_UPD64083
        tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the NEC Electronics uPD64083 3-Dimensional Y/C
          separation video chip. It is used to improve the quality of
@@ -802,6 +821,19 @@ config USB_ZR364XX
          To compile this driver as a module, choose M here: the
          module will be called zr364xx.
 
+config USB_STKWEBCAM
+       tristate "USB Syntek DC1125 Camera support"
+       depends on VIDEO_V4L2 && EXPERIMENTAL
+       ---help---
+         Say Y here if you want to use this type of camera.
+         Supported devices are typically found in some Asus laptops,
+         with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
+         may be supported by the stk11xx driver, from which this is
+         derived, see http://stk11xx.sourceforge.net
+
+         To compile this driver as a module, choose M here: the
+         module will be called stkwebcam.
+
 endif # V4L_USB_DRIVERS
 
 endif # VIDEO_CAPTURE_DRIVERS
index b5a064163e03f49231cd957db20790a11c19ac68..28ddd146c1c52a208222945cd816a0504db3431b 100644 (file)
@@ -4,10 +4,12 @@
 
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
-tuner-objs     :=      tuner-core.o tuner-types.o tda9887.o
+tuner-objs     :=      tuner-core.o tuner-types.o
 
 msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
 
+stkwebcam-objs :=      stk-webcam.o stk-sensor.o
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
                           v4l2-int-device.o
 
@@ -66,7 +68,9 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
@@ -81,11 +85,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 
+obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
 obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
 obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
 obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
 obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
 obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -112,6 +118,7 @@ obj-$(CONFIG_USB_SE401)         += se401.o
 obj-$(CONFIG_USB_STV680)        += stv680.o
 obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
+obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
@@ -129,3 +136,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
index 2ca162b390a219fe7b7cb8501ab99eb18f06f048..cfc822bb502a92b9cd2c6b66fe3c52d508ec91ef 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_BT848
        tristate "BT848 Video For Linux"
-       depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
+       depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
        select I2C_ALGOBIT
        select FW_LOADER
        select VIDEO_BTCX
index a096a03418aaf430dd7b83c1b130642cae4656f1..924d216d95705c1bb30dfc562294fb3c69255734 100644 (file)
@@ -4,7 +4,7 @@
 
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
                       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
-                      bttv-input.o
+                      bttv-input.o bttv-audio-hook.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
 
diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c
new file mode 100644 (file)
index 0000000..2364d16
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttv-audio-hook.h"
+
+#include <linux/delay.h>
+
+/* ----------------------------------------------------------------------- */
+/* winview                                                                 */
+
+void winview_volume(struct bttv *btv, __u16 volume)
+{
+       /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+       int bits_out, loops, vol, data;
+
+       /* 32 levels logarithmic */
+       vol = 32 - ((volume>>11));
+       /* units */
+       bits_out = (PT2254_DBS_IN_2>>(vol%5));
+       /* tens */
+       bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+       bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
+       data = gpio_read();
+       data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+                 WINVIEW_PT2254_STROBE);
+       for (loops = 17; loops >= 0 ; loops--) {
+               if (bits_out & (1<<loops))
+                       data |=  WINVIEW_PT2254_DATA;
+               else
+                       data &= ~WINVIEW_PT2254_DATA;
+               gpio_write(data);
+               udelay(5);
+               data |= WINVIEW_PT2254_CLK;
+               gpio_write(data);
+               udelay(5);
+               data &= ~WINVIEW_PT2254_CLK;
+               gpio_write(data);
+       }
+       data |=  WINVIEW_PT2254_STROBE;
+       data &= ~WINVIEW_PT2254_DATA;
+       gpio_write(data);
+       udelay(10);
+       data &= ~WINVIEW_PT2254_STROBE;
+       gpio_write(data);
+}
+
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but    */
+/* connect something to the GPIO pins                                      */
+
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned int con = 0;
+
+       if (set) {
+               gpio_inout(0x300, 0x300);
+               if (t->audmode & V4L2_TUNER_MODE_LANG1)
+                       con = 0x000;
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)
+                       con = 0x300;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)
+                       con = 0x200;
+/*             if (t->audmode & V4L2_TUNER_MODE_MONO)
+ *                     con = 0x100; */
+               gpio_bits(0x300, con);
+       } else {
+               t->audmode = V4L2_TUNER_MODE_STEREO |
+                         V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned int val, con;
+
+       if (btv->radio_user)
+               return;
+
+       val = gpio_read();
+       if (set) {
+               con = 0x000;
+               if (t->audmode & V4L2_TUNER_MODE_LANG2) {
+                       if (t->audmode & V4L2_TUNER_MODE_LANG1) {
+                               /* LANG1 + LANG2 */
+                               con = 0x100;
+                       }
+                       else {
+                               /* LANG2 */
+                               con = 0x300;
+                       }
+               }
+               if (con != (val & 0x300)) {
+                       gpio_bits(0x300, con);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"gvbctv5pci");
+               }
+       } else {
+               switch (val & 0x70) {
+                 case 0x10:
+                       t->rxsubchans = V4L2_TUNER_SUB_LANG1 |  V4L2_TUNER_SUB_LANG2;
+                       break;
+                 case 0x30:
+                       t->rxsubchans = V4L2_TUNER_SUB_LANG2;
+                       break;
+                 case 0x50:
+                       t->rxsubchans = V4L2_TUNER_SUB_LANG1;
+                       break;
+                 case 0x60:
+                       t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       break;
+                 case 0x70:
+                       t->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       break;
+                 default:
+                       t->rxsubchans = V4L2_TUNER_SUB_MONO |
+                                        V4L2_TUNER_SUB_STEREO |
+                                        V4L2_TUNER_SUB_LANG1 |
+                                        V4L2_TUNER_SUB_LANG2;
+               }
+               t->audmode = V4L2_TUNER_MODE_STEREO |
+                         V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ *  0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ *  input/output sound connection, so both must be set for output mode.
+ *
+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
+ * handles this with a tda9840
+ *
+ */
+
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       int val = 0;
+
+       if (set) {
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+                       val = 0x02;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)
+                       val = 0x01;
+               if (val) {
+                       gpio_bits(0x03,val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"avermedia");
+               }
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1;
+               return;
+       }
+}
+
+
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       int val = 0;
+
+       if (set) {
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+                       val = 0x01;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)  /* STEREO */
+                       val = 0x02;
+               btaor(val, ~0x03, BT848_GPIO_DATA);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"avermedia");
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+               return;
+       }
+}
+
+/* Lifetec 9415 handling */
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       int val = 0;
+
+       if (gpio_read() & 0x4000) {
+               t->audmode = V4L2_TUNER_MODE_MONO;
+               return;
+       }
+
+       if (set) {
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)  /* A2 SAP */
+                       val = 0x0080;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */
+                       val = 0x0880;
+               if ((t->audmode & V4L2_TUNER_MODE_LANG1) ||
+                   (t->audmode & V4L2_TUNER_MODE_MONO))
+                       val = 0;
+               gpio_bits(0x0880, val);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"lt9415");
+       } else {
+               /* autodetect doesn't work with this card :-( */
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+               return;
+       }
+}
+
+/* TDA9821 on TerraTV+ Bt848, Bt878 */
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *t, int set)
+{
+       unsigned int con = 0;
+
+       if (set) {
+               gpio_inout(0x180000,0x180000);
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)
+                       con = 0x080000;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)
+                       con = 0x180000;
+               gpio_bits(0x180000, con);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"terratv");
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned long val = 0;
+
+       if (set) {
+               /*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+               if (t->audmode & V4L2_TUNER_MODE_MONO)          /* Mono */
+                       val = 0x420000;
+               if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */
+                       val = 0x420000;
+               if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */
+                       val = 0x410000;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)        /* Stereo */
+                       val = 0x020000;
+               if (val) {
+                       gpio_bits(0x430000, val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"winfast2000");
+               }
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                         V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+ * revision 9B has on-board TDA9874A sound decoder).
+ *
+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+ *       will mute this cards.
+ */
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned int val = 0;
+
+       if (btv->radio_user)
+               return;
+
+       if (set) {
+               if (t->audmode & V4L2_TUNER_MODE_MONO)  {
+                       val = 0x01;
+               }
+               if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+                   || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+                       val = 0x02;
+               }
+               if (val) {
+                       gpio_bits(0x03,val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"pvbt878p9b");
+               }
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for FlyVideo 2000S (with tda9874 decoder)
+ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+ */
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned int val = 0xffff;
+
+       if (btv->radio_user)
+               return;
+
+       if (set) {
+               if (t->audmode & V4L2_TUNER_MODE_MONO)  {
+                       val = 0x0000;
+               }
+               if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+                   || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+                       val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
+               }
+               if (val != 0xffff) {
+                       gpio_bits(0x1800, val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"fv2000s");
+               }
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+/*
+ * sound control for Canopus WinDVR PCI
+ * Masaki Suzuki <masaki@btree.org>
+ */
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned long val = 0;
+
+       if (set) {
+               if (t->audmode & V4L2_TUNER_MODE_MONO)
+                       val = 0x040000;
+               if (t->audmode & V4L2_TUNER_MODE_LANG1)
+                       val = 0;
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)
+                       val = 0x100000;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)
+                       val = 0;
+               if (val) {
+                       gpio_bits(0x140000, val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"windvr");
+               }
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                         V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       }
+}
+
+/*
+ * sound control for AD-TVK503
+ * Hiroshi Takekawa <sian@big.or.jp>
+ */
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+       unsigned int con = 0xffffff;
+
+       /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
+
+       if (set) {
+               /* btor(***, BT848_GPIO_OUT_EN); */
+               if (t->audmode & V4L2_TUNER_MODE_LANG1)
+                       con = 0x00000000;
+               if (t->audmode & V4L2_TUNER_MODE_LANG2)
+                       con = 0x00180000;
+               if (t->audmode & V4L2_TUNER_MODE_STEREO)
+                       con = 0x00000000;
+               if (t->audmode & V4L2_TUNER_MODE_MONO)
+                       con = 0x00060000;
+               if (con != 0xffffff) {
+                       gpio_bits(0x1e0000,con);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv, "adtvk503");
+               }
+       } else {
+               t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+                         V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+       }
+}
diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h
new file mode 100644 (file)
index 0000000..159d07a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttvp.h"
+
+void winview_volume (struct bttv *btv, __u16 volume);
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *tuner, int set);
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+
index 585d1ef95afdd6956d5dca05b50c524f4e5511d7..63a47cd4c161110796503cfc3a83fa5412e9ba7a 100644 (file)
@@ -39,6 +39,7 @@
 #include "bttvp.h"
 #include <media/v4l2-common.h>
 #include <media/tvaudio.h>
+#include "bttv-audio-hook.h"
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
@@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
 static void init_RTV24(struct bttv *btv);
 
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
-static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
-static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
-                                   int set);
-static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
-                                     int set);
-static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
-static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
-static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
-static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
-static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
 static void rv605_muxsel(struct bttv *btv, unsigned int input);
 static void eagle_muxsel(struct bttv *btv, unsigned int input);
 static void xguard_muxsel(struct bttv *btv, unsigned int input);
@@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = avermedia_tvphone_audio,
+               .audio_mode_gpio= avermedia_tvphone_audio,
                .has_remote     = 1,
        },
        [BTTV_BOARD_MATRIX_VISION] = {
@@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = avermedia_tv_stereo_audio,
+               .audio_mode_gpio= avermedia_tv_stereo_audio,
                .no_gpioirq     = 1,
        },
        [BTTV_BOARD_VHX] = {
@@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = winview_audio,
+               .volume_gpio    = winview_volume,
                .has_radio      = 1,
        },
        [BTTV_BOARD_AVEC_INTERCAP] = {
@@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = terratv_audio,
+               .audio_mode_gpio= terratv_audio,
        },
        [BTTV_BOARD_HAUPPAUG_WCAM] = {
                .name           = "Hauppauge WinCam newer (bt878)",
@@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = terratv_audio,
+               .audio_mode_gpio= terratv_audio,
                /* GPIO wiring:
                External 20 pin connector (for Active Radio Upgrade board)
                gpio00: i2c-sda
@@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = winfast2000_audio,
+               .audio_mode_gpio= winfast2000_audio,
                .has_remote     = 1,
        },
        [BTTV_BOARD_CHRONOS_VS2] = {
@@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
-               .audio_hook     = avermedia_tvphone_audio,
+               .audio_mode_gpio= avermedia_tvphone_audio,
        },
        [BTTV_BOARD_PV951] = {
                .name           = "ProVideo PV951", /* pic16c54 */
@@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ALPS_TSHC6_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = gvbctv3pci_audio,
+               .audio_mode_gpio= gvbctv3pci_audio,
        },
        [BTTV_BOARD_PXELVWPLTVPAK] = {
                .name           = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
@@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = {
                                /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
                .gpiomux        = { 0x0000,0x0800,0x1000,0x1000 },
                .gpiomute       = 0x1800,
-               .audio_hook     = fv2000s_audio,
+               .audio_mode_gpio= fv2000s_audio,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .needs_tvaudio  = 1,
@@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = gvbctv3pci_audio,
+               .audio_mode_gpio= gvbctv3pci_audio,
        },
 
        /* ---- card 0x44 ---------------------------------- */
@@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
+               .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
                .has_radio      = 1,  /* Note: not all cards have radio */
                .has_remote     = 1,
                /* GPIO wiring:
@@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = windvr_audio,
+               .audio_mode_gpio= windvr_audio,
        },
        [BTTV_BOARD_GRANDTEC_MULTI] = {
                .name           = "GrandTec Multi Capture Card (Bt878)",
@@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_NTSC_M,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = gvbctv5pci_audio,
+               .audio_mode_gpio= gvbctv5pci_audio,
                .has_radio      = 1,
        },
        [BTTV_BOARD_OSPREY1x0] = {
@@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_hook     = adtvk503_audio,
+               .audio_mode_gpio= adtvk503_audio,
        },
 
                /* ---- card 0x64 ---------------------------------- */
@@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv)
        /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
         * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
         * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
-       if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
-       /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
+       if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+       /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
 }
 
 static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
@@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
        }
 
        if (btv->tda9887_conf) {
-               bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
-                                                       &btv->tda9887_conf);
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv = &btv->tda9887_conf;
+
+               bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
        }
 
        btv->svhs = bttv_tvcards[btv->c.type].svhs;
@@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv)
                btv->has_remote=1;
        if (!bttv_tvcards[btv->c.type].no_gpioirq)
                btv->gpioirq=1;
-       if (bttv_tvcards[btv->c.type].audio_hook)
-               btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
+       if (bttv_tvcards[btv->c.type].volume_gpio)
+               btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
+       if (bttv_tvcards[btv->c.type].audio_mode_gpio)
+               btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
 
        if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
                /* detect Bt832 chip for quartzsight digital camera */
@@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
 void bttv_tda9880_setnorm(struct bttv *btv, int norm)
 {
        /* fix up our card entry */
-       if(norm==VIDEO_MODE_NTSC) {
+       if(norm==V4L2_STD_NTSC) {
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
                bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
@@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
        tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
 }
 
-
-/* ----------------------------------------------------------------------- */
-/* winview                                                                 */
-
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
-       int bits_out, loops, vol, data;
-
-       if (!set) {
-               /* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
-               v->flags |= VIDEO_AUDIO_VOLUME;
-               return;
-       }
-
-       /* 32 levels logarithmic */
-       vol = 32 - ((v->volume>>11));
-       /* units */
-       bits_out = (PT2254_DBS_IN_2>>(vol%5));
-       /* tens */
-       bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-       bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
-       data = gpio_read();
-       data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
-                 WINVIEW_PT2254_STROBE);
-       for (loops = 17; loops >= 0 ; loops--) {
-               if (bits_out & (1<<loops))
-                       data |=  WINVIEW_PT2254_DATA;
-               else
-                       data &= ~WINVIEW_PT2254_DATA;
-               gpio_write(data);
-               udelay(5);
-               data |= WINVIEW_PT2254_CLK;
-               gpio_write(data);
-               udelay(5);
-               data &= ~WINVIEW_PT2254_CLK;
-               gpio_write(data);
-       }
-       data |=  WINVIEW_PT2254_STROBE;
-       data &= ~WINVIEW_PT2254_DATA;
-       gpio_write(data);
-       udelay(10);
-       data &= ~WINVIEW_PT2254_STROBE;
-       gpio_write(data);
-}
-
-/* ----------------------------------------------------------------------- */
-/* mono/stereo control for various cards (which don't use i2c chips but    */
-/* connect something to the GPIO pins                                      */
-
-static void
-gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int con = 0;
-
-       if (set) {
-               gpio_inout(0x300, 0x300);
-               if (v->mode & VIDEO_SOUND_LANG1)
-                       con = 0x000;
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       con = 0x300;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       con = 0x200;
-/*             if (v->mode & VIDEO_SOUND_MONO)
- *                     con = 0x100; */
-               gpio_bits(0x300, con);
-       } else {
-               v->mode = VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-       }
-}
-
-static void
-gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int val, con;
-
-       if (btv->radio_user)
-               return;
-
-       val = gpio_read();
-       if (set) {
-               con = 0x000;
-               if (v->mode & VIDEO_SOUND_LANG2) {
-                       if (v->mode & VIDEO_SOUND_LANG1) {
-                               /* LANG1 + LANG2 */
-                               con = 0x100;
-                       }
-                       else {
-                               /* LANG2 */
-                               con = 0x300;
-                       }
-               }
-               if (con != (val & 0x300)) {
-                       gpio_bits(0x300, con);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"gvbctv5pci");
-               }
-       } else {
-               switch (val & 0x70) {
-                 case 0x10:
-                       v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-                       break;
-                 case 0x30:
-                       v->mode = VIDEO_SOUND_LANG2;
-                       break;
-                 case 0x50:
-                       v->mode = VIDEO_SOUND_LANG1;
-                       break;
-                 case 0x60:
-                       v->mode = VIDEO_SOUND_STEREO;
-                       break;
-                 case 0x70:
-                       v->mode = VIDEO_SOUND_MONO;
-                       break;
-                 default:
-                       v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                                 VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               }
-       }
-}
-
-/*
- * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
- *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
- *  0xdde enables mono and 0xccd enables sap
- *
- * Petr Vandrovec <VANDROVE@vc.cvut.cz>
- *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
- *  input/output sound connection, so both must be set for output mode.
- *
- * Looks like it's needed only for the "tvphone", the "tvphone 98"
- * handles this with a tda9840
- *
- */
-static void
-avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       int val = 0;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-                       val = 0x02;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       val = 0x01;
-               if (val) {
-                       gpio_bits(0x03,val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"avermedia");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1;
-               return;
-       }
-}
-
-static void
-avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       int val = 0;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-                       val = 0x01;
-               if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
-                       val = 0x02;
-               btaor(val, ~0x03, BT848_GPIO_DATA);
-               if (bttv_gpio)
-                       bttv_gpio_tracking(btv,"avermedia");
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               return;
-       }
-}
-
-/* Lifetec 9415 handling */
-static void
-lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       int val = 0;
-
-       if (gpio_read() & 0x4000) {
-               v->mode = VIDEO_SOUND_MONO;
-               return;
-       }
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
-                       val = 0x0080;
-               if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
-                       val = 0x0880;
-               if ((v->mode & VIDEO_SOUND_LANG1) ||
-                   (v->mode & VIDEO_SOUND_MONO))
-                       val = 0;
-               gpio_bits(0x0880, val);
-               if (bttv_gpio)
-                       bttv_gpio_tracking(btv,"lt9415");
-       } else {
-               /* autodetect doesn't work with this card :-( */
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               return;
-       }
-}
-
-/* TDA9821 on TerraTV+ Bt848, Bt878 */
-static void
-terratv_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int con = 0;
-
-       if (set) {
-               gpio_inout(0x180000,0x180000);
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       con = 0x080000;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       con = 0x180000;
-               gpio_bits(0x180000, con);
-               if (bttv_gpio)
-                       bttv_gpio_tracking(btv,"terratv");
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-static void
-winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned long val = 0;
-
-       if (set) {
-               /*btor (0xc32000, BT848_GPIO_OUT_EN);*/
-               if (v->mode & VIDEO_SOUND_MONO)         /* Mono */
-                       val = 0x420000;
-               if (v->mode & VIDEO_SOUND_LANG1)        /* Mono */
-                       val = 0x420000;
-               if (v->mode & VIDEO_SOUND_LANG2)        /* SAP */
-                       val = 0x410000;
-               if (v->mode & VIDEO_SOUND_STEREO)       /* Stereo */
-                       val = 0x020000;
-               if (val) {
-                       gpio_bits(0x430000, val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"winfast2000");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
- * revision 9B has on-board TDA9874A sound decoder).
- *
- * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
- *       will mute this cards.
- */
-static void
-pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int val = 0;
-
-       if (btv->radio_user)
-               return;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_MONO) {
-                       val = 0x01;
-               }
-               if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-                   || (v->mode & VIDEO_SOUND_STEREO)) {
-                       val = 0x02;
-               }
-               if (val) {
-                       gpio_bits(0x03,val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"pvbt878p9b");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for FlyVideo 2000S (with tda9874 decoder)
- * based on pvbt878p9b_audio() - this is not tested, please fix!!!
- */
-static void
-fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int val = 0xffff;
-
-       if (btv->radio_user)
-               return;
-       if (set) {
-               if (v->mode & VIDEO_SOUND_MONO) {
-                       val = 0x0000;
-               }
-               if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-                   || (v->mode & VIDEO_SOUND_STEREO)) {
-                       val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
-               }
-               if (val != 0xffff) {
-                       gpio_bits(0x1800, val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"fv2000s");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * sound control for Canopus WinDVR PCI
- * Masaki Suzuki <masaki@btree.org>
- */
-static void
-windvr_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned long val = 0;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_MONO)
-                       val = 0x040000;
-               if (v->mode & VIDEO_SOUND_LANG1)
-                       val = 0;
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       val = 0x100000;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       val = 0;
-               if (val) {
-                       gpio_bits(0x140000, val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"windvr");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * sound control for AD-TVK503
- * Hiroshi Takekawa <sian@big.or.jp>
- */
-static void
-adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int con = 0xffffff;
-
-       /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
-
-       if (set) {
-               /* btor(***, BT848_GPIO_OUT_EN); */
-               if (v->mode & VIDEO_SOUND_LANG1)
-                       con = 0x00000000;
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       con = 0x00180000;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       con = 0x00000000;
-               if (v->mode & VIDEO_SOUND_MONO)
-                       con = 0x00060000;
-               if (con != 0xffffff) {
-                       gpio_bits(0x1e0000,con);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv, "adtvk503");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-       }
-}
-
 /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
  *
  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
index c02d92deacd2aab2b1009ca573183c898b818d42..907dc62c178319047cdcf45266ff18d8f3059875 100644 (file)
@@ -9,6 +9,12 @@
     some v4l2 code lines are taken from Justin's bttv2 driver which is
     (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
 
+    V4L1 removal from:
+    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+
+    Fixes to be fully V4L2 compliant by
+    (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+
     Cropping and overscan support
     Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
     Sponsored by OPQ Systems AB
@@ -157,7 +163,7 @@ MODULE_LICENSE("GPL");
 static ssize_t show_card(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
-       struct video_device *vfd = to_video_device(cd);
+       struct video_device *vfd = container_of(cd, struct video_device, class_dev);
        struct bttv *btv = dev_get_drvdata(vfd->dev);
        return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
 }
@@ -470,31 +476,27 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
 /* ----------------------------------------------------------------------- */
 /* bttv format list
    packed pixel formats must come first */
-static const struct bttv_format bttv_formats[] = {
+static const struct bttv_format formats[] = {
        {
                .name     = "8 bpp, gray",
-               .palette  = VIDEO_PALETTE_GREY,
                .fourcc   = V4L2_PIX_FMT_GREY,
                .btformat = BT848_COLOR_FMT_Y8,
                .depth    = 8,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "8 bpp, dithered color",
-               .palette  = VIDEO_PALETTE_HI240,
                .fourcc   = V4L2_PIX_FMT_HI240,
                .btformat = BT848_COLOR_FMT_RGB8,
                .depth    = 8,
                .flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
        },{
                .name     = "15 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB555,
                .fourcc   = V4L2_PIX_FMT_RGB555,
                .btformat = BT848_COLOR_FMT_RGB15,
                .depth    = 16,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "15 bpp RGB, be",
-               .palette  = -1,
                .fourcc   = V4L2_PIX_FMT_RGB555X,
                .btformat = BT848_COLOR_FMT_RGB15,
                .btswap   = 0x03, /* byteswap */
@@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = {
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "16 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB565,
                .fourcc   = V4L2_PIX_FMT_RGB565,
                .btformat = BT848_COLOR_FMT_RGB16,
                .depth    = 16,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "16 bpp RGB, be",
-               .palette  = -1,
                .fourcc   = V4L2_PIX_FMT_RGB565X,
                .btformat = BT848_COLOR_FMT_RGB16,
                .btswap   = 0x03, /* byteswap */
@@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = {
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "24 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB24,
                .fourcc   = V4L2_PIX_FMT_BGR24,
                .btformat = BT848_COLOR_FMT_RGB24,
                .depth    = 24,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "32 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB32,
                .fourcc   = V4L2_PIX_FMT_BGR32,
                .btformat = BT848_COLOR_FMT_RGB32,
                .depth    = 32,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "32 bpp RGB, be",
-               .palette  = -1,
                .fourcc   = V4L2_PIX_FMT_RGB32,
                .btformat = BT848_COLOR_FMT_RGB32,
                .btswap   = 0x0f, /* byte+word swap */
@@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = {
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "4:2:2, packed, YUYV",
-               .palette  = VIDEO_PALETTE_YUV422,
                .fourcc   = V4L2_PIX_FMT_YUYV,
                .btformat = BT848_COLOR_FMT_YUY2,
                .depth    = 16,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "4:2:2, packed, YUYV",
-               .palette  = VIDEO_PALETTE_YUYV,
                .fourcc   = V4L2_PIX_FMT_YUYV,
                .btformat = BT848_COLOR_FMT_YUY2,
                .depth    = 16,
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "4:2:2, packed, UYVY",
-               .palette  = VIDEO_PALETTE_UYVY,
                .fourcc   = V4L2_PIX_FMT_UYVY,
                .btformat = BT848_COLOR_FMT_YUY2,
                .btswap   = 0x03, /* byteswap */
@@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = {
                .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "4:2:2, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV422P,
                .fourcc   = V4L2_PIX_FMT_YUV422P,
                .btformat = BT848_COLOR_FMT_YCrCb422,
                .depth    = 16,
@@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = {
                .vshift   = 0,
        },{
                .name     = "4:2:0, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV420P,
                .fourcc   = V4L2_PIX_FMT_YUV420,
                .btformat = BT848_COLOR_FMT_YCrCb422,
                .depth    = 12,
@@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = {
                .vshift   = 1,
        },{
                .name     = "4:2:0, planar, Y-Cr-Cb",
-               .palette  = -1,
                .fourcc   = V4L2_PIX_FMT_YVU420,
                .btformat = BT848_COLOR_FMT_YCrCb422,
                .depth    = 12,
@@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = {
                .vshift   = 1,
        },{
                .name     = "4:1:1, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV411P,
                .fourcc   = V4L2_PIX_FMT_YUV411P,
                .btformat = BT848_COLOR_FMT_YCrCb411,
                .depth    = 12,
@@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = {
                .vshift   = 0,
        },{
                .name     = "4:1:0, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV410P,
                .fourcc   = V4L2_PIX_FMT_YUV410,
                .btformat = BT848_COLOR_FMT_YCrCb411,
                .depth    = 9,
@@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = {
                .vshift   = 2,
        },{
                .name     = "4:1:0, planar, Y-Cr-Cb",
-               .palette  = -1,
                .fourcc   = V4L2_PIX_FMT_YVU410,
                .btformat = BT848_COLOR_FMT_YCrCb411,
                .depth    = 9,
@@ -615,14 +603,13 @@ static const struct bttv_format bttv_formats[] = {
                .vshift   = 2,
        },{
                .name     = "raw scanlines",
-               .palette  = VIDEO_PALETTE_RAW,
                .fourcc   = -1,
                .btformat = BT848_COLOR_FMT_RAW,
                .depth    = 8,
                .flags    = FORMAT_FLAGS_RAW,
        }
 };
-static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
+static const unsigned int FORMATS = ARRAY_SIZE(formats);
 
 /* ----------------------------------------------------------------------- */
 
@@ -798,7 +785,17 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
 
 
 };
-static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
+
+static const struct v4l2_queryctrl *ctrl_by_id(int id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
+               if (bttv_ctls[i].id == id)
+                       return bttv_ctls+i;
+
+       return NULL;
+}
 
 /* ----------------------------------------------------------------------- */
 /* resource management                                                     */
@@ -1254,16 +1251,6 @@ audio_input(struct bttv *btv, int input)
        return audio_mux(btv, input, btv->mute);
 }
 
-static void
-i2c_vidiocschan(struct bttv *btv)
-{
-       v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
-
-       bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
-       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
-               bttv_tda9880_setnorm(btv,btv->tvnorm);
-}
-
 static void
 bttv_crop_calc_limits(struct bttv_crop *c)
 {
@@ -1298,6 +1285,7 @@ static int
 set_tvnorm(struct bttv *btv, unsigned int norm)
 {
        const struct bttv_tvnorm *tvnorm;
+       v4l2_std_id id;
 
        if (norm < 0 || norm >= BTTV_TVNORMS)
                return -EINVAL;
@@ -1334,6 +1322,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
                bttv_tda9880_setnorm(btv,norm);
                break;
        }
+       id = tvnorm->v4l2_id;
+       bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
+
        return 0;
 }
 
@@ -1359,7 +1350,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
        audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
                       TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
        set_tvnorm(btv, norm);
-       i2c_vidiocschan(btv);
 }
 
 static void init_irqreg(struct bttv *btv)
@@ -1452,38 +1442,12 @@ static void bttv_reinit_bt848(struct bttv *btv)
        set_input(btv, btv->input, btv->tvnorm);
 }
 
-static int get_control(struct bttv *btv, struct v4l2_control *c)
+static int bttv_g_ctrl(struct file *file, void *priv,
+                                       struct v4l2_control *c)
 {
-       struct video_audio va;
-       int i;
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-       for (i = 0; i < BTTV_CTLS; i++)
-               if (bttv_ctls[i].id == c->id)
-                       break;
-       if (i == BTTV_CTLS)
-               return -EINVAL;
-       if (btv->audio_hook && i >= 4 && i <= 8) {
-               memset(&va,0,sizeof(va));
-               btv->audio_hook(btv,&va,0);
-               switch (c->id) {
-               case V4L2_CID_AUDIO_MUTE:
-                       c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
-                       break;
-               case V4L2_CID_AUDIO_VOLUME:
-                       c->value = va.volume;
-                       break;
-               case V4L2_CID_AUDIO_BALANCE:
-                       c->value = va.balance;
-                       break;
-               case V4L2_CID_AUDIO_BASS:
-                       c->value = va.bass;
-                       break;
-               case V4L2_CID_AUDIO_TREBLE:
-                       c->value = va.treble;
-                       break;
-               }
-               return 0;
-       }
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
                c->value = btv->bright;
@@ -1503,7 +1467,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
+               bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
                break;
 
        case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1545,67 +1509,44 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
        return 0;
 }
 
-static int set_control(struct bttv *btv, struct v4l2_control *c)
+static int bttv_s_ctrl(struct file *file, void *f,
+                                       struct v4l2_control *c)
 {
-       struct video_audio va;
-       int i,val;
+       int err;
+       int val;
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
 
-       for (i = 0; i < BTTV_CTLS; i++)
-               if (bttv_ctls[i].id == c->id)
-                       break;
-       if (i == BTTV_CTLS)
-               return -EINVAL;
-       if (btv->audio_hook && i >= 4 && i <= 8) {
-               memset(&va,0,sizeof(va));
-               btv->audio_hook(btv,&va,0);
-               switch (c->id) {
-               case V4L2_CID_AUDIO_MUTE:
-                       if (c->value) {
-                               va.flags |= VIDEO_AUDIO_MUTE;
-                               audio_mute(btv, 1);
-                       } else {
-                               va.flags &= ~VIDEO_AUDIO_MUTE;
-                               audio_mute(btv, 0);
-                       }
-                       break;
+       err = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               case V4L2_CID_AUDIO_VOLUME:
-                       va.volume = c->value;
-                       break;
-               case V4L2_CID_AUDIO_BALANCE:
-                       va.balance = c->value;
-                       break;
-               case V4L2_CID_AUDIO_BASS:
-                       va.bass = c->value;
-                       break;
-               case V4L2_CID_AUDIO_TREBLE:
-                       va.treble = c->value;
-                       break;
-               }
-               btv->audio_hook(btv,&va,1);
-               return 0;
-       }
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
-               bt848_bright(btv,c->value);
+               bt848_bright(btv, c->value);
                break;
        case V4L2_CID_HUE:
-               bt848_hue(btv,c->value);
+               bt848_hue(btv, c->value);
                break;
        case V4L2_CID_CONTRAST:
-               bt848_contrast(btv,c->value);
+               bt848_contrast(btv, c->value);
                break;
        case V4L2_CID_SATURATION:
-               bt848_sat(btv,c->value);
+               bt848_sat(btv, c->value);
                break;
        case V4L2_CID_AUDIO_MUTE:
                audio_mute(btv, c->value);
                /* fall through */
        case V4L2_CID_AUDIO_VOLUME:
+               if (btv->volume_gpio)
+                       btv->volume_gpio(btv, c->value);
+
+               bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+               break;
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
-               bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
+               bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
                break;
 
        case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1632,8 +1573,9 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
                break;
        case V4L2_CID_PRIVATE_AGC_CRUSH:
                btv->opt_adc_crush = c->value;
-               btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
-                       BT848_ADC);
+               btwrite(BT848_ADC_RESERVED |
+                               (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+                               BT848_ADC);
                break;
        case V4L2_CID_PRIVATE_VCR_HACK:
                btv->opt_vcr_hack = c->value;
@@ -1692,30 +1634,16 @@ static void bttv_field_count(struct bttv *btv)
        }
 }
 
-static const struct bttv_format*
-format_by_palette(int palette)
-{
-       unsigned int i;
-
-       for (i = 0; i < BTTV_FORMATS; i++) {
-               if (-1 == bttv_formats[i].palette)
-                       continue;
-               if (bttv_formats[i].palette == palette)
-                       return bttv_formats+i;
-       }
-       return NULL;
-}
-
 static const struct bttv_format*
 format_by_fourcc(int fourcc)
 {
        unsigned int i;
 
-       for (i = 0; i < BTTV_FORMATS; i++) {
-               if (-1 == bttv_formats[i].fourcc)
+       for (i = 0; i < FORMATS; i++) {
+               if (-1 == formats[i].fourcc)
                        continue;
-               if (bttv_formats[i].fourcc == fourcc)
-                       return bttv_formats+i;
+               if (formats[i].fourcc == fourcc)
+                       return formats+i;
        }
        return NULL;
 }
@@ -1733,7 +1661,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 
        dprintk("switch_overlay: enter [new=%p]\n",new);
        if (new)
-               new->vb.state = STATE_DONE;
+               new->vb.state = VIDEOBUF_DONE;
        spin_lock_irqsave(&btv->s_lock,flags);
        old = btv->screen;
        btv->screen = new;
@@ -1844,7 +1772,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
        }
 
        /* alloc risc memory */
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                redo_dma_risc = 1;
                if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
                        goto fail;
@@ -1854,7 +1782,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
                if (0 != (rc = bttv_buffer_risc(btv,buf)))
                        goto fail;
 
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
 
  fail:
@@ -1893,7 +1821,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct bttv_fh *fh = q->priv_data;
        struct bttv    *btv = fh->btv;
 
-       buf->vb.state = STATE_QUEUED;
+       buf->vb.state = VIDEOBUF_QUEUED;
        list_add_tail(&buf->vb.queue,&btv->capture);
        if (!btv->curr.frame_irq) {
                btv->loop_irq |= 1;
@@ -1916,399 +1844,259 @@ static struct videobuf_queue_ops bttv_video_qops = {
        .buf_release  = buffer_release,
 };
 
-static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
+static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-       switch (cmd) {
-       case BTTV_VERSION:
-               return BTTV_VERSION_CODE;
+       struct bttv_fh *fh  = priv;
+       struct bttv *btv = fh->btv;
+       unsigned int i;
+       int err;
 
-       /* ***  v4l1  *** ************************************************ */
-       case VIDIOCGFREQ:
-       {
-               unsigned long *freq = arg;
-               *freq = btv->freq;
-               return 0;
-       }
-       case VIDIOCSFREQ:
-       {
-               struct v4l2_frequency freq;
+       err = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               memset(&freq, 0, sizeof(freq));
-               freq.frequency = *(unsigned long *)arg;
-               mutex_lock(&btv->lock);
-               freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               btv->freq = *(unsigned long *)arg;
-               bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
-               if (btv->has_matchbox && btv->radio_user)
-                       tea5757_set_freq(btv,*(unsigned long *)arg);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
+       for (i = 0; i < BTTV_TVNORMS; i++)
+               if (*id & bttv_tvnorms[i].v4l2_id)
+                       break;
+       if (i == BTTV_TVNORMS)
+               return -EINVAL;
 
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner *v = arg;
+       mutex_lock(&btv->lock);
+       set_tvnorm(btv, i);
+       mutex_unlock(&btv->lock);
 
-               if (UNSET == bttv_tvcards[btv->c.type].tuner)
-                       return -EINVAL;
-               if (v->tuner) /* Only tuner 0 */
-                       return -EINVAL;
-               strcpy(v->name, "Television");
-               v->rangelow  = 0;
-               v->rangehigh = 0x7FFFFFFF;
-               v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-               v->mode      = btv->tvnorm;
-               v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
-               bttv_call_i2c_clients(btv,cmd,v);
-               return 0;
-       }
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner *v = arg;
+       return 0;
+}
 
-               if (v->tuner) /* Only tuner 0 */
-                       return -EINVAL;
-               if (v->mode >= BTTV_TVNORMS)
-                       return -EINVAL;
+static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
 
-               mutex_lock(&btv->lock);
-               set_tvnorm(btv,v->mode);
-               bttv_call_i2c_clients(btv,cmd,v);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
+       if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
+               *id = V4L2_STD_625_50;
+       else
+               *id = V4L2_STD_525_60;
+       return 0;
+}
 
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-               unsigned int channel = v->channel;
+static int bttv_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       unsigned int n;
 
-               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               v->tuners=0;
-               v->flags = VIDEO_VC_AUDIO;
-               v->type = VIDEO_TYPE_CAMERA;
-               v->norm = btv->tvnorm;
-               if (channel == bttv_tvcards[btv->c.type].tuner)  {
-                       strcpy(v->name,"Television");
-                       v->flags|=VIDEO_VC_TUNER;
-                       v->type=VIDEO_TYPE_TV;
-                       v->tuners=1;
-               } else if (channel == btv->svhs) {
-                       strcpy(v->name,"S-Video");
-               } else {
-                       sprintf(v->name,"Composite%d",channel);
-               }
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-               unsigned int channel = v->channel;
+       n = i->index;
 
-               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               if (v->norm >= BTTV_TVNORMS)
-                       return -EINVAL;
+       if (n >= bttv_tvcards[btv->c.type].video_inputs)
+               return -EINVAL;
 
-               mutex_lock(&btv->lock);
-               if (channel == btv->input &&
-                   v->norm == btv->tvnorm) {
-                       /* nothing to do */
-                       mutex_unlock(&btv->lock);
-                       return 0;
-               }
+       memset(i, 0, sizeof(*i));
 
-               set_input(btv, v->channel, v->norm);
-               mutex_unlock(&btv->lock);
-               return 0;
+       i->index    = n;
+       i->type     = V4L2_INPUT_TYPE_CAMERA;
+       i->audioset = 1;
+
+       if (i->index == bttv_tvcards[btv->c.type].tuner) {
+               sprintf(i->name, "Television");
+               i->type  = V4L2_INPUT_TYPE_TUNER;
+               i->tuner = 0;
+       } else if (i->index == btv->svhs) {
+               sprintf(i->name, "S-Video");
+       } else {
+               sprintf(i->name, "Composite%d", i->index);
        }
 
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *v = arg;
+       if (i->index == btv->input) {
+               __u32 dstatus = btread(BT848_DSTATUS);
+               if (0 == (dstatus & BT848_DSTATUS_PRES))
+                       i->status |= V4L2_IN_ST_NO_SIGNAL;
+               if (0 == (dstatus & BT848_DSTATUS_HLOC))
+                       i->status |= V4L2_IN_ST_NO_H_LOCK;
+       }
 
-               memset(v,0,sizeof(*v));
-               strcpy(v->name,"Television");
-               v->flags |= VIDEO_AUDIO_MUTABLE;
-               v->mode  = VIDEO_SOUND_MONO;
+       for (n = 0; n < BTTV_TVNORMS; n++)
+               i->std |= bttv_tvnorms[n].v4l2_id;
 
-               mutex_lock(&btv->lock);
-               bttv_call_i2c_clients(btv,cmd,v);
+       return 0;
+}
 
-               /* card specific hooks */
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,v,0);
+static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *v = arg;
-               unsigned int audio = v->audio;
+       *i = btv->input;
+       return 0;
+}
 
-               if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
-                       return -EINVAL;
+static int bttv_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct bttv_fh *fh  = priv;
+       struct bttv *btv = fh->btv;
 
-               mutex_lock(&btv->lock);
-               audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
-               bttv_call_i2c_clients(btv,cmd,v);
+       int err;
 
-               /* card specific hooks */
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,v,1);
+       err = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
+       if (i > bttv_tvcards[btv->c.type].video_inputs)
+               return -EINVAL;
 
-       /* ***  v4l2  *** ************************************************ */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-               unsigned int index = e->index;
+       mutex_lock(&btv->lock);
+       set_input(btv, i, btv->tvnorm);
+       mutex_unlock(&btv->lock);
+       return 0;
+}
 
-               if (index >= BTTV_TVNORMS)
-                       return -EINVAL;
-               v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
-                                        bttv_tvnorms[e->index].name);
-               e->index = index;
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-               *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               unsigned int i;
+static int bttv_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct bttv_fh *fh  = priv;
+       struct bttv *btv = fh->btv;
+       int err;
 
-               for (i = 0; i < BTTV_TVNORMS; i++)
-                       if (*id & bttv_tvnorms[i].v4l2_id)
-                               break;
-               if (i == BTTV_TVNORMS)
-                       return -EINVAL;
+       err = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               mutex_lock(&btv->lock);
-               set_tvnorm(btv,i);
-               i2c_vidiocschan(btv);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOC_QUERYSTD:
-       {
-               v4l2_std_id *id = arg;
+       if (UNSET == bttv_tvcards[btv->c.type].tuner)
+               return -EINVAL;
 
-               if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
-                       *id = V4L2_STD_625_50;
-               else
-                       *id = V4L2_STD_525_60;
-               return 0;
-       }
+       if (0 != t->index)
+               return -EINVAL;
 
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-               unsigned int n;
+       mutex_lock(&btv->lock);
+       bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
 
-               n = i->index;
-               if (n >= bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               memset(i,0,sizeof(*i));
-               i->index    = n;
-               i->type     = V4L2_INPUT_TYPE_CAMERA;
-               i->audioset = 1;
-               if (i->index == bttv_tvcards[btv->c.type].tuner) {
-                       sprintf(i->name, "Television");
-                       i->type  = V4L2_INPUT_TYPE_TUNER;
-                       i->tuner = 0;
-               } else if (i->index == btv->svhs) {
-                       sprintf(i->name, "S-Video");
-               } else {
-                       sprintf(i->name,"Composite%d",i->index);
-               }
-               if (i->index == btv->input) {
-                       __u32 dstatus = btread(BT848_DSTATUS);
-                       if (0 == (dstatus & BT848_DSTATUS_PRES))
-                               i->status |= V4L2_IN_ST_NO_SIGNAL;
-                       if (0 == (dstatus & BT848_DSTATUS_HLOC))
-                               i->status |= V4L2_IN_ST_NO_H_LOCK;
-               }
-               for (n = 0; n < BTTV_TVNORMS; n++)
-                       i->std |= bttv_tvnorms[n].v4l2_id;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = btv->input;
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               unsigned int *i = arg;
+       if (btv->audio_mode_gpio)
+               btv->audio_mode_gpio(btv, t, 1);
 
-               if (*i > bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               set_input(btv, *i, btv->tvnorm);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
+       mutex_unlock(&btv->lock);
 
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       return 0;
+}
 
-               if (UNSET == bttv_tvcards[btv->c.type].tuner)
-                       return -EINVAL;
-               if (0 != t->index)
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               memset(t,0,sizeof(*t));
-               t->rxsubchans = V4L2_TUNER_SUB_MONO;
-               bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
-               strcpy(t->name, "Television");
-               t->capability = V4L2_TUNER_CAP_NORM;
-               t->type       = V4L2_TUNER_ANALOG_TV;
-               if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
-                       t->signal = 0xffff;
-
-               if (btv->audio_hook) {
-                       /* Hmmm ... */
-                       struct video_audio va;
-                       memset(&va, 0, sizeof(struct video_audio));
-                       btv->audio_hook(btv,&va,0);
-                       t->audmode    = V4L2_TUNER_MODE_MONO;
-                       t->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       if(va.mode & VIDEO_SOUND_STEREO) {
-                               t->audmode    = V4L2_TUNER_MODE_STEREO;
-                               t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       }
-                       if(va.mode & VIDEO_SOUND_LANG2) {
-                               t->audmode    = V4L2_TUNER_MODE_LANG1;
-                               t->rxsubchans = V4L2_TUNER_SUB_LANG1
-                                       | V4L2_TUNER_SUB_LANG2;
-                       }
-               }
-               /* FIXME: fill capability+audmode */
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+static int bttv_g_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct bttv_fh *fh  = priv;
+       struct bttv *btv = fh->btv;
+       int err;
 
-               if (UNSET == bttv_tvcards[btv->c.type].tuner)
-                       return -EINVAL;
-               if (0 != t->index)
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
-               if (btv->audio_hook) {
-                       struct video_audio va;
-                       memset(&va, 0, sizeof(struct video_audio));
-                       if (t->audmode == V4L2_TUNER_MODE_MONO)
-                               va.mode = VIDEO_SOUND_MONO;
-                       else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
-                                t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
-                               va.mode = VIDEO_SOUND_STEREO;
-                       else if (t->audmode == V4L2_TUNER_MODE_LANG1)
-                               va.mode = VIDEO_SOUND_LANG1;
-                       else if (t->audmode == V4L2_TUNER_MODE_LANG2)
-                               va.mode = VIDEO_SOUND_LANG2;
-                       btv->audio_hook(btv,&va,1);
-               }
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
+       err = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       f->type = V4L2_TUNER_ANALOG_TV;
+       f->frequency = btv->freq;
 
-               memset(f,0,sizeof(*f));
-               f->type = V4L2_TUNER_ANALOG_TV;
-               f->frequency = btv->freq;
-               return 0;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       return 0;
+}
 
-               if (unlikely(f->tuner != 0))
-                       return -EINVAL;
-               if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               btv->freq = f->frequency;
-               bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
-               if (btv->has_matchbox && btv->radio_user)
-                       tea5757_set_freq(btv,btv->freq);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOC_LOG_STATUS:
-       {
-               printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);
-               bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
-               printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
-               return 0;
-       }
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               /* bt848 has a 12-bit register space */
-               reg->reg &= 0xfff;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = btread(reg->reg);
-               else
-                       btwrite(reg->val, reg->reg);
-               return 0;
-       }
-#endif
+static int bttv_s_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct bttv_fh *fh  = priv;
+       struct bttv *btv = fh->btv;
+       int err;
 
-       default:
-               return -ENOIOCTLCMD;
+       err = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-       }
+       if (unlikely(f->tuner != 0))
+               return -EINVAL;
+       if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
+               return -EINVAL;
+       mutex_lock(&btv->lock);
+       btv->freq = f->frequency;
+       bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
+       if (btv->has_matchbox && btv->radio_user)
+               tea5757_set_freq(btv, btv->freq);
+       mutex_unlock(&btv->lock);
        return 0;
 }
 
-/* Given cropping boundaries b and the scaled width and height of a
-   single field or frame, which must not exceed hardware limits, this
-   function adjusts the cropping parameters c. */
-static void
-bttv_crop_adjust       (struct bttv_crop *             c,
-                        const struct v4l2_rect *       b,
-                        __s32                          width,
-                        __s32                          height,
-                        enum v4l2_field                field)
+static int bttv_log_status(struct file *file, void *f)
 {
-       __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
-       __s32 max_left;
-       __s32 max_top;
+       struct bttv_fh *fh  = f;
+       struct bttv *btv = fh->btv;
 
-       if (width < c->min_scaled_width) {
-               /* Max. hor. scale factor 16:1. */
-               c->rect.width = width * 16;
-       } else if (width > c->max_scaled_width) {
-               /* Min. hor. scale factor 1:1. */
-               c->rect.width = width;
+       printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
+                       btv->c.nr, btv->c.nr);
+       bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+       printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
+                       btv->c.nr, btv->c.nr);
+       return 0;
+}
 
-               max_left = b->left + b->width - width;
-               max_left = min(max_left, (__s32) MAX_HDELAY);
-               if (c->rect.left > max_left)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bttv_g_register(struct file *file, void *f,
+                                       struct v4l2_register *reg)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+
+       /* bt848 has a 12-bit register space */
+       reg->reg &= 0xfff;
+       reg->val = btread(reg->reg);
+
+       return 0;
+}
+
+static int bttv_s_register(struct file *file, void *f,
+                                       struct v4l2_register *reg)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+
+       /* bt848 has a 12-bit register space */
+       reg->reg &= 0xfff;
+       btwrite(reg->val, reg->reg);
+
+       return 0;
+}
+#endif
+
+/* Given cropping boundaries b and the scaled width and height of a
+   single field or frame, which must not exceed hardware limits, this
+   function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust       (struct bttv_crop *             c,
+                        const struct v4l2_rect *       b,
+                        __s32                          width,
+                        __s32                          height,
+                        enum v4l2_field                field)
+{
+       __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+       __s32 max_left;
+       __s32 max_top;
+
+       if (width < c->min_scaled_width) {
+               /* Max. hor. scale factor 16:1. */
+               c->rect.width = width * 16;
+       } else if (width > c->max_scaled_width) {
+               /* Min. hor. scale factor 1:1. */
+               c->rect.width = width;
+
+               max_left = b->left + b->width - width;
+               max_left = min(max_left, (__s32) MAX_HDELAY);
+               if (c->rect.left > max_left)
                        c->rect.left = max_left;
        }
 
@@ -2659,985 +2447,681 @@ pix_format_set_size     (struct v4l2_pix_format *       f,
        }
 }
 
-static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+static int bttv_g_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
-               pix_format_set_size (&f->fmt.pix, fh->fmt,
-                                    fh->width, fh->height);
-               f->fmt.pix.field        = fh->cap.field;
-               f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               memset(&f->fmt.win,0,sizeof(struct v4l2_window));
-               f->fmt.win.w     = fh->ov.w;
-               f->fmt.win.field = fh->ov.field;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               bttv_vbi_get_fmt(fh, &f->fmt.vbi);
-               return 0;
-       default:
-               return -EINVAL;
-       }
+       struct bttv_fh *fh  = priv;
+
+       pix_format_set_size(&f->fmt.pix, fh->fmt,
+                               fh->width, fh->height);
+       f->fmt.pix.field        = fh->cap.field;
+       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+
+       return 0;
 }
 
-static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
-                       struct v4l2_format *f, int adjust_crop)
+static int bttv_g_fmt_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               const struct bttv_format *fmt;
-               enum v4l2_field field;
-               __s32 width, height;
-               int rc;
+       struct bttv_fh *fh  = priv;
 
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
+       f->fmt.win.w     = fh->ov.w;
+       f->fmt.win.field = fh->ov.field;
 
-               field = f->fmt.pix.field;
-               if (V4L2_FIELD_ANY == field) {
-                       __s32 height2;
+       return 0;
+}
 
-                       height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-                       field = (f->fmt.pix.height > height2)
-                               ? V4L2_FIELD_INTERLACED
-                               : V4L2_FIELD_BOTTOM;
-               }
-               if (V4L2_FIELD_SEQ_BT == field)
-                       field = V4L2_FIELD_SEQ_TB;
-               switch (field) {
-               case V4L2_FIELD_TOP:
-               case V4L2_FIELD_BOTTOM:
-               case V4L2_FIELD_ALTERNATE:
-               case V4L2_FIELD_INTERLACED:
-                       break;
-               case V4L2_FIELD_SEQ_TB:
-                       if (fmt->flags & FORMAT_FLAGS_PLANAR)
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
+static int bttv_try_fmt_cap(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       const struct bttv_format *fmt;
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       enum v4l2_field field;
+       __s32 width, height;
+       int rc;
 
-               width = f->fmt.pix.width;
-               height = f->fmt.pix.height;
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
 
-               rc = limit_scaled_size(fh, &width, &height, field,
-                                      /* width_mask: 4 pixels */ ~3,
-                                      /* width_bias: nearest */ 2,
-                                      /* adjust_size */ 1,
-                                      adjust_crop);
-               if (0 != rc)
-                       return rc;
+       field = f->fmt.pix.field;
 
-               /* update data for the application */
-               f->fmt.pix.field = field;
-               pix_format_set_size(&f->fmt.pix, fmt, width, height);
+       if (V4L2_FIELD_ANY == field) {
+               __s32 height2;
 
-               return 0;
+               height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+               field = (f->fmt.pix.height > height2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
        }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               return verify_window(fh, &f->fmt.win,
-                                    /* adjust_size */ 1,
-                                    /* adjust_crop */ 0);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
+
+       if (V4L2_FIELD_SEQ_BT == field)
+               field = V4L2_FIELD_SEQ_TB;
+
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+       case V4L2_FIELD_ALTERNATE:
+       case V4L2_FIELD_INTERLACED:
+               break;
+       case V4L2_FIELD_SEQ_TB:
+               if (fmt->flags & FORMAT_FLAGS_PLANAR)
+                       return -EINVAL;
+               break;
        default:
                return -EINVAL;
        }
+
+       width = f->fmt.pix.width;
+       height = f->fmt.pix.height;
+
+       rc = limit_scaled_size(fh, &width, &height, field,
+                              /* width_mask: 4 pixels */ ~3,
+                              /* width_bias: nearest */ 2,
+                              /* adjust_size */ 1,
+                              /* adjust_crop */ 0);
+       if (0 != rc)
+               return rc;
+
+       /* update data for the application */
+       f->fmt.pix.field = field;
+       pix_format_set_size(&f->fmt.pix, fmt, width, height);
+
+       return 0;
+}
+
+static int bttv_try_fmt_overlay(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       struct bttv_fh *fh = priv;
+
+       return verify_window(fh, &f->fmt.win,
+                       /* adjust_size */ 1,
+                       /* adjust_crop */ 0);
 }
 
-static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
-                     struct v4l2_format *f)
+static int bttv_s_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
        int retval;
+       const struct bttv_format *fmt;
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       __s32 width, height;
+       enum v4l2_field field;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               const struct bttv_format *fmt;
+       retval = bttv_switch_type(fh, f->type);
+       if (0 != retval)
+               return retval;
 
-               retval = bttv_switch_type(fh,f->type);
-               if (0 != retval)
-                       return retval;
-               retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
-               if (0 != retval)
-                       return retval;
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       retval = bttv_try_fmt_cap(file, priv, f);
+       if (0 != retval)
+               return retval;
 
-               /* update our state informations */
-               mutex_lock(&fh->cap.lock);
-               fh->fmt              = fmt;
-               fh->cap.field        = f->fmt.pix.field;
-               fh->cap.last         = V4L2_FIELD_NONE;
-               fh->width            = f->fmt.pix.width;
-               fh->height           = f->fmt.pix.height;
-               btv->init.fmt        = fmt;
-               btv->init.width      = f->fmt.pix.width;
-               btv->init.height     = f->fmt.pix.height;
-               mutex_unlock(&fh->cap.lock);
+       width = f->fmt.pix.width;
+       height = f->fmt.pix.height;
+       field = f->fmt.pix.field;
 
-               return 0;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               if (no_overlay > 0) {
-                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-                       return -EINVAL;
-               }
-               return setup_window(fh, btv, &f->fmt.win, 1);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               retval = bttv_switch_type(fh,f->type);
-               if (0 != retval)
-                       return retval;
-               return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
-       default:
+       retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+                              /* width_mask: 4 pixels */ ~3,
+                              /* width_bias: nearest */ 2,
+                              /* adjust_size */ 1,
+                              /* adjust_crop */ 1);
+       if (0 != retval)
+               return retval;
+
+       f->fmt.pix.field = field;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+       /* update our state informations */
+       mutex_lock(&fh->cap.lock);
+       fh->fmt              = fmt;
+       fh->cap.field        = f->fmt.pix.field;
+       fh->cap.last         = V4L2_FIELD_NONE;
+       fh->width            = f->fmt.pix.width;
+       fh->height           = f->fmt.pix.height;
+       btv->init.fmt        = fmt;
+       btv->init.width      = f->fmt.pix.width;
+       btv->init.height     = f->fmt.pix.height;
+       mutex_unlock(&fh->cap.lock);
+
+       return 0;
+}
+
+static int bttv_s_fmt_overlay(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+
+       if (no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
+
+       return setup_window(fh, btv, &f->fmt.win, 1);
 }
 
-static int bttv_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-       struct bttv_fh *fh  = file->private_data;
-       struct bttv    *btv = fh->btv;
-       unsigned long flags;
-       int retval = 0;
+       int retval;
+       unsigned int i;
+       struct bttv_fh *fh = priv;
 
-       if (bttv_debug > 1)
-               v4l_print_ioctl(btv->c.name, cmd);
-
-       if (btv->errors)
-               bttv_reinit_bt848(btv);
-
-       switch (cmd) {
-       case VIDIOCSFREQ:
-       case VIDIOCSTUNER:
-       case VIDIOCSCHAN:
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-               retval = v4l2_prio_check(&btv->prio,&fh->prio);
-               if (0 != retval)
-                       return retval;
-       };
+       mutex_lock(&fh->cap.lock);
+       retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
+                                    V4L2_MEMORY_MMAP);
+       if (retval < 0) {
+               mutex_unlock(&fh->cap.lock);
+               return retval;
+       }
 
-       switch (cmd) {
+       gbuffers = retval;
+       memset(mbuf, 0, sizeof(*mbuf));
+       mbuf->frames = gbuffers;
+       mbuf->size   = gbuffers * gbufsize;
 
-       /* ***  v4l1  *** ************************************************ */
-       case VIDIOCGCAP:
-       {
-               struct video_capability *cap = arg;
+       for (i = 0; i < gbuffers; i++)
+               mbuf->offsets[i] = i * gbufsize;
 
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->name,btv->video_dev->name);
-               if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-                       /* vbi */
-                       cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
-               } else {
-                       /* others */
-                       cap->type = VID_TYPE_CAPTURE|
-                               VID_TYPE_TUNER|
-                               VID_TYPE_CLIPPING|
-                               VID_TYPE_SCALES;
-                       if (no_overlay <= 0)
-                               cap->type |= VID_TYPE_OVERLAY;
-
-                       cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
-                       cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
-                       cap->minwidth  = 48;
-                       cap->minheight = 32;
-               }
-               cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
-               cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
-               return 0;
-       }
+       mutex_unlock(&fh->cap.lock);
+       return 0;
+}
+#endif
 
-       case VIDIOCGPICT:
-       {
-               struct video_picture *pic = arg;
-
-               memset(pic,0,sizeof(*pic));
-               pic->brightness = btv->bright;
-               pic->contrast   = btv->contrast;
-               pic->hue        = btv->hue;
-               pic->colour     = btv->saturation;
-               if (fh->fmt) {
-                       pic->depth   = fh->fmt->depth;
-                       pic->palette = fh->fmt->palette;
-               }
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *pic = arg;
-               const struct bttv_format *fmt;
+static int bttv_querycap(struct file *file, void  *priv,
+                               struct v4l2_capability *cap)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-               fmt = format_by_palette(pic->palette);
-               if (NULL == fmt)
-                       return -EINVAL;
-               mutex_lock(&fh->cap.lock);
-               if (fmt->flags & FORMAT_FLAGS_RAW) {
-                       /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
-                          RAW_LINES * 2. F1 is stored at offset 0, F2
-                          at buffer size / 2. */
-                       fh->width = RAW_BPL;
-                       fh->height = gbufsize / RAW_BPL;
-                       btv->init.width  = RAW_BPL;
-                       btv->init.height = gbufsize / RAW_BPL;
-               }
-               fh->ovfmt   = fmt;
-               fh->fmt     = fmt;
-               btv->init.ovfmt   = fmt;
-               btv->init.fmt     = fmt;
-               if (bigendian) {
-                       /* dirty hack time:  swap bytes for overlay if the
-                          display adaptor is big endian (insmod option) */
-                       if (fmt->palette == VIDEO_PALETTE_RGB555 ||
-                           fmt->palette == VIDEO_PALETTE_RGB565 ||
-                           fmt->palette == VIDEO_PALETTE_RGB32) {
-                               fh->ovfmt = fmt+1;
-                       }
-               }
-               bt848_bright(btv,pic->brightness);
-               bt848_contrast(btv,pic->contrast);
-               bt848_hue(btv,pic->hue);
-               bt848_sat(btv,pic->colour);
-               mutex_unlock(&fh->cap.lock);
-               return 0;
-       }
+       if (0 == v4l2)
+               return -EINVAL;
 
-       case VIDIOCGWIN:
-       {
-               struct video_window *win = arg;
+       strlcpy(cap->driver, "bttv", sizeof(cap->driver));
+       strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                "PCI:%s", pci_name(btv->c.pci));
+       cap->version = BTTV_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_VBI_CAPTURE |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
+       if (no_overlay <= 0)
+               cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+       if (bttv_tvcards[btv->c.type].tuner != UNSET &&
+           bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
+               cap->capabilities |= V4L2_CAP_TUNER;
+       return 0;
+}
 
-               memset(win,0,sizeof(*win));
-               win->x      = fh->ov.w.left;
-               win->y      = fh->ov.w.top;
-               win->width  = fh->ov.w.width;
-               win->height = fh->ov.w.height;
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *win = arg;
-               struct v4l2_window w2;
+static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
+                               struct v4l2_fmtdesc *f)
+{
+       if (0 != f->index)
+               return -EINVAL;
 
-               if (no_overlay > 0) {
-                       printk ("VIDIOCSWIN: no_overlay\n");
-                       return -EINVAL;
-               }
+       f->pixelformat = V4L2_PIX_FMT_GREY;
+       strcpy(f->description, "vbi data");
 
-               w2.field = V4L2_FIELD_ANY;
-               w2.w.left    = win->x;
-               w2.w.top     = win->y;
-               w2.w.width   = win->width;
-               w2.w.height  = win->height;
-               w2.clipcount = win->clipcount;
-               w2.clips     = (struct v4l2_clip __user *)win->clips;
-               retval = setup_window(fh, btv, &w2, 0);
-               if (0 == retval) {
-                       /* on v4l1 this ioctl affects the read() size too */
-                       fh->width  = fh->ov.w.width;
-                       fh->height = fh->ov.w.height;
-                       btv->init.width  = fh->ov.w.width;
-                       btv->init.height = fh->ov.w.height;
-               }
-               return retval;
-       }
+       return 0;
+}
 
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *fbuf = arg;
-
-               fbuf->base          = btv->fbuf.base;
-               fbuf->width         = btv->fbuf.fmt.width;
-               fbuf->height        = btv->fbuf.fmt.height;
-               fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
-               if (fh->ovfmt)
-                       fbuf->depth = fh->ovfmt->depth;
-               else {
-                       if (fbuf->width)
-                               fbuf->depth   = ((fbuf->bytesperline<<3)
-                                                 + (fbuf->width-1) )
-                                                 /fbuf->width;
-                       else
-                               fbuf->depth = 0;
-               }
-               return 0;
-       }
-       case VIDIOCSFBUF:
-       {
-               struct video_buffer *fbuf = arg;
-               const struct bttv_format *fmt;
-               unsigned long end;
-
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
-               end = (unsigned long)fbuf->base +
-                       fbuf->height * fbuf->bytesperline;
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
+static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
+{
+       int index = -1, i;
 
-               switch (fbuf->depth) {
-               case 8:
-                       fmt = format_by_palette(VIDEO_PALETTE_HI240);
-                       break;
-               case 16:
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB565);
-                       break;
-               case 24:
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB24);
-                       break;
-               case 32:
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB32);
-                       break;
-               case 15:
-                       fbuf->depth = 16;
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB555);
-                       break;
-               default:
-                       fmt = NULL;
+       for (i = 0; i < FORMATS; i++) {
+               if (formats[i].fourcc != -1)
+                       index++;
+               if ((unsigned int)index == f->index)
                        break;
-               }
-               if (NULL == fmt)
-                       goto fh_unlock_and_return;
-
-               fh->ovfmt = fmt;
-               fh->fmt   = fmt;
-               btv->init.ovfmt = fmt;
-               btv->init.fmt   = fmt;
-               btv->fbuf.base             = fbuf->base;
-               btv->fbuf.fmt.width        = fbuf->width;
-               btv->fbuf.fmt.height       = fbuf->height;
-               if (fbuf->bytesperline)
-                       btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
-               else
-                       btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-               mutex_unlock(&fh->cap.lock);
-               return 0;
        }
+       if (FORMATS == i)
+               return -EINVAL;
 
-       case VIDIOCCAPTURE:
-       case VIDIOC_OVERLAY:
-       {
-               struct bttv_buffer *new;
-               int *on = arg;
+       f->pixelformat = formats[i].fourcc;
+       strlcpy(f->description, formats[i].name, sizeof(f->description));
 
-               if (*on) {
-                       /* verify args */
-                       if (NULL == btv->fbuf.base)
-                               return -EINVAL;
-                       if (!fh->ov.setup_ok) {
-                               dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
-                               return -EINVAL;
-                       }
-               }
+       return i;
+}
 
-               if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
-                       return -EBUSY;
+static int bttv_enum_fmt_cap(struct file *file, void  *priv,
+                               struct v4l2_fmtdesc *f)
+{
+       int rc = bttv_enum_fmt_cap_ovr(f);
 
-               mutex_lock(&fh->cap.lock);
-               if (*on) {
-                       fh->ov.tvnorm = btv->tvnorm;
-                       new = videobuf_pci_alloc(sizeof(*new));
-                       new->crop = btv->crop[!!fh->do_crop].rect;
-                       bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-               } else {
-                       new = NULL;
-               }
+       if (rc < 0)
+               return rc;
 
-               /* switch over */
-               retval = bttv_switch_overlay(btv,fh,new);
-               mutex_unlock(&fh->cap.lock);
-               return retval;
-       }
+       return 0;
+}
 
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *mbuf = arg;
-               unsigned int i;
+static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       int rc;
 
-               mutex_lock(&fh->cap.lock);
-               retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
-                                            V4L2_MEMORY_MMAP);
-               if (retval < 0)
-                       goto fh_unlock_and_return;
-
-               gbuffers = retval;
-               memset(mbuf,0,sizeof(*mbuf));
-               mbuf->frames = gbuffers;
-               mbuf->size   = gbuffers * gbufsize;
-               for (i = 0; i < gbuffers; i++)
-                       mbuf->offsets[i] = i * gbufsize;
-               mutex_unlock(&fh->cap.lock);
-               return 0;
+       if (no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
        }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-               struct bttv_buffer *buf;
-               enum v4l2_field field;
-               __s32 height2;
-               int res;
 
-               if (vm->frame >= VIDEO_MAX_FRAME)
-                       return -EINVAL;
+       rc = bttv_enum_fmt_cap_ovr(f);
 
-               res = bttv_resource(fh);
-               if (!check_alloc_btres(btv, fh, res))
-                       return -EBUSY;
+       if (rc < 0)
+               return rc;
 
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
-               buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
-               if (NULL == buf)
-                       goto fh_unlock_and_return;
-               if (0 == buf->vb.baddr)
-                       goto fh_unlock_and_return;
-               if (buf->vb.state == STATE_QUEUED ||
-                   buf->vb.state == STATE_ACTIVE)
-                       goto fh_unlock_and_return;
+       if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
+               return -EINVAL;
 
-               height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-               field = (vm->height > height2)
-                       ? V4L2_FIELD_INTERLACED
-                       : V4L2_FIELD_BOTTOM;
-               retval = bttv_prepare_buffer(&fh->cap,btv,buf,
-                                            format_by_palette(vm->format),
-                                            vm->width,vm->height,field);
-               if (0 != retval)
-                       goto fh_unlock_and_return;
-               btv->init.width = vm->width;
-               btv->init.height = vm->height;
-               spin_lock_irqsave(&btv->s_lock,flags);
-               buffer_queue(&fh->cap,&buf->vb);
-               spin_unlock_irqrestore(&btv->s_lock,flags);
-               mutex_unlock(&fh->cap.lock);
-               return 0;
-       }
-       case VIDIOCSYNC:
-       {
-               int *frame = arg;
-               struct bttv_buffer *buf;
+       return 0;
+}
+
+static int bttv_g_fbuf(struct file *file, void *f,
+                               struct v4l2_framebuffer *fb)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+
+       *fb = btv->fbuf;
+       fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+       if (fh->ovfmt)
+               fb->fmt.pixelformat  = fh->ovfmt->fourcc;
+       return 0;
+}
 
-               if (*frame >= VIDEO_MAX_FRAME)
+static int bttv_overlay(struct file *file, void *f, unsigned int on)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+       struct bttv_buffer *new;
+       int retval;
+
+       if (on) {
+               /* verify args */
+               if (NULL == btv->fbuf.base)
+                       return -EINVAL;
+               if (!fh->ov.setup_ok) {
+                       dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
                        return -EINVAL;
+               }
+       }
 
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
-               buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
-               if (NULL == buf)
-                       goto fh_unlock_and_return;
-               retval = videobuf_waiton(&buf->vb,0,1);
+       if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+               return -EBUSY;
+
+       mutex_lock(&fh->cap.lock);
+       if (on) {
+               fh->ov.tvnorm = btv->tvnorm;
+               new = videobuf_pci_alloc(sizeof(*new));
+               bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+       } else {
+               new = NULL;
+       }
+
+       /* switch over */
+       retval = bttv_switch_overlay(btv, fh, new);
+       mutex_unlock(&fh->cap.lock);
+       return retval;
+}
+
+static int bttv_s_fbuf(struct file *file, void *f,
+                               struct v4l2_framebuffer *fb)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+       const struct bttv_format *fmt;
+       int retval;
+
+       if (!capable(CAP_SYS_ADMIN) &&
+               !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       /* check args */
+       fmt = format_by_fourcc(fb->fmt.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+       if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
+               return -EINVAL;
+
+       retval = -EINVAL;
+       if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+               __s32 width = fb->fmt.width;
+               __s32 height = fb->fmt.height;
+
+               retval = limit_scaled_size(fh, &width, &height,
+                                          V4L2_FIELD_INTERLACED,
+                                          /* width_mask */ ~3,
+                                          /* width_bias */ 2,
+                                          /* adjust_size */ 0,
+                                          /* adjust_crop */ 0);
                if (0 != retval)
-                       goto fh_unlock_and_return;
-               switch (buf->vb.state) {
-               case STATE_ERROR:
-                       retval = -EIO;
-                       /* fall through */
-               case STATE_DONE:
-               {
-                       struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-                       videobuf_dma_sync(&fh->cap,dma);
-                       bttv_dma_free(&fh->cap,btv,buf);
-                       break;
-               }
-               default:
-                       retval = -EINVAL;
-                       break;
-               }
-               mutex_unlock(&fh->cap.lock);
-               return retval;
+                       return retval;
        }
 
-       case VIDIOCGVBIFMT:
-               if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
-                       retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-                       if (0 != retval)
-                               return retval;
-               }
+       /* ok, accept it */
+       mutex_lock(&fh->cap.lock);
+       btv->fbuf.base       = fb->base;
+       btv->fbuf.fmt.width  = fb->fmt.width;
+       btv->fbuf.fmt.height = fb->fmt.height;
+       if (0 != fb->fmt.bytesperline)
+               btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
+       else
+               btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
 
-               /* fall through */
+       retval = 0;
+       fh->ovfmt = fmt;
+       btv->init.ovfmt = fmt;
+       if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+               fh->ov.w.left   = 0;
+               fh->ov.w.top    = 0;
+               fh->ov.w.width  = fb->fmt.width;
+               fh->ov.w.height = fb->fmt.height;
+               btv->init.ov.w.width  = fb->fmt.width;
+               btv->init.ov.w.height = fb->fmt.height;
+                       kfree(fh->ov.clips);
+               fh->ov.clips = NULL;
+               fh->ov.nclips = 0;
+
+               if (check_btres(fh, RESOURCE_OVERLAY)) {
+                       struct bttv_buffer *new;
+
+                       new = videobuf_pci_alloc(sizeof(*new));
+                       new->crop = btv->crop[!!fh->do_crop].rect;
+                       bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+                       retval = bttv_switch_overlay(btv, fh, new);
+               }
+       }
+       mutex_unlock(&fh->cap.lock);
+       return retval;
+}
 
-       case VIDIOCSVBIFMT:
-               return v4l_compat_translate_ioctl(inode, file, cmd,
-                                                 arg, bttv_do_ioctl);
-
-       case BTTV_VERSION:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGCHAN:
-       case VIDIOCSCHAN:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return bttv_common_ioctls(btv,cmd,arg);
-
-       /* ***  v4l2  *** ************************************************ */
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
+static int bttv_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *p)
+{
+       struct bttv_fh *fh = priv;
+       return videobuf_reqbufs(bttv_queue(fh), p);
+}
 
-               if (0 == v4l2)
-                       return -EINVAL;
-               memset(cap, 0, sizeof (*cap));
-               strlcpy(cap->driver, "bttv", sizeof (cap->driver));
-               strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
-               snprintf(cap->bus_info, sizeof (cap->bus_info),
-                        "PCI:%s", pci_name(btv->c.pci));
-               cap->version = BTTV_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_VBI_CAPTURE |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
-               if (no_overlay <= 0)
-                       cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
-
-               if (bttv_tvcards[btv->c.type].tuner != UNSET &&
-                   bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
-                       cap->capabilities |= V4L2_CAP_TUNER;
-               return 0;
-       }
+static int bttv_querybuf(struct file *file, void *priv,
+                               struct v4l2_buffer *b)
+{
+       struct bttv_fh *fh = priv;
+       return videobuf_querybuf(bttv_queue(fh), b);
+}
 
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int i;
-               int index;
-
-               type  = f->type;
-               if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
-                       /* vbi */
-                       index = f->index;
-                       if (0 != index)
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index       = index;
-                       f->type        = type;
-                       f->pixelformat = V4L2_PIX_FMT_GREY;
-                       strcpy(f->description,"vbi data");
-                       return 0;
-               }
+static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       int res = bttv_resource(fh);
 
-               /* video capture + overlay */
-               index = -1;
-               for (i = 0; i < BTTV_FORMATS; i++) {
-                       if (bttv_formats[i].fourcc != -1)
-                               index++;
-                       if ((unsigned int)index == f->index)
-                               break;
-               }
-               if (BTTV_FORMATS == i)
-                       return -EINVAL;
+       if (!check_alloc_btres(btv, fh, res))
+               return -EBUSY;
 
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               memset(f,0,sizeof(*f));
-               f->index       = index;
-               f->type        = type;
-               f->pixelformat = bttv_formats[i].fourcc;
-               strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
-               return 0;
-       }
+       return videobuf_qbuf(bttv_queue(fh), b);
+}
 
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return bttv_g_fmt(fh,f);
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return bttv_s_fmt(fh,btv,f);
-       }
+static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct bttv_fh *fh = priv;
+       return videobuf_dqbuf(bttv_queue(fh), b,
+                       file->f_flags & O_NONBLOCK);
+}
 
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
+static int bttv_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       int res = bttv_resource(fh);
 
-               *fb = btv->fbuf;
-               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-               if (fh->ovfmt)
-                       fb->fmt.pixelformat  = fh->ovfmt->fourcc;
-               return 0;
-       }
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
-               const struct bttv_format *fmt;
+       if (!check_alloc_btres(btv, fh, res))
+               return -EBUSY;
+       return videobuf_streamon(bttv_queue(fh));
+}
 
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
 
-               /* check args */
-               fmt = format_by_fourcc(fb->fmt.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
-               if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
-                       return -EINVAL;
+static int bttv_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       int retval;
+       int res = bttv_resource(fh);
 
-               retval = -EINVAL;
-               if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-                       __s32 width = fb->fmt.width;
-                       __s32 height = fb->fmt.height;
-
-                       retval = limit_scaled_size(fh, &width, &height,
-                                                  V4L2_FIELD_INTERLACED,
-                                                  /* width_mask */ ~3,
-                                                  /* width_bias */ 2,
-                                                  /* adjust_size */ 0,
-                                                  /* adjust_crop */ 0);
-                       if (0 != retval)
-                               return retval;
-               }
 
-               /* ok, accept it */
-               mutex_lock(&fh->cap.lock);
-               btv->fbuf.base       = fb->base;
-               btv->fbuf.fmt.width  = fb->fmt.width;
-               btv->fbuf.fmt.height = fb->fmt.height;
-               if (0 != fb->fmt.bytesperline)
-                       btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
-               else
-                       btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
-
-               retval = 0;
-               fh->ovfmt = fmt;
-               btv->init.ovfmt = fmt;
-               if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-                       fh->ov.w.left   = 0;
-                       fh->ov.w.top    = 0;
-                       fh->ov.w.width  = fb->fmt.width;
-                       fh->ov.w.height = fb->fmt.height;
-                       btv->init.ov.w.width  = fb->fmt.width;
-                       btv->init.ov.w.height = fb->fmt.height;
-                               kfree(fh->ov.clips);
-                       fh->ov.clips = NULL;
-                       fh->ov.nclips = 0;
-
-                       if (check_btres(fh, RESOURCE_OVERLAY)) {
-                               struct bttv_buffer *new;
-
-                               new = videobuf_pci_alloc(sizeof(*new));
-                               new->crop = btv->crop[!!fh->do_crop].rect;
-                               bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
-                               retval = bttv_switch_overlay(btv,fh,new);
-                       }
-               }
-               mutex_unlock(&fh->cap.lock);
+       retval = videobuf_streamoff(bttv_queue(fh));
+       if (retval < 0)
                return retval;
-       }
+       free_btres(btv, fh, res);
+       return 0;
+}
 
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(bttv_queue(fh),arg);
+static int bttv_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+       const struct v4l2_queryctrl *ctrl;
 
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(bttv_queue(fh),arg);
+       if ((c->id <  V4L2_CID_BASE ||
+            c->id >= V4L2_CID_LASTP1) &&
+           (c->id <  V4L2_CID_PRIVATE_BASE ||
+            c->id >= V4L2_CID_PRIVATE_LASTP1))
+               return -EINVAL;
 
-       case VIDIOC_QBUF:
-       {
-               int res = bttv_resource(fh);
+       if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
+               *c = no_ctl;
+       else {
+               ctrl = ctrl_by_id(c->id);
 
-               if (!check_alloc_btres(btv, fh, res))
-                       return -EBUSY;
-               return videobuf_qbuf(bttv_queue(fh),arg);
+               *c = (NULL != ctrl) ? *ctrl : no_ctl;
        }
 
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(bttv_queue(fh),arg,
-                                     file->f_flags & O_NONBLOCK);
+       return 0;
+}
 
-       case VIDIOC_STREAMON:
-       {
-               int res = bttv_resource(fh);
+static int bttv_g_parm(struct file *file, void *f,
+                               struct v4l2_streamparm *parm)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+       struct v4l2_standard s;
 
-               if (!check_alloc_btres(btv,fh,res))
-                       return -EBUSY;
-               return videobuf_streamon(bttv_queue(fh));
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int res = bttv_resource(fh);
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
+                                bttv_tvnorms[btv->tvnorm].name);
+       parm->parm.capture.timeperframe = s.frameperiod;
+       return 0;
+}
 
-               retval = videobuf_streamoff(bttv_queue(fh));
-               if (retval < 0)
-                       return retval;
-               free_btres(btv,fh,res);
-               return 0;
-       }
+static int bttv_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *c = arg;
-               int i;
+       if (UNSET == bttv_tvcards[btv->c.type].tuner)
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
 
-               if ((c->id <  V4L2_CID_BASE ||
-                    c->id >= V4L2_CID_LASTP1) &&
-                   (c->id <  V4L2_CID_PRIVATE_BASE ||
-                    c->id >= V4L2_CID_PRIVATE_LASTP1))
-                       return -EINVAL;
-               for (i = 0; i < BTTV_CTLS; i++)
-                       if (bttv_ctls[i].id == c->id)
-                               break;
-               if (i == BTTV_CTLS) {
-                       *c = no_ctl;
-                       return 0;
-               }
-               *c = bttv_ctls[i];
-               if (btv->audio_hook && i >= 4 && i <= 8) {
-                       struct video_audio va;
-                       memset(&va,0,sizeof(va));
-                       btv->audio_hook(btv,&va,0);
-                       switch (bttv_ctls[i].id) {
-                       case V4L2_CID_AUDIO_VOLUME:
-                               if (!(va.flags & VIDEO_AUDIO_VOLUME))
-                                       *c = no_ctl;
-                               break;
-                       case V4L2_CID_AUDIO_BALANCE:
-                               if (!(va.flags & VIDEO_AUDIO_BALANCE))
-                                       *c = no_ctl;
-                               break;
-                       case V4L2_CID_AUDIO_BASS:
-                               if (!(va.flags & VIDEO_AUDIO_BASS))
-                                       *c = no_ctl;
-                               break;
-                       case V4L2_CID_AUDIO_TREBLE:
-                               if (!(va.flags & VIDEO_AUDIO_TREBLE))
-                                       *c = no_ctl;
-                               break;
-                       }
-               }
-               return 0;
-       }
-       case VIDIOC_G_CTRL:
-               return get_control(btv,arg);
-       case VIDIOC_S_CTRL:
-               return set_control(btv,arg);
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm *parm = arg;
-               struct v4l2_standard s;
-               if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               memset(parm,0,sizeof(*parm));
-               v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
-                                        bttv_tvnorms[btv->tvnorm].name);
-               parm->parm.capture.timeperframe = s.frameperiod;
-               return 0;
-       }
+       mutex_lock(&btv->lock);
+       memset(t, 0, sizeof(*t));
+       t->rxsubchans = V4L2_TUNER_SUB_MONO;
+       bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+       strcpy(t->name, "Television");
+       t->capability = V4L2_TUNER_CAP_NORM;
+       t->type       = V4L2_TUNER_ANALOG_TV;
+       if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
+               t->signal = 0xffff;
+
+       if (btv->audio_mode_gpio)
+               btv->audio_mode_gpio(btv, t, 0);
 
-       case VIDIOC_G_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
+       mutex_unlock(&btv->lock);
+       return 0;
+}
 
-               *p = v4l2_prio_max(&btv->prio);
-               return 0;
-       }
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *prio = arg;
+static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
 
-               return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
-       }
+       *p = v4l2_prio_max(&btv->prio);
 
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cap = arg;
-               enum v4l2_buf_type type;
+       return 0;
+}
 
-               type = cap->type;
+static int bttv_s_priority(struct file *file, void *f,
+                                       enum v4l2_priority prio)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
 
-               if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
+       return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+}
 
-               *cap = bttv_tvnorms[btv->tvnorm].cropcap;
-               cap->type = type;
+static int bttv_cropcap(struct file *file, void *priv,
+                               struct v4l2_cropcap *cap)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-               return 0;
-       }
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop * crop = arg;
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
+       *cap = bttv_tvnorms[btv->tvnorm].cropcap;
 
-               /* No fh->do_crop = 1; because btv->crop[1] may be
-                  inconsistent with fh->width or fh->height and apps
-                  do not expect a change here. */
+       return 0;
+}
 
-               crop->c = btv->crop[!!fh->do_crop].rect;
+static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
 
-               return 0;
-       }
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *crop = arg;
-               const struct v4l2_rect *b;
-               struct bttv_crop c;
-               __s32 b_left;
-               __s32 b_top;
-               __s32 b_right;
-               __s32 b_bottom;
-
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
 
-               retval = v4l2_prio_check(&btv->prio,&fh->prio);
-               if (0 != retval)
-                       return retval;
+       /* No fh->do_crop = 1; because btv->crop[1] may be
+          inconsistent with fh->width or fh->height and apps
+          do not expect a change here. */
 
-               /* Make sure tvnorm, vbi_end and the current cropping
-                  parameters remain consistent until we're done. Note
-                  read() may change vbi_end in check_alloc_btres(). */
-               mutex_lock(&btv->lock);
+       crop->c = btv->crop[!!fh->do_crop].rect;
 
-               retval = -EBUSY;
+       return 0;
+}
 
-               if (locked_btres(fh->btv, VIDEO_RESOURCES))
-                       goto btv_unlock_and_return;
+static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+       struct bttv_fh *fh = f;
+       struct bttv *btv = fh->btv;
+       const struct v4l2_rect *b;
+       int retval;
+       struct bttv_crop c;
+       __s32 b_left;
+       __s32 b_top;
+       __s32 b_right;
+       __s32 b_bottom;
 
-               b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
 
-               b_left = b->left;
-               b_right = b_left + b->width;
-               b_bottom = b->top + b->height;
+       retval = v4l2_prio_check(&btv->prio, &fh->prio);
+       if (0 != retval)
+               return retval;
 
-               b_top = max(b->top, btv->vbi_end);
-               if (b_top + 32 >= b_bottom)
-                       goto btv_unlock_and_return;
+       /* Make sure tvnorm, vbi_end and the current cropping
+          parameters remain consistent until we're done. Note
+          read() may change vbi_end in check_alloc_btres(). */
+       mutex_lock(&btv->lock);
 
-               /* Min. scaled size 48 x 32. */
-               c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
-               c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+       retval = -EBUSY;
 
-               c.rect.width = clamp(crop->c.width,
-                                    48, b_right - c.rect.left);
+       if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
+               mutex_unlock(&btv->lock);
+               return retval;
+       }
 
-               c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
-               /* Top and height must be a multiple of two. */
-               c.rect.top = (c.rect.top + 1) & ~1;
+       b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
 
-               c.rect.height = clamp(crop->c.height,
-                                     32, b_bottom - c.rect.top);
-               c.rect.height = (c.rect.height + 1) & ~1;
+       b_left = b->left;
+       b_right = b_left + b->width;
+       b_bottom = b->top + b->height;
 
-               bttv_crop_calc_limits(&c);
+       b_top = max(b->top, btv->vbi_end);
+       if (b_top + 32 >= b_bottom) {
+               mutex_unlock(&btv->lock);
+               return retval;
+       }
 
-               btv->crop[1] = c;
+       /* Min. scaled size 48 x 32. */
+       c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+       c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
 
-               mutex_unlock(&btv->lock);
+       c.rect.width = clamp(crop->c.width,
+                            48, b_right - c.rect.left);
 
-               fh->do_crop = 1;
+       c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+       /* Top and height must be a multiple of two. */
+       c.rect.top = (c.rect.top + 1) & ~1;
 
-               mutex_lock(&fh->cap.lock);
+       c.rect.height = clamp(crop->c.height,
+                             32, b_bottom - c.rect.top);
+       c.rect.height = (c.rect.height + 1) & ~1;
 
-               if (fh->width < c.min_scaled_width) {
-                       fh->width = c.min_scaled_width;
-                       btv->init.width = c.min_scaled_width;
-               } else if (fh->width > c.max_scaled_width) {
-                       fh->width = c.max_scaled_width;
-                       btv->init.width = c.max_scaled_width;
-               }
+       bttv_crop_calc_limits(&c);
 
-               if (fh->height < c.min_scaled_height) {
-                       fh->height = c.min_scaled_height;
-                       btv->init.height = c.min_scaled_height;
-               } else if (fh->height > c.max_scaled_height) {
-                       fh->height = c.max_scaled_height;
-                       btv->init.height = c.max_scaled_height;
-               }
+       btv->crop[1] = c;
 
-               mutex_unlock(&fh->cap.lock);
+       mutex_unlock(&btv->lock);
 
-               return 0;
-       }
+       fh->do_crop = 1;
 
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_ENUMINPUT:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_G_TUNER:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-       case VIDIOC_LOG_STATUS:
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-               return bttv_common_ioctls(btv,cmd,arg);
+       mutex_lock(&fh->cap.lock);
 
-       default:
-               return -ENOIOCTLCMD;
+       if (fh->width < c.min_scaled_width) {
+               fh->width = c.min_scaled_width;
+               btv->init.width = c.min_scaled_width;
+       } else if (fh->width > c.max_scaled_width) {
+               fh->width = c.max_scaled_width;
+               btv->init.width = c.max_scaled_width;
+       }
+
+       if (fh->height < c.min_scaled_height) {
+               fh->height = c.min_scaled_height;
+               btv->init.height = c.min_scaled_height;
+       } else if (fh->height > c.max_scaled_height) {
+               fh->height = c.max_scaled_height;
+               btv->init.height = c.max_scaled_height;
        }
-       return 0;
 
- fh_unlock_and_return:
        mutex_unlock(&fh->cap.lock);
-       return retval;
 
- btv_unlock_and_return:
-       mutex_unlock(&btv->lock);
-       return retval;
+       return 0;
 }
 
-static int bttv_ioctl(struct inode *inode, struct file *file,
-                     unsigned int cmd, unsigned long arg)
+static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
-       struct bttv_fh *fh  = file->private_data;
-
-       switch (cmd) {
-       case BTTV_VBISIZE:
-       {
-               const struct bttv_tvnorm *tvnorm;
-
-               tvnorm = fh->vbi_fmt.tvnorm;
-
-               if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
-                   fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
-                   fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
-                       /* BTTV_VBISIZE cannot express these parameters,
-                          however open() resets the paramters to defaults
-                          and apps shouldn't call BTTV_VBISIZE after
-                          VIDIOC_S_FMT. */
-                       return -EINVAL;
-               }
-
-               bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-               return (fh->vbi_fmt.fmt.count[0] * 2
-                       * fh->vbi_fmt.fmt.samples_per_line);
-       }
+       strcpy(a->name, "audio");
+       return 0;
+}
 
-       default:
-               return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
-       }
+static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       return 0;
 }
 
 static ssize_t bttv_read(struct file *file, char __user *data,
@@ -3721,8 +3205,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        }
 
        poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == STATE_DONE ||
-           buf->vb.state == STATE_ERROR)
+       if (buf->vb.state == VIDEOBUF_DONE ||
+           buf->vb.state == VIDEOBUF_ERROR)
                return POLLIN|POLLRDNORM;
        return 0;
 }
@@ -3779,7 +3263,7 @@ static int bttv_open(struct inode *inode, struct file *file)
                            V4L2_FIELD_SEQ_TB,
                            sizeof(struct bttv_buffer),
                            fh);
-       i2c_vidiocschan(btv);
+       set_tvnorm(btv,btv->tvnorm);
 
        btv->users++;
 
@@ -3859,7 +3343,7 @@ static const struct file_operations bttv_fops =
        .owner    = THIS_MODULE,
        .open     = bttv_open,
        .release  = bttv_release,
-       .ioctl    = bttv_ioctl,
+       .ioctl    = video_ioctl2,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
        .read     = bttv_read,
@@ -3869,19 +3353,61 @@ static const struct file_operations bttv_fops =
 
 static struct video_device bttv_video_template =
 {
-       .name     = "UNSET",
-       .type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-                   VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-       .fops     = &bttv_fops,
-       .minor    = -1,
-};
-
-static struct video_device bttv_vbi_template =
-{
-       .name     = "bt848/878 vbi",
-       .type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
        .fops     = &bttv_fops,
        .minor    = -1,
+       .vidioc_querycap                = bttv_querycap,
+       .vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
+       .vidioc_g_fmt_cap               = bttv_g_fmt_cap,
+       .vidioc_try_fmt_cap             = bttv_try_fmt_cap,
+       .vidioc_s_fmt_cap               = bttv_s_fmt_cap,
+       .vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
+       .vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
+       .vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
+       .vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
+       .vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
+       .vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
+       .vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
+       .vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
+       .vidioc_g_audio                 = bttv_g_audio,
+       .vidioc_s_audio                 = bttv_s_audio,
+       .vidioc_cropcap                 = bttv_cropcap,
+       .vidioc_reqbufs                 = bttv_reqbufs,
+       .vidioc_querybuf                = bttv_querybuf,
+       .vidioc_qbuf                    = bttv_qbuf,
+       .vidioc_dqbuf                   = bttv_dqbuf,
+       .vidioc_s_std                   = bttv_s_std,
+       .vidioc_enum_input              = bttv_enum_input,
+       .vidioc_g_input                 = bttv_g_input,
+       .vidioc_s_input                 = bttv_s_input,
+       .vidioc_queryctrl               = bttv_queryctrl,
+       .vidioc_g_ctrl                  = bttv_g_ctrl,
+       .vidioc_s_ctrl                  = bttv_s_ctrl,
+       .vidioc_streamon                = bttv_streamon,
+       .vidioc_streamoff               = bttv_streamoff,
+       .vidioc_g_tuner                 = bttv_g_tuner,
+       .vidioc_s_tuner                 = bttv_s_tuner,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf                    = vidiocgmbuf,
+#endif
+       .vidioc_g_crop                  = bttv_g_crop,
+       .vidioc_g_crop                  = bttv_g_crop,
+       .vidioc_s_crop                  = bttv_s_crop,
+       .vidioc_g_fbuf                  = bttv_g_fbuf,
+       .vidioc_s_fbuf                  = bttv_s_fbuf,
+       .vidioc_overlay                 = bttv_overlay,
+       .vidioc_g_priority              = bttv_g_priority,
+       .vidioc_s_priority              = bttv_s_priority,
+       .vidioc_g_parm                  = bttv_g_parm,
+       .vidioc_g_frequency             = bttv_g_frequency,
+       .vidioc_s_frequency             = bttv_s_frequency,
+       .vidioc_log_status              = bttv_log_status,
+       .vidioc_querystd                = bttv_querystd,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register              = bttv_g_register,
+       .vidioc_s_register              = bttv_s_register,
+#endif
+       .tvnorms                        = BTTV_NORMS,
+       .current_norm                   = V4L2_STD_PAL,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -3920,7 +3446,7 @@ static int radio_open(struct inode *inode, struct file *file)
 
 static int radio_release(struct inode *inode, struct file *file)
 {
-       struct bttv        *btv = file->private_data;
+       struct bttv *btv = file->private_data;
        struct rds_command cmd;
 
        btv->radio_user--;
@@ -3930,59 +3456,116 @@ static int radio_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+static int radio_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *cap)
 {
-       struct bttv    *btv = file->private_data;
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-       switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *cap = arg;
+       strcpy(cap->driver, "bttv");
+       strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
+       cap->version = BTTV_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_TUNER;
 
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->name,btv->radio_dev->name);
-               cap->type = VID_TYPE_TUNER;
-               cap->channels = 1;
-               cap->audios = 1;
-               return 0;
-       }
+       return 0;
+}
 
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner *v = arg;
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
 
-               if(v->tuner)
-                       return -EINVAL;
-               memset(v,0,sizeof(*v));
-               strcpy(v->name, "Radio");
-               bttv_call_i2c_clients(btv,cmd,v);
-               return 0;
-       }
-       case VIDIOCSTUNER:
-               /* nothing to do */
-               return 0;
+       if (UNSET == bttv_tvcards[btv->c.type].tuner)
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
+       mutex_lock(&btv->lock);
+       memset(t, 0, sizeof(*t));
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
 
-       case BTTV_VERSION:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-       case VIDIOC_LOG_STATUS:
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-               return bttv_common_ioctls(btv,cmd,arg);
+       bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+
+       if (btv->audio_mode_gpio)
+               btv->audio_mode_gpio(btv, t, 0);
+
+       mutex_unlock(&btv->lock);
+
+       return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       if (i->index != 0)
+               return -EINVAL;
+
+       strcpy(i->name, "Radio");
+        i->type = V4L2_INPUT_TYPE_TUNER;
+
+       return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       memset(a, 0, sizeof(*a));
+       strcpy(a->name, "Radio");
+       return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct bttv_fh *fh = priv;
+       struct bttv *btv = fh->btv;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+       return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       const struct v4l2_queryctrl *ctrl;
+
+       if (c->id <  V4L2_CID_BASE ||
+                       c->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+
+       if (c->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl = ctrl_by_id(c->id);
+               *c = *ctrl;
+       } else
+               *c = no_ctl;
 
-       default:
-               return -ENOIOCTLCMD;
-       }
        return 0;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
 {
-       return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+       *i = 0;
+       return 0;
 }
 
 static ssize_t radio_read(struct file *file, char __user *data,
@@ -4018,17 +3601,29 @@ static const struct file_operations radio_fops =
        .open     = radio_open,
        .read     = radio_read,
        .release  = radio_release,
-       .ioctl    = radio_ioctl,
+       .ioctl    = video_ioctl2,
        .llseek   = no_llseek,
        .poll     = radio_poll,
 };
 
 static struct video_device radio_template =
 {
-       .name     = "bt848/878 radio",
-       .type     = VID_TYPE_TUNER,
        .fops     = &radio_fops,
        .minor    = -1,
+       .vidioc_querycap        = radio_querycap,
+       .vidioc_g_tuner         = radio_g_tuner,
+       .vidioc_enum_input      = radio_enum_input,
+       .vidioc_g_audio         = radio_g_audio,
+       .vidioc_s_tuner         = radio_s_tuner,
+       .vidioc_s_audio         = radio_s_audio,
+       .vidioc_s_input         = radio_s_input,
+       .vidioc_s_std           = radio_s_std,
+       .vidioc_queryctrl       = radio_queryctrl,
+       .vidioc_g_input         = radio_g_input,
+       .vidioc_g_ctrl          = bttv_g_ctrl,
+       .vidioc_s_ctrl          = bttv_s_ctrl,
+       .vidioc_g_frequency     = bttv_g_frequency,
+       .vidioc_s_frequency     = bttv_s_frequency,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -4310,20 +3905,20 @@ static void bttv_irq_timeout(unsigned long data)
        bttv_set_dma(btv, 0);
 
        /* wake up */
-       bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
-       bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
+       bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
+       bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
 
        /* cancel all outstanding capture / vbi requests */
        while (!list_empty(&btv->capture)) {
                item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
                list_del(&item->vb.queue);
-               item->vb.state = STATE_ERROR;
+               item->vb.state = VIDEOBUF_ERROR;
                wake_up(&item->vb.done);
        }
        while (!list_empty(&btv->vcapture)) {
                item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
                list_del(&item->vb.queue);
-               item->vb.state = STATE_ERROR;
+               item->vb.state = VIDEOBUF_ERROR;
                wake_up(&item->vb.done);
        }
 
@@ -4346,7 +3941,7 @@ bttv_irq_wakeup_top(struct bttv *btv)
 
        do_gettimeofday(&wakeup->vb.ts);
        wakeup->vb.field_count = btv->field_count;
-       wakeup->vb.state = STATE_DONE;
+       wakeup->vb.state = VIDEOBUF_DONE;
        wake_up(&wakeup->vb.done);
        spin_unlock(&btv->s_lock);
 }
@@ -4395,7 +3990,7 @@ bttv_irq_switch_video(struct bttv *btv)
        }
 
        /* wake up finished buffers */
-       bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
+       bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
        spin_unlock(&btv->s_lock);
 }
 
@@ -4428,7 +4023,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
        bttv_buffer_activate_vbi(btv, new);
        bttv_set_dma(btv, 0);
 
-       bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
+       bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
        spin_unlock(&btv->s_lock);
 }
 
@@ -4550,8 +4145,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
 /* initialitation                                                          */
 
 static struct video_device *vdev_init(struct bttv *btv,
-                                     struct video_device *template,
-                                     char *type)
+                                     const struct video_device *template,
+                                     const char *type_name,
+                                     const int type)
 {
        struct video_device *vfd;
 
@@ -4562,9 +4158,10 @@ static struct video_device *vdev_init(struct bttv *btv,
        vfd->minor   = -1;
        vfd->dev     = &btv->c.pci->dev;
        vfd->release = video_device_release;
+       vfd->type    = type;
        snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
                 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
-                type, bttv_tvcards[btv->c.type].name);
+                type_name, bttv_tvcards[btv->c.type].name);
        return vfd;
 }
 
@@ -4596,6 +4193,11 @@ static void bttv_unregister_video(struct bttv *btv)
 /* register video4linux devices */
 static int __devinit bttv_register_video(struct bttv *btv)
 {
+       int video_type = VID_TYPE_CAPTURE |
+                        VID_TYPE_TUNER   |
+                        VID_TYPE_CLIPPING|
+                        VID_TYPE_SCALES;
+
        if (no_overlay <= 0) {
                bttv_video_template.type |= VID_TYPE_OVERLAY;
        } else {
@@ -4603,7 +4205,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
        }
 
        /* video */
-       btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+       btv->video_dev = vdev_init(btv, &bttv_video_template,
+                                  "video", video_type);
+
        if (NULL == btv->video_dev)
                goto err;
        if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
@@ -4618,7 +4222,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
        }
 
        /* vbi */
-       btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
+       btv->vbi_dev = vdev_init(btv, &bttv_video_template,
+                                "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT);
+
        if (NULL == btv->vbi_dev)
                goto err;
        if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
@@ -4629,7 +4235,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
        if (!btv->has_radio)
                return 0;
        /* radio */
-       btv->radio_dev = vdev_init(btv, &radio_template, "radio");
+       btv->radio_dev = vdev_init(btv, &radio_template,
+                                  "radio", VID_TYPE_TUNER);
        if (NULL == btv->radio_dev)
                goto err;
        if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
@@ -4770,7 +4377,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        btv->init.btv         = btv;
        btv->init.ov.w.width  = 320;
        btv->init.ov.w.height = 240;
-       btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
+       btv->init.fmt         = format_by_fourcc(V4L2_PIX_FMT_BGR24);
        btv->init.width       = 320;
        btv->init.height      = 240;
        btv->input = 0;
@@ -5015,14 +4622,17 @@ static int __init bttv_init_module(void)
                printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
                return ret;
        }
-       return pci_register_driver(&bttv_pci_driver);
+       ret = pci_register_driver(&bttv_pci_driver);
+       if (ret < 0)
+               bus_unregister(&bttv_sub_bus_type);
+
+       return ret;
 }
 
 static void __exit bttv_cleanup_module(void)
 {
        pci_unregister_driver(&bttv_pci_driver);
        bus_unregister(&bttv_sub_bus_type);
-       return;
 }
 
 module_init(bttv_init_module);
index e7c521b8444afea5dca779091a9fa4bda2b8c691..fc9ecb21eec6e66311e773126f93f3ab74bfe582 100644 (file)
@@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv)
            (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
                ir_input_keydown(ir->dev,&ir->ir,data,data);
        } else {
+               /* HACK: Probably, ir->mask_keydown is missing
+                  for this board */
+               if (btv->c.type == BTTV_BOARD_WINFAST2000)
+                       ir_input_keydown(ir->dev, &ir->ir, data, data);
+
                ir_input_nokey(ir->dev,&ir->ir);
        }
 
index 58986f1a5f1a492d93e11780df80d747a18ab974..e5979f77504c7329c2603905066735f636ae65ac 100644 (file)
@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
        videobuf_dma_free(dma);
        btcx_riscmem_free(btv->c.pci,&buf->bottom);
        btcx_riscmem_free(btv->c.pci,&buf->top);
-       buf->vb.state = STATE_NEEDS_INIT;
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 int
@@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
        if (vbi) {
                unsigned int crop, vdelay;
 
-               vbi->vb.state = STATE_ACTIVE;
+               vbi->vb.state = VIDEOBUF_ACTIVE;
                list_del(&vbi->vb.queue);
 
                /* VDELAY is start of video, end of VBI capturing. */
@@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv,
        /* video capture */
        if (NULL != set->top  &&  NULL != set->bottom) {
                if (set->top == set->bottom) {
-                       set->top->vb.state    = STATE_ACTIVE;
+                       set->top->vb.state    = VIDEOBUF_ACTIVE;
                        if (set->top->vb.queue.next)
                                list_del(&set->top->vb.queue);
                } else {
-                       set->top->vb.state    = STATE_ACTIVE;
-                       set->bottom->vb.state = STATE_ACTIVE;
+                       set->top->vb.state    = VIDEOBUF_ACTIVE;
+                       set->bottom->vb.state = VIDEOBUF_ACTIVE;
                        if (set->top->vb.queue.next)
                                list_del(&set->top->vb.queue);
                        if (set->bottom->vb.queue.next)
@@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv,
                btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
                      ~0x0f, BT848_COLOR_CTL);
        } else if (NULL != set->top) {
-               set->top->vb.state  = STATE_ACTIVE;
+               set->top->vb.state  = VIDEOBUF_ACTIVE;
                if (set->top->vb.queue.next)
                        list_del(&set->top->vb.queue);
                bttv_apply_geo(btv, &set->top->geo,1);
@@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv,
                btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
                btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
        } else if (NULL != set->bottom) {
-               set->bottom->vb.state = STATE_ACTIVE;
+               set->bottom->vb.state = VIDEOBUF_ACTIVE;
                if (set->bottom->vb.queue.next)
                        list_del(&set->bottom->vb.queue);
                bttv_apply_geo(btv, &set->bottom->geo,1);
index 346ce019bdcbd76c52379f9c7581d8171432c8c5..1f0cc79e2a33e8e75c969f7e003d62d7abd0e793 100644 (file)
@@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
                redo_dma_risc = 1;
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                redo_dma_risc = 1;
                if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
                        goto fail;
@@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
        /* For bttv_buffer_activate_vbi(). */
        buf->geo.vdelay = min_vdelay;
 
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->vb.field = field;
        dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
                vb, &buf->top, &buf->bottom,
@@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
 
        dprintk("queue %p\n",vb);
-       buf->vb.state = STATE_QUEUED;
+       buf->vb.state = VIDEOBUF_QUEUED;
        list_add_tail(&buf->vb.queue,&btv->vcapture);
        if (NULL == btv->cvbi) {
                fh->btv->loop_irq |= 4;
@@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = {
 
 /* ----------------------------------------------------------------------- */
 
-static int
-try_fmt                        (struct v4l2_vbi_format *       f,
-                        const struct bttv_tvnorm *     tvnorm,
-                        __s32                          crop_start)
+static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
+                       __s32 crop_start)
 {
        __s32 min_start, max_start, max_end, f2_offset;
        unsigned int i;
@@ -305,10 +303,9 @@ try_fmt                    (struct v4l2_vbi_format *       f,
        return 0;
 }
 
-int
-bttv_vbi_try_fmt       (struct bttv_fh *               fh,
-                        struct v4l2_vbi_format *       f)
+int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+       struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
        const struct bttv_tvnorm *tvnorm;
        __s32 crop_start;
@@ -320,13 +317,13 @@ bttv_vbi_try_fmt  (struct bttv_fh *               fh,
 
        mutex_unlock(&btv->lock);
 
-       return try_fmt(f, tvnorm, crop_start);
+       return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
 }
 
-int
-bttv_vbi_set_fmt       (struct bttv_fh *               fh,
-                        struct v4l2_vbi_format *       f)
+
+int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+       struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
        const struct bttv_tvnorm *tvnorm;
        __s32 start1, end;
@@ -340,11 +337,12 @@ bttv_vbi_set_fmt  (struct bttv_fh *               fh,
 
        tvnorm = &bttv_tvnorms[btv->tvnorm];
 
-       rc = try_fmt(f, tvnorm, btv->crop_start);
+       rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
        if (0 != rc)
                goto fail;
 
-       start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+       start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
+               tvnorm->vbistart[0];
 
        /* First possible line of video capturing. Should be
           max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
@@ -352,11 +350,11 @@ bttv_vbi_set_fmt  (struct bttv_fh *               fh,
           pretend the VBI and video capture window may overlap,
           so end = start + 1, the lowest possible value, times two
           because vbi_fmt.end counts field lines times two. */
-       end = max(f->start[0], start1) * 2 + 2;
+       end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
 
        mutex_lock(&fh->vbi.lock);
 
-       fh->vbi_fmt.fmt    = *f;
+       fh->vbi_fmt.fmt    = frt->fmt.vbi;
        fh->vbi_fmt.tvnorm = tvnorm;
        fh->vbi_fmt.end    = end;
 
@@ -370,13 +368,13 @@ bttv_vbi_set_fmt  (struct bttv_fh *               fh,
        return rc;
 }
 
-void
-bttv_vbi_get_fmt       (struct bttv_fh *               fh,
-                        struct v4l2_vbi_format *       f)
+
+int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+       struct bttv_fh *fh = f;
        const struct bttv_tvnorm *tvnorm;
 
-       *f = fh->vbi_fmt.fmt;
+       frt->fmt.vbi = fh->vbi_fmt.fmt;
 
        tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
 
@@ -391,28 +389,28 @@ bttv_vbi_get_fmt  (struct bttv_fh *               fh,
                max_end = (tvnorm->cropcap.bounds.top
                           + tvnorm->cropcap.bounds.height) >> 1;
 
-               f->sampling_rate = tvnorm->Fsc;
+               frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
 
                for (i = 0; i < 2; ++i) {
                        __s32 new_start;
 
-                       new_start = f->start[i]
+                       new_start = frt->fmt.vbi.start[i]
                                + tvnorm->vbistart[i]
                                - fh->vbi_fmt.tvnorm->vbistart[i];
 
-                       f->start[i] = min(new_start, max_end - 1);
-                       f->count[i] = min((__s32) f->count[i],
-                                         max_end - f->start[i]);
+                       frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
+                       frt->fmt.vbi.count[i] =
+                               min((__s32) frt->fmt.vbi.count[i],
+                                         max_end - frt->fmt.vbi.start[i]);
 
                        max_end += tvnorm->vbistart[1]
                                - tvnorm->vbistart[0];
                }
        }
+       return 0;
 }
 
-void
-bttv_vbi_fmt_reset     (struct bttv_vbi_fmt *          f,
-                        int                            norm)
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
 {
        const struct bttv_tvnorm *tvnorm;
        unsigned int real_samples_per_line;
index 19e75d50a107924d6559d68b7ba14bddc83443f2..bf4c339a520c879d5bf1a04e5c213d6a63f2cc5a 100644 (file)
@@ -241,7 +241,10 @@ struct tvcard
        unsigned int radio_addr;
 
        unsigned int has_radio;
-       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+
+       void (*volume_gpio)(struct bttv *btv, __u16 volume);
+       void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+
        void (*muxsel_hook)(struct bttv *btv, unsigned int input);
 };
 
index d4ac4c4b49b459a9b71a952aac453ec456ed4dcc..1305d315cfc50227445b952fda59b009b7b3af0d 100644 (file)
 
 #define clamp(x, low, high) min (max (low, x), high)
 
+#define BTTV_NORMS    (\
+               V4L2_STD_PAL    | V4L2_STD_PAL_N | \
+               V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+               V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
+               V4L2_STD_PAL_60)
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm {
@@ -112,7 +117,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[];
 
 struct bttv_format {
        char *name;
-       int  palette;         /* video4linux 1      */
        int  fourcc;          /* video4linux 2      */
        int  btformat;        /* BT848_COLOR_FMT_*  */
        int  btswap;          /* BT848_COLOR_CTL_*  */
@@ -253,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
 /* ---------------------------------------------------------- */
 /* bttv-vbi.c                                                 */
 
-int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
-int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
 
 extern struct videobuf_queue_ops bttv_vbi_qops;
 
@@ -337,7 +341,9 @@ struct bttv {
        /* old gpio interface */
        wait_queue_head_t gpioq;
        int shutdown;
-       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+
+       void (*volume_gpio)(struct bttv *btv, __u16 volume);
+       void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
 
        /* new gpio interface */
        spinlock_t gpio_lock;
@@ -458,10 +464,6 @@ struct bttv {
 extern unsigned int bttv_num;
 extern struct bttv bttvs[BTTV_MAX];
 
-/* private ioctls */
-#define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
-#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
-
 #endif
 
 #define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
index 58423525591fbce1f1e3f876713b8e47f3bced79..032265383df25203eabf1816a8a94f4bf43daa2d 100644 (file)
@@ -82,11 +82,16 @@ OTHER DEALINGS IN THE SOFTWARE.
 static unsigned int maxpoll=250;   /* Maximum busy-loop count for qcam I/O */
 static unsigned int yieldlines=4;  /* Yield after this many during capture */
 static int video_nr = -1;
+static unsigned int force_init;                /* Whether to probe aggressively */
 
 module_param(maxpoll, int, 0);
 module_param(yieldlines, int, 0);
 module_param(video_nr, int, 0);
 
+/* Set force_init=1 to avoid detection by polling status register and
+ * immediately attempt to initialize qcam */
+module_param(force_init, int, 0);
+
 static inline int read_lpstatus(struct qcam_device *q)
 {
        return parport_read_status(q->pport);
@@ -331,6 +336,9 @@ static int qc_detect(struct qcam_device *q)
        int count = 0;
        int i;
 
+       if (force_init)
+               return 1;
+
        lastreg = reg = read_lpstatus(q) & 0xf0;
 
        for (i = 0; i < 500; i++)
@@ -354,12 +362,12 @@ static int qc_detect(struct qcam_device *q)
 
        /* Be (even more) liberal in what you accept...  */
 
-/*     if (count > 30 && count < 200) */
        if (count > 20 && count < 400) {
                return 1;       /* found */
        } else {
                printk(KERN_ERR "No Quickcam found on port %s\n",
                        q->pport->name);
+               printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
                return 0;       /* not found */
        }
 }
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
new file mode 100644 (file)
index 0000000..fae469c
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC
+ * Copyright (C) 2007 Hans Verkuil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
+
+
+/* ----------------------------------------------------------------------- */
+
+static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int cs5345_read(struct i2c_client *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       struct v4l2_routing *route = arg;
+       struct v4l2_control *ctrl = arg;
+
+       switch (cmd) {
+       case VIDIOC_INT_G_AUDIO_ROUTING:
+               route->input = cs5345_read(client, 0x09) & 7;
+               route->input |= cs5345_read(client, 0x05) & 0x70;
+               route->output = 0;
+               break;
+
+       case VIDIOC_INT_S_AUDIO_ROUTING:
+               if ((route->input & 0xf) > 6) {
+                       v4l_err(client, "Invalid input %d.\n", route->input);
+                       return -EINVAL;
+               }
+               cs5345_write(client, 0x09, route->input & 0xf);
+               cs5345_write(client, 0x05, route->input & 0xf0);
+               break;
+
+       case VIDIOC_G_CTRL:
+               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+                       ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
+                       break;
+               }
+               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+                       return -EINVAL;
+               ctrl->value = cs5345_read(client, 0x07) & 0x3f;
+               if (ctrl->value >= 32)
+                       ctrl->value = ctrl->value - 64;
+               break;
+
+       case VIDIOC_S_CTRL:
+               break;
+               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+                       cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
+                       break;
+               }
+               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+                       return -EINVAL;
+               if (ctrl->value > 24 || ctrl->value < -24)
+                       return -EINVAL;
+               cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
+               cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
+               break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (!v4l2_chip_match_i2c_client(client,
+                                       reg->match_type, reg->match_chip))
+                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = cs5345_read(client, reg->reg & 0x1f);
+               else
+                       cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f);
+               break;
+       }
+#endif
+
+       case VIDIOC_G_CHIP_IDENT:
+               return v4l2_chip_ident_i2c_client(client,
+                               arg, V4L2_IDENT_CS5345, 0);
+
+       case VIDIOC_LOG_STATUS:
+               {
+                       u8 v = cs5345_read(client, 0x09) & 7;
+                       u8 m = cs5345_read(client, 0x04);
+                       int vol = cs5345_read(client, 0x08) & 0x3f;
+
+                       v4l_info(client, "Input:  %d%s\n", v,
+                                     (m & 0x80) ? " (muted)" : "");
+                       if (vol >= 32)
+                               vol = vol - 64;
+                       v4l_info(client, "Volume: %d dB\n", vol);
+                       break;
+               }
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs5345_probe(struct i2c_client *client)
+{
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       cs5345_write(client, 0x02, 0x00);
+       cs5345_write(client, 0x04, 0x01);
+       cs5345_write(client, 0x09, 0x01);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "cs5345",
+       .driverid = I2C_DRIVERID_CS5345,
+       .command = cs5345_command,
+       .probe = cs5345_probe,
+};
+
index a73e285af7305c5429c9f51898b7593ebeccdd67..f41bfde045fe9dcb667e1373ac6e8424599db459 100644 (file)
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 
 module_param(debug, bool, 0644);
 
@@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
-                           void *arg)
+static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct v4l2_routing *route = arg;
        struct v4l2_control *ctrl = arg;
@@ -105,7 +105,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0);
+               return v4l2_chip_ident_i2c_client(client,
+                               arg, V4L2_IDENT_CS53l32A, 0);
 
        case VIDIOC_LOG_STATUS:
                {
@@ -134,27 +135,18 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+static int cs53l32a_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        int i;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
        snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        for (i = 1; i <= 7; i++) {
                u8 v = cs53l32a_read(client, i);
@@ -179,55 +171,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
 
                v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
        }
-
-       i2c_attach_client(client);
-
        return 0;
 }
 
-static int cs53l32a_probe(struct i2c_adapter *adapter)
-{
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, cs53l32a_attach);
-       return 0;
-}
-
-static int cs53l32a_detach(struct i2c_client *client)
-{
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-       kfree(client);
-
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "cs53l32a",
-       },
-       .id = I2C_DRIVERID_CS53L32A,
-       .attach_adapter = cs53l32a_probe,
-       .detach_client = cs53l32a_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "cs53l32a",
+       .driverid = I2C_DRIVERID_CS53L32A,
        .command = cs53l32a_command,
+       .probe = cs53l32a_probe,
 };
 
-
-static int __init cs53l32a_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit cs53l32a_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(cs53l32a_init_module);
-module_exit(cs53l32a_cleanup_module);
index 62304255dcae120cbf669f451942003227f4330e..c592899a23175f8a75febad62b3e39b8e930f9cb 100644 (file)
@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
@@ -75,6 +75,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
        V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
        0
 };
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
 
 
 /* Map the control ID to the correct field in the cx2341x_mpeg_params
@@ -281,13 +282,14 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
                        return -EBUSY;
                params->stream_type = ctrl->value;
                params->video_encoding =
-                       (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
-                        params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
-                       V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-               if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+                   (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+                    params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+               if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
                        /* MPEG-1 implies CBR */
-                       params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
-               }
+                       params->video_bitrate_mode =
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
                break;
        case V4L2_CID_MPEG_STREAM_VBI_FMT:
                params->stream_vbi_fmt = ctrl->value;
@@ -334,7 +336,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
        return 0;
 }
 
-static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
+                                  s32 min, s32 max, s32 step, s32 def)
 {
        const char *name;
 
@@ -417,7 +420,8 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma
        return 0;
 }
 
-int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+                      struct v4l2_queryctrl *qctrl)
 {
        int err;
 
@@ -440,7 +444,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 
        case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
                err = v4l2_ctrl_query_fill_std(qctrl);
-               if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+               if (err == 0 &&
+                   params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
                        qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return err;
 
@@ -455,13 +460,16 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
                err = v4l2_ctrl_query_fill_std(qctrl);
-               if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+               if (err == 0 &&
+                   params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
                        qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return err;
 
        case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
                err = v4l2_ctrl_query_fill_std(qctrl);
-               if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+               if (err == 0 &&
+                   params->video_bitrate_mode ==
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
                        qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return err;
 
@@ -476,80 +484,90 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
        /* CX23415/6 specific */
        case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
                return cx2341x_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
-                               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
-                               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+                       V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+                       V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+                       V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
                cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-               if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               if (params->video_spatial_filter_mode ==
+                           V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
                cx2341x_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
-                               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
-                               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
-               if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+                       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+                       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+                       1,
+                       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+               if (params->video_spatial_filter_mode ==
+                           V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
                cx2341x_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
-                               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
-                               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
-               if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+                   V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+                   V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+                   1,
+                   V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+               if (params->video_spatial_filter_mode ==
+                       V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
                return cx2341x_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
-                               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
-                               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+                       V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+                       V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+                       V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
                cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-               if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               if (params->video_temporal_filter_mode ==
+                       V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
                return cx2341x_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
-                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
-                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+                       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+                       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+                       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
                cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               if (params->video_median_filter_type ==
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
                cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               if (params->video_median_filter_type ==
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
                cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               if (params->video_median_filter_type ==
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
                cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               if (params->video_median_filter_type ==
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
                return 0;
 
        case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
@@ -560,6 +578,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 
        }
 }
+EXPORT_SYMBOL(cx2341x_ctrl_query);
 
 const char **cx2341x_ctrl_get_menu(u32 id)
 {
@@ -629,6 +648,7 @@ const char **cx2341x_ctrl_get_menu(u32 id)
                return v4l2_ctrl_get_menu(id);
        }
 }
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
 
 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
 {
@@ -637,9 +657,8 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
                ((1 + params->audio_l2_bitrate) << 4) |
                (params->audio_mode << 8) |
                (params->audio_mode_extension << 10) |
-               (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
-                 3 :
-                 params->audio_emphasis) << 12) |
+               (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+                 ? 3 : params->audio_emphasis) << 12) |
                (params->audio_crc << 14);
 }
 
@@ -679,19 +698,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
                if (err)
                        break;
        }
-       if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
-                       params->video_bitrate_peak < params->video_bitrate) {
+       if (err == 0 &&
+           params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+           params->video_bitrate_peak < params->video_bitrate) {
                err = -ERANGE;
                ctrls->error_idx = ctrls->count;
        }
-       if (err) {
+       if (err)
                ctrls->error_idx = i;
-       }
-       else {
+       else
                cx2341x_calc_audio_properties(params);
-       }
        return err;
 }
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
 
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
 {
@@ -732,13 +751,18 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
        .video_mute_yuv = 0x008080,  /* YCbCr value for black */
 
        /* encoding filters */
-       .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+       .video_spatial_filter_mode =
+               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
        .video_spatial_filter = 0,
-       .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
-       .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
-       .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+       .video_luma_spatial_filter_type =
+               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+       .video_chroma_spatial_filter_type =
+               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+       .video_temporal_filter_mode =
+               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
        .video_temporal_filter = 8,
-       .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+       .video_median_filter_type =
+               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
        .video_luma_median_filter_top = 255,
        .video_luma_median_filter_bottom = 0,
        .video_chroma_median_filter_top = 255,
@@ -748,8 +772,10 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
        *p = default_params;
        cx2341x_calc_audio_properties(p);
 }
+EXPORT_SYMBOL(cx2341x_fill_defaults);
 
-static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+static int cx2341x_api(void *priv, cx2341x_mbox_func func,
+                      u32 cmd, int args, ...)
 {
        u32 data[CX2341X_MBOX_MAX_DATA];
        va_list vargs;
@@ -757,15 +783,17 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ..
 
        va_start(vargs, args);
 
-       for (i = 0; i < args; i++) {
+       for (i = 0; i < args; i++)
                data[i] = va_arg(vargs, int);
-       }
        va_end(vargs);
        return func(priv, cmd, args, 0, data);
 }
 
+#define NEQ(field) (old->field != new->field)
+
 int cx2341x_update(void *priv, cx2341x_mbox_func func,
-               const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+                  const struct cx2341x_mpeg_params *old,
+                  const struct cx2341x_mpeg_params *new)
 {
        static int mpeg_stream_type[] = {
                0,      /* MPEG-2 PS */
@@ -777,17 +805,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
        };
 
        int err = 0;
+       int force = (old == NULL);
        u16 temporal = new->video_temporal_filter;
 
        cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
 
-       if (old == NULL || old->is_50hz != new->is_50hz) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+       if (force || NEQ(is_50hz)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
+                                 new->is_50hz);
                if (err) return err;
        }
 
-       if (old == NULL || old->width != new->width || old->height != new->height ||
-                       old->video_encoding != new->video_encoding) {
+       if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
                u16 w = new->width;
                u16 h = new->height;
 
@@ -795,69 +824,74 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
                        w /= 2;
                        h /= 2;
                }
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
+                                 h, w);
                if (err) return err;
        }
 
        if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
-               /* Adjust temporal filter if necessary. The problem with the temporal
-                  filter is that it works well with full resolution capturing, but
-                  not when the capture window is scaled (the filter introduces
-                  a ghosting effect). So if the capture window is scaled, then
-                  force the filter to 0.
+               /* Adjust temporal filter if necessary. The problem with the
+                  temporal filter is that it works well with full resolution
+                  capturing, but not when the capture window is scaled (the
+                  filter introduces a ghosting effect). So if the capture
+                  window is scaled, then force the filter to 0.
 
                   For full resolution the filter really improves the video
-                  quality, especially if the original video quality is suboptimal. */
+                  quality, especially if the original video quality is
+                  suboptimal. */
                temporal = 0;
        }
 
-       if (old == NULL || old->stream_type != new->stream_type) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+       if (force || NEQ(stream_type)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
+                                 mpeg_stream_type[new->stream_type]);
                if (err) return err;
        }
-       if (old == NULL || old->video_aspect != new->video_aspect) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+       if (force || NEQ(video_aspect)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
+                                 1 + new->video_aspect);
                if (err) return err;
        }
-       if (old == NULL || old->video_b_frames != new->video_b_frames ||
-               old->video_gop_size != new->video_gop_size) {
+       if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
                err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
                                new->video_gop_size, new->video_b_frames + 1);
                if (err) return err;
        }
-       if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
+       if (force || NEQ(video_gop_closure)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
+                                 new->video_gop_closure);
                if (err) return err;
        }
-       if (old == NULL || old->audio_properties != new->audio_properties) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
+       if (force || NEQ(audio_properties)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
+                                 1, new->audio_properties);
                if (err) return err;
        }
-       if (old == NULL || old->audio_mute != new->audio_mute) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
+       if (force || NEQ(audio_mute)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
+                                 new->audio_mute);
                if (err) return err;
        }
-       if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
-               old->video_bitrate != new->video_bitrate ||
-               old->video_bitrate_peak != new->video_bitrate_peak) {
+       if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
+                                               NEQ(video_bitrate_peak)) {
                err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
                                new->video_bitrate_mode, new->video_bitrate,
                                new->video_bitrate_peak / 400, 0, 0);
                if (err) return err;
        }
-       if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
-               old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
-               old->video_median_filter_type != new->video_median_filter_type) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
-                               new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+       if (force || NEQ(video_spatial_filter_mode) ||
+                    NEQ(video_temporal_filter_mode) ||
+                    NEQ(video_median_filter_type)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
+                                 2, new->video_spatial_filter_mode |
+                                       (new->video_temporal_filter_mode << 1),
                                new->video_median_filter_type);
                if (err) return err;
        }
-       if (old == NULL ||
-               old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
-               old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
-               old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
-               old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+       if (force || NEQ(video_luma_median_filter_bottom) ||
+                    NEQ(video_luma_median_filter_top) ||
+                    NEQ(video_chroma_median_filter_bottom) ||
+                    NEQ(video_chroma_median_filter_top)) {
                err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
                                new->video_luma_median_filter_bottom,
                                new->video_luma_median_filter_top,
@@ -865,36 +899,39 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
                                new->video_chroma_median_filter_top);
                if (err) return err;
        }
-       if (old == NULL ||
-               old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
-               old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
-                       new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+       if (force || NEQ(video_luma_spatial_filter_type) ||
+                    NEQ(video_chroma_spatial_filter_type)) {
+               err = cx2341x_api(priv, func,
+                                 CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
+                                 2, new->video_luma_spatial_filter_type,
+                                 new->video_chroma_spatial_filter_type);
                if (err) return err;
        }
-       if (old == NULL ||
-               old->video_spatial_filter != new->video_spatial_filter ||
-               old->video_temporal_filter != temporal) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
-                       new->video_spatial_filter, temporal);
+       if (force || NEQ(video_spatial_filter) ||
+                    old->video_temporal_filter != temporal) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
+                                 2, new->video_spatial_filter, temporal);
                if (err) return err;
        }
-       if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
-                       new->video_temporal_decimation);
+       if (force || NEQ(video_temporal_decimation)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
+                                 1, new->video_temporal_decimation);
                if (err) return err;
        }
-       if (old == NULL || old->video_mute != new->video_mute ||
-                       (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
+       if (force || NEQ(video_mute) ||
+               (new->video_mute && NEQ(video_mute_yuv))) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
+                               new->video_mute | (new->video_mute_yuv << 8));
                if (err) return err;
        }
-       if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
-               err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
+       if (force || NEQ(stream_insert_nav_packets)) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
+                               7, new->stream_insert_nav_packets);
                if (err) return err;
        }
        return 0;
 }
+EXPORT_SYMBOL(cx2341x_update);
 
 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
 {
@@ -943,18 +980,17 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
                p->video_bitrate);
-       if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+       if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
                printk(", Peak %d", p->video_bitrate_peak);
-       }
        printk("\n");
-       printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
+       printk(KERN_INFO
+               "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
                prefix,
                p->video_gop_size, p->video_b_frames,
                p->video_gop_closure ? "" : "No ");
-       if (p->video_temporal_decimation) {
+       if (p->video_temporal_decimation)
                printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
                        prefix, p->video_temporal_decimation);
-       }
 
        /* Audio */
        printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
@@ -964,10 +1000,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
                p->audio_mute ? " (muted)" : "");
-       if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
-               printk(", %s",
-                       cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
-       }
+       if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+               printk(", %s", cx2341x_menu_item(p,
+                               V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
        printk(", %s, %s\n",
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
@@ -975,33 +1010,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
        /* Encoding filters */
        printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
                prefix,
-               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
-               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
-               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+               cx2341x_menu_item(p,
+                   V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+               cx2341x_menu_item(p,
+                   V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+               cx2341x_menu_item(p,
+                   V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
                p->video_spatial_filter);
-       if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
+
+       if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
                temporal = 0;
-       }
+
        printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
                prefix,
-               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+               cx2341x_menu_item(p,
+                       V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
                temporal);
-       printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+       printk(KERN_INFO
+               "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
                prefix,
-               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+               cx2341x_menu_item(p,
+                       V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
                p->video_luma_median_filter_bottom,
                p->video_luma_median_filter_top,
                p->video_chroma_median_filter_bottom,
                p->video_chroma_median_filter_top);
 }
-
-EXPORT_SYMBOL(cx2341x_fill_defaults);
-EXPORT_SYMBOL(cx2341x_ctrl_query);
-EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
-EXPORT_SYMBOL(cx2341x_ext_ctrls);
-EXPORT_SYMBOL(cx2341x_update);
 EXPORT_SYMBOL(cx2341x_log_status);
-EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
 
 /*
  * Local variables:
index 081ee6e1536fe675f6e9852aa89312cd773f90df..1fd326fe41136cd271717eb9b89582701782131f 100644 (file)
@@ -12,6 +12,10 @@ config VIDEO_CX23885
        select DVB_S5H1409 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_PLL if !DVB_FE_CUSTOMISE
+       select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
+       select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+       select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
+       select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
        ---help---
          This is a video4linux driver for Conexant 23885 based
          TV cards.
index 665067022d2adf3293ca860d88d52e95adf12d41..32c90be506029374d8e901c82938ec64b12390a1 100644 (file)
@@ -1,4 +1,4 @@
-cx23885-objs   := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+cx23885-objs   := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 
index b9012acabb2f2b6a5c01c9f83ee9bd619e430cb1..2d414dad5c31ac2b9c184459d6d04a6b42746dce 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <media/cx25840.h>
 
 #include "cx23885.h"
 
@@ -32,6 +33,8 @@
 struct cx23885_board cx23885_boards[] = {
        [CX23885_BOARD_UNKNOWN] = {
                .name           = "UNKNOWN/GENERIC",
+               /* Ensure safe default for unknown boards */
+               .clk_freq       = 0,
                .input          = {{
                        .type   = CX23885_VMUX_COMPOSITE1,
                        .vmux   = 0,
@@ -69,23 +72,29 @@ struct cx23885_board cx23885_boards[] = {
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
                .name           = "Hauppauge WinTV-HVR1800",
+               .porta          = CX23885_ANALOG_VIDEO,
                .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .tuner_addr     = 0x42, /* 0x84 >> 1 */
                .input          = {{
                        .type   = CX23885_VMUX_TELEVISION,
-                       .vmux   = 0,
-                       .gpio0  = 0xff00,
-               },{
-                       .type   = CX23885_VMUX_DEBUG,
-                       .vmux   = 0,
-                       .gpio0  = 0xff01,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_VIN2_CH1,
+                       .gpio0  = 0,
                },{
                        .type   = CX23885_VMUX_COMPOSITE1,
-                       .vmux   = 1,
-                       .gpio0  = 0xff02,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN6_CH1,
+                       .gpio0  = 0,
                },{
                        .type   = CX23885_VMUX_SVIDEO,
-                       .vmux   = 2,
-                       .gpio0  = 0xff02,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN8_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .gpio0  = 0,
                }},
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
@@ -113,6 +122,14 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "DViCO FusionHDTV5 Express",
                .portb          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
+               .name           = "Hauppauge WinTV-HVR1500Q",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1500] = {
+               .name           = "Hauppauge WinTV-HVR1500",
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -136,6 +153,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x7801,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x7809,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
        },{
                .subvendor = 0x0070,
                .subdevice = 0x7911,
@@ -144,6 +165,22 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xd500,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x7790,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x7797,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x7710,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x7717,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -184,9 +221,19 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
        switch (tv.model)
        {
        case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
-       case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
-       case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
-       case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+       case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
+       case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+       case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */
+       case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */
+       case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
+       case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
+       case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
+       case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
+       case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
+       case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */
+       case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */
+       case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
+       case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
                break;
        default:
                printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
@@ -197,6 +244,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
                        dev->name, tv.model);
 }
 
+/* Tuner callback function for cx23885 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int cx23885_tuner_callback(void *priv, int command, int arg)
+{
+       struct cx23885_i2c *bus = priv;
+       struct cx23885_dev *dev = bus->dev;
+
+       switch(dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+               if(command == 0) {      /* Tuner Reset Command from xc5000 */
+                       /* Drive the tuner into reset and out */
+                       cx_clear(GP0_IO, 0x00000004);
+                       mdelay(200);
+                       cx_set(GP0_IO, 0x00000004);
+                       return 0;
+               }
+               else {
+                       printk(KERN_ERR
+                               "%s(): Unknow command.\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               break;
+       }
+
+       return 0; /* Should never be here */
+}
+
 void cx23885_gpio_setup(struct cx23885_dev *dev)
 {
        switch(dev->board) {
@@ -204,6 +279,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                /* GPIO-0 cx24227 demodulator reset */
                cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
+               /* GPIO-0 cx24227 demodulator */
+               /* GPIO-2 xc3028 tuner */
+
+               /* Put the parts into reset */
+               cx_set(GP0_IO, 0x00050000);
+               cx_clear(GP0_IO, 0x00000005);
+               msleep(5);
+
+               /* Bring the parts out of reset */
+               cx_set(GP0_IO, 0x00050005);
+               break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+               /* GPIO-0 cx24227 demodulator reset */
+               /* GPIO-2 xc5000 tuner reset */
+               cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
                /* GPIO-0 656_CLK */
                /* GPIO-1 656_D0 */
@@ -212,7 +304,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                /* GPIO-11-14 cx23417 addr0-3 */
                /* GPIO-15-18 cx23417 READY, CS, RD, WR */
                /* GPIO-19 IR_RX */
-               // FIXME: Analog requires the tuner is brought out of reset
+
+               /* Force the TDA8295A into reset and back */
+               cx_set(GP0_IO, 0x00040004);
+               mdelay(20);
+               cx_clear(GP0_IO, 0x00000004);
+               mdelay(20);
+               cx_set(GP0_IO, 0x00040004);
+               mdelay(20);
                break;
        }
 }
@@ -221,6 +320,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 {
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
                /* FIXME: Implement me */
                break;
@@ -244,6 +345,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
                if (dev->i2c_bus[0].i2c_rc == 0)
@@ -258,6 +361,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        default:
@@ -270,8 +375,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
 /* ------------------------------------------------------------------ */
 
-EXPORT_SYMBOL(cx23885_boards);
-
 /*
  * Local variables:
  * c-basic-offset: 8
index 3cdd136477e58224dcca0ae81b4a5ad5ba260c45..8e40c7bcc06d08dbd7ed0363533cf26ab0ff01da 100644 (file)
@@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
 MODULE_LICENSE("GPL");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug,int,0644);
 MODULE_PARM_DESC(debug,"enable debug messages");
 
@@ -44,13 +44,15 @@ static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,"card type");
 
-#define dprintk(level,fmt, arg...)     if (debug >= level) \
-       printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
+#define dprintk(level, fmt, arg...)\
+       do { if (debug >= level)\
+               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+       } while (0)
 
 static unsigned int cx23885_devcount;
 
 static DEFINE_MUTEX(devlist);
-static LIST_HEAD(cx23885_devlist);
+LIST_HEAD(cx23885_devlist);
 
 #define NO_SYNC_LINE (-1U)
 
@@ -73,14 +75,14 @@ static LIST_HEAD(cx23885_devlist);
  * 0x00010ea0 0x00010xxx Free
  */
 
-struct sram_channel cx23885_sram_channels[] = {
+static struct sram_channel cx23885_sram_channels[] = {
        [SRAM_CH01] = {
-               .name           = "test ch1",
+               .name           = "VID A",
                .cmds_start     = 0x10000,
-               .ctrl_start     = 0x10500,
-               .cdt            = 0x10900,
-               .fifo_start     = 0x3000,
-               .fifo_size      = 0x1000,
+               .ctrl_start     = 0x105b0,
+               .cdt            = 0x107b0,
+               .fifo_start     = 0x40,
+               .fifo_size      = 0x2800,
                .ptr1_reg       = DMA1_PTR1,
                .ptr2_reg       = DMA1_PTR2,
                .cnt1_reg       = DMA1_CNT1,
@@ -102,8 +104,8 @@ struct sram_channel cx23885_sram_channels[] = {
        [SRAM_CH03] = {
                .name           = "TS1 B",
                .cmds_start     = 0x100A0,
-               .ctrl_start     = 0x10780,
-               .cdt            = 0x10400,
+               .ctrl_start     = 0x10630,
+               .cdt            = 0x10870,
                .fifo_start     = 0x5000,
                .fifo_size      = 0x1000,
                .ptr1_reg       = DMA3_PTR1,
@@ -139,7 +141,7 @@ struct sram_channel cx23885_sram_channels[] = {
                .name           = "TS2 C",
                .cmds_start     = 0x10140,
                .ctrl_start     = 0x10680,
-               .cdt            = 0x10480,
+               .cdt            = 0x108d0,
                .fifo_start     = 0x6000,
                .fifo_size      = 0x1000,
                .ptr1_reg       = DMA5_PTR1,
@@ -205,14 +207,14 @@ struct sram_channel cx23885_sram_channels[] = {
  * 0x00010ea0 0x00010xxx Free
  */
 
-struct sram_channel cx23887_sram_channels[] = {
+static struct sram_channel cx23887_sram_channels[] = {
        [SRAM_CH01] = {
-               .name           = "test ch1",
-               .cmds_start     = 0x0,
-               .ctrl_start     = 0x0,
-               .cdt            = 0x0,
-               .fifo_start     = 0x0,
-               .fifo_size      = 0x0,
+               .name           = "VID A",
+               .cmds_start     = 0x10000,
+               .ctrl_start     = 0x105b0,
+               .cdt            = 0x107b0,
+               .fifo_start     = 0x40,
+               .fifo_size      = 0x2800,
                .ptr1_reg       = DMA1_PTR1,
                .ptr2_reg       = DMA1_PTR2,
                .cnt1_reg       = DMA1_CNT1,
@@ -231,12 +233,12 @@ struct sram_channel cx23887_sram_channels[] = {
                .cnt2_reg       = DMA2_CNT2,
        },
        [SRAM_CH03] = {
-               .name           = "ch3",
-               .cmds_start     = 0x0,
-               .ctrl_start     = 0x0,
-               .cdt            = 0x0,
-               .fifo_start     = 0x0,
-               .fifo_size      = 0x0,
+               .name           = "TS1 B",
+               .cmds_start     = 0x100A0,
+               .ctrl_start     = 0x10780,
+               .cdt            = 0x10400,
+               .fifo_start     = 0x5000,
+               .fifo_size      = 0x1000,
                .ptr1_reg       = DMA3_PTR1,
                .ptr2_reg       = DMA3_PTR2,
                .cnt1_reg       = DMA3_CNT1,
@@ -357,7 +359,7 @@ static int cx23885_risc_decode(u32 risc)
 }
 
 void cx23885_wakeup(struct cx23885_tsport *port,
-                   struct cx23885_dmaqueue *q, u32 count)
+                          struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_buffer *buf;
@@ -378,7 +380,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
                do_gettimeofday(&buf->vb.ts);
                dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
                        count, buf->count);
-               buf->vb.state = STATE_DONE;
+               buf->vb.state = VIDEOBUF_DONE;
                list_del(&buf->vb.queue);
                wake_up(&buf->vb.done);
        }
@@ -391,12 +393,10 @@ void cx23885_wakeup(struct cx23885_tsport *port,
                printk("%s: %d buffers handled (should be 1)\n",
                       __FUNCTION__, bc);
 }
-void cx23885_sram_channel_dump(struct cx23885_dev *dev,
-                              struct sram_channel *ch);
 
 int cx23885_sram_channel_setup(struct cx23885_dev *dev,
-                              struct sram_channel *ch,
-                              unsigned int bpl, u32 risc)
+                                     struct sram_channel *ch,
+                                     unsigned int bpl, u32 risc)
 {
        unsigned int i, lines;
        u32 cdt;
@@ -468,7 +468,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
 }
 
 void cx23885_sram_channel_dump(struct cx23885_dev *dev,
-                              struct sram_channel *ch)
+                                     struct sram_channel *ch)
 {
        static char *name[] = {
                "init risc lo",
@@ -529,8 +529,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
               dev->name, cx_read(ch->cnt2_reg));
 }
 
-void cx23885_risc_disasm(struct cx23885_tsport *port,
-                        struct btcx_riscmem *risc)
+static void cx23885_risc_disasm(struct cx23885_tsport *port,
+                               struct btcx_riscmem *risc)
 {
        struct cx23885_dev *dev = port->dev;
        unsigned int i, j, n;
@@ -548,7 +548,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port,
        }
 }
 
-void cx23885_shutdown(struct cx23885_dev *dev)
+static void cx23885_shutdown(struct cx23885_dev *dev)
 {
        /* disable RISC controller */
        cx_write(DEV_CNTRL2, 0);
@@ -578,7 +578,7 @@ void cx23885_shutdown(struct cx23885_dev *dev)
 
 }
 
-void cx23885_reset(struct cx23885_dev *dev)
+static void cx23885_reset(struct cx23885_dev *dev)
 {
        dprintk(1, "%s()\n", __FUNCTION__);
 
@@ -594,15 +594,18 @@ void cx23885_reset(struct cx23885_dev *dev)
 
        mdelay(100);
 
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
-       cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
+               720*4, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
+               188*4, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
+               188*4, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
 
        cx23885_gpio_setup(dev);
 }
@@ -637,7 +640,7 @@ static int get_resources(struct cx23885_dev *dev)
 
 static void cx23885_timeout(unsigned long data);
 int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-                        u32 reg, u32 mask, u32 value);
+                               u32 reg, u32 mask, u32 value);
 
 static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
 {
@@ -704,6 +707,44 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
        return 0;
 }
 
+static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
+{
+       switch (cx_read(RDR_CFG2) & 0xff) {
+       case 0x00:
+               /* cx23885 */
+               dev->hwrevision = 0xa0;
+               break;
+       case 0x01:
+               /* CX23885-12Z */
+               dev->hwrevision = 0xa1;
+               break;
+       case 0x02:
+               /* CX23885-13Z */
+               dev->hwrevision = 0xb0;
+               break;
+       case 0x03:
+               /* CX23888-22Z */
+               dev->hwrevision = 0xc0;
+               break;
+       case 0x0e:
+               /* CX23887-15Z */
+               dev->hwrevision = 0xc0;
+       case 0x0f:
+               /* CX23887-14Z */
+               dev->hwrevision = 0xb1;
+               break;
+       default:
+               printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
+                       __FUNCTION__, dev->hwrevision);
+       }
+       if (dev->hwrevision)
+               printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
+                       __FUNCTION__, dev->hwrevision);
+       else
+               printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
+                       __FUNCTION__, dev->hwrevision);
+}
+
 static int cx23885_dev_setup(struct cx23885_dev *dev)
 {
        int i;
@@ -723,10 +764,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        if(dev->pci->device == 0x8880) {
                dev->bridge = CX23885_BRIDGE_887;
                dev->sram_channels = cx23887_sram_channels;
+               /* Apply a sensible clock frequency for the PCIe bridge */
+               dev->clk_freq = 25000000;
        } else
        if(dev->pci->device == 0x8852) {
                dev->bridge = CX23885_BRIDGE_885;
                dev->sram_channels = cx23885_sram_channels;
+               /* Apply a sensible clock frequency for the PCIe bridge */
+               dev->clk_freq = 28000000;
        } else
                BUG();
 
@@ -746,6 +791,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
                cx23885_card_list(dev);
        }
 
+       /* If the user specific a clk freq override, apply it */
+       if (cx23885_boards[dev->board].clk_freq > 0)
+               dev->clk_freq = cx23885_boards[dev->board].clk_freq;
+
        dev->pci_bus  = dev->pci->bus->number;
        dev->pci_slot = PCI_SLOT(dev->pci->devfn);
        dev->pci_irqmask = 0x001f00;
@@ -810,6 +859,17 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 
        cx23885_pci_quirks(dev);
 
+       /* Assume some sensible defaults */
+       dev->tuner_type = cx23885_boards[dev->board].tuner_type;
+       dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
+       dev->radio_type = cx23885_boards[dev->board].radio_type;
+       dev->radio_addr = cx23885_boards[dev->board].radio_addr;
+
+       dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
+               __FUNCTION__, dev->tuner_type, dev->tuner_addr);
+       dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
+               __FUNCTION__, dev->radio_type, dev->radio_addr);
+
        /* init hardware */
        cx23885_reset(dev);
 
@@ -820,24 +880,33 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        cx23885_card_setup(dev);
        cx23885_ir_init(dev);
 
-       if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+       if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
+               if (cx23885_video_register(dev) < 0) {
+                       printk(KERN_ERR "%s() Failed to register analog "
+                               "video adapters on VID_A\n", __FUNCTION__);
+               }
+       }
+
+       if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
                if (cx23885_dvb_register(&dev->ts1) < 0) {
                        printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
                               __FUNCTION__);
                }
        }
 
-       if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+       if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
                if (cx23885_dvb_register(&dev->ts2) < 0) {
                        printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
                               __FUNCTION__);
                }
        }
 
+       cx23885_dev_checkrevision(dev);
+
        return 0;
 }
 
-void cx23885_dev_unregister(struct cx23885_dev *dev)
+static void cx23885_dev_unregister(struct cx23885_dev *dev)
 {
        release_mem_region(pci_resource_start(dev->pci,0),
                           pci_resource_len(dev->pci,0));
@@ -845,6 +914,9 @@ void cx23885_dev_unregister(struct cx23885_dev *dev)
        if (!atomic_dec_and_test(&dev->refcount))
                return;
 
+       if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
+               cx23885_video_unregister(dev);
+
        if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
                cx23885_dvb_unregister(&dev->ts1);
 
@@ -952,9 +1024,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        return 0;
 }
 
-int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
-                           struct scatterlist *sglist, unsigned int bpl,
-                           unsigned int lines)
+static int cx23885_risc_databuffer(struct pci_dev *pci,
+                                  struct btcx_riscmem *risc,
+                                  struct scatterlist *sglist,
+                                  unsigned int bpl,
+                                  unsigned int lines)
 {
        u32 instructions;
        u32 *rp;
@@ -982,7 +1056,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-                        u32 reg, u32 mask, u32 value)
+                               u32 reg, u32 mask, u32 value)
 {
        u32 *rp;
        int rc;
@@ -1011,7 +1085,58 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
        videobuf_dma_unmap(q, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
-       buf->vb.state = STATE_NEEDS_INIT;
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
+{
+       struct cx23885_dev *dev = port->dev;
+
+       dprintk(1, "%s() Register Dump\n", __FUNCTION__);
+       dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __FUNCTION__,
+               cx_read(DEV_CNTRL2));
+       dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __FUNCTION__,
+               cx_read(PCI_INT_MSK));
+       dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __FUNCTION__,
+               cx_read(AUDIO_INT_INT_MSK));
+       dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __FUNCTION__,
+               cx_read(AUD_INT_DMA_CTL));
+       dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __FUNCTION__,
+               cx_read(AUDIO_EXT_INT_MSK));
+       dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __FUNCTION__,
+               cx_read(AUD_EXT_DMA_CTL));
+       dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __FUNCTION__,
+               cx_read(PAD_CTRL));
+       dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __FUNCTION__,
+               cx_read(ALT_PIN_OUT_SEL));
+       dprintk(1, "%s() GPIO2                    0x%08X\n", __FUNCTION__,
+               cx_read(GPIO2));
+       dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __FUNCTION__,
+               port->reg_gpcnt, cx_read(port->reg_gpcnt));
+       dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __FUNCTION__,
+               port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
+       dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __FUNCTION__,
+               port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
+       dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __FUNCTION__,
+               port->reg_src_sel, cx_read(port->reg_src_sel));
+       dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __FUNCTION__,
+               port->reg_lngth, cx_read(port->reg_lngth));
+       dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __FUNCTION__,
+               port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
+       dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __FUNCTION__,
+               port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
+       dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __FUNCTION__,
+               port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
+       dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __FUNCTION__,
+               port->reg_sop_status, cx_read(port->reg_sop_status));
+       dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
+               port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
+       dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __FUNCTION__,
+               port->reg_vld_misc, cx_read(port->reg_vld_misc));
+       dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __FUNCTION__,
+               port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
+       dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __FUNCTION__,
+               port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
 }
 
 static int cx23885_start_dma(struct cx23885_tsport *port,
@@ -1076,6 +1201,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
 
        cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
 
+       if (debug > 4)
+               cx23885_tsport_reg_dump(port);
+
        return 0;
 }
 
@@ -1091,7 +1219,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
        return 0;
 }
 
-static int cx23885_restart_queue(struct cx23885_tsport *port,
+int cx23885_restart_queue(struct cx23885_tsport *port,
                                struct cx23885_dmaqueue *q)
 {
        struct cx23885_dev *dev = port->dev;
@@ -1114,7 +1242,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
                                list_del(&buf->vb.queue);
                                list_add_tail(&buf->vb.queue, &q->active);
                                cx23885_start_dma(port, q, buf);
-                               buf->vb.state = STATE_ACTIVE;
+                               buf->vb.state = VIDEOBUF_ACTIVE;
                                buf->count    = q->count++;
                                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
                                dprintk(5, "[%p/%d] restart_queue - first active\n",
@@ -1125,7 +1253,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
                                   prev->fmt       == buf->fmt) {
                                list_del(&buf->vb.queue);
                                list_add_tail(&buf->vb.queue, &q->active);
-                               buf->vb.state = STATE_ACTIVE;
+                               buf->vb.state = VIDEOBUF_ACTIVE;
                                buf->count    = q->count++;
                                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                                prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
@@ -1162,7 +1290,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
                return -EINVAL;
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                buf->vb.width  = port->ts_packet_size;
                buf->vb.height = port->ts_packet_count;
                buf->vb.size   = size;
@@ -1174,7 +1302,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
                                        videobuf_to_dma(&buf->vb)->sglist,
                                        buf->vb.width, buf->vb.height);
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
 
  fail:
@@ -1197,7 +1325,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
                dprintk( 1, "queue is empty - first active\n" );
                list_add_tail(&buf->vb.queue, &cx88q->active);
                cx23885_start_dma(port, cx88q, buf);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = cx88q->count++;
                mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
                dprintk(1, "[%p/%d] %s - first active\n",
@@ -1207,7 +1335,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
                prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
                                  vb.queue);
                list_add_tail(&buf->vb.queue, &cx88q->active);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = cx88q->count++;
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
@@ -1231,7 +1359,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
                buf = list_entry(q->active.next, struct cx23885_buffer,
                                 vb.queue);
                list_del(&buf->vb.queue);
-               buf->vb.state = STATE_ERROR;
+               buf->vb.state = VIDEOBUF_ERROR;
                wake_up(&buf->vb.done);
                dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
                        buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
@@ -1243,16 +1371,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
        spin_unlock_irqrestore(&port->slock, flags);
 }
 
-void cx23885_cancel_buffers(struct cx23885_tsport *port)
-{
-       struct cx23885_dev *dev = port->dev;
-       struct cx23885_dmaqueue *q = &port->mpegq;
-
-       dprintk(1, "%s()\n", __FUNCTION__);
-       del_timer_sync(&q->timeout);
-       cx23885_stop_dma(port);
-       do_cancel_buffers(port, "cancel", 0);
-}
 
 static void cx23885_timeout(unsigned long data)
 {
@@ -1325,12 +1443,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        struct cx23885_tsport *ts1 = &dev->ts1;
        struct cx23885_tsport *ts2 = &dev->ts2;
        u32 pci_status, pci_mask;
+       u32 vida_status, vida_mask;
        u32 ts1_status, ts1_mask;
        u32 ts2_status, ts2_mask;
-       int ts1_count = 0, ts2_count = 0, handled = 0;
+       int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
 
        pci_status = cx_read(PCI_INT_STAT);
        pci_mask = cx_read(PCI_INT_MSK);
+       vida_status = cx_read(VID_A_INT_STAT);
+       vida_mask = cx_read(VID_A_INT_MSK);
        ts1_status = cx_read(VID_B_INT_STAT);
        ts1_mask = cx_read(VID_B_INT_MSK);
        ts2_status = cx_read(VID_C_INT_STAT);
@@ -1339,11 +1460,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
                goto out;
 
+       vida_count = cx_read(VID_A_GPCNT);
        ts1_count = cx_read(ts1->reg_gpcnt);
        ts2_count = cx_read(ts2->reg_gpcnt);
-       dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n", pci_status, pci_mask );
-       dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
-       dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
+       dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
+               pci_status, pci_mask);
+       dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
+               vida_status, vida_mask, vida_count);
+       dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
+               ts1_status, ts1_mask, ts1_count);
+       dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
+               ts2_status, ts2_mask, ts2_count);
 
        if ( (pci_status & PCI_MSK_RISC_RD) ||
             (pci_status & PCI_MSK_RISC_WR) ||
@@ -1380,11 +1507,18 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 
        }
 
-       if (ts1_status)
-               handled += cx23885_irq_ts(ts1, ts1_status);
+       if (ts1_status) {
+               if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+                       handled += cx23885_irq_ts(ts1, ts1_status);
+       }
+
+       if (ts2_status) {
+               if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+                       handled += cx23885_irq_ts(ts2, ts2_status);
+       }
 
-       if (ts2_status)
-               handled += cx23885_irq_ts(ts2, ts2_status);
+       if (vida_status)
+               handled += cx23885_video_irq(dev, vida_status);
 
        if (handled)
                cx_write(PCI_INT_STAT, pci_status);
index eda8c05d093106661af809dcd92d51868a7b4070..ed465c007cea64d201b001b20100827c10825608 100644 (file)
 
 #include "s5h1409.h"
 #include "mt2131.h"
+#include "tda8290.h"
+#include "tda18271.h"
 #include "lgdt330x.h"
+#include "xc5000.h"
 #include "dvb-pll.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
 
-static unsigned int debug = 0;
+static unsigned int debug;
 
-#define dprintk(level,fmt, arg...)     if (debug >= level) \
-       printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
+#define dprintk(level, fmt, arg...)\
+       do { if (debug >= level)\
+               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+       } while (0)
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int alt_tuner;
+module_param(alt_tuner, int, 0644);
+MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
 
 /* ------------------------------------------------------------------ */
 
@@ -85,18 +98,39 @@ static struct s5h1409_config hauppauge_generic_config = {
        .demod_address = 0x32 >> 1,
        .output_mode   = S5H1409_SERIAL_OUTPUT,
        .gpio          = S5H1409_GPIO_ON,
-       .if_freq       = 44000,
+       .qam_if        = 44000,
        .inversion     = S5H1409_INVERSION_OFF,
-       .status_mode   = S5H1409_DEMODLOCKING
+       .status_mode   = S5H1409_DEMODLOCKING,
+       .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_ezqam_config = {
+       .demod_address = 0x32 >> 1,
+       .output_mode   = S5H1409_SERIAL_OUTPUT,
+       .gpio          = S5H1409_GPIO_OFF,
+       .qam_if        = 4000,
+       .inversion     = S5H1409_INVERSION_ON,
+       .status_mode   = S5H1409_DEMODLOCKING,
+       .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
 static struct s5h1409_config hauppauge_hvr1800lp_config = {
        .demod_address = 0x32 >> 1,
        .output_mode   = S5H1409_SERIAL_OUTPUT,
        .gpio          = S5H1409_GPIO_OFF,
-       .if_freq       = 44000,
+       .qam_if        = 44000,
+       .inversion     = S5H1409_INVERSION_OFF,
+       .status_mode   = S5H1409_DEMODLOCKING,
+       .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_hvr1500_config = {
+       .demod_address = 0x32 >> 1,
+       .output_mode   = S5H1409_SERIAL_OUTPUT,
+       .gpio          = S5H1409_GPIO_OFF,
        .inversion     = S5H1409_INVERSION_OFF,
-       .status_mode   = S5H1409_DEMODLOCKING
+       .status_mode   = S5H1409_DEMODLOCKING,
+       .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
 static struct mt2131_config hauppauge_generic_tunerconfig = {
@@ -109,6 +143,66 @@ static struct lgdt330x_config fusionhdtv_5_express = {
        .serial_mpeg = 0x40,
 };
 
+static struct s5h1409_config hauppauge_hvr1500q_config = {
+       .demod_address = 0x32 >> 1,
+       .output_mode   = S5H1409_SERIAL_OUTPUT,
+       .gpio          = S5H1409_GPIO_ON,
+       .qam_if        = 44000,
+       .inversion     = S5H1409_INVERSION_OFF,
+       .status_mode   = S5H1409_DEMODLOCKING,
+       .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
+       .i2c_address      = 0x61,
+       .if_khz           = 5380,
+       .tuner_callback   = cx23885_tuner_callback
+};
+
+static struct tda829x_config tda829x_no_probe = {
+       .probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+       .atsc_6   = { .if_freq = 5380, .std_bits = 0x1b },
+       .qam_6    = { .if_freq = 4000, .std_bits = 0x18 },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+       .std_map = &hauppauge_tda18271_std_map,
+       .gate    = TDA18271_GATE_ANALOG,
+};
+
+static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
+{
+       struct cx23885_tsport *port = ptr;
+       struct cx23885_dev *dev = port->dev;
+
+       switch (command) {
+       case XC2028_TUNER_RESET:
+               /* Send the tuner in then out of reset */
+               /* GPIO-2 xc3028 tuner */
+               dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+
+               cx_set(GP0_IO, 0x00040000);
+               cx_clear(GP0_IO, 0x00000004);
+               msleep(5);
+
+               cx_set(GP0_IO, 0x00040004);
+               msleep(5);
+               break;
+       case XC2028_RESET_CLK:
+               dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+               break;
+       default:
+               dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+                       command, arg);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
@@ -120,7 +214,6 @@ static int dvb_register(struct cx23885_tsport *port)
        /* init frontend */
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
-       case CX23885_BOARD_HAUPPAUGE_HVR1800:
                i2c_bus = &dev->i2c_bus[0];
                port->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &hauppauge_generic_config,
@@ -131,6 +224,36 @@ static int dvb_register(struct cx23885_tsport *port)
                                   &hauppauge_generic_tunerconfig, 0);
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1800:
+               i2c_bus = &dev->i2c_bus[0];
+               switch (alt_tuner) {
+               case 1:
+                       port->dvb.frontend =
+                               dvb_attach(s5h1409_attach,
+                                          &hauppauge_ezqam_config,
+                                          &i2c_bus->i2c_adap);
+                       if (port->dvb.frontend != NULL) {
+                               dvb_attach(tda829x_attach, port->dvb.frontend,
+                                          &dev->i2c_bus[1].i2c_adap, 0x42,
+                                          &tda829x_no_probe);
+                               dvb_attach(tda18271_attach, port->dvb.frontend,
+                                          0x60, &dev->i2c_bus[1].i2c_adap,
+                                          &hauppauge_tda18271_config);
+                       }
+                       break;
+               case 0:
+               default:
+                       port->dvb.frontend =
+                               dvb_attach(s5h1409_attach,
+                                          &hauppauge_generic_config,
+                                          &i2c_bus->i2c_adap);
+                       if (port->dvb.frontend != NULL)
+                               dvb_attach(mt2131_attach, port->dvb.frontend,
+                                          &i2c_bus->i2c_adap,
+                                          &hauppauge_generic_tunerconfig, 0);
+                       break;
+               }
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
                i2c_bus = &dev->i2c_bus[0];
                port->dvb.frontend = dvb_attach(s5h1409_attach,
@@ -152,6 +275,43 @@ static int dvb_register(struct cx23885_tsport *port)
                                   &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+               i2c_bus = &dev->i2c_bus[1];
+               port->dvb.frontend = dvb_attach(s5h1409_attach,
+                                               &hauppauge_hvr1500q_config,
+                                               &dev->i2c_bus[0].i2c_adap);
+               if (port->dvb.frontend != NULL) {
+                       hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
+                       dvb_attach(xc5000_attach, port->dvb.frontend,
+                               &i2c_bus->i2c_adap,
+                               &hauppauge_hvr1500q_tunerconfig);
+               }
+               break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
+               i2c_bus = &dev->i2c_bus[1];
+               port->dvb.frontend = dvb_attach(s5h1409_attach,
+                                               &hauppauge_hvr1500_config,
+                                               &dev->i2c_bus[0].i2c_adap);
+               if (port->dvb.frontend != NULL) {
+                       struct dvb_frontend *fe;
+                       struct xc2028_config cfg = {
+                               .i2c_adap  = &i2c_bus->i2c_adap,
+                               .i2c_addr  = 0x61,
+                               .video_dev = port,
+                               .callback  = cx23885_hvr1500_xc3028_callback,
+                       };
+                       static struct xc2028_ctrl ctl = {
+                               .fname       = "xc3028-v27.fw",
+                               .max_len     = 64,
+                               .scode_table = OREN538,
+                       };
+
+                       fe = dvb_attach(xc2028_attach,
+                                       port->dvb.frontend, &cfg);
+                       if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+                               fe->ops.tuner_ops.set_config(fe, &ctl);
+               }
+               break;
        default:
                printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
                       dev->name);
@@ -165,6 +325,9 @@ static int dvb_register(struct cx23885_tsport *port)
        /* Put the analog decoder in standby to keep it quiet */
        cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
 
+       if (port->dvb.frontend->ops.analog_ops.standby)
+               port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
+
        /* register everything */
        return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
                                     &dev->pci->dev);
index 71da528932df99fd6196bef22af67f147ec71785..92fe0bd37c84293e9b27e3933d142eaf4c7196ec 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <media/v4l2-common.h>
 
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
@@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
-#define dprintk(level,fmt, arg...)     if (i2c_debug >= level) \
-       printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+#define dprintk(level, fmt, arg...)\
+       do { if (i2c_debug >= level)\
+               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+       } while (0)
 
 #define I2C_WAIT_DELAY 32
 #define I2C_WAIT_RETRY 64
@@ -77,14 +79,19 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap)
 }
 
 static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
-                        const struct i2c_msg *msg, int last)
+                        const struct i2c_msg *msg, int joined_rlen)
 {
        struct cx23885_i2c *bus = i2c_adap->algo_data;
        struct cx23885_dev *dev = bus->dev;
        u32 wdata, addr, ctrl;
        int retval, cnt;
 
-       dprintk(1, "%s()\n", __FUNCTION__);
+       if (joined_rlen)
+               dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
+                       msg->len, joined_rlen);
+       else
+               dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+
        /* Deal with i2c probe functions with zero payload */
        if (msg->len == 0) {
                cx_write(bus->reg_addr, msg->addr << 25);
@@ -106,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
        if (msg->len > 1)
                ctrl |= I2C_NOSTOP | I2C_EXTEND;
+       else if (joined_rlen)
+               ctrl |= I2C_NOSTOP;
 
        cx_write(bus->reg_addr, addr);
        cx_write(bus->reg_wdata, wdata);
@@ -127,8 +136,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
                wdata = msg->buf[cnt];
                ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
 
-               if (cnt < msg->len-1 || !last)
+               if (cnt < msg->len - 1)
                        ctrl |= I2C_NOSTOP | I2C_EXTEND;
+               else if (joined_rlen)
+                       ctrl |= I2C_NOSTOP;
 
                cx_write(bus->reg_addr, addr);
                cx_write(bus->reg_wdata, wdata);
@@ -150,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
  eio:
        retval = -EIO;
  err:
-       printk(" ERR: %d\n", retval);
+       if (i2c_debug)
+               printk(" ERR: %d\n", retval);
        return retval;
 }
 
 static int i2c_readbytes(struct i2c_adapter *i2c_adap,
-                        const struct i2c_msg *msg, int last)
+                        const struct i2c_msg *msg, int joined)
 {
        struct cx23885_i2c *bus = i2c_adap->algo_data;
        struct cx23885_dev *dev = bus->dev;
        u32 ctrl, cnt;
        int retval;
 
-       dprintk(1, "%s()\n", __FUNCTION__);
+
+       if (i2c_debug && !joined)
+               dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
 
        /* Deal with i2c probe functions with zero payload */
        if (msg->len == 0) {
@@ -178,11 +192,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
                return 0;
        }
 
+       if (i2c_debug) {
+               if (joined)
+                       printk(" R");
+               else
+                       printk(" <R %02x", (msg->addr << 1) + 1);
+       }
+
        for(cnt = 0; cnt < msg->len; cnt++) {
 
                ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
 
-               if (cnt < msg->len-1 || !last)
+               if (cnt < msg->len - 1)
                        ctrl |= I2C_NOSTOP | I2C_EXTEND;
 
                cx_write(bus->reg_addr, msg->addr << 25);
@@ -195,9 +216,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
                        goto eio;
                msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
                if (i2c_debug) {
-                       if (!(ctrl & I2C_NOSTOP))
-                               printk(" <R %02x", (msg->addr << 1) +1);
-                       printk(" =%02x", msg->buf[cnt]);
+                       printk(" %02x", msg->buf[cnt]);
                        if (!(ctrl & I2C_NOSTOP))
                                printk(" >\n");
                }
@@ -207,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
  eio:
        retval = -EIO;
  err:
-       printk(" ERR: %d\n", retval);
+       if (i2c_debug)
+               printk(" ERR: %d\n", retval);
        return retval;
 }
 
@@ -225,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
                        __FUNCTION__, num, msgs[i].addr, msgs[i].len);
                if (msgs[i].flags & I2C_M_RD) {
                        /* read */
-                       retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
+                       retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+               } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+                          msgs[i].addr == msgs[i + 1].addr) {
+                       /* write then read from same address */
+                       retval = i2c_sendbytes(i2c_adap, &msgs[i],
+                                              msgs[i + 1].len);
                        if (retval < 0)
                                goto err;
+                       i++;
+                       retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
                } else {
                        /* write */
-                       retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
-                       if (retval < 0)
-                               goto err;
+                       retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
                }
+               if (retval < 0)
+                       goto err;
        }
        return num;
 
@@ -243,7 +270,9 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
 
 static int attach_inform(struct i2c_client *client)
 {
-       struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+       struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter);
+       struct cx23885_dev *dev = bus->dev;
+       struct tuner_setup tun_setup;
 
        dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
                client->driver->driver.name, client->addr, client->name);
@@ -251,6 +280,31 @@ static int attach_inform(struct i2c_client *client)
        if (!client->driver->command)
                return 0;
 
+       if (dev->tuner_type != UNSET) {
+
+               dprintk(1, "%s  (tuner) i2c attach [addr=0x%x,client=%s]\n",
+                       client->driver->driver.name, client->addr,
+                       client->name);
+
+               if ((dev->tuner_addr == ADDR_UNSET) ||
+                       (dev->tuner_addr == client->addr)) {
+
+                       dprintk(1, "%s (tuner || addr UNSET)\n",
+                               client->driver->driver.name);
+
+                       dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+                               client->driver->driver.name,
+                               client->addr, client->name);
+
+                       tun_setup.mode_mask = T_ANALOG_TV;
+                       tun_setup.type = dev->tuner_type;
+                       tun_setup.addr = dev->tuner_addr;
+
+                       client->driver->command(client, TUNER_SET_TYPE_ADDR,
+                               &tun_setup);
+               }
+       }
+
        return 0;
 }
 
@@ -289,6 +343,7 @@ static struct i2c_adapter cx23885_i2c_adap_template = {
        .owner             = THIS_MODULE,
        .id                = I2C_HW_B_CX23885,
        .algo              = &cx23885_i2c_algo_template,
+       .class             = I2C_CLASS_TV_ANALOG,
        .client_register   = attach_inform,
        .client_unregister = detach_inform,
 };
@@ -305,7 +360,7 @@ static char *i2c_devs[128] = {
        [ 0x84 >> 1 ] = "tda8295",
        [ 0xa0 >> 1 ] = "eeprom",
        [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
-       [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
+       [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -344,6 +399,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
 
        bus->i2c_algo.data = bus;
        bus->i2c_adap.algo_data = bus;
+       i2c_set_adapdata(&bus->i2c_adap, bus);
        i2c_add_adapter(&bus->i2c_adap);
 
        bus->i2c_client.adapter = &bus->i2c_adap;
@@ -366,8 +422,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus)
 
 /* ----------------------------------------------------------------------- */
 
-EXPORT_SYMBOL(cx23885_call_i2c_clients);
-
 /*
  * Local variables:
  * c-basic-offset: 8
index 162169f9091b18c52ed38d945f901817ebc80864..bdd11bc513adc3d07c66547ec871c666af0180a3 100644 (file)
@@ -233,6 +233,17 @@ Channel manager Data Structure entry = 20 DWORD
 #define VID_A_INT_SSTAT        0x0004002C
 
 #define VID_B_INT_MSK  0x00040030
+#define VID_B_MSK_BAD_PKT     (1 << 20)
+#define VID_B_MSK_VBI_OPC_ERR (1 << 17)
+#define VID_B_MSK_OPC_ERR     (1 << 16)
+#define VID_B_MSK_VBI_SYNC    (1 << 13)
+#define VID_B_MSK_SYNC        (1 << 12)
+#define VID_B_MSK_VBI_OF      (1 <<  9)
+#define VID_B_MSK_OF          (1 <<  8)
+#define VID_B_MSK_VBI_RISCI2  (1 <<  5)
+#define VID_B_MSK_RISCI2      (1 <<  4)
+#define VID_B_MSK_VBI_RISCI1  (1 <<  1)
+#define VID_B_MSK_RISCI1       1
 #define VID_B_INT_STAT 0x00040034
 #define VID_B_INT_MSTAT        0x00040038
 #define VID_B_INT_SSTAT        0x0004003C
@@ -276,6 +287,7 @@ Channel manager Data Structure entry = 20 DWORD
 
 #define RDR_CFG0       0x00050000
 #define RDR_CFG1       0x00050004
+#define RDR_CFG2       0x00050008
 #define RDR_TLCTL0     0x00050318
 
 /* APB DMAC Current Buffer Pointer */
@@ -335,6 +347,7 @@ Channel manager Data Structure entry = 20 DWORD
 /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
 #define MC417_OEN      0x00110024
 #define MC417_CTL      0x00110028
+#define ALT_PIN_OUT_SEL 0x0011002C
 #define CLK_DELAY      0x00110048
 #define PAD_CTRL       0x0011004C
 
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
new file mode 100644 (file)
index 0000000..e36e3fc
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "cx23885.h"
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
+
+#define dprintk(level, fmt, arg...)\
+       do { if (vbi_debug >= level)\
+               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+       } while (0)
+
+/* ------------------------------------------------------------------ */
+
+int cx23885_vbi_fmt(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct cx23885_fh *fh = priv;
+       struct cx23885_dev *dev = fh->dev;
+
+       if (dev->tvnorm & V4L2_STD_525_60) {
+               /* ntsc */
+               f->fmt.vbi.sampling_rate = 28636363;
+               f->fmt.vbi.start[0] = 10;
+               f->fmt.vbi.start[1] = 273;
+
+       } else if (dev->tvnorm & V4L2_STD_625_50) {
+               /* pal */
+               f->fmt.vbi.sampling_rate = 35468950;
+               f->fmt.vbi.start[0] = 7 - 1;
+               f->fmt.vbi.start[1] = 319 - 1;
+       }
+       return 0;
+}
+
+static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
+                        struct cx23885_dmaqueue *q,
+                        struct cx23885_buffer   *buf)
+{
+       /* setup fifo + format */
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
+                               buf->vb.width, buf->risc.dma);
+
+       /* reset counter */
+       q->count = 1;
+
+       /* enable irqs */
+       cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
+       cx_set(VID_A_INT_MSK, 0x000022);
+
+       /* start dma */
+       cx_set(DEV_CNTRL2, (1<<5));
+       cx_set(VID_A_DMA_CTL, 0x00000022);
+
+       return 0;
+}
+
+int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
+{
+       /* stop dma */
+       cx_clear(VID_A_DMA_CTL, 0x00000022);
+
+       /* disable irqs */
+       cx_clear(PCI_INT_MSK, 0x000001);
+       cx_clear(VID_A_INT_MSK, 0x00000022);
+       return 0;
+}
+
+int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
+                            struct cx23885_dmaqueue *q)
+{
+       struct cx23885_buffer *buf;
+       struct list_head *item;
+
+       if (list_empty(&q->active))
+               return 0;
+
+       buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+       dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+               buf, buf->vb.i);
+       cx23885_start_vbi_dma(dev, q, buf);
+       list_for_each(item, &q->active) {
+               buf = list_entry(item, struct cx23885_buffer, vb.queue);
+               buf->count = q->count++;
+       }
+       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       return 0;
+}
+
+void cx23885_vbi_timeout(unsigned long data)
+{
+       struct cx23885_dev *dev = (struct cx23885_dev *)data;
+       struct cx23885_dmaqueue *q = &dev->vbiq;
+       struct cx23885_buffer *buf;
+       unsigned long flags;
+
+       cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]);
+
+       cx_clear(VID_A_DMA_CTL, 0x22);
+
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&q->active)) {
+               buf = list_entry(q->active.next, struct cx23885_buffer,
+                       vb.queue);
+               list_del(&buf->vb.queue);
+               buf->vb.state = VIDEOBUF_ERROR;
+               wake_up(&buf->vb.done);
+               printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
+                      buf, buf->vb.i, (unsigned long)buf->risc.dma);
+       }
+       cx23885_restart_vbi_queue(dev, q);
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/* ------------------------------------------------------------------ */
+#define VBI_LINE_LENGTH 2048
+#define VBI_LINE_COUNT 17
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+       *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+       if (0 == *count)
+               *count = vbibufs;
+       if (*count < 2)
+               *count = 2;
+       if (*count > 32)
+               *count = 32;
+       return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+           enum v4l2_field field)
+{
+       struct cx23885_fh *fh  = q->priv_data;
+       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+       unsigned int size;
+       int rc;
+
+       size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+               return -EINVAL;
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               buf->vb.width  = VBI_LINE_LENGTH;
+               buf->vb.height = VBI_LINE_COUNT;
+               buf->vb.size   = size;
+               buf->vb.field  = V4L2_FIELD_SEQ_TB;
+
+               rc = videobuf_iolock(q, &buf->vb, NULL);
+               if (0 != rc)
+                       goto fail;
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                                dma->sglist,
+                                0, buf->vb.width * buf->vb.height,
+                                buf->vb.width, 0,
+                                buf->vb.height);
+       }
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+ fail:
+       cx23885_free_buffer(q, buf);
+       return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct cx23885_buffer   *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+       struct cx23885_buffer   *prev;
+       struct cx23885_fh       *fh   = vq->priv_data;
+       struct cx23885_dev      *dev  = fh->dev;
+       struct cx23885_dmaqueue *q    = &dev->vbiq;
+
+       /* add jump to stopper */
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+       if (list_empty(&q->active)) {
+               list_add_tail(&buf->vb.queue, &q->active);
+               cx23885_start_vbi_dma(dev, q, buf);
+               buf->vb.state = VIDEOBUF_ACTIVE;
+               buf->count    = q->count++;
+               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+               dprintk(2, "[%p/%d] vbi_queue - first active\n",
+                       buf, buf->vb.i);
+
+       } else {
+               prev = list_entry(q->active.prev, struct cx23885_buffer,
+                       vb.queue);
+               list_add_tail(&buf->vb.queue, &q->active);
+               buf->vb.state = VIDEOBUF_ACTIVE;
+               buf->count    = q->count++;
+               prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+               prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
+               dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+                       buf, buf->vb.i);
+       }
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct cx23885_buffer *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+
+       cx23885_free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops cx23885_vbi_qops = {
+       .buf_setup    = vbi_setup,
+       .buf_prepare  = vbi_prepare,
+       .buf_queue    = vbi_queue,
+       .buf_release  = vbi_release,
+};
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
new file mode 100644 (file)
index 0000000..d3c4d2c
--- /dev/null
@@ -0,0 +1,1557 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+#endif
+
+MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr,   int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+static unsigned int irq_debug;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+#define dprintk(level, fmt, arg...)\
+       do { if (video_debug >= level)\
+               printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+       } while (0)
+
+/* ------------------------------------------------------------------- */
+/* static data                                                         */
+
+#define FORMAT_FLAGS_PACKED       0x01
+
+static struct cx23885_fmt formats[] = {
+       {
+               .name     = "8 bpp, gray",
+               .fourcc   = V4L2_PIX_FMT_GREY,
+               .depth    = 8,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "15 bpp RGB, le",
+               .fourcc   = V4L2_PIX_FMT_RGB555,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "15 bpp RGB, be",
+               .fourcc   = V4L2_PIX_FMT_RGB555X,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "16 bpp RGB, le",
+               .fourcc   = V4L2_PIX_FMT_RGB565,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "16 bpp RGB, be",
+               .fourcc   = V4L2_PIX_FMT_RGB565X,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "24 bpp RGB, le",
+               .fourcc   = V4L2_PIX_FMT_BGR24,
+               .depth    = 24,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "32 bpp RGB, le",
+               .fourcc   = V4L2_PIX_FMT_BGR32,
+               .depth    = 32,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "32 bpp RGB, be",
+               .fourcc   = V4L2_PIX_FMT_RGB32,
+               .depth    = 32,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       }, {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },
+};
+
+static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(formats); i++)
+               if (formats[i].fourcc == fourcc)
+                       return formats+i;
+
+       printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
+       return NULL;
+}
+
+/* ------------------------------------------------------------------- */
+
+static const struct v4l2_queryctrl no_ctl = {
+       .name  = "42",
+       .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct cx23885_ctrl cx23885_ctls[] = {
+       /* --- video --- */
+       {
+               .v = {
+                       .id            = V4L2_CID_BRIGHTNESS,
+                       .name          = "Brightness",
+                       .minimum       = 0x00,
+                       .maximum       = 0xff,
+                       .step          = 1,
+                       .default_value = 0x7f,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 128,
+               .reg                   = LUMA_CTRL,
+               .mask                  = 0x00ff,
+               .shift                 = 0,
+       }, {
+               .v = {
+                       .id            = V4L2_CID_CONTRAST,
+                       .name          = "Contrast",
+                       .minimum       = 0,
+                       .maximum       = 0xff,
+                       .step          = 1,
+                       .default_value = 0x3f,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 0,
+               .reg                   = LUMA_CTRL,
+               .mask                  = 0xff00,
+               .shift                 = 8,
+       }, {
+               .v = {
+                       .id            = V4L2_CID_HUE,
+                       .name          = "Hue",
+                       .minimum       = 0,
+                       .maximum       = 0xff,
+                       .step          = 1,
+                       .default_value = 0x7f,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 128,
+               .reg                   = CHROMA_CTRL,
+               .mask                  = 0xff0000,
+               .shift                 = 16,
+       }, {
+               /* strictly, this only describes only U saturation.
+                * V saturation is handled specially through code.
+                */
+               .v = {
+                       .id            = V4L2_CID_SATURATION,
+                       .name          = "Saturation",
+                       .minimum       = 0,
+                       .maximum       = 0xff,
+                       .step          = 1,
+                       .default_value = 0x7f,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 0,
+               .reg                   = CHROMA_CTRL,
+               .mask                  = 0x00ff,
+               .shift                 = 0,
+       }, {
+       /* --- audio --- */
+               .v = {
+                       .id            = V4L2_CID_AUDIO_MUTE,
+                       .name          = "Mute",
+                       .minimum       = 0,
+                       .maximum       = 1,
+                       .default_value = 1,
+                       .type          = V4L2_CTRL_TYPE_BOOLEAN,
+               },
+               .reg                   = PATH1_CTL1,
+               .mask                  = (0x1f << 24),
+               .shift                 = 24,
+       }, {
+               .v = {
+                       .id            = V4L2_CID_AUDIO_VOLUME,
+                       .name          = "Volume",
+                       .minimum       = 0,
+                       .maximum       = 0x3f,
+                       .step          = 1,
+                       .default_value = 0x3f,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .reg                   = PATH1_VOL_CTL,
+               .mask                  = 0xff,
+               .shift                 = 0,
+       }
+};
+static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
+
+const u32 cx23885_user_ctrls[] = {
+       V4L2_CID_USER_CLASS,
+       V4L2_CID_BRIGHTNESS,
+       V4L2_CID_CONTRAST,
+       V4L2_CID_SATURATION,
+       V4L2_CID_HUE,
+       V4L2_CID_AUDIO_VOLUME,
+       V4L2_CID_AUDIO_MUTE,
+       0
+};
+EXPORT_SYMBOL(cx23885_user_ctrls);
+
+static const u32 *ctrl_classes[] = {
+       cx23885_user_ctrls,
+       NULL
+};
+
+void cx23885_video_wakeup(struct cx23885_dev *dev,
+                struct cx23885_dmaqueue *q, u32 count)
+{
+       struct cx23885_buffer *buf;
+       int bc;
+
+       for (bc = 0;; bc++) {
+               if (list_empty(&q->active))
+                       break;
+               buf = list_entry(q->active.next,
+                                struct cx23885_buffer, vb.queue);
+
+               /* count comes from the hw and is is 16bit wide --
+                * this trick handles wrap-arounds correctly for
+                * up to 32767 buffers in flight... */
+               if ((s16) (count - buf->count) < 0)
+                       break;
+
+               do_gettimeofday(&buf->vb.ts);
+               dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+                       count, buf->count);
+               buf->vb.state = VIDEOBUF_DONE;
+               list_del(&buf->vb.queue);
+               wake_up(&buf->vb.done);
+       }
+       if (list_empty(&q->active)) {
+               del_timer(&q->timeout);
+       } else {
+               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       }
+       if (bc != 1)
+               printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
+                       __FUNCTION__, bc);
+}
+
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+{
+       dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
+               __FUNCTION__,
+               (unsigned int)norm,
+               v4l2_norm_to_name(norm));
+
+       dev->tvnorm = norm;
+
+       /* Tell the analog tuner/demods */
+       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm);
+
+       /* Tell the internal A/V decoder */
+       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm);
+
+       return 0;
+}
+
+struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
+                                   struct pci_dev *pci,
+                                   struct video_device *template,
+                                   char *type)
+{
+       struct video_device *vfd;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+       *vfd = *template;
+       vfd->minor   = -1;
+       vfd->dev     = &pci->dev;
+       vfd->release = video_device_release;
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+                dev->name, type, cx23885_boards[dev->board].name);
+       return vfd;
+}
+
+int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+       int i;
+
+       if (qctrl->id < V4L2_CID_BASE ||
+           qctrl->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       for (i = 0; i < CX23885_CTLS; i++)
+               if (cx23885_ctls[i].v.id == qctrl->id)
+                       break;
+       if (i == CX23885_CTLS) {
+               *qctrl = no_ctl;
+               return 0;
+       }
+       *qctrl = cx23885_ctls[i].v;
+       return 0;
+}
+EXPORT_SYMBOL(cx23885_ctrl_query);
+
+/* ------------------------------------------------------------------- */
+/* resource management                                                 */
+
+static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
+       unsigned int bit)
+{
+       dprintk(1, "%s()\n", __FUNCTION__);
+       if (fh->resources & bit)
+               /* have it already allocated */
+               return 1;
+
+       /* is it free? */
+       mutex_lock(&dev->lock);
+       if (dev->resources & bit) {
+               /* no, someone else uses it */
+               mutex_unlock(&dev->lock);
+               return 0;
+       }
+       /* it's free, grab it */
+       fh->resources  |= bit;
+       dev->resources |= bit;
+       dprintk(1, "res: get %d\n", bit);
+       mutex_unlock(&dev->lock);
+       return 1;
+}
+
+static int res_check(struct cx23885_fh *fh, unsigned int bit)
+{
+       return (fh->resources & bit);
+}
+
+static int res_locked(struct cx23885_dev *dev, unsigned int bit)
+{
+       return (dev->resources & bit);
+}
+
+static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
+       unsigned int bits)
+{
+       BUG_ON((fh->resources & bits) != bits);
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       mutex_lock(&dev->lock);
+       fh->resources  &= ~bits;
+       dev->resources &= ~bits;
+       dprintk(1, "res: put %d\n", bits);
+       mutex_unlock(&dev->lock);
+}
+
+int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+{
+       struct v4l2_routing route;
+       memset(&route, 0, sizeof(route));
+
+       dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
+               __FUNCTION__,
+               input, INPUT(input)->vmux,
+               INPUT(input)->gpio0, INPUT(input)->gpio1,
+               INPUT(input)->gpio2, INPUT(input)->gpio3);
+       dev->input = input;
+
+       route.input = INPUT(input)->vmux;
+
+       /* Tell the internal A/V decoder */
+       cx23885_call_i2c_clients(&dev->i2c_bus[2],
+               VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+       return 0;
+}
+EXPORT_SYMBOL(cx23885_video_mux);
+
+/* ------------------------------------------------------------------ */
+int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
+       unsigned int height, enum v4l2_field field)
+{
+       dprintk(1, "%s()\n", __FUNCTION__);
+       return 0;
+}
+
+static int cx23885_start_video_dma(struct cx23885_dev *dev,
+                          struct cx23885_dmaqueue *q,
+                          struct cx23885_buffer *buf)
+{
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       /* setup fifo + format */
+       cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
+                               buf->bpl, buf->risc.dma);
+       cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
+
+       /* reset counter */
+       cx_write(VID_A_GPCNT_CTL, 3);
+       q->count = 1;
+
+       /* enable irq */
+       cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
+       cx_set(VID_A_INT_MSK, 0x000011);
+
+       /* start dma */
+       cx_set(DEV_CNTRL2, (1<<5));
+       cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */
+
+       return 0;
+}
+
+
+static int cx23885_restart_video_queue(struct cx23885_dev *dev,
+                              struct cx23885_dmaqueue *q)
+{
+       struct cx23885_buffer *buf, *prev;
+       struct list_head *item;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       if (!list_empty(&q->active)) {
+               buf = list_entry(q->active.next, struct cx23885_buffer,
+                       vb.queue);
+               dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+                       buf, buf->vb.i);
+               cx23885_start_video_dma(dev, q, buf);
+               list_for_each(item, &q->active) {
+                       buf = list_entry(item, struct cx23885_buffer,
+                               vb.queue);
+                       buf->count    = q->count++;
+               }
+               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+               return 0;
+       }
+
+       prev = NULL;
+       for (;;) {
+               if (list_empty(&q->queued))
+                       return 0;
+               buf = list_entry(q->queued.next, struct cx23885_buffer,
+                       vb.queue);
+               if (NULL == prev) {
+                       list_move_tail(&buf->vb.queue, &q->active);
+                       cx23885_start_video_dma(dev, q, buf);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       buf->count    = q->count++;
+                       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+                       dprintk(2, "[%p/%d] restart_queue - first active\n",
+                               buf, buf->vb.i);
+
+               } else if (prev->vb.width  == buf->vb.width  &&
+                          prev->vb.height == buf->vb.height &&
+                          prev->fmt       == buf->fmt) {
+                       list_move_tail(&buf->vb.queue, &q->active);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       buf->count    = q->count++;
+                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+                       prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
+                       dprintk(2, "[%p/%d] restart_queue - move to active\n",
+                               buf, buf->vb.i);
+               } else {
+                       return 0;
+               }
+               prev = buf;
+       }
+}
+
+static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
+       unsigned int *size)
+{
+       struct cx23885_fh *fh = q->priv_data;
+
+       *size = fh->fmt->depth*fh->width*fh->height >> 3;
+       if (0 == *count)
+               *count = 32;
+       while (*size * *count > vid_limit * 1024 * 1024)
+               (*count)--;
+       return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+              enum v4l2_field field)
+{
+       struct cx23885_fh *fh  = q->priv_data;
+       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_buffer *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+       int rc, init_buffer = 0;
+       u32 line0_offset, line1_offset;
+       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+       BUG_ON(NULL == fh->fmt);
+       if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
+           fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
+               return -EINVAL;
+       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       if (buf->fmt       != fh->fmt    ||
+           buf->vb.width  != fh->width  ||
+           buf->vb.height != fh->height ||
+           buf->vb.field  != field) {
+               buf->fmt       = fh->fmt;
+               buf->vb.width  = fh->width;
+               buf->vb.height = fh->height;
+               buf->vb.field  = field;
+               init_buffer = 1;
+       }
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               init_buffer = 1;
+               rc = videobuf_iolock(q, &buf->vb, NULL);
+               if (0 != rc)
+                       goto fail;
+       }
+
+       if (init_buffer) {
+               buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
+               switch (buf->vb.field) {
+               case V4L2_FIELD_TOP:
+                       cx23885_risc_buffer(dev->pci, &buf->risc,
+                                        dma->sglist, 0, UNSET,
+                                        buf->bpl, 0, buf->vb.height);
+                       break;
+               case V4L2_FIELD_BOTTOM:
+                       cx23885_risc_buffer(dev->pci, &buf->risc,
+                                        dma->sglist, UNSET, 0,
+                                        buf->bpl, 0, buf->vb.height);
+                       break;
+               case V4L2_FIELD_INTERLACED:
+                       if (dev->tvnorm & V4L2_STD_NTSC) {
+                               /* cx25840 transmits NTSC bottom field first */
+                               dprintk(1, "%s() Creating NTSC risc\n",
+                                       __FUNCTION__);
+                               line0_offset = buf->bpl;
+                               line1_offset = 0;
+                       } else {
+                               /* All other formats are top field first */
+                               dprintk(1, "%s() Creating PAL/SECAM risc\n",
+                                       __FUNCTION__);
+                               line0_offset = 0;
+                               line1_offset = buf->bpl;
+                       }
+                       cx23885_risc_buffer(dev->pci, &buf->risc,
+                                       dma->sglist, line0_offset,
+                                       line1_offset,
+                                       buf->bpl, buf->bpl,
+                                       buf->vb.height >> 1);
+                       break;
+               case V4L2_FIELD_SEQ_TB:
+                       cx23885_risc_buffer(dev->pci, &buf->risc,
+                                        dma->sglist,
+                                        0, buf->bpl * (buf->vb.height >> 1),
+                                        buf->bpl, 0,
+                                        buf->vb.height >> 1);
+                       break;
+               case V4L2_FIELD_SEQ_BT:
+                       cx23885_risc_buffer(dev->pci, &buf->risc,
+                                        dma->sglist,
+                                        buf->bpl * (buf->vb.height >> 1), 0,
+                                        buf->bpl, 0,
+                                        buf->vb.height >> 1);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+       dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+               buf, buf->vb.i,
+               fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+               (unsigned long)buf->risc.dma);
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+ fail:
+       cx23885_free_buffer(q, buf);
+       return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct cx23885_buffer   *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct cx23885_buffer   *prev;
+       struct cx23885_fh       *fh   = vq->priv_data;
+       struct cx23885_dev      *dev  = fh->dev;
+       struct cx23885_dmaqueue *q    = &dev->vidq;
+
+       /* add jump to stopper */
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+       if (!list_empty(&q->queued)) {
+               list_add_tail(&buf->vb.queue, &q->queued);
+               buf->vb.state = VIDEOBUF_QUEUED;
+               dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+                       buf, buf->vb.i);
+
+       } else if (list_empty(&q->active)) {
+               list_add_tail(&buf->vb.queue, &q->active);
+               cx23885_start_video_dma(dev, q, buf);
+               buf->vb.state = VIDEOBUF_ACTIVE;
+               buf->count    = q->count++;
+               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+               dprintk(2, "[%p/%d] buffer_queue - first active\n",
+                       buf, buf->vb.i);
+
+       } else {
+               prev = list_entry(q->active.prev, struct cx23885_buffer,
+                       vb.queue);
+               if (prev->vb.width  == buf->vb.width  &&
+                   prev->vb.height == buf->vb.height &&
+                   prev->fmt       == buf->fmt) {
+                       list_add_tail(&buf->vb.queue, &q->active);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       buf->count    = q->count++;
+                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+                       /* 64 bit bits 63-32 */
+                       prev->risc.jmp[2] = cpu_to_le32(0);
+                       dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+                               buf, buf->vb.i);
+
+               } else {
+                       list_add_tail(&buf->vb.queue, &q->queued);
+                       buf->vb.state = VIDEOBUF_QUEUED;
+                       dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+                               buf, buf->vb.i);
+               }
+       }
+}
+
+static void buffer_release(struct videobuf_queue *q,
+       struct videobuf_buffer *vb)
+{
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+
+       cx23885_free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx23885_video_qops = {
+       .buf_setup    = buffer_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_queue    = buffer_queue,
+       .buf_release  = buffer_release,
+};
+
+static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
+{
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &fh->vidq;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return &fh->vbiq;
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static int get_resource(struct cx23885_fh *fh)
+{
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return RESOURCE_VIDEO;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return RESOURCE_VBI;
+       default:
+               BUG();
+               return 0;
+       }
+}
+
+static int video_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct cx23885_dev *h, *dev = NULL;
+       struct cx23885_fh *fh;
+       struct list_head *list;
+       enum v4l2_buf_type type = 0;
+       int radio = 0;
+
+       list_for_each(list, &cx23885_devlist) {
+               h = list_entry(list, struct cx23885_dev, devlist);
+               if (h->video_dev->minor == minor) {
+                       dev  = h;
+                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               }
+               if (h->vbi_dev &&
+                  h->vbi_dev->minor == minor) {
+                       dev  = h;
+                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               }
+               if (h->radio_dev &&
+                   h->radio_dev->minor == minor) {
+                       radio = 1;
+                       dev   = h;
+               }
+       }
+       if (NULL == dev)
+               return -ENODEV;
+
+       dprintk(1, "open minor=%d radio=%d type=%s\n",
+               minor, radio, v4l2_type_names[type]);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+       file->private_data = fh;
+       fh->dev      = dev;
+       fh->radio    = radio;
+       fh->type     = type;
+       fh->width    = 320;
+       fh->height   = 240;
+       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+
+       videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops,
+                           dev->pci, &dev->slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_INTERLACED,
+                           sizeof(struct cx23885_buffer),
+                           fh);
+
+       dprintk(1, "post videobuf_queue_init()\n");
+
+
+       return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user *data,
+       size_t count, loff_t *ppos)
+{
+       struct cx23885_fh *fh = file->private_data;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (res_locked(fh->dev, RESOURCE_VIDEO))
+                       return -EBUSY;
+               return videobuf_read_one(&fh->vidq, data, count, ppos,
+                                        file->f_flags & O_NONBLOCK);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (!res_get(fh->dev, fh, RESOURCE_VBI))
+                       return -EBUSY;
+               return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
+                                           file->f_flags & O_NONBLOCK);
+       default:
+               BUG();
+               return 0;
+       }
+}
+
+static unsigned int video_poll(struct file *file,
+       struct poll_table_struct *wait)
+{
+       struct cx23885_fh *fh = file->private_data;
+       struct cx23885_buffer *buf;
+
+       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+               if (!res_get(fh->dev, fh, RESOURCE_VBI))
+                       return POLLERR;
+               return videobuf_poll_stream(file, &fh->vbiq, wait);
+       }
+
+       if (res_check(fh, RESOURCE_VIDEO)) {
+               /* streaming capture */
+               if (list_empty(&fh->vidq.stream))
+                       return POLLERR;
+               buf = list_entry(fh->vidq.stream.next,
+                       struct cx23885_buffer, vb.stream);
+       } else {
+               /* read() capture */
+               buf = (struct cx23885_buffer *)fh->vidq.read_buf;
+               if (NULL == buf)
+                       return POLLERR;
+       }
+       poll_wait(file, &buf->vb.done, wait);
+       if (buf->vb.state == VIDEOBUF_DONE ||
+           buf->vb.state == VIDEOBUF_ERROR)
+               return POLLIN|POLLRDNORM;
+       return 0;
+}
+
+static int video_release(struct inode *inode, struct file *file)
+{
+       struct cx23885_fh *fh = file->private_data;
+       struct cx23885_dev *dev = fh->dev;
+
+       /* turn off overlay */
+       if (res_check(fh, RESOURCE_OVERLAY)) {
+               /* FIXME */
+               res_free(dev, fh, RESOURCE_OVERLAY);
+       }
+
+       /* stop video capture */
+       if (res_check(fh, RESOURCE_VIDEO)) {
+               videobuf_queue_cancel(&fh->vidq);
+               res_free(dev, fh, RESOURCE_VIDEO);
+       }
+       if (fh->vidq.read_buf) {
+               buffer_release(&fh->vidq, fh->vidq.read_buf);
+               kfree(fh->vidq.read_buf);
+       }
+
+       /* stop vbi capture */
+       if (res_check(fh, RESOURCE_VBI)) {
+               if (fh->vbiq.streaming)
+                       videobuf_streamoff(&fh->vbiq);
+               if (fh->vbiq.reading)
+                       videobuf_read_stop(&fh->vbiq);
+               res_free(dev, fh, RESOURCE_VBI);
+       }
+
+       videobuf_mmap_free(&fh->vidq);
+       file->private_data = NULL;
+       kfree(fh);
+
+       /* We are not putting the tuner to sleep here on exit, because
+        * we want to use the mpeg encoder in another session to capture
+        * tuner video. Closing this will result in no video to the encoder.
+        */
+
+       return 0;
+}
+
+static int video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct cx23885_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(get_queue(fh), vma);
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS                                                  */
+
+int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+{
+       dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
+       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
+       return 0;
+}
+EXPORT_SYMBOL(cx23885_get_control);
+
+int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+{
+       dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
+               " (disabled - no action)\n", __FUNCTION__);
+       return 0;
+}
+EXPORT_SYMBOL(cx23885_set_control);
+
+static void init_controls(struct cx23885_dev *dev)
+{
+       struct v4l2_control ctrl;
+       int i;
+
+       for (i = 0; i < CX23885_CTLS; i++) {
+               ctrl.id = cx23885_ctls[i].v.id;
+               ctrl.value = cx23885_ctls[i].v.default_value;
+
+               cx23885_set_control(dev, &ctrl);
+       }
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS                                                       */
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct cx23885_fh *fh   = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->vidq.field;
+       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_fmt *fmt;
+       enum v4l2_field   field;
+       unsigned int      maxw, maxh;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       field = f->fmt.pix.field;
+       maxw  = norm_maxw(dev->tvnorm);
+       maxh  = norm_maxh(dev->tvnorm);
+
+       if (V4L2_FIELD_ANY == field) {
+               field = (f->fmt.pix.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+       }
+
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.height < 32)
+               f->fmt.pix.height = 32;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
+       if (f->fmt.pix.width < 48)
+               f->fmt.pix.width = 48;
+       if (f->fmt.pix.width > maxw)
+               f->fmt.pix.width = maxw;
+       f->fmt.pix.width &= ~0x03;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct cx23885_fh *fh = priv;
+       struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+       int err;
+
+       dprintk(2, "%s()\n", __FUNCTION__);
+       err = vidioc_try_fmt_cap(file, priv, f);
+
+       if (0 != err)
+               return err;
+       fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->width      = f->fmt.pix.width;
+       fh->height     = f->fmt.pix.height;
+       fh->vidq.field = f->fmt.pix.field;
+       dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
+               fh->width, fh->height, fh->vidq.field);
+       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
+       return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+       struct v4l2_capability *cap)
+{
+       struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+
+       strcpy(cap->driver, "cx23885");
+       strlcpy(cap->card, cx23885_boards[dev->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
+       cap->version = CX23885_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE     |
+               V4L2_CAP_STREAMING     |
+               V4L2_CAP_VBI_CAPTURE;
+       if (UNSET != dev->tuner_type)
+               cap->capabilities |= V4L2_CAP_TUNER;
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+       struct v4l2_fmtdesc *f)
+{
+       if (unlikely(f->index >= ARRAY_SIZE(formats)))
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv,
+       struct video_mbuf *mbuf)
+{
+       struct cx23885_fh *fh = priv;
+       struct videobuf_queue *q;
+       struct v4l2_requestbuffers req;
+       unsigned int i;
+       int err;
+
+       q = get_queue(fh);
+       memset(&req, 0, sizeof(req));
+       req.type   = q->type;
+       req.count  = 8;
+       req.memory = V4L2_MEMORY_MMAP;
+       err = videobuf_reqbufs(q, &req);
+       if (err < 0)
+               return err;
+
+       mbuf->frames = req.count;
+       mbuf->size   = 0;
+       for (i = 0; i < mbuf->frames; i++) {
+               mbuf->offsets[i]  = q->bufs[i]->boff;
+               mbuf->size       += q->bufs[i]->bsize;
+       }
+       return 0;
+}
+#endif
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+       struct v4l2_requestbuffers *p)
+{
+       struct cx23885_fh *fh = priv;
+       return (videobuf_reqbufs(get_queue(fh), p));
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+       struct v4l2_buffer *p)
+{
+       struct cx23885_fh *fh = priv;
+       return (videobuf_querybuf(get_queue(fh), p));
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+       struct v4l2_buffer *p)
+{
+       struct cx23885_fh *fh = priv;
+       return (videobuf_qbuf(get_queue(fh), p));
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv,
+       struct v4l2_buffer *p)
+{
+       struct cx23885_fh *fh = priv;
+       return (videobuf_dqbuf(get_queue(fh), p,
+                               file->f_flags & O_NONBLOCK));
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+       enum v4l2_buf_type i)
+{
+       struct cx23885_fh *fh = priv;
+       struct cx23885_dev *dev = fh->dev;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+               return -EINVAL;
+       if (unlikely(i != fh->type))
+               return -EINVAL;
+
+       if (unlikely(!res_get(dev, fh, get_resource(fh))))
+               return -EBUSY;
+       return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx23885_fh *fh = priv;
+       struct cx23885_dev *dev = fh->dev;
+       int err, res;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
+
+       res = get_resource(fh);
+       err = videobuf_streamoff(get_queue(fh));
+       if (err < 0)
+               return err;
+       res_free(dev, fh, res);
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       mutex_lock(&dev->lock);
+       cx23885_set_tvnorm(dev, *tvnorms);
+       mutex_unlock(&dev->lock);
+
+       return 0;
+}
+
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+{
+       static const char *iname[] = {
+               [CX23885_VMUX_COMPOSITE1] = "Composite1",
+               [CX23885_VMUX_COMPOSITE2] = "Composite2",
+               [CX23885_VMUX_COMPOSITE3] = "Composite3",
+               [CX23885_VMUX_COMPOSITE4] = "Composite4",
+               [CX23885_VMUX_SVIDEO]     = "S-Video",
+               [CX23885_VMUX_TELEVISION] = "Television",
+               [CX23885_VMUX_CABLE]      = "Cable TV",
+               [CX23885_VMUX_DVB]        = "DVB",
+               [CX23885_VMUX_DEBUG]      = "for debug only",
+       };
+       unsigned int n;
+       dprintk(1, "%s()\n", __FUNCTION__);
+
+       n = i->index;
+       if (n >= 4)
+               return -EINVAL;
+
+       if (0 == INPUT(n)->type)
+               return -EINVAL;
+
+       memset(i, 0, sizeof(*i));
+       i->index = n;
+       i->type  = V4L2_INPUT_TYPE_CAMERA;
+       strcpy(i->name, iname[INPUT(n)->type]);
+       if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
+               (CX23885_VMUX_CABLE == INPUT(n)->type))
+               i->type = V4L2_INPUT_TYPE_TUNER;
+               i->std = CX23885_NORMS;
+       return 0;
+}
+EXPORT_SYMBOL(cx23885_enum_input);
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       dprintk(1, "%s()\n", __FUNCTION__);
+       return cx23885_enum_input(dev, i);
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       *i = dev->input;
+       dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       dprintk(1, "%s(%d)\n", __FUNCTION__, i);
+
+       if (i >= 4) {
+               dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->lock);
+       cx23885_video_mux(dev, i);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *qctrl)
+{
+       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+       if (unlikely(qctrl->id == 0))
+               return -EINVAL;
+       return cx23885_ctrl_query(qctrl);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       return cx23885_get_control(dev, ctl);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       return cx23885_set_control(dev, ctl);
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       if (unlikely(UNSET == dev->tuner_type))
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
+
+       strcpy(t->name, "Television");
+       t->type       = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM;
+       t->rangehigh  = 0xffffffffUL;
+       t->signal = 0xffff ; /* LOCKED */
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+       if (UNSET == dev->tuner_type)
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct cx23885_fh *fh = priv;
+       struct cx23885_dev *dev = fh->dev;
+
+       if (unlikely(UNSET == dev->tuner_type))
+               return -EINVAL;
+
+       /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->frequency = dev->freq;
+
+       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
+
+       return 0;
+}
+
+int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+{
+       if (unlikely(UNSET == dev->tuner_type))
+               return -EINVAL;
+       if (unlikely(f->tuner != 0))
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+       dev->freq = f->frequency;
+
+       cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
+
+       /* When changing channels it is required to reset TVAUDIO */
+       msleep(10);
+
+       mutex_unlock(&dev->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(cx23885_set_freq);
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct cx23885_fh *fh = priv;
+       struct cx23885_dev *dev = fh->dev;
+
+       if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+               return -EINVAL;
+       if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+               return -EINVAL;
+
+       return
+               cx23885_set_freq(dev, f);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *fh,
+                               struct v4l2_register *reg)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+
+       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
+
+       return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *fh,
+                               struct v4l2_register *reg)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+
+       cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
+
+       return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static void cx23885_vid_timeout(unsigned long data)
+{
+       struct cx23885_dev *dev = (struct cx23885_dev *)data;
+       struct cx23885_dmaqueue *q = &dev->vidq;
+       struct cx23885_buffer *buf;
+       unsigned long flags;
+
+       cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
+
+       cx_clear(VID_A_DMA_CTL, 0x11);
+
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&q->active)) {
+               buf = list_entry(q->active.next,
+                       struct cx23885_buffer, vb.queue);
+               list_del(&buf->vb.queue);
+               buf->vb.state = VIDEOBUF_ERROR;
+               wake_up(&buf->vb.done);
+               printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n",
+                       dev->name, buf, buf->vb.i,
+                       (unsigned long)buf->risc.dma);
+       }
+       cx23885_restart_video_queue(dev, q);
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
+{
+       u32 mask, count;
+       int handled = 0;
+
+       mask   = cx_read(VID_A_INT_MSK);
+       if (0 == (status & mask))
+               return handled;
+       cx_write(VID_A_INT_STAT, status);
+
+       dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
+       /* risc op code error */
+       if (status & (1 << 16)) {
+               printk(KERN_WARNING "%s/0: video risc op code error\n",
+                       dev->name);
+               cx_clear(VID_A_DMA_CTL, 0x11);
+               cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
+       }
+
+       /* risc1 y */
+       if (status & 0x01) {
+               spin_lock(&dev->slock);
+               count = cx_read(VID_A_GPCNT);
+               cx23885_video_wakeup(dev, &dev->vidq, count);
+               spin_unlock(&dev->slock);
+               handled++;
+       }
+       /* risc2 y */
+       if (status & 0x10) {
+               dprintk(2, "stopper video\n");
+               spin_lock(&dev->slock);
+               cx23885_restart_video_queue(dev, &dev->vidq);
+               spin_unlock(&dev->slock);
+               handled++;
+       }
+
+       return handled;
+}
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+static const struct file_operations video_fops = {
+       .owner         = THIS_MODULE,
+       .open          = video_open,
+       .release       = video_release,
+       .read          = video_read,
+       .poll          = video_poll,
+       .mmap          = video_mmap,
+       .ioctl         = video_ioctl2,
+       .compat_ioctl  = v4l_compat_ioctl32,
+       .llseek        = no_llseek,
+};
+
+static struct video_device cx23885_vbi_template;
+static struct video_device cx23885_video_template = {
+       .name                 = "cx23885-video",
+       .type                 = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
+       .fops                 = &video_fops,
+       .minor                = -1,
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+       .vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+       .vidioc_g_fmt_vbi     = cx23885_vbi_fmt,
+       .vidioc_try_fmt_vbi   = cx23885_vbi_fmt,
+       .vidioc_s_fmt_vbi     = cx23885_vbi_fmt,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf          = vidiocgmbuf,
+#endif
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register    = vidioc_g_register,
+       .vidioc_s_register    = vidioc_s_register,
+#endif
+       .tvnorms              = CX23885_NORMS,
+       .current_norm         = V4L2_STD_NTSC_M,
+};
+
+static const struct file_operations radio_fops = {
+       .owner         = THIS_MODULE,
+       .open          = video_open,
+       .release       = video_release,
+       .ioctl         = video_ioctl2,
+       .compat_ioctl  = v4l_compat_ioctl32,
+       .llseek        = no_llseek,
+};
+
+
+void cx23885_video_unregister(struct cx23885_dev *dev)
+{
+       dprintk(1, "%s()\n", __FUNCTION__);
+       cx_clear(PCI_INT_MSK, 1);
+
+       if (dev->video_dev) {
+               if (-1 != dev->video_dev->minor)
+                       video_unregister_device(dev->video_dev);
+               else
+                       video_device_release(dev->video_dev);
+               dev->video_dev = NULL;
+
+               btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
+       }
+}
+
+int cx23885_video_register(struct cx23885_dev *dev)
+{
+       int err;
+
+       dprintk(1, "%s()\n", __FUNCTION__);
+       spin_lock_init(&dev->slock);
+
+       /* Initialize VBI template */
+       memcpy(&cx23885_vbi_template, &cx23885_video_template,
+               sizeof(cx23885_vbi_template));
+       strcpy(cx23885_vbi_template.name, "cx23885-vbi");
+       cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
+
+       dev->tvnorm = cx23885_video_template.current_norm;
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       INIT_LIST_HEAD(&dev->vidq.queued);
+       dev->vidq.timeout.function = cx23885_vid_timeout;
+       dev->vidq.timeout.data = (unsigned long)dev;
+       init_timer(&dev->vidq.timeout);
+       cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
+               VID_A_DMA_CTL, 0x11, 0x00);
+
+       /* Don't enable VBI yet */
+       cx_set(PCI_INT_MSK, 1);
+
+
+       /* register v4l devices */
+       dev->video_dev = cx23885_vdev_init(dev, dev->pci,
+               &cx23885_video_template, "video");
+       err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
+                                   video_nr[dev->nr]);
+       if (err < 0) {
+               printk(KERN_INFO "%s: can't register video device\n",
+                       dev->name);
+               goto fail_unreg;
+       }
+       printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
+              dev->name, dev->video_dev->minor & 0x1f);
+       /* initial device configuration */
+       mutex_lock(&dev->lock);
+       cx23885_set_tvnorm(dev, dev->tvnorm);
+       init_controls(dev);
+       cx23885_video_mux(dev, 0);
+       mutex_unlock(&dev->lock);
+
+       return 0;
+
+fail_unreg:
+       cx23885_video_unregister(dev);
+       return err;
+}
+
index dec4dc2fcbb465cf7bb9dcef2e86dfa15456ef25..7cb2179f26227456ed25a507ee8ac20a1da3047b 100644 (file)
 
 /* Max number of inputs by card */
 #define MAX_CX23885_INPUT 8
+#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
 
 #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
 
 #define CX23885_BOARD_HAUPPAUGE_HVR1800        2
 #define CX23885_BOARD_HAUPPAUGE_HVR1250        3
 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
+#define CX23885_BOARD_HAUPPAUGE_HVR1500Q       5
+#define CX23885_BOARD_HAUPPAUGE_HVR1500        6
+
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX23885_NORMS (\
+       V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
+       V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+       V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
+       V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
+
+struct cx23885_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+       int   flags;
+       u32   cxformat;
+};
+
+struct cx23885_ctrl {
+       struct v4l2_queryctrl v;
+       u32                   off;
+       u32                   reg;
+       u32                   mask;
+       u32                   shift;
+};
+
+struct cx23885_tvnorm {
+       char            *name;
+       v4l2_std_id     id;
+       u32             cxiformat;
+       u32             cxoformat;
+};
+
+struct cx23885_fh {
+       struct cx23885_dev         *dev;
+       enum v4l2_buf_type         type;
+       int                        radio;
+       u32                        resources;
+
+       /* video overlay */
+       struct v4l2_window         win;
+       struct v4l2_clip           *clips;
+       unsigned int               nclips;
+
+       /* video capture */
+       struct cx23885_fmt         *fmt;
+       unsigned int               width, height;
+
+       /* vbi capture */
+       struct videobuf_queue      vidq;
+       struct videobuf_queue      vbiq;
+
+       /* MPEG Encoder specifics ONLY */
+       struct videobuf_queue      mpegq;
+       atomic_t                   v4l_reading;
+};
 
 enum cx23885_itype {
        CX23885_VMUX_COMPOSITE1 = 1,
@@ -92,12 +152,28 @@ struct cx23885_input {
 
 typedef enum {
        CX23885_MPEG_UNDEFINED = 0,
-       CX23885_MPEG_DVB
+       CX23885_MPEG_DVB,
+       CX23885_ANALOG_VIDEO,
 } port_t;
 
 struct cx23885_board {
        char                    *name;
-       port_t                  portb, portc;
+       port_t                  porta, portb, portc;
+       unsigned int            tuner_type;
+       unsigned int            radio_type;
+       unsigned char           tuner_addr;
+       unsigned char           radio_addr;
+
+       /* Vendors can and do run the PCIe bridge at different
+        * clock rates, driven physically by crystals on the PCBs.
+        * The core has to accomodate this. This allows the user
+        * to add new boards with new frequencys. The value is
+        * expressed in Hz.
+        *
+        * The core framework will default this value based on
+        * current designs, but it can vary.
+        */
+       u32                     clk_freq;
        struct cx23885_input    input[MAX_CX23885_INPUT];
 };
 
@@ -189,6 +265,11 @@ struct cx23885_dev {
        u32                        __iomem *lmmio;
        u8                         __iomem *bmmio;
        int                        pci_irqmask;
+       int                        hwrevision;
+
+       /* This valud is board specific and is used to configure the
+        * AV core so we see nice clean and stable video and audio. */
+       u32                        clk_freq;
 
        /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
        struct cx23885_i2c         i2c_bus[3];
@@ -210,8 +291,31 @@ struct cx23885_dev {
                CX23885_BRIDGE_885 = 885,
                CX23885_BRIDGE_887 = 887,
        } bridge;
+
+       /* Analog video */
+       u32                        resources;
+       unsigned int               input;
+       u32                        tvaudio;
+       v4l2_std_id                tvnorm;
+       unsigned int               tuner_type;
+       unsigned char              tuner_addr;
+       unsigned int               radio_type;
+       unsigned char              radio_addr;
+       unsigned int               has_radio;
+
+       /* V4l */
+       u32                        freq;
+       struct video_device        *video_dev;
+       struct video_device        *vbi_dev;
+       struct video_device        *radio_dev;
+
+       struct cx23885_dmaqueue    vidq;
+       struct cx23885_dmaqueue    vbiq;
+       spinlock_t                 slock;
 };
 
+extern struct list_head cx23885_devlist;
+
 #define SRAM_CH01  0 /* Video A */
 #define SRAM_CH02  1 /* VBI A */
 #define SRAM_CH03  2 /* Video B */
@@ -254,19 +358,42 @@ struct sram_channel {
 #define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
 #define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
 
+/* ----------------------------------------------------------- */
+/* cx23885-core.c                                              */
+
 extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
        struct sram_channel *ch,
        unsigned int bpl, u32 risc);
 
-/* ----------------------------------------------------------- */
-/* cx23885-cards.c                                                */
+extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+       struct sram_channel *ch);
 
+extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+       u32 reg, u32 mask, u32 value);
+
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+       struct scatterlist *sglist,
+       unsigned int top_offset, unsigned int bottom_offset,
+       unsigned int bpl, unsigned int padding, unsigned int lines);
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port);
+
+extern int cx23885_restart_queue(struct cx23885_tsport *port,
+                               struct cx23885_dmaqueue *q);
+
+extern void cx23885_wakeup(struct cx23885_tsport *port,
+                          struct cx23885_dmaqueue *q, u32 count);
+
+
+/* ----------------------------------------------------------- */
+/* cx23885-cards.c                                             */
 extern struct cx23885_board cx23885_boards[];
 extern const unsigned int cx23885_bcount;
 
 extern struct cx23885_subid cx23885_subids[];
 extern const unsigned int cx23885_idcount;
 
+extern int cx23885_tuner_callback(void *priv, int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
@@ -280,19 +407,50 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q,
                               struct cx23885_tsport *port,
                               struct cx23885_buffer *buf,
                               enum v4l2_field field);
-
 extern void cx23885_buf_queue(struct cx23885_tsport *port,
                              struct cx23885_buffer *buf);
 extern void cx23885_free_buffer(struct videobuf_queue *q,
                                struct cx23885_buffer *buf);
 
 /* ----------------------------------------------------------- */
+/* cx23885-video.c                                             */
+/* Video */
+extern int cx23885_video_register(struct cx23885_dev *dev);
+extern void cx23885_video_unregister(struct cx23885_dev *dev);
+extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
+
+/* ----------------------------------------------------------- */
+/* cx23885-vbi.c                                               */
+extern int cx23885_vbi_fmt(struct file *file, void *priv,
+       struct v4l2_format *f);
+extern void cx23885_vbi_timeout(unsigned long data);
+extern struct videobuf_queue_ops cx23885_vbi_qops;
+
 /* cx23885-i2c.c                                                */
 extern int cx23885_i2c_register(struct cx23885_i2c *bus);
 extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
 extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
                                     void *arg);
 
+/* ----------------------------------------------------------- */
+/* tv norms                                                    */
+
+static inline unsigned int norm_maxw(v4l2_std_id norm)
+{
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+}
+
+static inline unsigned int norm_maxh(v4l2_std_id norm)
+{
+       return (norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
+static inline unsigned int norm_swidth(v4l2_std_id norm)
+{
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+}
+
+
 /*
  * Local variables:
  * c-basic-offset: 8
index 3d46a776df36a44e1b92c668d6f89e567503b33b..d6421e1e8f6a793e0cdaeddca6885e9746b188e3 100644 (file)
@@ -32,118 +32,156 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
 
        /* common for all inputs and rates */
        /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
-       cx25840_write(client, 0x127, 0x50);
+       if (!state->is_cx23885)
+               cx25840_write(client, 0x127, 0x50);
 
        if (state->aud_input != CX25840_AUDIO_SERIAL) {
                switch (freq) {
                case 32000:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040610);
+                       cx25840_write4(client, 0x108, 0x1006040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xee39bb01);
+                       cx25840_write4(client, 0x110, 0x01bb39ee);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src3/4/6_ctl = 0x0801f77f */
-                       cx25840_write4(client, 0x900, 0x7ff70108);
-                       cx25840_write4(client, 0x904, 0x7ff70108);
-                       cx25840_write4(client, 0x90c, 0x7ff70108);
+                       cx25840_write4(client, 0x900, 0x0801f77f);
+                       cx25840_write4(client, 0x904, 0x0801f77f);
+                       cx25840_write4(client, 0x90c, 0x0801f77f);
                        break;
 
                case 44100:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040910);
+                       cx25840_write4(client, 0x108, 0x1009040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xd66bec00);
+                       cx25840_write4(client, 0x110, 0x00ec6bd6);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src3/4/6_ctl = 0x08016d59 */
-                       cx25840_write4(client, 0x900, 0x596d0108);
-                       cx25840_write4(client, 0x904, 0x596d0108);
-                       cx25840_write4(client, 0x90c, 0x596d0108);
+                       cx25840_write4(client, 0x900, 0x08016d59);
+                       cx25840_write4(client, 0x904, 0x08016d59);
+                       cx25840_write4(client, 0x90c, 0x08016d59);
                        break;
 
                case 48000:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040a10);
+                       cx25840_write4(client, 0x108, 0x100a040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xe5d69800);
+                       cx25840_write4(client, 0x110, 0x0098d6e5);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src3/4/6_ctl = 0x08014faa */
-                       cx25840_write4(client, 0x900, 0xaa4f0108);
-                       cx25840_write4(client, 0x904, 0xaa4f0108);
-                       cx25840_write4(client, 0x90c, 0xaa4f0108);
+                       cx25840_write4(client, 0x900, 0x08014faa);
+                       cx25840_write4(client, 0x904, 0x08014faa);
+                       cx25840_write4(client, 0x90c, 0x08014faa);
                        break;
                }
        } else {
                switch (freq) {
                case 32000:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f04081e);
+                       cx25840_write4(client, 0x108, 0x1e08040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0x69082a01);
+                       cx25840_write4(client, 0x110, 0x012a0869);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src1_ctl = 0x08010000 */
-                       cx25840_write4(client, 0x8f8, 0x00000108);
+                       cx25840_write4(client, 0x8f8, 0x08010000);
 
                        /* src3/4/6_ctl = 0x08020000 */
-                       cx25840_write4(client, 0x900, 0x00000208);
-                       cx25840_write4(client, 0x904, 0x00000208);
-                       cx25840_write4(client, 0x90c, 0x00000208);
+                       cx25840_write4(client, 0x900, 0x08020000);
+                       cx25840_write4(client, 0x904, 0x08020000);
+                       cx25840_write4(client, 0x90c, 0x08020000);
 
                        /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
                        cx25840_write(client, 0x127, 0x54);
                        break;
 
                case 44100:
+                       if (state->is_cx23885) {
+                               /* We don't have register values
+                                * so avoid destroying registers. */
+                               break;
+                       }
+
                        /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040918);
+                       cx25840_write4(client, 0x108, 0x1809040f);
 
                        /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xd66bec00);
+                       cx25840_write4(client, 0x110, 0x00ec6bd6);
 
                        if (state->is_cx25836)
                                break;
 
                        /* src1_ctl = 0x08010000 */
-                       cx25840_write4(client, 0x8f8, 0xcd600108);
+                       cx25840_write4(client, 0x8f8, 0x080160cd);
 
                        /* src3/4/6_ctl = 0x08020000 */
-                       cx25840_write4(client, 0x900, 0x85730108);
-                       cx25840_write4(client, 0x904, 0x85730108);
-                       cx25840_write4(client, 0x90c, 0x85730108);
+                       cx25840_write4(client, 0x900, 0x08017385);
+                       cx25840_write4(client, 0x904, 0x08017385);
+                       cx25840_write4(client, 0x90c, 0x08017385);
                        break;
 
                case 48000:
-                       /* VID_PLL and AUX_PLL */
-                       cx25840_write4(client, 0x108, 0x0f040a18);
+                       if (!state->is_cx23885) {
+                               /* VID_PLL and AUX_PLL */
+                               cx25840_write4(client, 0x108, 0x180a040f);
 
-                       /* AUX_PLL_FRAC */
-                       cx25840_write4(client, 0x110, 0xe5d69800);
+                               /* AUX_PLL_FRAC */
+                               cx25840_write4(client, 0x110, 0x0098d6e5);
+                       }
 
                        if (state->is_cx25836)
                                break;
 
-                       /* src1_ctl = 0x08010000 */
-                       cx25840_write4(client, 0x8f8, 0x00800108);
+                       if (!state->is_cx23885) {
+                               /* src1_ctl */
+                               cx25840_write4(client, 0x8f8, 0x08018000);
 
-                       /* src3/4/6_ctl = 0x08020000 */
-                       cx25840_write4(client, 0x900, 0x55550108);
-                       cx25840_write4(client, 0x904, 0x55550108);
-                       cx25840_write4(client, 0x90c, 0x55550108);
+                               /* src3/4/6_ctl */
+                               cx25840_write4(client, 0x900, 0x08015555);
+                               cx25840_write4(client, 0x904, 0x08015555);
+                               cx25840_write4(client, 0x90c, 0x08015555);
+                       } else {
+
+                               cx25840_write4(client, 0x8f8, 0x0801867c);
+
+                               cx25840_write4(client, 0x900, 0x08014faa);
+                               cx25840_write4(client, 0x904, 0x08014faa);
+                               cx25840_write4(client, 0x90c, 0x08014faa);
+                       }
                        break;
                }
        }
@@ -168,14 +206,14 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
        if (state->aud_input == CX25840_AUDIO_SERIAL) {
                /* Set Path1 to Serial Audio Input */
-               cx25840_write4(client, 0x8d0, 0x12100101);
+               cx25840_write4(client, 0x8d0, 0x01011012);
 
                /* The microcontroller should not be started for the
                 * non-tuner inputs: autodetection is specific for
                 * TV audio. */
        } else {
                /* Set Path1 to Analog Demod Main Channel */
-               cx25840_write4(client, 0x8d0, 0x7038061f);
+               cx25840_write4(client, 0x8d0, 0x1f063870);
        }
 
        set_audclk_freq(client, state->audclk_freq);
@@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
        /* deassert soft reset */
        cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+       if (state->is_cx23885) {
+               /* Ensure the controller is running when we exit */
+               cx25840_and_or(client, 0x803, ~0x10, 0x10);
+       }
 }
 
 static int get_volume(struct i2c_client *client)
index 15f191e170d28318370f2f4c03656a6d8c59ec36..756a1eeb274e0da969e49a0ad6424e7ea3339035 100644 (file)
@@ -13,6 +13,8 @@
  * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
  * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
  *
+ * CX23885 support by Steven Toth <stoth@hauppauge.com>.
+ *
  * 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
@@ -37,6 +39,7 @@
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/cx25840.h>
 
 #include "cx25840-core.h"
@@ -72,10 +75,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
        u8 buffer[6];
        buffer[0] = addr >> 8;
        buffer[1] = addr & 0xff;
-       buffer[2] = value >> 24;
-       buffer[3] = (value >> 16) & 0xff;
-       buffer[4] = (value >> 8) & 0xff;
-       buffer[5] = value & 0xff;
+       buffer[2] = value & 0xff;
+       buffer[3] = (value >> 8) & 0xff;
+       buffer[4] = (value >> 16) & 0xff;
+       buffer[5] = value >> 24;
        return i2c_master_send(client, buffer, 6);
 }
 
@@ -122,8 +125,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
 
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
                                                enum cx25840_audio_input aud_input);
-static void log_audio_status(struct i2c_client *client);
-static void log_video_status(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 
@@ -256,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client)
        cx25840_and_or(client, 0x803, ~0x10, 0x10);
 }
 
+static void cx23885_initialize(struct i2c_client *client)
+{
+       DEFINE_WAIT(wait);
+       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct workqueue_struct *q;
+
+       /* Internal Reset */
+       cx25840_and_or(client, 0x102, ~0x01, 0x01);
+       cx25840_and_or(client, 0x102, ~0x01, 0x00);
+
+       /* Stop microcontroller */
+       cx25840_and_or(client, 0x803, ~0x10, 0x00);
+
+       /* DIF in reset? */
+       cx25840_write(client, 0x398, 0);
+
+       /* Trust the default xtal, no division */
+       /* This changes for the cx23888 products */
+       cx25840_write(client, 0x2, 0x76);
+
+       /* Bring down the regulator for AUX clk */
+       cx25840_write(client, 0x1, 0x40);
+
+       /* Sys PLL frac */
+       cx25840_write4(client, 0x11c, 0x01d1744c);
+
+       /* Sys PLL int */
+       cx25840_write4(client, 0x118, 0x00000416);
+
+       /* Disable DIF bypass */
+       cx25840_write4(client, 0x33c, 0x00000001);
+
+       /* DIF Src phase inc */
+       cx25840_write4(client, 0x340, 0x0df7df83);
+
+       /* Vid PLL frac */
+       cx25840_write4(client, 0x10c, 0x01b6db7b);
+
+       /* Vid PLL int */
+       cx25840_write4(client, 0x108, 0x00000512);
+
+       /* Luma */
+       cx25840_write4(client, 0x414, 0x00107d12);
+
+       /* Chroma */
+       cx25840_write4(client, 0x420, 0x3d008282);
+
+       /* Aux PLL frac */
+       cx25840_write4(client, 0x114, 0x017dbf48);
+
+       /* Aux PLL int */
+       cx25840_write4(client, 0x110, 0x000a030e);
+
+       /* ADC2 input select */
+       cx25840_write(client, 0x102, 0x10);
+
+       /* VIN1 & VIN5 */
+       cx25840_write(client, 0x103, 0x11);
+
+       /* Enable format auto detect */
+       cx25840_write(client, 0x400, 0);
+       /* Fast subchroma lock */
+       /* White crush, Chroma AGC & Chroma Killer enabled */
+       cx25840_write(client, 0x401, 0xe8);
+
+       /* Select AFE clock pad output source */
+       cx25840_write(client, 0x144, 0x05);
+
+       /* Do the firmware load in a work handler to prevent.
+          Otherwise the kernel is blocked waiting for the
+          bit-banging i2c interface to finish uploading the
+          firmware. */
+       INIT_WORK(&state->fw_work, cx25840_work_handler);
+       init_waitqueue_head(&state->fw_wait);
+       q = create_singlethread_workqueue("cx25840_fw");
+       prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+       queue_work(q, &state->fw_work);
+       schedule();
+       finish_wait(&state->fw_wait, &wait);
+       destroy_workqueue(q);
+
+       cx25840_vbi_setup(client);
+
+       /* (re)set input */
+       set_input(client, state->vid_input, state->aud_input);
+
+       /* start microcontroller */
+       cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void input_change(struct i2c_client *client)
@@ -319,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                           vid_input <= CX25840_COMPOSITE8);
        u8 reg;
 
-       v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n",
-                       vid_input, aud_input);
+       v4l_dbg(1, cx25840_debug, client,
+               "decoder set video input %d, audio input %d\n",
+               vid_input, aud_input);
+
+       if (vid_input >= CX25840_VIN1_CH1) {
+               v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
+                       vid_input);
+               reg = vid_input & 0xff;
+               if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)
+                       is_composite = 0;
+               else
+                       is_composite = 1;
 
+               v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
+                       reg, is_composite);
+       } else
        if (is_composite) {
                reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
        } else {
@@ -331,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                if ((vid_input & ~0xff0) ||
                    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
                    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
-                       v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
+                       v4l_err(client, "0x%04x is not a valid video input!\n",
+                               vid_input);
                        return -EINVAL;
                }
                reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
@@ -344,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                }
        }
 
-       switch (aud_input) {
-       case CX25840_AUDIO_SERIAL:
-               /* do nothing, use serial audio input */
-               break;
-       case CX25840_AUDIO4: reg &= ~0x30; break;
-       case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
-       case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
-       case CX25840_AUDIO7: reg &= ~0xc0; break;
-       case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+       /* The caller has previously prepared the correct routing
+        * configuration in reg (for the cx23885) so we have no
+        * need to attempt to flip bits for earlier av decoders.
+        */
+       if (!state->is_cx23885) {
+               switch (aud_input) {
+               case CX25840_AUDIO_SERIAL:
+                       /* do nothing, use serial audio input */
+                       break;
+               case CX25840_AUDIO4: reg &= ~0x30; break;
+               case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+               case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+               case CX25840_AUDIO7: reg &= ~0xc0; break;
+               case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
 
-       default:
-               v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
-               return -EINVAL;
+               default:
+                       v4l_err(client, "0x%04x is not a valid audio input!\n",
+                               aud_input);
+                       return -EINVAL;
+               }
        }
 
        cx25840_write(client, 0x103, reg);
+
        /* Set INPUT_MODE to Composite (0) or S-Video (1) */
        cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
-       /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-       cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
-       /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
-       if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-               cx25840_and_or(client, 0x102, ~0x4, 4);
-       else
-               cx25840_and_or(client, 0x102, ~0x4, 0);
+
+       if (!state->is_cx23885) {
+               /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+               cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+               /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
+               if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+                       cx25840_and_or(client, 0x102, ~0x4, 4);
+               else
+                       cx25840_and_or(client, 0x102, ~0x4, 0);
+       } else {
+               if (is_composite)
+                       /* ADC2 input select channel 2 */
+                       cx25840_and_or(client, 0x102, ~0x2, 0);
+               else
+                       /* ADC2 input select channel 3 */
+                       cx25840_and_or(client, 0x102, ~0x2, 2);
+       }
 
        state->vid_input = vid_input;
        state->aud_input = aud_input;
@@ -376,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                cx25840_audio_set_path(client);
                input_change(client);
        }
+
+       if (state->is_cx23885) {
+               /* Audio channel 1 src : Parallel 1 */
+               cx25840_write(client, 0x124, 0x03);
+
+               /* Select AFE clock pad output source */
+               cx25840_write(client, 0x144, 0x05);
+
+               /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
+               cx25840_write(client, 0x914, 0xa0);
+
+               /* I2S_OUT_CTL:
+                * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
+                * I2S_OUT_MASTER_MODE = Master
+                */
+               cx25840_write(client, 0x918, 0xa0);
+               cx25840_write(client, 0x919, 0x01);
+       }
+
        return 0;
 }
 
@@ -641,6 +783,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
 /* ----------------------------------------------------------------------- */
 
+static void log_video_status(struct i2c_client *client)
+{
+       static const char *const fmt_strs[] = {
+               "0x0",
+               "NTSC-M", "NTSC-J", "NTSC-4.43",
+               "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+               "0x9", "0xA", "0xB",
+               "SECAM",
+               "0xD", "0xE", "0xF"
+       };
+
+       struct cx25840_state *state = i2c_get_clientdata(client);
+       u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+       u8 gen_stat1 = cx25840_read(client, 0x40d);
+       u8 gen_stat2 = cx25840_read(client, 0x40e);
+       int vid_input = state->vid_input;
+
+       v4l_info(client, "Video signal:              %spresent\n",
+                   (gen_stat2 & 0x20) ? "" : "not ");
+       v4l_info(client, "Detected format:           %s\n",
+                   fmt_strs[gen_stat1 & 0xf]);
+
+       v4l_info(client, "Specified standard:        %s\n",
+                   vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+       if (vid_input >= CX25840_COMPOSITE1 &&
+           vid_input <= CX25840_COMPOSITE8) {
+               v4l_info(client, "Specified video input:     Composite %d\n",
+                       vid_input - CX25840_COMPOSITE1 + 1);
+       } else {
+               v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+                       (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+       }
+
+       v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+       struct cx25840_state *state = i2c_get_clientdata(client);
+       u8 download_ctl = cx25840_read(client, 0x803);
+       u8 mod_det_stat0 = cx25840_read(client, 0x804);
+       u8 mod_det_stat1 = cx25840_read(client, 0x805);
+       u8 audio_config = cx25840_read(client, 0x808);
+       u8 pref_mode = cx25840_read(client, 0x809);
+       u8 afc0 = cx25840_read(client, 0x80b);
+       u8 mute_ctl = cx25840_read(client, 0x8d3);
+       int aud_input = state->aud_input;
+       char *p;
+
+       switch (mod_det_stat0) {
+       case 0x00: p = "mono"; break;
+       case 0x01: p = "stereo"; break;
+       case 0x02: p = "dual"; break;
+       case 0x04: p = "tri"; break;
+       case 0x10: p = "mono with SAP"; break;
+       case 0x11: p = "stereo with SAP"; break;
+       case 0x12: p = "dual with SAP"; break;
+       case 0x14: p = "tri with SAP"; break;
+       case 0xfe: p = "forced mode"; break;
+       default: p = "not defined";
+       }
+       v4l_info(client, "Detected audio mode:       %s\n", p);
+
+       switch (mod_det_stat1) {
+       case 0x00: p = "not defined"; break;
+       case 0x01: p = "EIAJ"; break;
+       case 0x02: p = "A2-M"; break;
+       case 0x03: p = "A2-BG"; break;
+       case 0x04: p = "A2-DK1"; break;
+       case 0x05: p = "A2-DK2"; break;
+       case 0x06: p = "A2-DK3"; break;
+       case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+       case 0x08: p = "AM-L"; break;
+       case 0x09: p = "NICAM-BG"; break;
+       case 0x0a: p = "NICAM-DK"; break;
+       case 0x0b: p = "NICAM-I"; break;
+       case 0x0c: p = "NICAM-L"; break;
+       case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+       case 0x0e: p = "IF FM Radio"; break;
+       case 0x0f: p = "BTSC"; break;
+       case 0x10: p = "high-deviation FM"; break;
+       case 0x11: p = "very high-deviation FM"; break;
+       case 0xfd: p = "unknown audio standard"; break;
+       case 0xfe: p = "forced audio standard"; break;
+       case 0xff: p = "no detected audio standard"; break;
+       default: p = "not defined";
+       }
+       v4l_info(client, "Detected audio standard:   %s\n", p);
+       v4l_info(client, "Audio muted:               %s\n",
+                   (state->unmute_volume >= 0) ? "yes" : "no");
+       v4l_info(client, "Audio microcontroller:     %s\n",
+                   (download_ctl & 0x10) ?
+                               ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
+
+       switch (audio_config >> 4) {
+       case 0x00: p = "undefined"; break;
+       case 0x01: p = "BTSC"; break;
+       case 0x02: p = "EIAJ"; break;
+       case 0x03: p = "A2-M"; break;
+       case 0x04: p = "A2-BG"; break;
+       case 0x05: p = "A2-DK1"; break;
+       case 0x06: p = "A2-DK2"; break;
+       case 0x07: p = "A2-DK3"; break;
+       case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+       case 0x09: p = "AM-L"; break;
+       case 0x0a: p = "NICAM-BG"; break;
+       case 0x0b: p = "NICAM-DK"; break;
+       case 0x0c: p = "NICAM-I"; break;
+       case 0x0d: p = "NICAM-L"; break;
+       case 0x0e: p = "FM radio"; break;
+       case 0x0f: p = "automatic detection"; break;
+       default: p = "undefined";
+       }
+       v4l_info(client, "Configured audio standard: %s\n", p);
+
+       if ((audio_config >> 4) < 0xF) {
+               switch (audio_config & 0xF) {
+               case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+               case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+               case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+               case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+               case 0x04: p = "STEREO"; break;
+               case 0x05: p = "DUAL1 (AB)"; break;
+               case 0x06: p = "DUAL2 (AC) (FM)"; break;
+               case 0x07: p = "DUAL3 (BC) (FM)"; break;
+               case 0x08: p = "DUAL4 (AC) (AM)"; break;
+               case 0x09: p = "DUAL5 (BC) (AM)"; break;
+               case 0x0a: p = "SAP"; break;
+               default: p = "undefined";
+               }
+               v4l_info(client, "Configured audio mode:     %s\n", p);
+       } else {
+               switch (audio_config & 0xF) {
+               case 0x00: p = "BG"; break;
+               case 0x01: p = "DK1"; break;
+               case 0x02: p = "DK2"; break;
+               case 0x03: p = "DK3"; break;
+               case 0x04: p = "I"; break;
+               case 0x05: p = "L"; break;
+               case 0x06: p = "BTSC"; break;
+               case 0x07: p = "EIAJ"; break;
+               case 0x08: p = "A2-M"; break;
+               case 0x09: p = "FM Radio"; break;
+               case 0x0f: p = "automatic standard and mode detection"; break;
+               default: p = "undefined";
+               }
+               v4l_info(client, "Configured audio system:   %s\n", p);
+       }
+
+       if (aud_input) {
+               v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+       } else {
+               v4l_info(client, "Specified audio input:     External\n");
+       }
+
+       switch (pref_mode & 0xf) {
+       case 0: p = "mono/language A"; break;
+       case 1: p = "language B"; break;
+       case 2: p = "language C"; break;
+       case 3: p = "analog fallback"; break;
+       case 4: p = "stereo"; break;
+       case 5: p = "language AC"; break;
+       case 6: p = "language BC"; break;
+       case 7: p = "language AB"; break;
+       default: p = "undefined";
+       }
+       v4l_info(client, "Preferred audio mode:      %s\n", p);
+
+       if ((audio_config & 0xf) == 0xf) {
+               switch ((afc0 >> 3) & 0x3) {
+               case 0: p = "system DK"; break;
+               case 1: p = "system L"; break;
+               case 2: p = "autodetect"; break;
+               default: p = "undefined";
+               }
+               v4l_info(client, "Selected 65 MHz format:    %s\n", p);
+
+               switch (afc0 & 0x7) {
+               case 0: p = "chroma"; break;
+               case 1: p = "BTSC"; break;
+               case 2: p = "EIAJ"; break;
+               case 3: p = "A2-M"; break;
+               case 4: p = "autodetect"; break;
+               default: p = "undefined";
+               }
+               v4l_info(client, "Selected 45 MHz format:    %s\n", p);
+       }
+}
+
+/* ----------------------------------------------------------------------- */
+
 static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                           void *arg)
 {
@@ -660,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                state->is_initialized = 1;
                if (state->is_cx25836)
                        cx25836_initialize(client);
+               else if (state->is_cx23885)
+                       cx23885_initialize(client);
                else
                        cx25840_initialize(client);
        }
@@ -677,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
+
                if (cmd == VIDIOC_DBG_G_REGISTER)
                        reg->val = cx25840_read(client, reg->reg & 0x0fff);
                else
@@ -693,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 
        case VIDIOC_STREAMON:
                v4l_dbg(1, cx25840_debug, client, "enable output\n");
-               cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
-               cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
+               if (state->is_cx23885) {
+                       u8 v = (cx25840_read(client, 0x421) | 0x0b);
+                       cx25840_write(client, 0x421, v);
+               } else {
+                       cx25840_write(client, 0x115,
+                               state->is_cx25836 ? 0x0c : 0x8c);
+                       cx25840_write(client, 0x116,
+                               state->is_cx25836 ? 0x04 : 0x07);
+               }
                break;
 
        case VIDIOC_STREAMOFF:
                v4l_dbg(1, cx25840_debug, client, "disable output\n");
-               cx25840_write(client, 0x115, 0x00);
-               cx25840_write(client, 0x116, 0x00);
+               if (state->is_cx23885) {
+                       u8 v = cx25840_read(client, 0x421) & ~(0x0b);
+                       cx25840_write(client, 0x421, v);
+               } else {
+                       cx25840_write(client, 0x115, 0x00);
+                       cx25840_write(client, 0x116, 0x00);
+               }
                break;
 
        case VIDIOC_LOG_STATUS:
@@ -863,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
        case VIDIOC_INT_RESET:
                if (state->is_cx25836)
                        cx25836_initialize(client);
+               else if (state->is_cx23885)
+                       cx23885_initialize(client);
                else
                        cx25840_initialize(client);
                break;
@@ -879,35 +1232,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_cx25840;
-
-static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
-                                int kind)
+static int cx25840_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct cx25840_state *state;
        u32 id;
        u16 device_id;
 
-       /* Check if the adapter supports the needed features
-        * Not until kernel version 2.6.11 did the bit-algo
-        * correctly report that it would do an I2C-level xfer */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_cx25840;
-       snprintf(client->name, sizeof(client->name) - 1, "cx25840");
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
        v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
 
        device_id = cx25840_read(client, 0x101) << 8;
        device_id |= cx25840_read(client, 0x100);
+       v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
 
        /* The high byte of the device ID should be
         * 0x83 for the cx2583x and 0x84 for the cx2584x */
@@ -916,16 +1255,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        }
        else if ((device_id & 0xff00) == 0x8400) {
                id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+       } else if (device_id == 0x0000) {
+               id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+       } else if (device_id == 0x1313) {
+               id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
        }
        else {
                v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
-               kfree(client);
-               return 0;
+               return -ENODEV;
        }
 
        state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
        if (state == NULL) {
-               kfree(client);
                return -ENOMEM;
        }
 
@@ -939,6 +1280,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        i2c_set_clientdata(client, state);
        state->c = client;
        state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
+       state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
        state->vid_input = CX25840_COMPOSITE7;
        state->aud_input = CX25840_AUDIO8;
        state->audclk_freq = 48000;
@@ -949,250 +1291,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        state->id = id;
        state->rev = device_id;
 
-       i2c_attach_client(client);
-
-       return 0;
-}
-
-static int cx25840_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
        return 0;
 }
 
-static int cx25840_detach_client(struct i2c_client *client)
+static int cx25840_remove(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(state);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver i2c_driver_cx25840 = {
-       .driver = {
-               .name = "cx25840",
-       },
-       .id = I2C_DRIVERID_CX25840,
-       .attach_adapter = cx25840_attach_adapter,
-       .detach_client = cx25840_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "cx25840",
+       .driverid = I2C_DRIVERID_CX25840,
        .command = cx25840_command,
+       .probe = cx25840_probe,
+       .remove = cx25840_remove,
 };
-
-
-static int __init m__init(void)
-{
-       return i2c_add_driver(&i2c_driver_cx25840);
-}
-
-static void __exit m__exit(void)
-{
-       i2c_del_driver(&i2c_driver_cx25840);
-}
-
-module_init(m__init);
-module_exit(m__exit);
-
-/* ----------------------------------------------------------------------- */
-
-static void log_video_status(struct i2c_client *client)
-{
-       static const char *const fmt_strs[] = {
-               "0x0",
-               "NTSC-M", "NTSC-J", "NTSC-4.43",
-               "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
-               "0x9", "0xA", "0xB",
-               "SECAM",
-               "0xD", "0xE", "0xF"
-       };
-
-       struct cx25840_state *state = i2c_get_clientdata(client);
-       u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
-       u8 gen_stat1 = cx25840_read(client, 0x40d);
-       u8 gen_stat2 = cx25840_read(client, 0x40e);
-       int vid_input = state->vid_input;
-
-       v4l_info(client, "Video signal:              %spresent\n",
-                   (gen_stat2 & 0x20) ? "" : "not ");
-       v4l_info(client, "Detected format:           %s\n",
-                   fmt_strs[gen_stat1 & 0xf]);
-
-       v4l_info(client, "Specified standard:        %s\n",
-                   vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
-       if (vid_input >= CX25840_COMPOSITE1 &&
-           vid_input <= CX25840_COMPOSITE8) {
-               v4l_info(client, "Specified video input:     Composite %d\n",
-                       vid_input - CX25840_COMPOSITE1 + 1);
-       } else {
-               v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
-                       (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
-       }
-
-       v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void log_audio_status(struct i2c_client *client)
-{
-       struct cx25840_state *state = i2c_get_clientdata(client);
-       u8 download_ctl = cx25840_read(client, 0x803);
-       u8 mod_det_stat0 = cx25840_read(client, 0x804);
-       u8 mod_det_stat1 = cx25840_read(client, 0x805);
-       u8 audio_config = cx25840_read(client, 0x808);
-       u8 pref_mode = cx25840_read(client, 0x809);
-       u8 afc0 = cx25840_read(client, 0x80b);
-       u8 mute_ctl = cx25840_read(client, 0x8d3);
-       int aud_input = state->aud_input;
-       char *p;
-
-       switch (mod_det_stat0) {
-       case 0x00: p = "mono"; break;
-       case 0x01: p = "stereo"; break;
-       case 0x02: p = "dual"; break;
-       case 0x04: p = "tri"; break;
-       case 0x10: p = "mono with SAP"; break;
-       case 0x11: p = "stereo with SAP"; break;
-       case 0x12: p = "dual with SAP"; break;
-       case 0x14: p = "tri with SAP"; break;
-       case 0xfe: p = "forced mode"; break;
-       default: p = "not defined";
-       }
-       v4l_info(client, "Detected audio mode:       %s\n", p);
-
-       switch (mod_det_stat1) {
-       case 0x00: p = "not defined"; break;
-       case 0x01: p = "EIAJ"; break;
-       case 0x02: p = "A2-M"; break;
-       case 0x03: p = "A2-BG"; break;
-       case 0x04: p = "A2-DK1"; break;
-       case 0x05: p = "A2-DK2"; break;
-       case 0x06: p = "A2-DK3"; break;
-       case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
-       case 0x08: p = "AM-L"; break;
-       case 0x09: p = "NICAM-BG"; break;
-       case 0x0a: p = "NICAM-DK"; break;
-       case 0x0b: p = "NICAM-I"; break;
-       case 0x0c: p = "NICAM-L"; break;
-       case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
-       case 0x0e: p = "IF FM Radio"; break;
-       case 0x0f: p = "BTSC"; break;
-       case 0x10: p = "high-deviation FM"; break;
-       case 0x11: p = "very high-deviation FM"; break;
-       case 0xfd: p = "unknown audio standard"; break;
-       case 0xfe: p = "forced audio standard"; break;
-       case 0xff: p = "no detected audio standard"; break;
-       default: p = "not defined";
-       }
-       v4l_info(client, "Detected audio standard:   %s\n", p);
-       v4l_info(client, "Audio muted:               %s\n",
-                   (state->unmute_volume >= 0) ? "yes" : "no");
-       v4l_info(client, "Audio microcontroller:     %s\n",
-                   (download_ctl & 0x10) ?
-                               ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
-
-       switch (audio_config >> 4) {
-       case 0x00: p = "undefined"; break;
-       case 0x01: p = "BTSC"; break;
-       case 0x02: p = "EIAJ"; break;
-       case 0x03: p = "A2-M"; break;
-       case 0x04: p = "A2-BG"; break;
-       case 0x05: p = "A2-DK1"; break;
-       case 0x06: p = "A2-DK2"; break;
-       case 0x07: p = "A2-DK3"; break;
-       case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
-       case 0x09: p = "AM-L"; break;
-       case 0x0a: p = "NICAM-BG"; break;
-       case 0x0b: p = "NICAM-DK"; break;
-       case 0x0c: p = "NICAM-I"; break;
-       case 0x0d: p = "NICAM-L"; break;
-       case 0x0e: p = "FM radio"; break;
-       case 0x0f: p = "automatic detection"; break;
-       default: p = "undefined";
-       }
-       v4l_info(client, "Configured audio standard: %s\n", p);
-
-       if ((audio_config >> 4) < 0xF) {
-               switch (audio_config & 0xF) {
-               case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
-               case 0x01: p = "MONO2 (LANGUAGE B)"; break;
-               case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
-               case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
-               case 0x04: p = "STEREO"; break;
-               case 0x05: p = "DUAL1 (AB)"; break;
-               case 0x06: p = "DUAL2 (AC) (FM)"; break;
-               case 0x07: p = "DUAL3 (BC) (FM)"; break;
-               case 0x08: p = "DUAL4 (AC) (AM)"; break;
-               case 0x09: p = "DUAL5 (BC) (AM)"; break;
-               case 0x0a: p = "SAP"; break;
-               default: p = "undefined";
-               }
-               v4l_info(client, "Configured audio mode:     %s\n", p);
-       } else {
-               switch (audio_config & 0xF) {
-               case 0x00: p = "BG"; break;
-               case 0x01: p = "DK1"; break;
-               case 0x02: p = "DK2"; break;
-               case 0x03: p = "DK3"; break;
-               case 0x04: p = "I"; break;
-               case 0x05: p = "L"; break;
-               case 0x06: p = "BTSC"; break;
-               case 0x07: p = "EIAJ"; break;
-               case 0x08: p = "A2-M"; break;
-               case 0x09: p = "FM Radio"; break;
-               case 0x0f: p = "automatic standard and mode detection"; break;
-               default: p = "undefined";
-               }
-               v4l_info(client, "Configured audio system:   %s\n", p);
-       }
-
-       if (aud_input) {
-               v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
-       } else {
-               v4l_info(client, "Specified audio input:     External\n");
-       }
-
-       switch (pref_mode & 0xf) {
-       case 0: p = "mono/language A"; break;
-       case 1: p = "language B"; break;
-       case 2: p = "language C"; break;
-       case 3: p = "analog fallback"; break;
-       case 4: p = "stereo"; break;
-       case 5: p = "language AC"; break;
-       case 6: p = "language BC"; break;
-       case 7: p = "language AB"; break;
-       default: p = "undefined";
-       }
-       v4l_info(client, "Preferred audio mode:      %s\n", p);
-
-       if ((audio_config & 0xf) == 0xf) {
-               switch ((afc0 >> 3) & 0x3) {
-               case 0: p = "system DK"; break;
-               case 1: p = "system L"; break;
-               case 2: p = "autodetect"; break;
-               default: p = "undefined";
-               }
-               v4l_info(client, "Selected 65 MHz format:    %s\n", p);
-
-               switch (afc0 & 0x7) {
-               case 0: p = "chroma"; break;
-               case 1: p = "BTSC"; break;
-               case 2: p = "EIAJ"; break;
-               case 3: p = "A2-M"; break;
-               case 4: p = "autodetect"; break;
-               default: p = "undefined";
-               }
-               v4l_info(client, "Selected 45 MHz format:    %s\n", p);
-       }
-}
index ea669b1f084d46462f06bbd2b2b78b2bc80877fc..95093edc9186d669395a0e6b531ba6b186de1fcb 100644 (file)
@@ -47,6 +47,7 @@ struct cx25840_state {
        u32 id;
        u32 rev;
        int is_cx25836;
+       int is_cx23885;
        int is_initialized;
        wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
        struct work_struct fw_work;   /* work entry for fw load */
index e852024a5ea3c52a49c9e6ba01b7bdb9f3488eb9..1ddf724a2c74ca6332dd52e1f702dfc4bf18aba0 100644 (file)
@@ -24,6 +24,7 @@
 #include "cx25840-core.h"
 
 #define FWFILE "v4l-cx25840.fw"
+#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
 
 /*
  * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
@@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size)
 
 int cx25840_loadfw(struct i2c_client *client)
 {
+       struct cx25840_state *state = i2c_get_clientdata(client);
        const struct firmware *fw = NULL;
        u8 buffer[4], *ptr;
        int size, send, retval;
 
+       if (state->is_cx23885)
+               firmware = FWFILE_CX23885;
+
        if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
                v4l_err(client, "unable to open firmware %s\n", firmware);
                return -EINVAL;
index ced13febed895396965483c7d710584637d1e8b6..6828f59b9d83555dee36e0e7a11656f8a6cfbe92 100644 (file)
@@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client)
                                                fsc/1000000,fsc%1000000);
 
                v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
-                       "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+                       "vblank %i, vactive %i, vblank656 %i, src_dec %i, "
                        "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
                        " sc 0x%06x\n",
                        hblank, hactive, vblank, vactive, vblank656,
index ceb31d4a251267f66d5d2baf265d6463e2d05f95..49d3813a9b48e69ac83ac84d8368d94a212fe945 100644 (file)
@@ -8,6 +8,7 @@ config VIDEO_CX88
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select VIDEO_IR
+       select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
        ---help---
          This is a video4linux driver for Conexant 2388x based
          TV cards.
index 40ffd7a5579a6f49347263cb21ad287b0ec1e6b7..8735227f7e47b5e798d7291b01883628f0f9367a 100644 (file)
@@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
        buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
        buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
 
        chip->buf = buf;
        chip->dma_risc = dma;
index f802b5653569874fa0a6dbef531c964566c784c8..a99e9d5950aa0da61483288f4da687f56a427844 100644 (file)
@@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
 
 /* ------------------------------------------------------------------ */
 
-static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
 {
        struct cx8802_dev *dev = priv;
        unsigned long timeout;
@@ -536,11 +536,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
        dprintk(1,"Initialize codec\n");
        retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
        if (retval < 0) {
+
+               dev->mpeg_active = 0;
+
                /* ping was not successful, reset and upload firmware */
                cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
-               msleep(1);
                cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
-               msleep(1);
                retval = blackbird_load_firmware(dev);
                if (retval < 0)
                        return retval;
@@ -562,7 +563,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
                }
                dprintk(0, "Firmware version is 0x%08x\n", version);
        }
-       msleep(1);
 
        cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
        cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
@@ -570,40 +570,68 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
        cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
 
        blackbird_codec_settings(dev);
-       msleep(1);
 
-       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
-          blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
-          blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
        blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
                        BLACKBIRD_FIELD1_SAA7115,
                        BLACKBIRD_FIELD2_SAA7115
                );
 
-       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
        blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
                        BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
-       /* initialize the video input */
-       blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+       return 0;
+}
 
-       msleep(1);
+static int blackbird_start_codec(struct file *file, void *priv)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+       struct cx88_core *core = dev->core;
+       /* start capturing to the host interface */
+       u32 reg;
 
-       blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
-       msleep(1);
-       blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
-       msleep(1);
+       int i;
+       int lastchange = -1;
+       int lastval = 0;
+
+       for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) {
+               reg = cx_read(AUD_STATUS);
+
+               dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg);
+               if ((reg & 0x0F) != lastval) {
+                       lastval = reg & 0x0F;
+                       lastchange = i;
+               }
+               msleep(100);
+       }
+
+       /* unmute audio source */
+       cx_clear(AUD_VOL_CTL, (1 << 6));
+
+       blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0);
+
+       /* initialize the video input */
+       blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
 
        /* start capturing to the host interface */
-       /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
        blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
                        BLACKBIRD_MPEG_CAPTURE,
                        BLACKBIRD_RAW_BITS_NONE
                );
-       msleep(10);
 
-       blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
+       dev->mpeg_active = 1;
+       return 0;
+}
+
+static int blackbird_stop_codec(struct cx8802_dev *dev)
+{
+       blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+                       BLACKBIRD_END_NOW,
+                       BLACKBIRD_MPEG_CAPTURE,
+                       BLACKBIRD_RAW_BITS_NONE
+               );
+
+       dev->mpeg_active = 0;
        return 0;
 }
 
@@ -833,6 +861,10 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv,
 
        if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                return -EINVAL;
+
+       if (dev->mpeg_active)
+               blackbird_stop_codec(dev);
+
        p = dev->params;
        err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
        if (!err) {
@@ -864,10 +896,9 @@ static int vidioc_s_frequency (struct file *file, void *priv,
        struct cx8802_dev *dev  = fh->dev;
        struct cx88_core  *core = dev->core;
 
-       blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-                               BLACKBIRD_END_NOW,
-                               BLACKBIRD_MPEG_CAPTURE,
-                               BLACKBIRD_RAW_BITS_NONE);
+       if (dev->mpeg_active)
+               blackbird_stop_codec(dev);
+
        cx88_set_freq (core,f);
        blackbird_initialize_codec(dev);
        cx88_set_scale(dev->core, dev->width, dev->height,
@@ -1073,15 +1104,11 @@ static int mpeg_open(struct inode *inode, struct file *file)
 static int mpeg_release(struct inode *inode, struct file *file)
 {
        struct cx8802_fh  *fh  = file->private_data;
-       struct cx8802_dev *dev = NULL;
+       struct cx8802_dev *dev = fh->dev;
        struct cx8802_driver *drv = NULL;
 
-       /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
-       blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-                       BLACKBIRD_END_NOW,
-                       BLACKBIRD_MPEG_CAPTURE,
-                       BLACKBIRD_RAW_BITS_NONE
-               );
+       if (dev->mpeg_active)
+               blackbird_stop_codec(dev);
 
        cx8802_cancel_buffers(fh->dev);
        /* stop mpeg capture */
@@ -1107,6 +1134,10 @@ static ssize_t
 mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct cx8802_fh *fh = file->private_data;
+       struct cx8802_dev *dev = fh->dev;
+
+       if (!dev->mpeg_active)
+               blackbird_start_codec(file, fh);
 
        return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
                                    file->f_flags & O_NONBLOCK);
@@ -1282,6 +1313,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
               core->name);
        host_setup(dev->core);
 
+       blackbird_initialize_codec(dev);
        blackbird_register_video(dev);
 
        /* initial device configuration: needed ? */
index a4eb6a87a761ded2d022726c117429d3ff07eee8..e6b7f518c56e8f552ade9e463b4fb2093e8f6519 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 
 #include "cx88.h"
+#include "tea5767.h"
 
 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
@@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = {
                }},
                .radio = {
                         .type   = CX88_RADIO,
+                        .vmux   = 3,
+                        .gpio0  = 0x000040bf,
+                        .gpio1  = 0x000080c0,
+                        .gpio2  = 0x0000ff20,
                },
        },
        [CX88_BOARD_WINFAST_DV2000] = {
@@ -297,22 +302,22 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000bde2,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0000bde6,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000bde6,
-                       .extadc = 1,
+                       .audioroute = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0000bd62,
-                       .extadc = 1,
+                       .audioroute = 1,
                },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -373,7 +378,7 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
-                       .extadc = 1,
+                       .audioroute = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
@@ -544,7 +549,7 @@ static const struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .extadc = 1,
+                       .audioroute = 1,
                }},
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -667,22 +672,22 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00009d80,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00009d76,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00009d76,
-                       .extadc = 1,
+                       .audioroute = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00009d00,
-                       .extadc = 1,
+                       .audioroute = 1,
                },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -821,23 +826,23 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
                        .gpio0  = 0x0000cd73,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 1,
                        .gpio0  = 0x0000cd73,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 3,
                        .gpio0  = 0x0000cdb3,
-                       .extadc = 1,
+                       .audioroute = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .vmux   = 2,
                        .gpio0  = 0x0000cdf3,
-                       .extadc = 1,
+                       .audioroute = 1,
                },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -1105,12 +1110,12 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x3de6,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x3de6,
-                       .extadc = 1,
+                       .audioroute = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
@@ -1335,17 +1340,17 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xe780,
-                       .extadc = 1,
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xe780,
-                       .extadc = 1,
+                       .audioroute = 2,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xe780,
-                       .extadc = 1,
+                       .audioroute = 2,
                }},
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
@@ -1370,6 +1375,32 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio0  = 0x07fa,
                }},
        },
+       [CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
+               .name           = "Pinnacle PCTV HD 800i",
+               .tuner_type     = TUNER_XC5000,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x04fb,
+                       .gpio1  = 0x10ff,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x04fb,
+                       .gpio1  = 0x10ef,
+                       .audioroute = 1,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x04fb,
+                       .gpio1  = 0x10ef,
+                       .audioroute = 1,
+               }},
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -1679,6 +1710,10 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x1421,
                .subdevice = 0x0390,
                .card      = CX88_BOARD_ADSTECH_PTV_390,
+       },{
+               .subvendor = 0x11bd,
+               .subdevice = 0x0051,
+               .card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
        },
 };
 
@@ -1845,6 +1880,36 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
        }
 }
 
+/* ----------------------------------------------------------------------- */
+/* Tuner callback function. Currently only needed for the Pinnacle        *
+ * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both      *
+ * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c)    */
+
+int cx88_tuner_callback(void *priv, int command, int arg)
+{
+       struct i2c_algo_bit_data *i2c_algo = priv;
+       struct cx88_core *core = i2c_algo->data;
+
+       switch(core->boardnr) {
+       case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+               if(command == 0) { /* This is the reset command from xc5000 */
+                       /* Reset XC5000 tuner via SYS_RSTO_pin */
+                       cx_write(MO_SRST_IO, 0);
+                       msleep(10);
+                       cx_write(MO_SRST_IO, 1);
+                       return 0;
+               }
+               else {
+                       printk(KERN_ERR
+                               "xc5000: unknown tuner callback command.\n");
+                       return -EINVAL;
+               }
+               break;
+       }
+       return 0; /* Should never be here */
+}
+EXPORT_SYMBOL(cx88_tuner_callback);
+
 /* ----------------------------------------------------------------------- */
 
 static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
@@ -1979,6 +2044,23 @@ static void cx88_card_setup(struct cx88_core *core)
                                                core->name, i);
                }
                break;
+       case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+       {
+               struct v4l2_priv_tun_config tea5767_cfg;
+               struct tea5767_ctrl ctl;
+
+               memset(&ctl, 0, sizeof(ctl));
+
+               ctl.high_cut  = 1;
+               ctl.st_noise  = 1;
+               ctl.deemph_75 = 1;
+               ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+
+               tea5767_cfg.tuner = TUNER_TEA5767;
+               tea5767_cfg.priv  = &ctl;
+
+               cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
+       }
        }
 }
 
index 62e8dd24c5f5413b978f6019a1d8b01c955aa4ed..01e2ac98970b3d14310bbf52660f85271ef1326b 100644 (file)
@@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
        videobuf_dma_unmap(q, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
-       buf->vb.state = STATE_NEEDS_INIT;
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 /* ------------------------------------------------------------------ */
@@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core,
                do_gettimeofday(&buf->vb.ts);
                dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
                        count, buf->count);
-               buf->vb.state = STATE_DONE;
+               buf->vb.state = VIDEOBUF_DONE;
                list_del(&buf->vb.queue);
                wake_up(&buf->vb.done);
        }
index fce19caf9d040ddea7f731b8b2996bb021d24298..f7b41eb1bb5a63a689c6e105718f20a262d0a2a0 100644 (file)
@@ -40,6 +40,8 @@
 #include "cx22702.h"
 #include "or51132.h"
 #include "lgdt330x.h"
+#include "s5h1409.h"
+#include "xc5000.h"
 #include "nxt200x.h"
 #include "cx24123.h"
 #include "isl6421.h"
@@ -371,6 +373,22 @@ static struct cx24123_config kworld_dvbs_100_config = {
        .lnb_polarity  = 1,
 };
 
+static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
+       .demod_address = 0x32 >> 1,
+       .output_mode   = S5H1409_PARALLEL_OUTPUT,
+       .gpio          = S5H1409_GPIO_ON,
+       .qam_if        = 44000,
+       .inversion     = S5H1409_INVERSION_OFF,
+       .status_mode   = S5H1409_DEMODLOCKING,
+       .mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
+       .i2c_address    = 0x64,
+       .if_khz         = 5380,
+       .tuner_callback = cx88_tuner_callback,
+};
+
 static int dvb_register(struct cx8802_dev *dev)
 {
        /* init struct videobuf_dvb */
@@ -625,6 +643,21 @@ static int dvb_register(struct cx8802_dev *dev)
                        dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
                }
                break;
+       case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+               dev->dvb.frontend = dvb_attach(s5h1409_attach,
+                                              &pinnacle_pctv_hd_800i_config,
+                                              &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       /* tuner_config.video_dev must point to
+                        * i2c_adap.algo_data
+                        */
+                       pinnacle_pctv_hd_800i_tuner_config.priv =
+                                               dev->core->i2c_adap.algo_data;
+                       dvb_attach(xc5000_attach, dev->dvb.frontend,
+                                  &dev->core->i2c_adap,
+                                  &pinnacle_pctv_hd_800i_tuner_config);
+               }
+               break;
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
                       dev->core->name);
index c8b1c50625f4701455edd0632f4ad18ef409fabc..566b26af523e74b132113ed968af94782dddc472 100644 (file)
@@ -109,26 +109,32 @@ static int attach_inform(struct i2c_client *client)
 
        if (core->board.radio_type != UNSET) {
                if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
-                       tun_setup.mode_mask = T_RADIO;
-                       tun_setup.type = core->board.radio_type;
-                       tun_setup.addr = core->board.radio_addr;
-
+                       tun_setup.mode_mask      = T_RADIO;
+                       tun_setup.type           = core->board.radio_type;
+                       tun_setup.addr           = core->board.radio_addr;
+                       tun_setup.tuner_callback = cx88_tuner_callback;
                        client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
                }
        }
        if (core->board.tuner_type != UNSET) {
                if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
 
-                       tun_setup.mode_mask = T_ANALOG_TV;
-                       tun_setup.type = core->board.tuner_type;
-                       tun_setup.addr = core->board.tuner_addr;
-
+                       tun_setup.mode_mask      = T_ANALOG_TV;
+                       tun_setup.type           = core->board.tuner_type;
+                       tun_setup.addr           = core->board.tuner_addr;
+                       tun_setup.tuner_callback = cx88_tuner_callback;
                        client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
                }
        }
 
-       if (core->board.tda9887_conf)
-               client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
+       if (core->board.tda9887_conf) {
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv  = &core->board.tda9887_conf;
+
+               client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
+       }
        return 0;
 }
 
@@ -176,6 +182,7 @@ static char *i2c_devs[128] = {
        [ 0xa0 >> 1 ] = "eeprom",
        [ 0xc0 >> 1 ] = "tuner (analog)",
        [ 0xc2 >> 1 ] = "tuner (analog/dvb)",
+       [ 0xc8 >> 1 ] = "xc5000",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
index e52de3968c6351d4fa4cd60874ca767db8e87d2b..bb0911b4d2f683ada952b8197d31c8f7445b667b 100644 (file)
@@ -305,6 +305,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->mask_keycode = 0xfa;
                ir->polling = 50; /* ms */
                break;
+       case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+               ir_codes = ir_codes_pinnacle_pctv_hd;
+               ir_type = IR_TYPE_RC5;
+               ir->sampling = 1;
+               break;
        }
 
        if (NULL == ir_codes) {
@@ -443,6 +448,7 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
+       case CX88_BOARD_PINNACLE_PCTV_HD_800i:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
                if ((ircode & 0xfffff000) != 0x3000)
index 448c67380945e62d4598793b19bb027445c7ac02..0aedbeaf94cd7edfacc59c3271e3166f3dd75cb1 100644 (file)
@@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
                cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
                udelay(100);
                cx_write(MO_PINMUX_IO, 0x00);
-               cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
+               cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01);
                switch (core->boardnr) {
                case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
                case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
@@ -117,6 +117,15 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
                        break;
                case CX88_BOARD_HAUPPAUGE_HVR1300:
                        break;
+               case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+                       /* Enable MPEG parallel IO and video signal pins */
+                       cx_write(MO_PINMUX_IO, 0x88);
+                       cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4));
+                       dev->ts_gen_cntrl = 5;
+                       cx_write(TS_SOP_STAT, 0);
+                       cx_write(TS_VALERR_CNTRL, 0);
+                       udelay(100);
+                       break;
                default:
                        cx_write(TS_SOP_STAT, 0x00);
                        break;
@@ -195,7 +204,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
                                list_del(&buf->vb.queue);
                                list_add_tail(&buf->vb.queue,&q->active);
                                cx8802_start_dma(dev, q, buf);
-                               buf->vb.state = STATE_ACTIVE;
+                               buf->vb.state = VIDEOBUF_ACTIVE;
                                buf->count    = q->count++;
                                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
                                dprintk(1,"[%p/%d] restart_queue - first active\n",
@@ -206,7 +215,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
                                   prev->fmt       == buf->fmt) {
                                list_del(&buf->vb.queue);
                                list_add_tail(&buf->vb.queue,&q->active);
-                               buf->vb.state = STATE_ACTIVE;
+                               buf->vb.state = VIDEOBUF_ACTIVE;
                                buf->count    = q->count++;
                                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                                dprintk(1,"[%p/%d] restart_queue - move to active\n",
@@ -242,7 +251,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
                return -EINVAL;
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                buf->vb.width  = dev->ts_packet_size;
                buf->vb.height = dev->ts_packet_count;
                buf->vb.size   = size;
@@ -254,7 +263,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
                                     dma->sglist,
                                     buf->vb.width, buf->vb.height, 0);
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
 
  fail:
@@ -276,7 +285,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
                dprintk( 1, "queue is empty - first active\n" );
                list_add_tail(&buf->vb.queue,&cx88q->active);
                cx8802_start_dma(dev, cx88q, buf);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = cx88q->count++;
                mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
                dprintk(1,"[%p/%d] %s - first active\n",
@@ -286,7 +295,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
                dprintk( 1, "queue is not empty - append to active\n" );
                prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
                list_add_tail(&buf->vb.queue,&cx88q->active);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = cx88q->count++;
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                dprintk( 1, "[%p/%d] %s - append to active\n",
@@ -306,7 +315,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
        while (!list_empty(&q->active)) {
                buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
                list_del(&buf->vb.queue);
-               buf->vb.state = STATE_ERROR;
+               buf->vb.state = VIDEOBUF_ERROR;
                wake_up(&buf->vb.done);
                dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
                        buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
@@ -437,10 +446,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
-/* ----------------------------------------------------------- */
-/* exported stuff                                              */
-
-int cx8802_init_common(struct cx8802_dev *dev)
+static int cx8802_init_common(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
        int err;
@@ -488,7 +494,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
        return 0;
 }
 
-void cx8802_fini_common(struct cx8802_dev *dev)
+static void cx8802_fini_common(struct cx8802_dev *dev)
 {
        dprintk( 2, "cx8802_fini_common\n" );
        cx8802_stop_dma(dev);
@@ -504,7 +510,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
 
 /* ----------------------------------------------------------- */
 
-int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
+static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 {
        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
@@ -530,7 +536,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
        return 0;
 }
 
-int cx8802_resume_common(struct pci_dev *pci_dev)
+static int cx8802_resume_common(struct pci_dev *pci_dev)
 {
        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
@@ -874,9 +880,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare);
 EXPORT_SYMBOL(cx8802_buf_queue);
 EXPORT_SYMBOL(cx8802_cancel_buffers);
 
-EXPORT_SYMBOL(cx8802_init_common);
-EXPORT_SYMBOL(cx8802_fini_common);
-
 EXPORT_SYMBOL(cx8802_register_driver);
 EXPORT_SYMBOL(cx8802_unregister_driver);
 EXPORT_SYMBOL(cx8802_get_driver);
index babb085564067715548bd580bc510a0a6670c939..d96ecfcf393a06d0ad99920a9c044d6c71c0ca19 100644 (file)
@@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data)
        while (!list_empty(&q->active)) {
                buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
                list_del(&buf->vb.queue);
-               buf->vb.state = STATE_ERROR;
+               buf->vb.state = VIDEOBUF_ERROR;
                wake_up(&buf->vb.done);
                printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
                       buf, buf->vb.i, (unsigned long)buf->risc.dma);
@@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
                return -EINVAL;
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
                buf->vb.width  = VBI_LINE_LENGTH;
                buf->vb.height = VBI_LINE_COUNT;
@@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                                 buf->vb.width, 0,
                                 buf->vb.height);
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
 
  fail:
@@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
        if (list_empty(&q->active)) {
                list_add_tail(&buf->vb.queue,&q->active);
                cx8800_start_vbi_dma(dev, q, buf);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = q->count++;
                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
                dprintk(2,"[%p/%d] vbi_queue - first active\n",
@@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
        } else {
                prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
                list_add_tail(&buf->vb.queue,&q->active);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = q->count++;
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                dprintk(2,"[%p/%d] buffer_queue - append to active\n",
index c84dafbdb991aae420a0f4bc80f3b8f71174110c..7f1931aed2070a926ac1502a30518cb72c0bb164 100644 (file)
@@ -392,13 +392,41 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
                break;
        }
 
-       if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
-               /* sets sound input from external adc */
-               if (INPUT(input).extadc)
+       /* if there are audioroutes defined, we have an external
+          ADC to deal with audio */
+
+       if (INPUT(input).audioroute) {
+
+               /* cx2388's C-ADC is connected to the tuner only.
+                  When used with S-Video, that ADC is busy dealing with
+                  chroma, so an external must be used for baseband audio */
+
+               if (INPUT(input).type != CX88_VMUX_TELEVISION &&
+                       INPUT(input).type != CX88_RADIO) {
+                       /* "ADC mode" */
+                       cx_write(AUD_I2SCNTL, 0x1);
                        cx_set(AUD_CTL, EN_I2SIN_ENABLE);
-               else
+               } else {
+                       /* Normal mode */
+                       cx_write(AUD_I2SCNTL, 0x0);
                        cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+               }
+
+               /* The wm8775 module has the "2" route hardwired into
+                  the initialization. Some boards may use different
+                  routes for different inputs. HVR-1300 surely does */
+               if (core->board.audio_chip &&
+                   core->board.audio_chip == AUDIO_CHIP_WM8775) {
+                       struct v4l2_routing route;
+
+                       route.input = INPUT(input).audioroute;
+                       cx88_call_i2c_clients(core,
+                               VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+               }
+
        }
+
        return 0;
 }
 EXPORT_SYMBOL(cx88_video_mux);
@@ -486,7 +514,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
                if (NULL == prev) {
                        list_move_tail(&buf->vb.queue, &q->active);
                        start_video_dma(dev, q, buf);
-                       buf->vb.state = STATE_ACTIVE;
+                       buf->vb.state = VIDEOBUF_ACTIVE;
                        buf->count    = q->count++;
                        mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
                        dprintk(2,"[%p/%d] restart_queue - first active\n",
@@ -496,7 +524,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
                           prev->vb.height == buf->vb.height &&
                           prev->fmt       == buf->fmt) {
                        list_move_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = STATE_ACTIVE;
+                       buf->vb.state = VIDEOBUF_ACTIVE;
                        buf->count    = q->count++;
                        prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                        dprintk(2,"[%p/%d] restart_queue - move to active\n",
@@ -553,7 +581,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                init_buffer = 1;
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                init_buffer = 1;
                if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
                        goto fail;
@@ -601,7 +629,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
                (unsigned long)buf->risc.dma);
 
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
 
  fail:
@@ -625,14 +653,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 
        if (!list_empty(&q->queued)) {
                list_add_tail(&buf->vb.queue,&q->queued);
-               buf->vb.state = STATE_QUEUED;
+               buf->vb.state = VIDEOBUF_QUEUED;
                dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
                        buf, buf->vb.i);
 
        } else if (list_empty(&q->active)) {
                list_add_tail(&buf->vb.queue,&q->active);
                start_video_dma(dev, q, buf);
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                buf->count    = q->count++;
                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
                dprintk(2,"[%p/%d] buffer_queue - first active\n",
@@ -644,7 +672,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
                    prev->vb.height == buf->vb.height &&
                    prev->fmt       == buf->fmt) {
                        list_add_tail(&buf->vb.queue,&q->active);
-                       buf->vb.state = STATE_ACTIVE;
+                       buf->vb.state = VIDEOBUF_ACTIVE;
                        buf->count    = q->count++;
                        prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                        dprintk(2,"[%p/%d] buffer_queue - append to active\n",
@@ -652,7 +680,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 
                } else {
                        list_add_tail(&buf->vb.queue,&q->queued);
-                       buf->vb.state = STATE_QUEUED;
+                       buf->vb.state = VIDEOBUF_QUEUED;
                        dprintk(2,"[%p/%d] buffer_queue - first queued\n",
                                buf, buf->vb.i);
                }
@@ -822,8 +850,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                        return POLLERR;
        }
        poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == STATE_DONE ||
-           buf->vb.state == STATE_ERROR)
+       if (buf->vb.state == VIDEOBUF_DONE ||
+           buf->vb.state == VIDEOBUF_ERROR)
                return POLLIN|POLLRDNORM;
        return 0;
 }
@@ -1496,7 +1524,7 @@ static void cx8800_vid_timeout(unsigned long data)
        while (!list_empty(&q->active)) {
                buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
                list_del(&buf->vb.queue);
-               buf->vb.state = STATE_ERROR;
+               buf->vb.state = VIDEOBUF_ERROR;
                wake_up(&buf->vb.done);
                printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
                       buf, buf->vb.i, (unsigned long)buf->risc.dma);
index eb296bdecb1eb7444e6d6c46572e49992fd4aa01..4e823f2a539a39eb88186c6c774f57947384617b 100644 (file)
@@ -210,6 +210,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
 #define CX88_BOARD_HAUPPAUGE_HVR1300       56
 #define CX88_BOARD_ADSTECH_PTV_390         57
+#define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -228,7 +229,7 @@ struct cx88_input {
        enum cx88_itype type;
        u32             gpio0, gpio1, gpio2, gpio3;
        unsigned int    vmux:2;
-       unsigned int    extadc:1;
+       unsigned int    audioroute:2;
 };
 
 struct cx88_board {
@@ -461,6 +462,7 @@ struct cx8802_dev {
        u32                        mailbox;
        int                        width;
        int                        height;
+       unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
 
        /* mpeg params */
        struct cx2341x_mpeg_params params;
@@ -588,6 +590,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
 /* ----------------------------------------------------------- */
 /* cx88-cards.c                                                */
 
+extern int cx88_tuner_callback(void *dev, int command, int arg);
 extern int cx88_get_resources(const struct cx88_core *core,
                              struct pci_dev *pci);
 extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
@@ -633,12 +636,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
 void cx8802_cancel_buffers(struct cx8802_dev *dev);
 
-int cx8802_init_common(struct cx8802_dev *dev);
-void cx8802_fini_common(struct cx8802_dev *dev);
-
-int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
-int cx8802_resume_common(struct pci_dev *pci_dev);
-
 /* ----------------------------------------------------------- */
 /* cx88-video.c*/
 extern const u32 cx88_user_ctrls[];
index c1127802ad9cd3cf1f6f2f7baacf4dc23f25509d..abbd38c1ebba896f06256d75a8f145ef363ebfbd 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_EM28XX
        tristate "Empia EM2800/2820/2840 USB video capture support"
-       depends on VIDEO_V4L1 && I2C && INPUT
+       depends on VIDEO_DEV && I2C && INPUT
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select VIDEO_IR
@@ -11,3 +11,18 @@ config VIDEO_EM28XX
 
          To compile this driver as a module, choose M here: the
          module will be called em28xx
+
+config VIDEO_EM28XX_ALSA
+       depends on VIDEO_EM28XX
+       tristate "Empia EM28xx ALSA audio module"
+       ---help---
+         This is an ALSA driver for some Empia 28xx based TV cards.
+
+         This is not required for em2800/em2820/em2821 boards. However,
+         newer em28xx devices uses Vendor Class for audio, instead of
+         implementing the USB Audio Class. For those chips, this module
+         will enable digital audio.
+
+         To compile this driver as a module, choose M here: the
+         module will be called em28xx-alsa
+
index 826d0e3407535cee83680c68700272f3999544fd..0924550992d0e4f37781bf66b5166ef30ce9a8de 100644 (file)
@@ -1,6 +1,12 @@
 em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
                   em28xx-input.o
 
+em28xx-alsa-objs := em28xx-audio.o
+
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 
 EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
new file mode 100644 (file)
index 0000000..941357c
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ *  Empiatech em28x1 audio extension
+ *
+ *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
+ *
+ *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *     - Port to work with the in-kernel driver
+ *     - Several cleanups
+ *
+ *  This driver is based on my previous au600 usb pstn audio driver
+ *  and inherits all the copyrights
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <media/v4l2-common.h>
+#include "em28xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define dprintk(fmt, arg...) do {                                      \
+           if (debug)                                                  \
+               printk(KERN_INFO "em28xx-audio %s: " fmt,               \
+                                 __FUNCTION__, ##arg);                 \
+       } while (0)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+static int em28xx_isoc_audio_deinit(struct em28xx *dev)
+{
+       int i;
+
+       dprintk("Stopping isoc\n");
+       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+               usb_kill_urb(dev->adev->urb[i]);
+               usb_free_urb(dev->adev->urb[i]);
+               dev->adev->urb[i] = NULL;
+       }
+
+       return 0;
+}
+
+static void em28xx_audio_isocirq(struct urb *urb)
+{
+       struct em28xx            *dev = urb->context;
+       int                      i;
+       unsigned int             oldptr;
+       unsigned long            flags;
+       int                      period_elapsed = 0;
+       int                      status;
+       unsigned char            *cp;
+       unsigned int             stride;
+       struct snd_pcm_substream *substream;
+       struct snd_pcm_runtime   *runtime;
+       if (dev->adev->capture_pcm_substream) {
+               substream = dev->adev->capture_pcm_substream;
+               runtime = substream->runtime;
+               stride = runtime->frame_bits >> 3;
+
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       int length =
+                           urb->iso_frame_desc[i].actual_length / stride;
+                       cp = (unsigned char *)urb->transfer_buffer +
+                           urb->iso_frame_desc[i].offset;
+
+                       if (!length)
+                               continue;
+
+                       spin_lock_irqsave(&dev->adev->slock, flags);
+
+                       oldptr = dev->adev->hwptr_done_capture;
+                       dev->adev->hwptr_done_capture += length;
+                       if (dev->adev->hwptr_done_capture >=
+                           runtime->buffer_size)
+                               dev->adev->hwptr_done_capture -=
+                                   runtime->buffer_size;
+
+                       dev->adev->capture_transfer_done += length;
+                       if (dev->adev->capture_transfer_done >=
+                           runtime->period_size) {
+                               dev->adev->capture_transfer_done -=
+                                   runtime->period_size;
+                               period_elapsed = 1;
+                       }
+
+                       spin_unlock_irqrestore(&dev->adev->slock, flags);
+
+                       if (oldptr + length >= runtime->buffer_size) {
+                               unsigned int cnt =
+                                   runtime->buffer_size - oldptr - 1;
+                               memcpy(runtime->dma_area + oldptr * stride, cp,
+                                      cnt * stride);
+                               memcpy(runtime->dma_area, cp + cnt,
+                                      length * stride - cnt * stride);
+                       } else {
+                               memcpy(runtime->dma_area + oldptr * stride, cp,
+                                      length * stride);
+                       }
+               }
+               if (period_elapsed)
+                       snd_pcm_period_elapsed(substream);
+       }
+       urb->status = 0;
+
+       if (dev->adev->shutdown)
+               return;
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status < 0) {
+               em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
+                             status);
+       }
+       return;
+}
+
+static int em28xx_init_audio_isoc(struct em28xx *dev)
+{
+       int       i, errCode;
+       const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
+                           EM28XX_AUDIO_MAX_PACKET_SIZE;
+
+       dprintk("Starting isoc transfers\n");
+
+       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+               struct urb *urb;
+               int j, k;
+
+               dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+               if (!dev->adev->transfer_buffer[i])
+                       return -ENOMEM;
+
+               memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
+               urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+               if (!urb)
+                       return -ENOMEM;
+
+               urb->dev = dev->udev;
+               urb->context = dev;
+               urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = dev->adev->transfer_buffer[i];
+               urb->interval = 1;
+               urb->complete = em28xx_audio_isocirq;
+               urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
+               urb->transfer_buffer_length = sb_size;
+
+               for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
+                            j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length =
+                           EM28XX_AUDIO_MAX_PACKET_SIZE;
+               }
+               dev->adev->urb[i] = urb;
+       }
+
+       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+               errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
+               if (errCode) {
+                       em28xx_isoc_audio_deinit(dev);
+
+                       return errCode;
+               }
+       }
+
+       return 0;
+}
+
+static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
+{
+       dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)?
+                                "stop" : "start");
+
+       switch (cmd) {
+       case EM28XX_CAPTURE_STREAM_EN:
+               if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {
+                       dev->adev->capture_stream = STREAM_ON;
+                       em28xx_init_audio_isoc(dev);
+               } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {
+                       dev->adev->capture_stream = STREAM_OFF;
+                       em28xx_isoc_audio_deinit(dev);
+               } else {
+                       printk(KERN_ERR "An underrun very likely occurred. "
+                                       "Ignoring it.\n");
+               }
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+                                       size_t size)
+{
+       struct snd_pcm_runtime *runtime = subs->runtime;
+
+       dprintk("Alocating vbuffer\n");
+       if (runtime->dma_area) {
+               if (runtime->dma_bytes > size)
+                       return 0;
+
+               vfree(runtime->dma_area);
+       }
+       runtime->dma_area = vmalloc(size);
+       if (!runtime->dma_area)
+               return -ENOMEM;
+
+       runtime->dma_bytes = size;
+
+       return 0;
+}
+
+static struct snd_pcm_hardware snd_em28xx_hw_capture = {
+       .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP           |
+               SNDRV_PCM_INFO_INTERLEAVED    |
+               SNDRV_PCM_INFO_MMAP_VALID,
+
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 62720 * 8,  /* just about the value in usbaudio.c */
+       .period_bytes_min = 64,         /* 12544/2, */
+       .period_bytes_max = 12544,
+       .periods_min = 2,
+       .periods_max = 98,              /* 12544, */
+};
+
+static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
+{
+       struct em28xx *dev = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret = 0;
+
+       dprintk("opening device and trying to acquire exclusive lock\n");
+
+       /* Sets volume, mute, etc */
+       dev->mute = 0;
+       ret = em28xx_audio_analog_set(dev);
+       if (ret < 0)
+               goto err;
+
+       runtime->hw = snd_em28xx_hw_capture;
+       if (dev->alt == 0 && dev->adev->users == 0) {
+               int errCode;
+               dev->alt = 7;
+               errCode = usb_set_interface(dev->udev, 0, 7);
+               dprintk("changing alternate number to 7\n");
+       }
+
+       dev->adev->users++;
+
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       dev->adev->capture_pcm_substream = substream;
+       runtime->private_data = dev;
+
+       return 0;
+err:
+       printk(KERN_ERR "Error while configuring em28xx mixer\n");
+       return ret;
+}
+
+static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct em28xx *dev = snd_pcm_substream_chip(substream);
+       dev->adev->users--;
+
+       dprintk("closing device\n");
+
+       dev->mute = 1;
+       em28xx_audio_analog_set(dev);
+
+       if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
+               dprintk("audio users: %d\n", dev->adev->users);
+               dprintk("disabling audio stream!\n");
+               dev->adev->shutdown = 0;
+               dprintk("released lock\n");
+               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+       }
+       return 0;
+}
+
+static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       unsigned int channels, rate, format;
+       int ret;
+
+       dprintk("Setting capture parameters\n");
+
+       ret = snd_pcm_alloc_vmalloc_buffer(substream,
+                               params_buffer_bytes(hw_params));
+       format = params_format(hw_params);
+       rate = params_rate(hw_params);
+       channels = params_channels(hw_params);
+
+       /* TODO: set up em28xx audio chip to deliver the correct audio format,
+          current default is 48000hz multiplexed => 96000hz mono
+          which shouldn't matter since analogue TV only supports mono */
+       return 0;
+}
+
+static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+       struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+       dprintk("Stop capture, if needed\n");
+
+       if (dev->adev->capture_stream == STREAM_ON)
+               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+
+       return 0;
+}
+
+static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
+                                     int cmd)
+{
+       struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+       dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)?
+                                      "start": "stop");
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               dev->adev->shutdown = 1;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
+                                                   *substream)
+{
+       struct em28xx *dev;
+
+       snd_pcm_uframes_t hwptr_done;
+       dev = snd_pcm_substream_chip(substream);
+       hwptr_done = dev->adev->hwptr_done_capture;
+
+       return hwptr_done;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+                                            unsigned long offset)
+{
+       void *pageptr = subs->runtime->dma_area + offset;
+
+       return vmalloc_to_page(pageptr);
+}
+
+static struct snd_pcm_ops snd_em28xx_pcm_capture = {
+       .open      = snd_em28xx_capture_open,
+       .close     = snd_em28xx_pcm_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = snd_em28xx_hw_capture_params,
+       .hw_free   = snd_em28xx_hw_capture_free,
+       .prepare   = snd_em28xx_prepare,
+       .trigger   = snd_em28xx_capture_trigger,
+       .pointer   = snd_em28xx_capture_pointer,
+       .page      = snd_pcm_get_vmalloc_page,
+};
+
+static int em28xx_audio_init(struct em28xx *dev)
+{
+       struct em28xx_audio *adev;
+       struct snd_pcm      *pcm;
+       struct snd_card     *card;
+       static int          devnr;
+       int                 ret, err;
+
+       printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
+                        "non standard usbaudio\n");
+       printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
+                        "Rechberger\n");
+
+       adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+       if (!adev) {
+               printk(KERN_ERR "em28xx-audio.c: out of memory\n");
+               return -1;
+       }
+       card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
+       if (card == NULL) {
+               kfree(adev);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&adev->slock);
+       ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
+       pcm->info_flags = 0;
+       pcm->private_data = dev;
+       strcpy(pcm->name, "Empia 28xx Capture");
+       strcpy(card->driver, "Empia Em28xx Audio");
+       strcpy(card->shortname, "Em28xx Audio");
+       strcpy(card->longname, "Empia Em28xx Audio");
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return -ENOMEM;
+       }
+       adev->sndcard = card;
+       adev->udev = dev->udev;
+       dev->adev = adev;
+
+       return 0;
+}
+
+static int em28xx_audio_fini(struct em28xx *dev)
+{
+       if (dev == NULL)
+               return 0;
+
+       if (dev->adev) {
+               snd_card_free(dev->adev->sndcard);
+               kfree(dev->adev);
+               dev->adev = NULL;
+       }
+
+       return 0;
+}
+
+static struct em28xx_ops audio_ops = {
+       .id   = EM28XX_AUDIO,
+       .name = "Em28xx Audio Extension",
+       .init = em28xx_audio_init,
+       .fini = em28xx_audio_fini,
+};
+
+static int __init em28xx_alsa_register(void)
+{
+       return em28xx_register_extension(&audio_ops);
+}
+
+static void __exit em28xx_alsa_unregister(void)
+{
+       em28xx_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Em28xx Audio driver");
+
+module_init(em28xx_alsa_register);
+module_exit(em28xx_alsa_unregister);
index 418ea8b7f85a7f8c28b056f5e08a921c71745462..2159d0160df248aaf28cc5325dc25d3a02d712b6 100644 (file)
@@ -1,5 +1,6 @@
 /*
-   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
+                   video capture devices
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
                      Markus Rechberger <mrechberger@gmail.com>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
+#include "tuner-xc2028.h"
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+
+struct em28xx_hash_table {
+       unsigned long hash;
+       unsigned int  model;
+       unsigned int  tuner;
+};
+
+/* Boards supported by driver */
+
+#define EM2800_BOARD_UNKNOWN                   0
+#define EM2820_BOARD_UNKNOWN                   1
+#define EM2820_BOARD_TERRATEC_CINERGY_250      2
+#define EM2820_BOARD_PINNACLE_USB_2            3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+#define EM2820_BOARD_MSI_VOX_USB_2              5
+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
+#define EM2800_BOARD_KWORLD_USB2800             8
+#define EM2820_BOARD_PINNACLE_DVC_90           9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900   10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS                11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF                12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS       13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2       14
+#define EM2800_BOARD_VGEAR_POCKETTV             15
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950   16
 
 struct em28xx_board em28xx_boards[] = {
        [EM2800_BOARD_UNKNOWN] = {
                .name         = "Unknown EM2800 video grabber",
                .is_em2800    = 1,
                .vchannels    = 2,
-               .norm         = VIDEO_MODE_PAL,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input           = {{
+               .input           = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2820_BOARD_UNKNOWN] = {
-               .name         = "Unknown EM2820/2840 video grabber",
+               .name         = "Unknown EM2750/28xx video grabber",
                .is_em2800    = 0,
-               .vchannels    = 2,
-               .norm         = VIDEO_MODE_PAL,
-               .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
-               .decoder      = EM28XX_SAA7113,
-               .input           = {{
-                       .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
-               },{
-                       .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
-               }},
+               .tuner_type   = TUNER_ABSENT,
        },
        [EM2820_BOARD_KWORLD_PVRTV2800RF] = {
                .name         = "Kworld PVR TV 2800 RF",
                .is_em2800    = 0,
                .vchannels    = 2,
-               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_TEMIC_PAL,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input           = {{
+               .input           = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2820_BOARD_TERRATEC_CINERGY_250] = {
                .name         = "Terratec Cinergy 250 USB",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2820_BOARD_PINNACLE_USB_2] = {
                .name         = "Pinnacle PCTV USB 2",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
                .name         = "Hauppauge WinTV USB 2",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_NTSC,
                .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
-               .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
-               .has_tuner    = 1,
+               .tda9887_conf = TDA9887_PRESENT |
+                               TDA9887_PORT1_ACTIVE|
+                               TDA9887_PORT2_ACTIVE,
                .decoder      = EM28XX_TVP5150,
                .has_msp34xx  = 1,
                /*FIXME: S-Video not tested */
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = MSP_INPUT_DEFAULT,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
                        .amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
                                        MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
-               }},
+               } },
        },
-       [EM2820_BOARD_MSI_VOX_USB_2] = {
-               .name           = "MSI VOX USB 2.0",
-               .vchannels      = 3,
-               .norm           = VIDEO_MODE_PAL,
-               .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
-               .tda9887_conf   = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
-               .has_tuner      = 1,
-               .decoder        = EM28XX_SAA7114,
-               .input          = {{
+       [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
+               .name         = "Hauppauge WinTV HVR 900",
+               .vchannels    = 3,
+               .tda9887_conf = TDA9887_PRESENT,
+               .tuner_type   = TUNER_XC2028,
+               .mts_firmware = 1,
+               .decoder      = EM28XX_TVP5150,
+               .input          = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = 0,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = 1,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = 1,
+               } },
+       },
+       [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
+               .name           = "Hauppauge WinTV HVR 950",
+               .vchannels      = 3,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .tuner_type     = TUNER_XC2028,
+               .mts_firmware   = 1,
+               .has_12mhz_i2s  = 1,
+               .decoder        = EM28XX_TVP5150,
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = SAA7115_COMPOSITE4,
+                       .vmux     = TVP5150_COMPOSITE0,
                        .amux     = 0,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = SAA7115_COMPOSITE0,
+                       .vmux     = TVP5150_COMPOSITE1,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = SAA7115_SVIDEO3,
+                       .vmux     = TVP5150_SVIDEO,
                        .amux     = 1,
-               }},
+               } },
+
+               /* gpio's 4, 1, 0 */
+               .analog_gpio = 0x003d2d,
+       },
+       [EM2880_BOARD_TERRATEC_HYBRID_XS] = {
+               .name         = "Terratec Hybrid XS",
+               .vchannels    = 3,
+               .tda9887_conf = TDA9887_PRESENT,
+               .tuner_type   = TUNER_XC2028,
+               .decoder      = EM28XX_TVP5150,
+               .input          = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = 0,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = 1,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = 1,
+               } },
+       },
+       /* maybe there's a reason behind it why Terratec sells the Hybrid XS
+          as Prodigy XS with a different PID, let's keep it separated for now
+          maybe we'll need it lateron */
+       [EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
+               .name         = "Terratec Prodigy XS",
+               .vchannels    = 3,
+               .tda9887_conf = TDA9887_PRESENT,
+               .tuner_type   = TUNER_XC2028,
+               .decoder      = EM28XX_TVP5150,
+               .input          = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = 0,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = 1,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = 1,
+               } },
+       },
+       [EM2820_BOARD_MSI_VOX_USB_2] = {
+               .name              = "MSI VOX USB 2.0",
+               .vchannels         = 3,
+               .tuner_type        = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf      = TDA9887_PRESENT      |
+                                    TDA9887_PORT1_ACTIVE |
+                                    TDA9887_PORT2_ACTIVE,
+               .max_range_640_480 = 1,
+
+               .decoder           = EM28XX_SAA7114,
+               .input             = { {
+                       .type      = EM28XX_VMUX_TELEVISION,
+                       .vmux      = SAA7115_COMPOSITE4,
+                       .amux      = 0,
+               }, {
+                       .type      = EM28XX_VMUX_COMPOSITE1,
+                       .vmux      = SAA7115_COMPOSITE0,
+                       .amux      = 1,
+               }, {
+                       .type      = EM28XX_VMUX_SVIDEO,
+                       .vmux      = SAA7115_SVIDEO3,
+                       .amux      = 1,
+               } },
        },
        [EM2800_BOARD_TERRATEC_CINERGY_200] = {
                .name         = "Terratec Cinergy 200 USB",
                .is_em2800    = 1,
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
                .name         = "Leadtek Winfast USB II",
                .is_em2800    = 1,
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2800_BOARD_KWORLD_USB2800] = {
                .name         = "Kworld USB2800",
                .is_em2800    = 1,
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_PHILIPS_ATSC,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
        [EM2820_BOARD_PINNACLE_DVC_90] = {
-               .name         = "Pinnacle Dazzle DVC 90",
+               .name         = "Pinnacle Dazzle DVC 90/DVC 100",
+               .vchannels    = 3,
+               .tuner_type   = TUNER_ABSENT,
+               .decoder      = EM28XX_SAA7113,
+               .input          = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = 1,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = 1,
+               } },
+       },
+       [EM2800_BOARD_VGEAR_POCKETTV] = {
+               .name         = "V-Gear PocketTV",
+               .is_em2800    = 1,
+               .vchannels    = 3,
+               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .decoder      = EM28XX_SAA7113,
+               .input          = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = SAA7115_COMPOSITE2,
+                       .amux     = 0,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = 1,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = 1,
+               } },
+       },
+       [EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
+               .name         = "Pixelview Prolink PlayTV USB 2.0",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
-               .has_tuner    = 0,
+               .tda9887_conf = TDA9887_PRESENT,
+               .tuner_type   = TUNER_YMEC_TVF_5533MF,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = SAA7115_COMPOSITE2,
+                       .amux     = 1,
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
-               },{
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
-               }},
+               } },
        },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
 struct usb_device_id em28xx_id_table [] = {
-       { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
-       { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
-       { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
-       { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
-       { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
-       { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+       { USB_DEVICE(0xeb1a, 0x2750),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2800),
+                       .driver_info = EM2800_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2820),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2821),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2860),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2861),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2870),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2881),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2883),
+                       .driver_info = EM2820_BOARD_UNKNOWN },
+       { USB_DEVICE(0x0ccd, 0x0036),
+                       .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+       { USB_DEVICE(0x2304, 0x0208),
+                       .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+       { USB_DEVICE(0x2040, 0x4200),
+                       .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+       { USB_DEVICE(0x2040, 0x4201),
+                       .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+       { USB_DEVICE(0x2304, 0x0207),
+                       .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+       { USB_DEVICE(0x2304, 0x021a),
+                       .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+       { USB_DEVICE(0x2040, 0x6500),
+                       .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+       { USB_DEVICE(0x2040, 0x6513),
+                       .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+       { USB_DEVICE(0x0ccd, 0x0042),
+                       .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
+       { USB_DEVICE(0x0ccd, 0x0047),
+                       .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
        { },
 };
+MODULE_DEVICE_TABLE(usb, em28xx_id_table);
+
+/* EEPROM hash table for devices with generic USB IDs */
+static struct em28xx_hash_table em28xx_eeprom_hash [] = {
+       /* P/N: SA 60002070465 Tuner: TVF7533-MF */
+       {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+};
+
+/* I2C devicelist hash table for devices with generic USB IDs */
+static struct em28xx_hash_table em28xx_i2c_hash[] = {
+       {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
+       {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
+};
 
+/* Since em28xx_pre_card_setup() requires a proper dev->model,
+ * this won't work for boards with generic PCI IDs
+ */
 void em28xx_pre_card_setup(struct em28xx *dev)
 {
        /* request some modules */
-       switch(dev->model){
-               case EM2880_BOARD_TERRATEC_PRODIGY_XS:
-               case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-               case EM2880_BOARD_TERRATEC_HYBRID_XS:
-                       {
-                               em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO?
-                               break;
+       switch (dev->model) {
+       case EM2880_BOARD_TERRATEC_PRODIGY_XS:
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+       case EM2880_BOARD_TERRATEC_HYBRID_XS:
+               em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
+               em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
+               em28xx_write_regs(dev, 0x08, "\xff", 1);
+               em28xx_write_regs(dev, 0x04, "\x00", 1);
+               msleep(100);
+               em28xx_write_regs(dev, 0x04, "\x08", 1);
+               msleep(100);
+               em28xx_write_regs(dev, 0x08, "\xff", 1);
+               msleep(50);
+               em28xx_write_regs(dev, 0x08, "\x2d", 1);
+               msleep(50);
+               em28xx_write_regs(dev, 0x08, "\x3d", 1);
+               break;
+       }
+}
+
+static int em28xx_tuner_callback(void *ptr, int command, int arg)
+{
+       int rc = 0;
+       struct em28xx *dev = ptr;
+
+       if (dev->tuner_type != TUNER_XC2028)
+               return 0;
+
+       switch (command) {
+       case XC2028_TUNER_RESET:
+       {
+               /* GPIO and initialization codes for analog TV and radio
+                  This code should be complemented for DTV, since reset
+                  codes are different.
+                */
+
+               dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+               dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+
+               if (dev->analog_gpio) {
+                       char gpio0 = dev->analog_gpio & 0xff;
+                       char gpio1 = (dev->analog_gpio >> 8) & 0xff;
+                       char gpio4 = dev->analog_gpio >> 24;
+
+                       if (gpio4) {
+                               dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
+                               msleep(140);
                        }
+
+                       msleep(6);
+                       dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
+                       msleep(10);
+                       dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
+                       msleep(5);
+               }
+
+               break;
+       }
+       }
+       return rc;
+}
+
+static void em28xx_config_tuner(struct em28xx *dev)
+{
+       struct v4l2_priv_tun_config  xc2028_cfg;
+       struct xc2028_ctrl           ctl;
+       struct tuner_setup           tun_setup;
+       struct v4l2_frequency        f;
+
+       if (dev->tuner_type == TUNER_ABSENT)
+               return;
+
+       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+       tun_setup.type = dev->tuner_type;
+       tun_setup.addr = dev->tuner_addr;
+       tun_setup.tuner_callback = em28xx_tuner_callback;
+
+       em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+
+       if (dev->tuner_type == TUNER_XC2028) {
+               memset(&ctl, 0, sizeof(ctl));
+
+               ctl.fname   = XC2028_DEFAULT_FIRMWARE;
+               ctl.max_len = 64;
+               ctl.mts = em28xx_boards[dev->model].mts_firmware;
+
+               xc2028_cfg.tuner = TUNER_XC2028;
+               xc2028_cfg.priv  = &ctl;
+
+               em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+       }
+
+       /* configure tuner */
+       f.tuner = 0;
+       f.type = V4L2_TUNER_ANALOG_TV;
+       f.frequency = 9076;     /* just a magic number */
+       dev->ctl_freq = f.frequency;
+       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+}
+
+static int em28xx_hint_board(struct em28xx *dev)
+{
+       int i;
+
+       /* HINT method: EEPROM
+        *
+        * This method works only for boards with eeprom.
+        * Uses a hash of all eeprom bytes. The hash should be
+        * unique for a vendor/tuner pair.
+        * There are a high chance that tuners for different
+        * video standards produce different hashes.
+        */
+       for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) {
+               if (dev->hash == em28xx_eeprom_hash[i].hash) {
+                       dev->model = em28xx_eeprom_hash[i].model;
+                       dev->tuner_type = em28xx_eeprom_hash[i].tuner;
+
+                       em28xx_errdev("Your board has no unique USB ID.\n");
+                       em28xx_errdev("A hint were successfully done, "
+                                     "based on eeprom hash.\n");
+                       em28xx_errdev("This method is not 100%% failproof.\n");
+                       em28xx_errdev("If the board were missdetected, "
+                                     "please email this log to:\n");
+                       em28xx_errdev("\tV4L Mailing List "
+                                     " <video4linux-list@redhat.com>\n");
+                       em28xx_errdev("Board detected as %s\n",
+                                     em28xx_boards[dev->model].name);
+
+                       return 0;
+               }
+       }
+
+       /* HINT method: I2C attached devices
+        *
+        * This method works for all boards.
+        * Uses a hash of i2c scanned devices.
+        * Devices with the same i2c attached chips will
+        * be considered equal.
+        * This method is less precise than the eeprom one.
+        */
+
+       /* user did not request i2c scanning => do it now */
+       if (!dev->i2c_hash)
+               em28xx_do_i2c_scan(dev);
+
+       for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
+               if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
+                       dev->model = em28xx_i2c_hash[i].model;
+                       dev->tuner_type = em28xx_i2c_hash[i].tuner;
+                       em28xx_errdev("Your board has no unique USB ID.\n");
+                       em28xx_errdev("A hint were successfully done, "
+                                     "based on i2c devicelist hash.\n");
+                       em28xx_errdev("This method is not 100%% failproof.\n");
+                       em28xx_errdev("If the board were missdetected, "
+                                     "please email this log to:\n");
+                       em28xx_errdev("\tV4L Mailing List "
+                                     " <video4linux-list@redhat.com>\n");
+                       em28xx_errdev("Board detected as %s\n",
+                                     em28xx_boards[dev->model].name);
+
+                       return 0;
+               }
+       }
+
+       em28xx_errdev("Your board has no unique USB ID and thus need a "
+                     "hint to be detected.\n");
+       em28xx_errdev("You may try to use card=<n> insmod option to "
+                     "workaround that.\n");
+       em28xx_errdev("Please send an email with this log to:\n");
+       em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n");
+       em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
+       em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
+
+       em28xx_errdev("Here is a list of valid choices for the card=<n>"
+                     " insmod option:\n");
+       for (i = 0; i < em28xx_bcount; i++) {
+               em28xx_errdev("    card=%d -> %s\n",
+                               i, em28xx_boards[i].name);
+       }
+       return -1;
+}
+
+
+static void em28xx_set_model(struct em28xx *dev)
+{
+       dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+       dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
+       dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+       dev->decoder = em28xx_boards[dev->model].decoder;
+       dev->video_inputs = em28xx_boards[dev->model].vchannels;
+       dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
+       dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+       dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+}
+
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+{
+       if (disable_ir) {
+               ir->get_key = NULL;
+               return ;
+       }
+
+       /* detect & configure */
+       switch (dev->model) {
+       case (EM2800_BOARD_UNKNOWN):
+               break;
+       case (EM2820_BOARD_UNKNOWN):
+               break;
+       case (EM2800_BOARD_TERRATEC_CINERGY_200):
+       case (EM2820_BOARD_TERRATEC_CINERGY_250):
+               ir->ir_codes = ir_codes_em_terratec;
+               ir->get_key = em28xx_get_key_terratec;
+               snprintf(ir->c.name, sizeof(ir->c.name),
+                        "i2c IR (EM28XX Terratec)");
+               break;
+       case (EM2820_BOARD_PINNACLE_USB_2):
+               ir->ir_codes = ir_codes_pinnacle_grey;
+               ir->get_key = em28xx_get_key_pinnacle_usb_grey;
+               snprintf(ir->c.name, sizeof(ir->c.name),
+                        "i2c IR (EM28XX Pinnacle PCTV)");
+               break;
+       case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+               ir->ir_codes = ir_codes_hauppauge_new;
+               ir->get_key = em28xx_get_key_em_haup;
+               snprintf(ir->c.name, sizeof(ir->c.name),
+                        "i2c IR (EM2840 Hauppauge)");
+               break;
+       case (EM2820_BOARD_MSI_VOX_USB_2):
+               break;
+       case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+               break;
+       case (EM2800_BOARD_KWORLD_USB2800):
+               break;
        }
 }
 
 void em28xx_card_setup(struct em28xx *dev)
 {
+       em28xx_set_model(dev);
+
+       dev->tuner_type = em28xx_boards[dev->model].tuner_type;
+
        /* request some modules */
-       switch(dev->model){
-               case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-                       {
-                               struct tveeprom tv;
+       switch (dev->model) {
+       case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+       {
+               struct tveeprom tv;
 #ifdef CONFIG_MODULES
-                               request_module("tveeprom");
-                               request_module("ir-kbd-i2c");
-                               request_module("msp3400");
+               request_module("tveeprom");
 #endif
-                               /* Call first TVeeprom */
-
-                               dev->i2c_client.addr = 0xa0 >> 1;
-                               tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
-
-                               dev->tuner_type= tv.tuner_type;
-                               if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
-                                       dev->i2s_speed=2048000;
-                                       dev->has_msp34xx=1;
-                               } else
-                                       dev->has_msp34xx=0;
-                               break;
-                       }
-               case EM2820_BOARD_KWORLD_PVRTV2800RF:
-                       {
-                               em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF
-                               break;
-                       }
+               /* Call first TVeeprom */
+
+               dev->i2c_client.addr = 0xa0 >> 1;
+               tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
 
+               dev->tuner_type = tv.tuner_type;
+
+               if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+                       dev->i2s_speed = 2048000;
+                       dev->has_msp34xx = 1;
+               }
+#ifdef CONFIG_MODULES
+               if (tv.has_ir)
+                       request_module("ir-kbd-i2c");
+#endif
+               break;
+       }
+       case EM2820_BOARD_KWORLD_PVRTV2800RF:
+               /* GPIO enables sound on KWORLD PVR TV 2800RF */
+               em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1);
+               break;
+       case EM2820_BOARD_UNKNOWN:
+       case EM2800_BOARD_UNKNOWN:
+               if (!em28xx_hint_board(dev))
+                       em28xx_set_model(dev);
        }
-}
 
-MODULE_DEVICE_TABLE (usb, em28xx_id_table);
+       /* Allow override tuner type by a module parameter */
+       if (tuner >= 0)
+               dev->tuner_type = tuner;
+
+#ifdef CONFIG_MODULES
+       /* request some modules */
+       if (dev->has_msp34xx)
+               request_module("msp3400");
+       if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+               request_module("saa7115");
+       if (dev->decoder == EM28XX_TVP5150)
+               request_module("tvp5150");
+       if (dev->tuner_type != TUNER_ABSENT)
+               request_module("tuner");
+#endif
+
+       em28xx_config_tuner(dev);
+}
index d56484f204677105c9fd435fdeb7bf8aca30ed75..f6b78357f0e517633f10bc5c7186b6be3d957085 100644 (file)
@@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
  * em28xx_write_ac97()
  * write a 16 bit value to the specified AC97 address (LSB first!)
  */
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
 {
        int ret;
        u8 addr = reg & 0x7f;
@@ -268,16 +268,98 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
        return 0;
 }
 
+int em28xx_set_audio_source(struct em28xx *dev)
+{
+       static char *enable  = "\x08\x08";
+       static char *disable = "\x08\x88";
+       char *video = enable, *line = disable;
+       int ret, no_ac97;
+       u8 input;
+
+       if (dev->is_em2800) {
+               if (dev->ctl_ainput)
+                       input = EM2800_AUDIO_SRC_LINE;
+               else
+                       input = EM2800_AUDIO_SRC_TUNER;
+
+               ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (dev->has_msp34xx)
+               input = EM28XX_AUDIO_SRC_TUNER;
+       else {
+               switch (dev->ctl_ainput) {
+               case EM28XX_AMUX_VIDEO:
+                       input = EM28XX_AUDIO_SRC_TUNER;
+                       no_ac97 = 1;
+                       break;
+               case EM28XX_AMUX_LINE_IN:
+                       input = EM28XX_AUDIO_SRC_LINE;
+                       no_ac97 = 1;
+                       break;
+               case EM28XX_AMUX_AC97_VIDEO:
+                       input = EM28XX_AUDIO_SRC_LINE;
+                       break;
+               case EM28XX_AMUX_AC97_LINE_IN:
+                       input = EM28XX_AUDIO_SRC_LINE;
+                       video = disable;
+                       line  = enable;
+                       break;
+               }
+       }
+
+       ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+       if (ret < 0)
+               return ret;
+
+       if (no_ac97)
+               return 0;
+
+       /* Sets AC97 mixer registers */
+
+       ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+
+       return ret;
+}
+
 int em28xx_audio_analog_set(struct em28xx *dev)
 {
+       int ret;
        char s[2] = { 0x00, 0x00 };
+       u8 xclk = 0x07;
+
        s[0] |= 0x1f - dev->volume;
        s[1] |= 0x1f - dev->volume;
+
        if (dev->mute)
                s[1] |= 0x80;
-       return em28xx_write_ac97(dev, MASTER_AC97, s);
-}
+       ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+       if (ret < 0)
+               return ret;
+
+       if (dev->has_12mhz_i2s)
+               xclk |= 0x20;
+
+       if (!dev->mute)
+               xclk |= 0x80;
 
+       ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+       if (ret < 0)
+               return ret;
+       msleep(10);
+
+       /* Selects the proper audio input */
+       ret = em28xx_set_audio_source(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
 
 int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
index e3a4aa7a9df414769bf0b8e208e3487a154fd200..cacd04d46e99eb85145c9ee5e14ed0cff792bfde 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/kernel.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/video_decoder.h>
 
 #include "em28xx.h"
+#include "tuner-xc2028.h"
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 
@@ -291,6 +291,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
        return rc;
 }
 
+/* based on linux/sunrpc/svcauth.h and linux/hash.h
+ * The original hash function returns a different value, if arch is x86_64
+ *  or i386.
+ */
+static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
+{
+       unsigned long hash = 0;
+       unsigned long l = 0;
+       int len = 0;
+       unsigned char c;
+       do {
+               if (len == length) {
+                       c = (char)len;
+                       len = -1;
+               } else
+                       c = *buf++;
+               l = (l << 8) | c;
+               len++;
+               if ((len & (32 / 8 - 1)) == 0)
+                       hash = ((hash^l) * 0x9e370001UL);
+       } while (len);
+
+       return (hash >> (32 - bits)) & 0xffffffffUL;
+}
+
 static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
 {
        unsigned char buf, *p = eedata;
@@ -334,7 +359,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
                        printk("\n");
        }
 
-       printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
+       if (em_eeprom->id == 0x9567eb1a)
+               dev->hash = em28xx_hash_mem(eedata, len, 32);
+
+       printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
+              em_eeprom->id, dev->hash);
        printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
               em_eeprom->product_ID);
 
@@ -391,21 +420,6 @@ static u32 functionality(struct i2c_adapter *adap)
 }
 
 
-static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
-{
-       struct em28xx *dev = client->adapter->algo_data;
-       struct tuner_setup tun_setup;
-
-       if (dev->has_tuner) {
-               tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-               tun_setup.type = dev->tuner_type;
-               tun_setup.addr = dev->tuner_addr;
-               em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
-       }
-
-       return (0);
-}
-
 /*
  * attach_inform()
  * gets called when a device attaches to the i2c bus
@@ -421,6 +435,8 @@ static int attach_inform(struct i2c_client *client)
                case 0x96:
                case 0x94:
                {
+                       struct v4l2_priv_tun_config tda9887_cfg;
+
                        struct tuner_setup tun_setup;
 
                        tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
@@ -428,7 +444,11 @@ static int attach_inform(struct i2c_client *client)
                        tun_setup.addr = client->addr;
 
                        em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
-                       em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
+
+                       tda9887_cfg.tuner = TUNER_TDA9887;
+                       tda9887_cfg.priv = &dev->tda9887_conf;
+                       em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
+                                               &tda9887_cfg);
                        break;
                }
                case 0x42:
@@ -458,9 +478,11 @@ static int attach_inform(struct i2c_client *client)
                        break;
 
                default:
+                       if (!dev->tuner_addr)
+                               dev->tuner_addr = client->addr;
+
                        dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
-                       dev->tuner_addr = client->addr;
-                       em28xx_set_tuner(-1, client);
+
        }
 
        return 0;
@@ -510,19 +532,26 @@ static char *i2c_devs[128] = {
  * do_i2c_scan()
  * check i2c address range for devices
  */
-static void do_i2c_scan(char *name, struct i2c_client *c)
+void em28xx_do_i2c_scan(struct em28xx *dev)
 {
+       u8 i2c_devicelist[128];
        unsigned char buf;
        int i, rc;
 
+       memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
+
        for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
-               c->addr = i;
-               rc = i2c_master_recv(c, &buf, 0);
+               dev->i2c_client.addr = i;
+               rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
                if (rc < 0)
                        continue;
-               printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
-                      i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+               i2c_devicelist[i] = i;
+               printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
+                      dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
        }
+
+       dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
+                                       ARRAY_SIZE(i2c_devicelist), 32);
 }
 
 /*
@@ -555,7 +584,7 @@ int em28xx_i2c_register(struct em28xx *dev)
        em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
 
        if (i2c_scan)
-               do_i2c_scan(dev->name, &dev->i2c_client);
+               em28xx_do_i2c_scan(dev);
        return 0;
 }
 
index e3894b68c4ee26b778aebe3945c9f3489e20c609..10da2fd8d9875072fe3476ed683266c450c4f08d 100644 (file)
 
 #include "em28xx.h"
 
-static unsigned int disable_ir = 0;
-module_param(disable_ir, int, 0444);
-MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
-
-static unsigned int ir_debug = 0;
+static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
@@ -43,7 +39,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char b;
 
@@ -72,7 +68,7 @@ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 }
 
 
-static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char buf[2];
        unsigned char code;
@@ -103,7 +99,8 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+                                    u32 *ir_raw)
 {
        unsigned char buf[3];
 
@@ -125,45 +122,6 @@ static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw
        return 1;
 }
 
-/* ----------------------------------------------------------------------- */
-void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
-{
-       if (disable_ir) {
-               ir->get_key=NULL;
-               return ;
-       }
-
-       /* detect & configure */
-       switch (dev->model) {
-       case (EM2800_BOARD_UNKNOWN):
-               break;
-       case (EM2820_BOARD_UNKNOWN):
-               break;
-       case (EM2800_BOARD_TERRATEC_CINERGY_200):
-       case (EM2820_BOARD_TERRATEC_CINERGY_250):
-               ir->ir_codes = ir_codes_em_terratec;
-               ir->get_key = get_key_terratec;
-               snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
-               break;
-       case (EM2820_BOARD_PINNACLE_USB_2):
-               ir->ir_codes = ir_codes_pinnacle_grey;
-               ir->get_key = get_key_pinnacle_usb_grey;
-               snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
-               break;
-       case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
-               ir->ir_codes = ir_codes_hauppauge_new;
-               ir->get_key = get_key_em_haup;
-               snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
-               break;
-       case (EM2820_BOARD_MSI_VOX_USB_2):
-               break;
-       case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
-               break;
-       case (EM2800_BOARD_KWORLD_USB2800):
-               break;
-       }
-}
-
 /* ----------------------------------------------------------------------
  * Local variables:
  * c-basic-offset: 8
index 0906bc5766cc0b46becbe85735df042333c56b59..a0c334672488ddd882a8254580ed6622563774f1 100644 (file)
 #include <linux/i2c.h>
 #include <linux/version.h>
 #include <linux/mm.h>
-#include <linux/video_decoder.h>
 #include <linux/mutex.h>
 
 #include "em28xx.h"
-#include <media/tuner.h>
 #include <media/v4l2-common.h>
 #include <media/msp3400.h>
+#include <media/tuner.h>
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
                      "Markus Rechberger <mrechberger@gmail.com>, " \
@@ -48,7 +47,7 @@
 
 #define DRIVER_NAME         "em28xx"
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 0, 1)
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
@@ -63,17 +62,17 @@ static LIST_HEAD(em28xx_devlist);
 
 static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+
 module_param_array(card,  int, NULL, 0444);
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr, int, NULL, 0444);
-MODULE_PARM_DESC(card,"card type");
-MODULE_PARM_DESC(video_nr,"video device numbers");
-MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
-
-static int tuner = -1;
-module_param(tuner, int, 0444);
-MODULE_PARM_DESC(tuner, "tuner type");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(card,     "card type");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 static unsigned int video_debug = 0;
 module_param(video_debug,int,0644);
@@ -82,29 +81,6 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
 /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
 static unsigned long em28xx_devused;
 
-/* supported tv norms */
-static struct em28xx_tvnorm tvnorms[] = {
-       {
-               .name = "PAL",
-               .id = V4L2_STD_PAL,
-               .mode = VIDEO_MODE_PAL,
-        }, {
-               .name = "NTSC",
-               .id = V4L2_STD_NTSC,
-               .mode = VIDEO_MODE_NTSC,
-       }, {
-                .name = "SECAM",
-                .id = V4L2_STD_SECAM,
-                .mode = VIDEO_MODE_SECAM,
-       }, {
-               .name = "PAL-M",
-               .id = V4L2_STD_PAL_M,
-               .mode = VIDEO_MODE_PAL,
-       }
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
 /* supported controls */
 /* Common to all boards */
 static struct v4l2_queryctrl em28xx_qctrl[] = {
@@ -131,8 +107,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
 
 static struct usb_driver em28xx_usb_driver;
 
-static DEFINE_MUTEX(em28xx_sysfs_lock);
-static DECLARE_RWSEM(em28xx_disconnect);
 
 /*********************  v4l2 interface  ******************************************/
 
@@ -153,11 +127,9 @@ static int em28xx_config(struct em28xx *dev)
 /*     em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
        em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
 
-       em28xx_audio_usb_mute(dev, 1);
        dev->mute = 1;          /* maybe not the right place... */
        dev->volume = 0x1f;
-       em28xx_audio_analog_set(dev);
-       em28xx_audio_analog_setup(dev);
+
        em28xx_outfmt_set_yuv422(dev);
        em28xx_colorlevels_set_default(dev);
        em28xx_compression_disable(dev);
@@ -171,7 +143,6 @@ static int em28xx_config(struct em28xx *dev)
  */
 static void em28xx_config_i2c(struct em28xx *dev)
 {
-       struct v4l2_frequency f;
        struct v4l2_routing route;
 
        route.input = INPUT(dev->ctl_input)->vmux;
@@ -179,18 +150,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
        em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
        em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
        em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-
-       /* configure tuner */
-       f.tuner = 0;
-       f.type = V4L2_TUNER_ANALOG_TV;
-       f.frequency = 9076;     /* FIXME:remove magic number */
-       dev->ctl_freq = f.frequency;
-       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
-
-       /* configure tda9887 */
-
-
-/*     em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
 }
 
 /*
@@ -212,7 +171,6 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
 
 static void video_mux(struct em28xx *dev, int index)
 {
-       int ainput;
        struct v4l2_routing route;
 
        route.input = INPUT(index)->vmux;
@@ -222,8 +180,6 @@ static void video_mux(struct em28xx *dev, int index)
 
        em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
-       em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
-
        if (dev->has_msp34xx) {
                if (dev->i2s_speed)
                        em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
@@ -231,1314 +187,1693 @@ static void video_mux(struct em28xx *dev, int index)
                route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
                /* Note: this is msp3400 specific */
                em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-               ainput = EM28XX_AUDIO_SRC_TUNER;
-               em28xx_audio_source(dev, ainput);
-       } else {
-               switch (dev->ctl_ainput) {
-                       case 0:
-                               ainput = EM28XX_AUDIO_SRC_TUNER;
-                               break;
-                       default:
-                               ainput = EM28XX_AUDIO_SRC_LINE;
-               }
-               em28xx_audio_source(dev, ainput);
        }
+
+       em28xx_set_audio_source(dev);
 }
 
-/*
- * em28xx_v4l2_open()
- * inits the device and starts isoc transfer
- */
-static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+/* Usage lock check functions */
+static int res_get(struct em28xx_fh *fh)
 {
-       int minor = iminor(inode);
-       int errCode = 0;
-       struct em28xx *h,*dev = NULL;
-
-       list_for_each_entry(h, &em28xx_devlist, devlist) {
-               if (h->vdev->minor == minor) {
-                       dev  = h;
-                       dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               }
-               if (h->vbi_dev->minor == minor) {
-                       dev  = h;
-                       dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               }
-       }
-       if (NULL == dev)
-               return -ENODEV;
-
-       em28xx_videodbg("open minor=%d type=%s users=%d\n",
-                               minor,v4l2_type_names[dev->type],dev->users);
-
-       if (!down_read_trylock(&em28xx_disconnect))
-               return -ERESTARTSYS;
-
-       if (dev->users) {
-               em28xx_warn("this driver can be opened only once\n");
-               up_read(&em28xx_disconnect);
-               return -EBUSY;
-       }
+       struct em28xx    *dev = fh->dev;
+       int              rc   = 0;
 
-       mutex_init(&dev->fileop_lock);  /* to 1 == available */
-       spin_lock_init(&dev->queue_lock);
-       init_waitqueue_head(&dev->wait_frame);
-       init_waitqueue_head(&dev->wait_stream);
+       /* This instance already has stream_on */
+       if (fh->stream_on)
+               return rc;
 
        mutex_lock(&dev->lock);
 
-       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               em28xx_set_alternate(dev);
-
-               dev->width = norm_maxw(dev);
-               dev->height = norm_maxh(dev);
-               dev->frame_size = dev->width * dev->height * 2;
-               dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
-               dev->bytesperline = dev->width * 2;
-               dev->hscale = 0;
-               dev->vscale = 0;
-
-               em28xx_capture_start(dev, 1);
-               em28xx_resolution_set(dev);
-
-               /* device needs to be initialized before isoc transfer */
-               video_mux(dev, 0);
-
-               /* start the transfer */
-               errCode = em28xx_init_isoc(dev);
-               if (errCode)
-                       goto err;
-
+       if (dev->stream_on)
+               rc = -EINVAL;
+       else {
+               dev->stream_on = 1;
+               fh->stream_on  = 1;
        }
 
-       dev->users++;
-       filp->private_data = dev;
-       dev->io = IO_NONE;
-       dev->stream = STREAM_OFF;
-       dev->num_frames = 0;
+       mutex_unlock(&dev->lock);
+       return rc;
+}
 
-       /* prepare queues */
-       em28xx_empty_framequeues(dev);
+static int res_check(struct em28xx_fh *fh)
+{
+       return (fh->stream_on);
+}
 
-       dev->state |= DEV_INITIALIZED;
+static void res_free(struct em28xx_fh *fh)
+{
+       struct em28xx    *dev = fh->dev;
 
-err:
+       mutex_lock(&dev->lock);
+       fh->stream_on = 0;
+       dev->stream_on = 0;
        mutex_unlock(&dev->lock);
-       up_read(&em28xx_disconnect);
-       return errCode;
 }
 
 /*
- * em28xx_realease_resources()
- * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconected or at module unload
-*/
-static void em28xx_release_resources(struct em28xx *dev)
+ * em28xx_vm_open()
+ */
+static void em28xx_vm_open(struct vm_area_struct *vma)
 {
-       mutex_lock(&em28xx_sysfs_lock);
-
-       /*FIXME: I2C IR should be disconnected */
-
-       em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
-       list_del(&dev->devlist);
-       video_unregister_device(dev->vdev);
-       video_unregister_device(dev->vbi_dev);
-       em28xx_i2c_unregister(dev);
-       usb_put_dev(dev->udev);
-       mutex_unlock(&em28xx_sysfs_lock);
-
-
-       /* Mark device as unused */
-       em28xx_devused&=~(1<<dev->devno);
+       struct em28xx_frame_t *f = vma->vm_private_data;
+       f->vma_use_count++;
 }
 
 /*
- * em28xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ * em28xx_vm_close()
  */
-static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+static void em28xx_vm_close(struct vm_area_struct *vma)
 {
-       int errCode;
-       struct em28xx *dev=filp->private_data;
-
-       em28xx_videodbg("users=%d\n", dev->users);
+       /* NOTE: buffers are not freed here */
+       struct em28xx_frame_t *f = vma->vm_private_data;
 
-       mutex_lock(&dev->lock);
+       if (f->vma_use_count)
+               f->vma_use_count--;
+}
 
-       em28xx_uninit_isoc(dev);
+static struct vm_operations_struct em28xx_vm_ops = {
+       .open = em28xx_vm_open,
+       .close = em28xx_vm_close,
+};
 
-       em28xx_release_buffers(dev);
 
-       /* the device is already disconnect, free the remaining resources */
-       if (dev->state & DEV_DISCONNECTED) {
-               em28xx_release_resources(dev);
-               mutex_unlock(&dev->lock);
-               kfree(dev);
+/*
+ * em28xx_get_ctrl()
+ * return the current saturation, brightness or contrast, mute state
+ */
+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = dev->mute;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = dev->volume;
                return 0;
+       default:
+               return -EINVAL;
        }
+}
 
-       /* set alternate 0 */
-       dev->alt = 0;
-       em28xx_videodbg("setting alternate 0\n");
-       errCode = usb_set_interface(dev->udev, 0, 0);
-       if (errCode < 0) {
-               em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
-                    errCode);
+/*
+ * em28xx_set_ctrl()
+ * mute or set new saturation, brightness or contrast
+ */
+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value != dev->mute) {
+                       dev->mute = ctrl->value;
+                       return em28xx_audio_analog_set(dev);
+               }
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               dev->volume = ctrl->value;
+               return em28xx_audio_analog_set(dev);
+       default:
+               return -EINVAL;
        }
-
-       dev->users--;
-       wake_up_interruptible_nr(&dev->open, 1);
-       mutex_unlock(&dev->lock);
-       return 0;
 }
 
 /*
- * em28xx_v4l2_read()
- * will allocate buffers when called for the first time
+ * em28xx_stream_interrupt()
+ * stops streaming
  */
-static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
-                loff_t * f_pos)
+static int em28xx_stream_interrupt(struct em28xx *dev)
 {
-       struct em28xx_frame_t *f, *i;
-       unsigned long lock_flags;
-       int ret = 0;
-       struct em28xx *dev = filp->private_data;
+       int rc = 0;
 
-       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
-       }
-       if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
-               em28xx_videodbg("not supported yet! ...\n");
-               if (copy_to_user(buf, "", 1)) {
-                       mutex_unlock(&dev->fileop_lock);
-                       return -EFAULT;
-               }
-               return (1);
-       }
-       if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-               em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
-               em28xx_videodbg("not supported yet! ...\n");
-               if (copy_to_user(buf, "", 1)) {
-                       mutex_unlock(&dev->fileop_lock);
-                       return -EFAULT;
-               }
-               return (1);
+       /* stop reading from the device */
+
+       dev->stream = STREAM_INTERRUPT;
+       rc = wait_event_timeout(dev->wait_stream,
+                               (dev->stream == STREAM_OFF) ||
+                               (dev->state & DEV_DISCONNECTED),
+                               EM28XX_URB_TIMEOUT);
+
+       if (rc) {
+               dev->state |= DEV_MISCONFIGURED;
+               em28xx_videodbg("device is misconfigured; close and "
+                       "open /dev/video%d again\n",
+                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+               return rc;
        }
 
-       if (mutex_lock_interruptible(&dev->fileop_lock))
-               return -ERESTARTSYS;
+       return 0;
+}
+
 
+static int check_dev(struct em28xx *dev)
+{
        if (dev->state & DEV_DISCONNECTED) {
-               em28xx_videodbg("device not present\n");
-               mutex_unlock(&dev->fileop_lock);
+               em28xx_errdev("v4l2 ioctl: device not present\n");
                return -ENODEV;
        }
 
        if (dev->state & DEV_MISCONFIGURED) {
-               em28xx_videodbg("device misconfigured; close and open it again\n");
-               mutex_unlock(&dev->fileop_lock);
+               em28xx_errdev("v4l2 ioctl: device is misconfigured; "
+                             "close and open it again\n");
                return -EIO;
        }
+       return 0;
+}
 
-       if (dev->io == IO_MMAP) {
-               em28xx_videodbg ("IO method is set to mmap; close and open"
-                               " the device again to choose the read method\n");
-               mutex_unlock(&dev->fileop_lock);
-               return -EINVAL;
-       }
+static void get_scale(struct em28xx *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);
 
-       if (dev->io == IO_NONE) {
-               if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
-                       em28xx_errdev("read failed, not enough memory\n");
-                       mutex_unlock(&dev->fileop_lock);
-                       return -ENOMEM;
-               }
-               dev->io = IO_READ;
-               dev->stream = STREAM_ON;
-               em28xx_queue_unusedframes(dev);
-       }
+       *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
+       if (*hscale >= 0x4000)
+               *hscale = 0x3fff;
 
-       if (!count) {
-               mutex_unlock(&dev->fileop_lock);
-               return 0;
-       }
+       *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
+       if (*vscale >= 0x4000)
+               *vscale = 0x3fff;
+}
 
-       if (list_empty(&dev->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&dev->fileop_lock);
-                       return -EAGAIN;
-               }
-               ret = wait_event_interruptible
-                   (dev->wait_frame,
-                    (!list_empty(&dev->outqueue)) ||
-                    (dev->state & DEV_DISCONNECTED));
-               if (ret) {
-                       mutex_unlock(&dev->fileop_lock);
-                       return ret;
-               }
-               if (dev->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&dev->fileop_lock);
-                       return -ENODEV;
-               }
-       }
+/* ------------------------------------------------------------------
+       IOCTL vidioc handling
+   ------------------------------------------------------------------*/
 
-       f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
 
-       spin_lock_irqsave(&dev->queue_lock, lock_flags);
-       list_for_each_entry(i, &dev->outqueue, frame)
-           i->state = F_UNUSED;
-       INIT_LIST_HEAD(&dev->outqueue);
-       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+       mutex_lock(&dev->lock);
 
-       em28xx_queue_unusedframes(dev);
+       f->fmt.pix.width = dev->width;
+       f->fmt.pix.height = dev->height;
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+       f->fmt.pix.bytesperline = dev->bytesperline;
+       f->fmt.pix.sizeimage = dev->frame_size;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-       if (count > f->buf.length)
-               count = f->buf.length;
+       /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+       f->fmt.pix.field = dev->interlaced ?
+                          V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
 
-       if (copy_to_user(buf, f->bufmem, count)) {
-               mutex_unlock(&dev->fileop_lock);
-               return -EFAULT;
-       }
-       *f_pos += count;
+       mutex_unlock(&dev->lock);
+       return 0;
+}
 
-       mutex_unlock(&dev->fileop_lock);
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct em28xx_fh      *fh    = priv;
+       struct em28xx         *dev   = fh->dev;
+       int                   width  = f->fmt.pix.width;
+       int                   height = f->fmt.pix.height;
+       unsigned int          maxw   = norm_maxw(dev);
+       unsigned int          maxh   = norm_maxh(dev);
+       unsigned int          hscale, vscale;
+
+       /* width must even because of the YUYV format
+          height must be even because of interlacing */
+       height &= 0xfffe;
+       width &= 0xfffe;
 
-       return count;
+       if (height < 32)
+               height = 32;
+       if (height > maxh)
+               height = maxh;
+       if (width < 48)
+               width = 48;
+       if (width > maxw)
+               width = maxw;
+
+       mutex_lock(&dev->lock);
+
+       if (dev->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 */
+               if (width == maxw && height == maxh)
+                       width /= 2;
+       }
+
+       get_scale(dev, width, height, &hscale, &vscale);
+
+       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+       f->fmt.pix.width = width;
+       f->fmt.pix.height = height;
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+       f->fmt.pix.bytesperline = width * 2;
+       f->fmt.pix.sizeimage = width * 2 * height;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+       mutex_unlock(&dev->lock);
+       return 0;
 }
 
-/*
- * em28xx_v4l2_poll()
- * will allocate buffers when called for the first time
- */
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
 {
-       unsigned int mask = 0;
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc, i;
 
-       if (mutex_lock_interruptible(&dev->fileop_lock))
-               return POLLERR;
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
 
-       if (dev->state & DEV_DISCONNECTED) {
-               em28xx_videodbg("device not present\n");
-       } else if (dev->state & DEV_MISCONFIGURED) {
-               em28xx_videodbg("device is misconfigured; close and open it again\n");
+       vidioc_try_fmt_cap(file, priv, f);
+
+       mutex_lock(&dev->lock);
+
+       for (i = 0; i < dev->num_frames; i++)
+               if (dev->frame[i].vma_use_count) {
+                       em28xx_videodbg("VIDIOC_S_FMT failed. "
+                                       "Unmap the buffers first.\n");
+                       rc = -EINVAL;
+                       goto err;
+               }
+
+       /* stop io in case it is already in progress */
+       if (dev->stream == STREAM_ON) {
+               em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
+               rc = em28xx_stream_interrupt(dev);
+               if (rc < 0)
+                       goto err;
+       }
+
+       em28xx_release_buffers(dev);
+       dev->io = IO_NONE;
+
+       /* set new image size */
+       dev->width = f->fmt.pix.width;
+       dev->height = f->fmt.pix.height;
+       dev->frame_size = dev->width * dev->height * 2;
+       dev->field_size = dev->frame_size >> 1;
+       dev->bytesperline = dev->width * 2;
+       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+       /* FIXME: This is really weird! Why capture is starting with
+          this ioctl ???
+        */
+       em28xx_uninit_isoc(dev);
+       em28xx_set_alternate(dev);
+       em28xx_capture_start(dev, 1);
+       em28xx_resolution_set(dev);
+       em28xx_init_isoc(dev);
+       rc = 0;
+
+err:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+       struct v4l2_format f;
+       int                rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&dev->lock);
+       dev->norm = *norm;
+       mutex_unlock(&dev->lock);
+
+       /* Adjusts width/height, if needed */
+       f.fmt.pix.width = dev->width;
+       f.fmt.pix.height = dev->height;
+       vidioc_try_fmt_cap(file, priv, &f);
+
+       mutex_lock(&dev->lock);
+
+       /* set new image size */
+       dev->width = f.fmt.pix.width;
+       dev->height = f.fmt.pix.height;
+       dev->frame_size = dev->width * dev->height * 2;
+       dev->field_size = dev->frame_size >> 1;
+       dev->bytesperline = dev->width * 2;
+       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+       em28xx_resolution_set(dev);
+       em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static const char *iname[] = {
+       [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+       [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+       [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+       [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+       [EM28XX_VMUX_SVIDEO]     = "S-Video",
+       [EM28XX_VMUX_TELEVISION] = "Television",
+       [EM28XX_VMUX_CABLE]      = "Cable TV",
+       [EM28XX_VMUX_DVB]        = "DVB",
+       [EM28XX_VMUX_DEBUG]      = "for debug only",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+       unsigned int       n;
+
+       n = i->index;
+       if (n >= MAX_EM28XX_INPUT)
+               return -EINVAL;
+       if (0 == INPUT(n)->type)
+               return -EINVAL;
+
+       i->index = n;
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+
+       strcpy(i->name, iname[INPUT(n)->type]);
+
+       if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+               (EM28XX_VMUX_CABLE == INPUT(n)->type))
+               i->type = V4L2_INPUT_TYPE_TUNER;
+
+       i->std = dev->vdev->tvnorms;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+
+       *i = dev->ctl_input;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+       int                rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (i >= MAX_EM28XX_INPUT)
+               return -EINVAL;
+       if (0 == INPUT(i)->type)
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+
+       video_mux(dev, i);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       struct em28xx_fh   *fh    = priv;
+       struct em28xx      *dev   = fh->dev;
+       unsigned int        index = a->index;
+
+       if (a->index > 1)
+               return -EINVAL;
+
+       index = dev->ctl_ainput;
+
+       if (index == 0) {
+               strcpy(a->name, "Television");
        } else {
-               if (dev->io == IO_NONE) {
-                       if (!em28xx_request_buffers
-                           (dev, EM28XX_NUM_READ_FRAMES)) {
-                               em28xx_warn
-                                   ("poll() failed, not enough memory\n");
-                       } else {
-                               dev->io = IO_READ;
-                               dev->stream = STREAM_ON;
+               strcpy(a->name, "Line In");
+       }
+       a->capability = V4L2_AUDCAP_STEREO;
+       a->index = index;
+
+       return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+
+       if (a->index != dev->ctl_ainput)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   id  = qc->id;
+       int                   i;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       memset(qc, 0, sizeof(*qc));
+
+       qc->id = id;
+
+       if (!dev->has_msp34xx) {
+               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                       if (qc->id && qc->id == em28xx_qctrl[i].id) {
+                               memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
+                               return 0;
                        }
                }
+       }
+       mutex_lock(&dev->lock);
+       em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
+       mutex_unlock(&dev->lock);
 
-               if (dev->io == IO_READ) {
-                       em28xx_queue_unusedframes(dev);
-                       poll_wait(filp, &dev->wait_frame, wait);
+       if (qc->type)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+       mutex_lock(&dev->lock);
+
+       if (!dev->has_msp34xx)
+               rc = em28xx_get_ctrl(dev, ctrl);
+       else
+               rc = -EINVAL;
+
+       if (rc == -EINVAL) {
+               em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
+               rc = 0;
+       }
+
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       u8                    i;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&dev->lock);
+
+       if (dev->has_msp34xx)
+               em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
+       else {
+               rc = 1;
+               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                       if (ctrl->id == em28xx_qctrl[i].id) {
+                               if (ctrl->value < em28xx_qctrl[i].minimum ||
+                                   ctrl->value > em28xx_qctrl[i].maximum) {
+                                       rc = -ERANGE;
+                                       break;
+                               }
+
+                               rc = em28xx_set_ctrl(dev, ctrl);
+                               break;
+                       }
+               }
+       }
+
+       /* Control not found - try to send it to the attached devices */
+       if (rc == 1) {
+               em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
+               rc = 0;
+       }
+
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       strcpy(t->name, "Tuner");
+
+       mutex_lock(&dev->lock);
+
+       em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+
+       em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->frequency = dev->ctl_freq;
+
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (0 != f->tuner)
+               return -EINVAL;
+
+       if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+               return -EINVAL;
+       if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+
+       dev->ctl_freq = f->frequency;
+       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cc)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+
+       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cc->bounds.left = 0;
+       cc->bounds.top = 0;
+       cc->bounds.width = dev->width;
+       cc->bounds.height = dev->height;
+       cc->defrect = cc->bounds;
+       cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+       cc->pixelaspect.denominator = 59;
+
+       return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&dev->inqueue))
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+
+       if (unlikely(res_get(fh) < 0)) {
+               mutex_unlock(&dev->lock);
+               return -EBUSY;
+       }
+
+       dev->stream = STREAM_ON;        /* FIXME: Start video capture here? */
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+
+       if (dev->stream == STREAM_ON) {
+               em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
+               rc = em28xx_stream_interrupt(dev);
+               if (rc < 0) {
+                       mutex_unlock(&dev->lock);
+                       return rc;
+               }
+       }
+
+       em28xx_empty_framequeues(dev);
+
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+
+       strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+       strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+       strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+
+       cap->version = EM28XX_VERSION_CODE;
+
+       cap->capabilities =
+                       V4L2_CAP_SLICED_VBI_CAPTURE |
+                       V4L2_CAP_VIDEO_CAPTURE |
+                       V4L2_CAP_AUDIO |
+                       V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+
+       if (dev->tuner_type != TUNER_ABSENT)
+               cap->capabilities |= V4L2_CAP_TUNER;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *fmtd)
+{
+       if (fmtd->index != 0)
+               return -EINVAL;
+
+       fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       strcpy(fmtd->description, "Packed YUY2");
+       fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+       memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+
+       return 0;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
 
-                       if (!list_empty(&dev->outqueue))
-                               mask |= POLLIN | POLLRDNORM;
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
 
-                       mutex_unlock(&dev->fileop_lock);
+       mutex_lock(&dev->lock);
 
-                       return mask;
-               }
-       }
+       f->fmt.sliced.service_set = 0;
 
-       mutex_unlock(&dev->fileop_lock);
-       return POLLERR;
-}
+       em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
 
-/*
- * em28xx_vm_open()
- */
-static void em28xx_vm_open(struct vm_area_struct *vma)
-{
-       struct em28xx_frame_t *f = vma->vm_private_data;
-       f->vma_use_count++;
+       if (f->fmt.sliced.service_set == 0)
+               rc = -EINVAL;
+
+       mutex_unlock(&dev->lock);
+       return rc;
 }
 
-/*
- * em28xx_vm_close()
- */
-static void em28xx_vm_close(struct vm_area_struct *vma)
+static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
+                       struct v4l2_format *f)
 {
-       /* NOTE: buffers are not freed here */
-       struct em28xx_frame_t *f = vma->vm_private_data;
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
 
-       if (f->vma_use_count)
-               f->vma_use_count--;
-}
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
 
-static struct vm_operations_struct em28xx_vm_ops = {
-       .open = em28xx_vm_open,
-       .close = em28xx_vm_close,
-};
+       mutex_lock(&dev->lock);
+       em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+       mutex_unlock(&dev->lock);
 
-/*
- * em28xx_v4l2_mmap()
- */
-static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-       unsigned long size = vma->vm_end - vma->vm_start,
-           start = vma->vm_start;
-       void *pos;
-       u32 i;
+       if (f->fmt.sliced.service_set == 0)
+               return -EINVAL;
 
-       struct em28xx *dev = filp->private_data;
+       return 0;
+}
 
-       if (mutex_lock_interruptible(&dev->fileop_lock))
-               return -ERESTARTSYS;
 
-       if (dev->state & DEV_DISCONNECTED) {
-               em28xx_videodbg("mmap: device not present\n");
-               mutex_unlock(&dev->fileop_lock);
-               return -ENODEV;
-       }
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *rb)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       u32                   i;
+       int                   rc;
 
-       if (dev->state & DEV_MISCONFIGURED) {
-               em28xx_videodbg ("mmap: Device is misconfigured; close and "
-                                               "open it again\n");
-               mutex_unlock(&dev->fileop_lock);
-               return -EIO;
-       }
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
 
-       if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(dev->frame[0].buf.length)) {
-               mutex_unlock(&dev->fileop_lock);
+       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+               rb->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
-       }
 
-       for (i = 0; i < dev->num_frames; i++) {
-               if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == dev->num_frames) {
-               em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
-               mutex_unlock(&dev->fileop_lock);
+       if (dev->io == IO_READ) {
+               em28xx_videodbg("method is set to read;"
+                               " close and open the device again to"
+                               " choose the mmap I/O method\n");
                return -EINVAL;
        }
 
-       /* VM_IO is eventually going to replace PageReserved altogether */
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
+       for (i = 0; i < dev->num_frames; i++)
+               if (dev->frame[i].vma_use_count) {
+                       em28xx_videodbg("VIDIOC_REQBUFS failed; "
+                                       "previous buffers are still mapped\n");
+                       return -EINVAL;
+               }
 
-       pos = dev->frame[i].bufmem;
-       while (size > 0) {      /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       em28xx_videodbg("mmap: vm_insert_page failed\n");
-                       mutex_unlock(&dev->fileop_lock);
-                       return -EAGAIN;
+       mutex_lock(&dev->lock);
+
+       if (dev->stream == STREAM_ON) {
+               em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+               rc = em28xx_stream_interrupt(dev);
+               if (rc < 0) {
+                       mutex_unlock(&dev->lock);
+                       return rc;
                }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
        }
 
-       vma->vm_ops = &em28xx_vm_ops;
-       vma->vm_private_data = &dev->frame[i];
+       em28xx_empty_framequeues(dev);
 
-       em28xx_vm_open(vma);
-       mutex_unlock(&dev->fileop_lock);
+       em28xx_release_buffers(dev);
+       if (rb->count)
+               rb->count = em28xx_request_buffers(dev, rb->count);
+
+       dev->frame_current = NULL;
+       dev->io = rb->count ? IO_MMAP : IO_NONE;
+
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
-/*
- * em28xx_get_ctrl()
- * return the current saturation, brightness or contrast, mute state
- */
-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *b)
 {
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = dev->mute;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = dev->volume;
-               return 0;
-       default:
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+               b->index >= dev->num_frames || dev->io != IO_MMAP)
                return -EINVAL;
-       }
+
+       mutex_lock(&dev->lock);
+
+       memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+
+       if (dev->frame[b->index].vma_use_count)
+               b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (dev->frame[b->index].state == F_DONE)
+               b->flags |= V4L2_BUF_FLAG_DONE;
+       else if (dev->frame[b->index].state != F_UNUSED)
+               b->flags |= V4L2_BUF_FLAG_QUEUED;
+
+       mutex_unlock(&dev->lock);
+       return 0;
 }
 
-/*
- * em28xx_set_ctrl()
- * mute or set new saturation, brightness or contrast
- */
-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value != dev->mute) {
-                       dev->mute = ctrl->value;
-                       em28xx_audio_usb_mute(dev, ctrl->value);
-                       return em28xx_audio_analog_set(dev);
-               }
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               dev->volume = ctrl->value;
-               return em28xx_audio_analog_set(dev);
-       default:
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       unsigned long         lock_flags;
+       int                   rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE  || dev->io != IO_MMAP ||
+                                               b->index >= dev->num_frames)
                return -EINVAL;
-       }
+
+       if (dev->frame[b->index].state != F_UNUSED)
+               return -EAGAIN;
+
+       dev->frame[b->index].state = F_QUEUED;
+
+       /* add frame to fifo */
+       spin_lock_irqsave(&dev->queue_lock, lock_flags);
+       list_add_tail(&dev->frame[b->index].frame, &dev->inqueue);
+       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+       return 0;
 }
 
-/*
- * em28xx_stream_interrupt()
- * stops streaming
- */
-static int em28xx_stream_interrupt(struct em28xx *dev)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
-       int ret = 0;
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       int                   rc;
+       struct em28xx_frame_t *f;
+       unsigned long         lock_flags;
 
-       /* stop reading from the device */
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
 
-       dev->stream = STREAM_INTERRUPT;
-       ret = wait_event_timeout(dev->wait_stream,
-                                (dev->stream == STREAM_OFF) ||
-                                (dev->state & DEV_DISCONNECTED),
-                                EM28XX_URB_TIMEOUT);
-       if (dev->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (ret) {
-               dev->state |= DEV_MISCONFIGURED;
-               em28xx_videodbg("device is misconfigured; close and "
-                       "open /dev/video%d again\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
-               return ret;
+       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&dev->outqueue)) {
+               if (dev->stream == STREAM_OFF)
+                       return -EINVAL;
+
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               rc = wait_event_interruptible(dev->wait_frame,
+                                       (!list_empty(&dev->outqueue)) ||
+                                       (dev->state & DEV_DISCONNECTED));
+               if (rc)
+                       return rc;
+
+               if (dev->state & DEV_DISCONNECTED)
+                       return -ENODEV;
        }
 
+       spin_lock_irqsave(&dev->queue_lock, lock_flags);
+       f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame);
+       list_del(dev->outqueue.next);
+       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+       memcpy(b, &f->buf, sizeof(*b));
+
+       if (f->vma_use_count)
+               b->flags |= V4L2_BUF_FLAG_MAPPED;
+
        return 0;
 }
 
-static int em28xx_set_norm(struct em28xx *dev, int width, int height)
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void  *priv,
+                         struct v4l2_capability *cap)
 {
-       unsigned int hscale, vscale;
-       unsigned int maxh, maxw;
+       struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 
-       maxw = norm_maxw(dev);
-       maxh = norm_maxh(dev);
+       strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+       strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+       strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
 
-       /* width must even because of the YUYV format */
-       /* height must be even because of interlacing */
-       height &= 0xfffe;
-       width &= 0xfffe;
+       cap->version = EM28XX_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
 
-       if (height < 32)
-               height = 32;
-       if (height > maxh)
-               height = maxh;
-       if (width < 48)
-               width = 48;
-       if (width > maxw)
-               width = maxw;
+static int radio_g_tuner(struct file *file, void *priv,
+                        struct v4l2_tuner *t)
+{
+       struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 
-       if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
-               hscale = 0x3fff;
-       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+       if (unlikely(t->index > 0))
+               return -EINVAL;
 
-       if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
-               vscale = 0x3fff;
-       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
 
-       /* set new image size */
-       dev->width = width;
-       dev->height = height;
-       dev->frame_size = dev->width * dev->height * 2;
-       dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
-       dev->bytesperline = dev->width * 2;
-       dev->hscale = hscale;
-       dev->vscale = vscale;
+       em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+       return 0;
+}
 
-       em28xx_resolution_set(dev);
+static int radio_enum_input(struct file *file, void *priv,
+                           struct v4l2_input *i)
+{
+       if (i->index != 0)
+               return -EINVAL;
+       strcpy(i->name, "Radio");
+       i->type = V4L2_INPUT_TYPE_TUNER;
 
        return 0;
 }
 
-static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format)
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
-       em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
-               (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
-               "V4L2_BUF_TYPE_VIDEO_CAPTURE" :
-               (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?
-               "V4L2_BUF_TYPE_VBI_CAPTURE" :
-               (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?
-               "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :
-               "not supported");
+       if (unlikely(a->index))
+               return -EINVAL;
 
-       switch (format->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               format->fmt.pix.width = dev->width;
-               format->fmt.pix.height = dev->height;
-               format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-               format->fmt.pix.bytesperline = dev->bytesperline;
-               format->fmt.pix.sizeimage = dev->frame_size;
-               format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-               format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;       /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+       strcpy(a->name, "Radio");
+       return 0;
+}
 
-               em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
-                       dev->height);
-               break;
-       }
+static int radio_s_tuner(struct file *file, void *priv,
+                        struct v4l2_tuner *t)
+{
+       struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 
-       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-       {
-               format->fmt.sliced.service_set=0;
+       if (0 != t->index)
+               return -EINVAL;
 
-               em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+       em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
 
-               if (format->fmt.sliced.service_set==0)
-                       return -EINVAL;
+       return 0;
+}
 
-               break;
-       }
+static int radio_s_audio(struct file *file, void *fh,
+                        struct v4l2_audio *a)
+{
+       return 0;
+}
 
-       default:
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+       return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+                          struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       if (qc->id <  V4L2_CID_BASE ||
+               qc->id >= V4L2_CID_LASTP1)
                return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+               if (qc->id && qc->id == em28xx_qctrl[i].id) {
+                       memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
+                       return 0;
+               }
        }
-       return (0);
+
+       return -EINVAL;
 }
 
-static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 {
-       u32 i;
-       int ret = 0;
-       int width = format->fmt.pix.width;
-       int height = format->fmt.pix.height;
-       unsigned int hscale, vscale;
-       unsigned int maxh, maxw;
+       int minor = iminor(inode);
+       int errCode = 0, radio = 0;
+       struct em28xx *h,*dev = NULL;
+       struct em28xx_fh *fh;
 
-       maxw = norm_maxw(dev);
-       maxh = norm_maxh(dev);
+       list_for_each_entry(h, &em28xx_devlist, devlist) {
+               if (h->vdev->minor == minor) {
+                       dev  = h;
+                       dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               }
+               if (h->vbi_dev->minor == minor) {
+                       dev  = h;
+                       dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               }
+               if (h->radio_dev &&
+                   h->radio_dev->minor == minor) {
+                       radio = 1;
+                       dev   = h;
+               }
+       }
+       if (NULL == dev)
+               return -ENODEV;
+
+       em28xx_videodbg("open minor=%d type=%s users=%d\n",
+                               minor,v4l2_type_names[dev->type],dev->users);
+
+       fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+
+       if (!fh) {
+               em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+               return -ENOMEM;
+       }
+       mutex_lock(&dev->lock);
+       fh->dev = dev;
+       fh->radio = radio;
+       filp->private_data = fh;
+
+       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+               em28xx_set_alternate(dev);
+
+               dev->width = norm_maxw(dev);
+               dev->height = norm_maxh(dev);
+               dev->frame_size = dev->width * dev->height * 2;
+               dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+               dev->bytesperline = dev->width * 2;
+               dev->hscale = 0;
+               dev->vscale = 0;
 
-       em28xx_videodbg("%s: type=%s\n",
-                       cmd == VIDIOC_TRY_FMT ?
-                       "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
-                       format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-                       "V4L2_BUF_TYPE_VIDEO_CAPTURE" :
-                       format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
-                       "V4L2_BUF_TYPE_VBI_CAPTURE " :
-                       "not supported");
+               em28xx_capture_start(dev, 1);
+               em28xx_resolution_set(dev);
 
-       if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-               em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
 
-               if (format->fmt.sliced.service_set==0)
-                       return -EINVAL;
+               /* start the transfer */
+               errCode = em28xx_init_isoc(dev);
+               if (errCode)
+                       goto err;
 
-               return 0;
+               em28xx_empty_framequeues(dev);
+       }
+       if (fh->radio) {
+               em28xx_videodbg("video_open: setting radio device\n");
+               em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
        }
 
+       dev->users++;
 
-       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       em28xx_videodbg("%s: requested %dx%d\n",
-               cmd == VIDIOC_TRY_FMT ?
-               "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
-               format->fmt.pix.width, format->fmt.pix.height);
+err:
+       mutex_unlock(&dev->lock);
+       return errCode;
+}
 
-       /* FIXME: Move some code away from here */
-       /* width must even because of the YUYV format */
-       /* height must be even because of interlacing */
-       height &= 0xfffe;
-       width &= 0xfffe;
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+static void em28xx_release_resources(struct em28xx *dev)
+{
 
-       if (height < 32)
-               height = 32;
-       if (height > maxh)
-               height = maxh;
-       if (width < 48)
-               width = 48;
-       if (width > maxw)
-               width = maxw;
+       /*FIXME: I2C IR should be disconnected */
 
-       if(dev->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 */
-               if(width == maxw && height == maxh)
-                       width /= 2;
+       em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
+                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
+       list_del(&dev->devlist);
+       if (dev->radio_dev) {
+               if (-1 != dev->radio_dev->minor)
+                       video_unregister_device(dev->radio_dev);
+               else
+                       video_device_release(dev->radio_dev);
+               dev->radio_dev = NULL;
+       }
+       if (dev->vbi_dev) {
+               if (-1 != dev->vbi_dev->minor)
+                       video_unregister_device(dev->vbi_dev);
+               else
+                       video_device_release(dev->vbi_dev);
+               dev->vbi_dev = NULL;
+       }
+       if (dev->vdev) {
+               if (-1 != dev->vdev->minor)
+                       video_unregister_device(dev->vdev);
+               else
+                       video_device_release(dev->vdev);
+               dev->vdev = NULL;
        }
+       em28xx_i2c_unregister(dev);
+       usb_put_dev(dev->udev);
 
-       if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
-               hscale = 0x3fff;
+       /* Mark device as unused */
+       em28xx_devused&=~(1<<dev->devno);
+}
 
-       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ */
+static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+{
+       struct em28xx_fh *fh  = filp->private_data;
+       struct em28xx    *dev = fh->dev;
+       int              errCode;
 
-       if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
-               vscale = 0x3fff;
+       em28xx_videodbg("users=%d\n", dev->users);
 
-       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
 
-       format->fmt.pix.width = width;
-       format->fmt.pix.height = height;
-       format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       format->fmt.pix.bytesperline = width * 2;
-       format->fmt.pix.sizeimage = width * 2 * height;
-       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       if (res_check(fh))
+               res_free(fh);
 
-       em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
-               cmd == VIDIOC_TRY_FMT ?
-               "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",
-               format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);
+       mutex_lock(&dev->lock);
 
-       if (cmd == VIDIOC_TRY_FMT)
-               return 0;
+       if (dev->users == 1) {
+               em28xx_uninit_isoc(dev);
+               em28xx_release_buffers(dev);
+               dev->io = IO_NONE;
 
-       for (i = 0; i < dev->num_frames; i++)
-               if (dev->frame[i].vma_use_count) {
-                       em28xx_videodbg("VIDIOC_S_FMT failed. "
-                               "Unmap the buffers first.\n");
-                       return -EINVAL;
+               /* the device is already disconnect,
+                  free the remaining resources */
+               if (dev->state & DEV_DISCONNECTED) {
+                       em28xx_release_resources(dev);
+                       mutex_unlock(&dev->lock);
+                       kfree(dev);
+                       return 0;
                }
 
-       /* stop io in case it is already in progress */
-       if (dev->stream == STREAM_ON) {
-               em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
-               if ((ret = em28xx_stream_interrupt(dev)))
-                       return ret;
+               /* set alternate 0 */
+               dev->alt = 0;
+               em28xx_videodbg("setting alternate 0\n");
+               errCode = usb_set_interface(dev->udev, 0, 0);
+               if (errCode < 0) {
+                       em28xx_errdev("cannot change alternate number to "
+                                       "0 (error=%i)\n", errCode);
+               }
        }
-
-       em28xx_release_buffers(dev);
-       dev->io = IO_NONE;
-
-       /* set new image size */
-       dev->width = width;
-       dev->height = height;
-       dev->frame_size = dev->width * dev->height * 2;
-       dev->field_size = dev->frame_size >> 1;
-       dev->bytesperline = dev->width * 2;
-       dev->hscale = hscale;
-       dev->vscale = vscale;
-       em28xx_uninit_isoc(dev);
-       em28xx_set_alternate(dev);
-       em28xx_capture_start(dev, 1);
-       em28xx_resolution_set(dev);
-       em28xx_init_isoc(dev);
-
+       kfree(fh);
+       dev->users--;
+       wake_up_interruptible_nr(&dev->open, 1);
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
 /*
- * em28xx_v4l2_do_ioctl()
- * This function is _not_ called directly, but from
- * em28xx_v4l2_ioctl. Userspace
- * copying is done already, arg is a kernel pointer.
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
  */
-static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
-                          struct em28xx *dev, unsigned int cmd, void *arg,
-                          v4l2_kioctl driver_ioctl)
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+                loff_t * f_pos)
 {
-       int ret;
-
-       switch (cmd) {
-               /* ---------- tv norms ---------- */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-               unsigned int i;
-
-               i = e->index;
-               if (i >= TVNORMS)
-                       return -EINVAL;
-               ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                               tvnorms[e->index].name);
-               e->index = i;
-               if (ret < 0)
-                       return ret;
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-
-               *id = dev->tvnorm->id;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               unsigned int i;
+       struct em28xx_frame_t *f, *i;
+       unsigned long lock_flags;
+       int ret = 0;
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev = fh->dev;
 
-               for (i = 0; i < TVNORMS; i++)
-                       if (*id == tvnorms[i].id)
-                               break;
-               if (i == TVNORMS)
-                       for (i = 0; i < TVNORMS; i++)
-                               if (*id & tvnorms[i].id)
-                                       break;
-               if (i == TVNORMS)
-                       return -EINVAL;
+       /* FIXME: read() is not prepared to allow changing the video
+          resolution while streaming. Seems a bug at em28xx_set_fmt
+        */
 
-               mutex_lock(&dev->lock);
-               dev->tvnorm = &tvnorms[i];
+       if (unlikely(res_get(fh) < 0))
+               return -EBUSY;
 
-               em28xx_set_norm(dev, dev->width, dev->height);
+       mutex_lock(&dev->lock);
 
-               em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
-                                       &dev->tvnorm->id);
+       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
 
+       if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
+               em28xx_videodbg("not supported yet! ...\n");
+               if (copy_to_user(buf, "", 1)) {
+                       mutex_unlock(&dev->lock);
+                       return -EFAULT;
+               }
                mutex_unlock(&dev->lock);
-
-               return 0;
+               return (1);
        }
-
-       /* ------ input switching ---------- */
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-               unsigned int n;
-               static const char *iname[] = {
-                       [EM28XX_VMUX_COMPOSITE1] = "Composite1",
-                       [EM28XX_VMUX_COMPOSITE2] = "Composite2",
-                       [EM28XX_VMUX_COMPOSITE3] = "Composite3",
-                       [EM28XX_VMUX_COMPOSITE4] = "Composite4",
-                       [EM28XX_VMUX_SVIDEO] = "S-Video",
-                       [EM28XX_VMUX_TELEVISION] = "Television",
-                       [EM28XX_VMUX_CABLE] = "Cable TV",
-                       [EM28XX_VMUX_DVB] = "DVB",
-                       [EM28XX_VMUX_DEBUG] = "for debug only",
-               };
-
-               n = i->index;
-               if (n >= MAX_EM28XX_INPUT)
-                       return -EINVAL;
-               if (0 == INPUT(n)->type)
-                       return -EINVAL;
-               memset(i, 0, sizeof(*i));
-               i->index = n;
-               i->type = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(i->name, iname[INPUT(n)->type]);
-               if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
-                       (EM28XX_VMUX_CABLE == INPUT(n)->type))
-                       i->type = V4L2_INPUT_TYPE_TUNER;
-               for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
-                       i->std |= tvnorms[n].id;
-               return 0;
+       if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+               em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
+               em28xx_videodbg("not supported yet! ...\n");
+               if (copy_to_user(buf, "", 1)) {
+                       mutex_unlock(&dev->lock);
+                       return -EFAULT;
+               }
+               mutex_unlock(&dev->lock);
+               return (1);
        }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = dev->ctl_input;
 
-               return 0;
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_videodbg("device not present\n");
+               mutex_unlock(&dev->lock);
+               return -ENODEV;
        }
-       case VIDIOC_S_INPUT:
-       {
-               int *index = arg;
-
-               if (*index >= MAX_EM28XX_INPUT)
-                       return -EINVAL;
-               if (0 == INPUT(*index)->type)
-                       return -EINVAL;
 
-               mutex_lock(&dev->lock);
-               video_mux(dev, *index);
+       if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_videodbg("device misconfigured; close and open it again\n");
                mutex_unlock(&dev->lock);
-
-               return 0;
+               return -EIO;
        }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
-               unsigned int index = a->index;
 
-               if (a->index > 1)
-                       return -EINVAL;
-               memset(a, 0, sizeof(*a));
-               index = dev->ctl_ainput;
+       if (dev->io == IO_MMAP) {
+               em28xx_videodbg ("IO method is set to mmap; close and open"
+                               " the device again to choose the read method\n");
+               mutex_unlock(&dev->lock);
+               return -EINVAL;
+       }
 
-               if (index == 0) {
-                       strcpy(a->name, "Television");
-               } else {
-                       strcpy(a->name, "Line In");
+       if (dev->io == IO_NONE) {
+               if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
+                       em28xx_errdev("read failed, not enough memory\n");
+                       mutex_unlock(&dev->lock);
+                       return -ENOMEM;
                }
-               a->capability = V4L2_AUDCAP_STEREO;
-               a->index = index;
-               return 0;
+               dev->io = IO_READ;
+               dev->stream = STREAM_ON;
+               em28xx_queue_unusedframes(dev);
        }
-       case VIDIOC_S_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
-
-               if (a->index != dev->ctl_ainput)
-                       return -EINVAL;
 
+       if (!count) {
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
-       /* --- controls ---------------------------------------------- */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-               int i, id=qc->id;
-
-               memset(qc,0,sizeof(*qc));
-               qc->id=id;
-
-               if (!dev->has_msp34xx) {
-                       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                               if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                                       memcpy(qc, &(em28xx_qctrl[i]),
-                                       sizeof(*qc));
-                                       return 0;
-                               }
-                       }
+       if (list_empty(&dev->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&dev->lock);
+                       return -EAGAIN;
                }
-               em28xx_i2c_call_clients(dev,cmd,qc);
-               if (qc->type)
-                       return 0;
-               else
-                       return -EINVAL;
+               ret = wait_event_interruptible
+                   (dev->wait_frame,
+                    (!list_empty(&dev->outqueue)) ||
+                    (dev->state & DEV_DISCONNECTED));
+               if (ret) {
+                       mutex_unlock(&dev->lock);
+                       return ret;
+               }
+               if (dev->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&dev->lock);
+                       return -ENODEV;
+               }
+               dev->video_bytesread = 0;
        }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               int retval=-EINVAL;
 
-               if (!dev->has_msp34xx)
-                       retval=em28xx_get_ctrl(dev, ctrl);
-               if (retval==-EINVAL) {
-                       em28xx_i2c_call_clients(dev,cmd,arg);
-                       return 0;
-               } else return retval;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               u8 i;
-
-               if (!dev->has_msp34xx){
-                       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                               if (ctrl->id == em28xx_qctrl[i].id) {
-                                       if (ctrl->value <
-                                       em28xx_qctrl[i].minimum
-                                       || ctrl->value >
-                                       em28xx_qctrl[i].maximum)
-                                               return -ERANGE;
-                                       return em28xx_set_ctrl(dev, ctrl);
-                               }
-                       }
-               }
+       f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
 
-               em28xx_i2c_call_clients(dev,cmd,arg);
-               return 0;
-       }
-       /* --- tuner ioctls ------------------------------------------ */
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       em28xx_queue_unusedframes(dev);
 
-               if (0 != t->index)
-                       return -EINVAL;
+       if (count > f->buf.length)
+               count = f->buf.length;
 
-               memset(t, 0, sizeof(*t));
-               strcpy(t->name, "Tuner");
-               mutex_lock(&dev->lock);
-               /* let clients fill in the remainder of this struct */
-               em28xx_i2c_call_clients(dev, cmd, t);
-               mutex_unlock(&dev->lock);
-               em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
-                               t->afc);
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       if ((dev->video_bytesread + count) > dev->frame_size)
+               count = dev->frame_size - dev->video_bytesread;
 
-               if (0 != t->index)
-                       return -EINVAL;
-               mutex_lock(&dev->lock);
-               /* let clients handle this */
-               em28xx_i2c_call_clients(dev, cmd, t);
-               mutex_unlock(&dev->lock);
-               return 0;
+       if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
+               em28xx_err("Error while copying to user\n");
+               return -EFAULT;
        }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       dev->video_bytesread += count;
 
-               memset(f, 0, sizeof(*f));
-               f->type = V4L2_TUNER_ANALOG_TV;
-               f->frequency = dev->ctl_freq;
+       if (dev->video_bytesread == dev->frame_size) {
+               spin_lock_irqsave(&dev->queue_lock, lock_flags);
+               list_for_each_entry(i, &dev->outqueue, frame)
+                                   i->state = F_UNUSED;
+               INIT_LIST_HEAD(&dev->outqueue);
+               spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
 
-               return 0;
+               em28xx_queue_unusedframes(dev);
+               dev->video_bytesread = 0;
        }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
 
-               if (0 != f->tuner)
-                       return -EINVAL;
+       *f_pos += count;
 
-               if (V4L2_TUNER_ANALOG_TV != f->type)
-                       return -EINVAL;
+       mutex_unlock(&dev->lock);
 
-               mutex_lock(&dev->lock);
-               dev->ctl_freq = f->frequency;
-               em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cc = arg;
+       return count;
+}
 
-               if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               cc->bounds.left = 0;
-               cc->bounds.top = 0;
-               cc->bounds.width = dev->width;
-               cc->bounds.height = dev->height;
-               cc->defrect = cc->bounds;
-               cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
-               cc->pixelaspect.denominator = 59;
-               return 0;
-       }
-       case VIDIOC_STREAMON:
-       {
-               int *type = arg;
+/*
+ * em28xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+{
+       unsigned int mask = 0;
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev = fh->dev;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-                       || dev->io != IO_MMAP)
-                       return -EINVAL;
+       if (unlikely(res_get(fh) < 0))
+               return POLLERR;
 
-               if (list_empty(&dev->inqueue))
-                       return -EINVAL;
+       mutex_lock(&dev->lock);
 
-               dev->stream = STREAM_ON;        /* FIXME: Start video capture here? */
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_videodbg("device not present\n");
+       } else if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_videodbg("device is misconfigured; close and open it again\n");
+       } else {
+               if (dev->io == IO_NONE) {
+                       if (!em28xx_request_buffers
+                           (dev, EM28XX_NUM_READ_FRAMES)) {
+                               em28xx_warn
+                                   ("poll() failed, not enough memory\n");
+                       } else {
+                               dev->io = IO_READ;
+                               dev->stream = STREAM_ON;
+                       }
+               }
 
-               em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+               if (dev->io == IO_READ) {
+                       em28xx_queue_unusedframes(dev);
+                       poll_wait(filp, &dev->wait_frame, wait);
 
-               return 0;
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int *type = arg;
-               int ret;
+                       if (!list_empty(&dev->outqueue))
+                               mask |= POLLIN | POLLRDNORM;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-                       || dev->io != IO_MMAP)
-                       return -EINVAL;
+                       mutex_unlock(&dev->lock);
 
-               if (dev->stream == STREAM_ON) {
-                       em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
-                       if ((ret = em28xx_stream_interrupt(dev)))
-                               return ret;
+                       return mask;
                }
-               em28xx_empty_framequeues(dev);
-
-               return 0;
        }
-       default:
-               return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
-                                                 driver_ioctl);
-       }
-       return 0;
+
+       mutex_unlock(&dev->lock);
+       return POLLERR;
 }
 
 /*
- * em28xx_v4l2_do_ioctl()
- * This function is _not_ called directly, but from
- * em28xx_v4l2_ioctl. Userspace
- * copying is done already, arg is a kernel pointer.
+ * em28xx_v4l2_mmap()
  */
-static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
-                                unsigned int cmd, void *arg)
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh *fh    = filp->private_data;
+       struct em28xx    *dev   = fh->dev;
+       unsigned long    size   = vma->vm_end - vma->vm_start;
+       unsigned long    start  = vma->vm_start;
+       void             *pos;
+       u32              i;
+
+       if (unlikely(res_get(fh) < 0))
+               return -EBUSY;
 
-       if (!dev)
-               return -ENODEV;
+       mutex_lock(&dev->lock);
 
-       if (video_debug > 1)
-               v4l_print_ioctl(dev->name,cmd);
-
-       switch (cmd) {
-
-               /* --- capabilities ------------------------------------------ */
-       case VIDIOC_QUERYCAP:
-               {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap, 0, sizeof(*cap));
-               strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
-               strlcpy(cap->card, em28xx_boards[dev->model].name,
-                       sizeof(cap->card));
-               strlcpy(cap->bus_info, dev->udev->dev.bus_id,
-                       sizeof(cap->bus_info));
-               cap->version = EM28XX_VERSION_CODE;
-               cap->capabilities =
-                               V4L2_CAP_SLICED_VBI_CAPTURE |
-                               V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_AUDIO |
-                               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-               if (dev->has_tuner)
-                       cap->capabilities |= V4L2_CAP_TUNER;
-               return 0;
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_videodbg("mmap: device not present\n");
+               mutex_unlock(&dev->lock);
+               return -ENODEV;
        }
-       /* --- capture ioctls ---------------------------------------- */
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *fmtd = arg;
 
-               if (fmtd->index != 0)
-                       return -EINVAL;
-               memset(fmtd, 0, sizeof(*fmtd));
-               fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               strcpy(fmtd->description, "Packed YUY2");
-               fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-               memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
-               return 0;
+       if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_videodbg ("mmap: Device is misconfigured; close and "
+                                               "open it again\n");
+               mutex_unlock(&dev->lock);
+               return -EIO;
        }
-       case VIDIOC_G_FMT:
-               return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
 
-       case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers *rb = arg;
-               u32 i;
-               int ret;
+       if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
+               mutex_unlock(&dev->lock);
+               return -EINVAL;
+       }
 
-               if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                       rb->memory != V4L2_MEMORY_MMAP)
-                       return -EINVAL;
+       if (size > PAGE_ALIGN(dev->frame[0].buf.length))
+               size = PAGE_ALIGN(dev->frame[0].buf.length);
 
-               if (dev->io == IO_READ) {
-                       em28xx_videodbg ("method is set to read;"
-                               " close and open the device again to"
-                               " choose the mmap I/O method\n");
-                       return -EINVAL;
-               }
+       for (i = 0; i < dev->num_frames; i++) {
+               if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == dev->num_frames) {
+               em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
+               mutex_unlock(&dev->lock);
+               return -EINVAL;
+       }
 
-               for (i = 0; i < dev->num_frames; i++)
-                       if (dev->frame[i].vma_use_count) {
-                               em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
-                               return -EINVAL;
-                       }
+       /* VM_IO is eventually going to replace PageReserved altogether */
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
 
-               if (dev->stream == STREAM_ON) {
-                       em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
-                       if ((ret = em28xx_stream_interrupt(dev)))
-                               return ret;
+       pos = dev->frame[i].bufmem;
+       while (size > 0) {      /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       em28xx_videodbg("mmap: vm_insert_page failed\n");
+                       mutex_unlock(&dev->lock);
+                       return -EAGAIN;
                }
-
-               em28xx_empty_framequeues(dev);
-
-               em28xx_release_buffers(dev);
-               if (rb->count)
-                       rb->count =
-                               em28xx_request_buffers(dev, rb->count);
-
-               dev->frame_current = NULL;
-
-               em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
-                                               rb->count);
-               dev->io = rb->count ? IO_MMAP : IO_NONE;
-               return 0;
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
        }
-       case VIDIOC_QUERYBUF:
-       {
-               struct v4l2_buffer *b = arg;
 
-               if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                       b->index >= dev->num_frames || dev->io != IO_MMAP)
-                       return -EINVAL;
+       vma->vm_ops = &em28xx_vm_ops;
+       vma->vm_private_data = &dev->frame[i];
 
-               memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+       em28xx_vm_open(vma);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
 
-               if (dev->frame[b->index].vma_use_count) {
-                       b->flags |= V4L2_BUF_FLAG_MAPPED;
-               }
-               if (dev->frame[b->index].state == F_DONE)
-                       b->flags |= V4L2_BUF_FLAG_DONE;
-               else if (dev->frame[b->index].state != F_UNUSED)
-                       b->flags |= V4L2_BUF_FLAG_QUEUED;
-               return 0;
-       }
-       case VIDIOC_QBUF:
-       {
-               struct v4l2_buffer *b = arg;
-               unsigned long lock_flags;
+static const struct file_operations em28xx_v4l_fops = {
+       .owner         = THIS_MODULE,
+       .open          = em28xx_v4l2_open,
+       .release       = em28xx_v4l2_close,
+       .read          = em28xx_v4l2_read,
+       .poll          = em28xx_v4l2_poll,
+       .mmap          = em28xx_v4l2_mmap,
+       .ioctl         = video_ioctl2,
+       .llseek        = no_llseek,
+       .compat_ioctl  = v4l_compat_ioctl32,
+};
 
-               if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                       b->index >= dev->num_frames || dev->io != IO_MMAP) {
-                       return -EINVAL;
-               }
+static const struct file_operations radio_fops = {
+       .owner         = THIS_MODULE,
+       .open          = em28xx_v4l2_open,
+       .release       = em28xx_v4l2_close,
+       .ioctl         = video_ioctl2,
+       .compat_ioctl  = v4l_compat_ioctl32,
+       .llseek        = no_llseek,
+};
 
-               if (dev->frame[b->index].state != F_UNUSED) {
-                       return -EAGAIN;
-               }
-               dev->frame[b->index].state = F_QUEUED;
+static const struct video_device em28xx_video_template = {
+       .fops                       = &em28xx_v4l_fops,
+       .release                    = video_device_release,
+
+       .minor                      = -1,
+       .vidioc_querycap            = vidioc_querycap,
+       .vidioc_enum_fmt_cap        = vidioc_enum_fmt_cap,
+       .vidioc_g_fmt_cap           = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_cap         = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap           = vidioc_s_fmt_cap,
+       .vidioc_g_audio             = vidioc_g_audio,
+       .vidioc_s_audio             = vidioc_s_audio,
+       .vidioc_cropcap             = vidioc_cropcap,
+
+       .vidioc_g_fmt_vbi_capture   = vidioc_g_fmt_vbi_capture,
+       .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
+       .vidioc_s_fmt_vbi_capture   = vidioc_try_set_vbi_capture,
+
+       .vidioc_reqbufs             = vidioc_reqbufs,
+       .vidioc_querybuf            = vidioc_querybuf,
+       .vidioc_qbuf                = vidioc_qbuf,
+       .vidioc_dqbuf               = vidioc_dqbuf,
+       .vidioc_s_std               = vidioc_s_std,
+       .vidioc_enum_input          = vidioc_enum_input,
+       .vidioc_g_input             = vidioc_g_input,
+       .vidioc_s_input             = vidioc_s_input,
+       .vidioc_queryctrl           = vidioc_queryctrl,
+       .vidioc_g_ctrl              = vidioc_g_ctrl,
+       .vidioc_s_ctrl              = vidioc_s_ctrl,
+       .vidioc_streamon            = vidioc_streamon,
+       .vidioc_streamoff           = vidioc_streamoff,
+       .vidioc_g_tuner             = vidioc_g_tuner,
+       .vidioc_s_tuner             = vidioc_s_tuner,
+       .vidioc_g_frequency         = vidioc_g_frequency,
+       .vidioc_s_frequency         = vidioc_s_frequency,
+
+       .tvnorms                    = V4L2_STD_ALL,
+       .current_norm               = V4L2_STD_PAL,
+};
 
-               /* add frame to fifo */
-               spin_lock_irqsave(&dev->queue_lock, lock_flags);
-               list_add_tail(&dev->frame[b->index].frame,
-                               &dev->inqueue);
-               spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+static struct video_device em28xx_radio_template = {
+       .name                 = "em28xx-radio",
+       .type                 = VID_TYPE_TUNER,
+       .fops                 = &radio_fops,
+       .minor                = -1,
+       .vidioc_querycap      = radio_querycap,
+       .vidioc_g_tuner       = radio_g_tuner,
+       .vidioc_enum_input    = radio_enum_input,
+       .vidioc_g_audio       = radio_g_audio,
+       .vidioc_s_tuner       = radio_s_tuner,
+       .vidioc_s_audio       = radio_s_audio,
+       .vidioc_s_input       = radio_s_input,
+       .vidioc_queryctrl     = radio_queryctrl,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+};
 
-               return 0;
-       }
-       case VIDIOC_DQBUF:
-       {
-               struct v4l2_buffer *b = arg;
-               struct em28xx_frame_t *f;
-               unsigned long lock_flags;
-               int ret = 0;
+/******************************** usb interface *****************************************/
 
-               if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-                       || dev->io != IO_MMAP)
-                       return -EINVAL;
 
-               if (list_empty(&dev->outqueue)) {
-                       if (dev->stream == STREAM_OFF)
-                               return -EINVAL;
-                       if (filp->f_flags & O_NONBLOCK)
-                               return -EAGAIN;
-                       ret = wait_event_interruptible
-                               (dev->wait_frame,
-                               (!list_empty(&dev->outqueue)) ||
-                               (dev->state & DEV_DISCONNECTED));
-                       if (ret)
-                               return ret;
-                       if (dev->state & DEV_DISCONNECTED)
-                               return -ENODEV;
-               }
+static LIST_HEAD(em28xx_extension_devlist);
+static DEFINE_MUTEX(em28xx_extension_devlist_lock);
 
-               spin_lock_irqsave(&dev->queue_lock, lock_flags);
-               f = list_entry(dev->outqueue.next,
-                               struct em28xx_frame_t, frame);
-               list_del(dev->outqueue.next);
-               spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+int em28xx_register_extension(struct em28xx_ops *ops)
+{
+       struct em28xx *h, *dev = NULL;
 
-               f->state = F_UNUSED;
-               memcpy(b, &f->buf, sizeof(*b));
+       list_for_each_entry(h, &em28xx_devlist, devlist)
+               dev = h;
 
-               if (f->vma_use_count)
-                       b->flags |= V4L2_BUF_FLAG_MAPPED;
+       mutex_lock(&em28xx_extension_devlist_lock);
+       list_add_tail(&ops->next, &em28xx_extension_devlist);
+       if (dev)
+               ops->init(dev);
+
+       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+       mutex_unlock(&em28xx_extension_devlist_lock);
 
-               return 0;
-       }
-       default:
-               return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
-                                      em28xx_video_do_ioctl);
-       }
        return 0;
 }
+EXPORT_SYMBOL(em28xx_register_extension);
 
-/*
- * em28xx_v4l2_ioctl()
- * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
- */
-static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
-                            unsigned int cmd, unsigned long arg)
+void em28xx_unregister_extension(struct em28xx_ops *ops)
 {
-       int ret = 0;
-       struct em28xx *dev = filp->private_data;
+       struct em28xx *h, *dev = NULL;
 
-       if (mutex_lock_interruptible(&dev->fileop_lock))
-               return -ERESTARTSYS;
+       list_for_each_entry(h, &em28xx_devlist, devlist)
+               dev = h;
 
-       if (dev->state & DEV_DISCONNECTED) {
-               em28xx_errdev("v4l2 ioctl: device not present\n");
-               mutex_unlock(&dev->fileop_lock);
-               return -ENODEV;
-       }
-
-       if (dev->state & DEV_MISCONFIGURED) {
-               em28xx_errdev
-                   ("v4l2 ioctl: device is misconfigured; close and open it again\n");
-               mutex_unlock(&dev->fileop_lock);
-               return -EIO;
-       }
+       if (dev)
+               ops->fini(dev);
 
-       ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
+       mutex_lock(&em28xx_extension_devlist_lock);
+       printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+       list_del(&ops->next);
+       mutex_unlock(&em28xx_extension_devlist_lock);
+}
+EXPORT_SYMBOL(em28xx_unregister_extension);
 
-       mutex_unlock(&dev->fileop_lock);
+struct video_device *em28xx_vdev_init(struct em28xx *dev,
+                                     const struct video_device *template,
+                                     const int type,
+                                     const char *type_name)
+{
+       struct video_device *vfd;
 
-       return ret;
-}
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+       *vfd = *template;
+       vfd->minor   = -1;
+       vfd->dev = &dev->udev->dev;
+       vfd->release = video_device_release;
+       vfd->type = type;
 
-static const struct file_operations em28xx_v4l_fops = {
-       .owner = THIS_MODULE,
-       .open = em28xx_v4l2_open,
-       .release = em28xx_v4l2_close,
-       .ioctl = em28xx_v4l2_ioctl,
-       .read = em28xx_v4l2_read,
-       .poll = em28xx_v4l2_poll,
-       .mmap = em28xx_v4l2_mmap,
-       .llseek = no_llseek,
-       .compat_ioctl   = v4l_compat_ioctl32,
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s",
+                dev->name, type_name);
 
-};
+       return vfd;
+}
 
-/******************************** usb interface *****************************************/
 
 /*
  * em28xx_init_dev()
  * allocates and inits the device structs, registers i2c bus and v4l device
  */
 static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
-                          int minor, int model)
+                          int minor)
 {
+       struct em28xx_ops *ops = NULL;
        struct em28xx *dev = *devhandle;
        int retval = -ENOMEM;
-       int errCode, i;
+       int errCode;
        unsigned int maxh, maxw;
 
        dev->udev = udev;
-       dev->model = model;
        mutex_init(&dev->lock);
+       spin_lock_init(&dev->queue_lock);
        init_waitqueue_head(&dev->open);
+       init_waitqueue_head(&dev->wait_frame);
+       init_waitqueue_head(&dev->wait_stream);
 
        dev->em28xx_write_regs = em28xx_write_regs;
        dev->em28xx_read_reg = em28xx_read_reg;
        dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
        dev->em28xx_write_regs_req = em28xx_write_regs_req;
        dev->em28xx_read_reg_req = em28xx_read_reg_req;
-       dev->is_em2800 = em28xx_boards[model].is_em2800;
-       dev->has_tuner = em28xx_boards[model].has_tuner;
-       dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
-       dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
-       dev->decoder = em28xx_boards[model].decoder;
-
-       if (tuner >= 0)
-               dev->tuner_type = tuner;
-       else
-               dev->tuner_type = em28xx_boards[model].tuner_type;
+       dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
 
-       dev->video_inputs = em28xx_boards[model].vchannels;
+       errCode = em28xx_read_reg(dev, CHIPID_REG);
+       if (errCode >= 0)
+               em28xx_info("em28xx chip ID = %d\n", errCode);
 
-       for (i = 0; i < TVNORMS; i++)
-               if (em28xx_boards[model].norm == tvnorms[i].mode)
-                       break;
-       if (i == TVNORMS)
-               i = 0;
+       em28xx_pre_card_setup(dev);
+
+       errCode = em28xx_config(dev);
+       if (errCode) {
+               em28xx_errdev("error configuring device\n");
+               em28xx_devused &= ~(1<<dev->devno);
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       /* register i2c bus */
+       em28xx_i2c_register(dev);
 
-       dev->tvnorm = &tvnorms[i];      /* set default norm */
+       /* Do board specific init and eeprom reading */
+       em28xx_card_setup(dev);
+
+       /* Configure audio */
+       em28xx_audio_analog_set(dev);
 
-       em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+       /* configure the device */
+       em28xx_config_i2c(dev);
+
+       /* set default norm */
+       dev->norm = em28xx_video_template.current_norm;
 
        maxw = norm_maxw(dev);
        maxh = norm_maxh(dev);
@@ -1555,138 +1890,110 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        dev->vscale = 0;
        dev->ctl_input = 2;
 
-       /* setup video picture settings for saa7113h */
-       memset(&dev->vpic, 0, sizeof(dev->vpic));
-       dev->vpic.colour = 128 << 8;
-       dev->vpic.hue = 128 << 8;
-       dev->vpic.brightness = 128 << 8;
-       dev->vpic.contrast = 192 << 8;
-       dev->vpic.whiteness = 128 << 8; /* This one isn't used */
-       dev->vpic.depth = 16;
-       dev->vpic.palette = VIDEO_PALETTE_YUV422;
-
-       em28xx_pre_card_setup(dev);
-#ifdef CONFIG_MODULES
-       /* request some modules */
-       if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
-               request_module("saa7115");
-       if (dev->decoder == EM28XX_TVP5150)
-               request_module("tvp5150");
-       if (dev->has_tuner)
-               request_module("tuner");
-#endif
        errCode = em28xx_config(dev);
-       if (errCode) {
-               em28xx_errdev("error configuring device\n");
-               em28xx_devused&=~(1<<dev->devno);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       mutex_lock(&dev->lock);
-       /* register i2c bus */
-       em28xx_i2c_register(dev);
-
-       /* Do board specific init and eeprom reading */
-       em28xx_card_setup(dev);
-
-       /* configure the device */
-       em28xx_config_i2c(dev);
-
-       mutex_unlock(&dev->lock);
 
-       errCode = em28xx_config(dev);
+       list_add_tail(&dev->devlist, &em28xx_devlist);
 
-#ifdef CONFIG_MODULES
-       if (dev->has_msp34xx)
-               request_module("msp3400");
-#endif
-       /* allocate and fill v4l2 device struct */
-       dev->vdev = video_device_alloc();
+       /* allocate and fill video video_device struct */
+       dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template,
+                                         VID_TYPE_CAPTURE, "video");
        if (NULL == dev->vdev) {
                em28xx_errdev("cannot allocate video_device.\n");
-               em28xx_devused&=~(1<<dev->devno);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       dev->vbi_dev = video_device_alloc();
-       if (NULL == dev->vbi_dev) {
-               em28xx_errdev("cannot allocate video_device.\n");
-               kfree(dev->vdev);
-               em28xx_devused&=~(1<<dev->devno);
-               kfree(dev);
-               return -ENOMEM;
+               goto fail_unreg;
        }
-
-       /* Fills VBI device info */
-       dev->vbi_dev->type = VFL_TYPE_VBI;
-       dev->vbi_dev->fops = &em28xx_v4l_fops;
-       dev->vbi_dev->minor = -1;
-       dev->vbi_dev->dev = &dev->udev->dev;
-       dev->vbi_dev->release = video_device_release;
-       snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
-                                                        "em28xx",dev->devno,"vbi");
-
-       /* Fills CAPTURE device info */
-       dev->vdev->type = VID_TYPE_CAPTURE;
-       if (dev->has_tuner)
+       if (dev->tuner_type != TUNER_ABSENT)
                dev->vdev->type |= VID_TYPE_TUNER;
-       dev->vdev->fops = &em28xx_v4l_fops;
-       dev->vdev->minor = -1;
-       dev->vdev->dev = &dev->udev->dev;
-       dev->vdev->release = video_device_release;
-       snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
-                                                        "em28xx",dev->devno,"video");
-
-       list_add_tail(&dev->devlist,&em28xx_devlist);
 
-       /* register v4l2 device */
-       mutex_lock(&dev->lock);
-       if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
-                                        video_nr[dev->devno]))) {
+       /* register v4l2 video video_device */
+       retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+                                      video_nr[dev->devno]);
+       if (retval) {
                em28xx_errdev("unable to register video device (error=%i).\n",
                              retval);
-               mutex_unlock(&dev->lock);
-               list_del(&dev->devlist);
-               video_device_release(dev->vdev);
-               em28xx_devused&=~(1<<dev->devno);
-               kfree(dev);
-               return -ENODEV;
+               goto fail_unreg;
        }
 
+       /* Allocate and fill vbi video_device struct */
+       dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+                                         VFL_TYPE_VBI, "vbi");
+       /* register v4l2 vbi video_device */
        if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
                                        vbi_nr[dev->devno]) < 0) {
-               printk("unable to register vbi device\n");
-               mutex_unlock(&dev->lock);
-               list_del(&dev->devlist);
-               video_device_release(dev->vbi_dev);
-               video_device_release(dev->vdev);
-               em28xx_devused&=~(1<<dev->devno);
-               kfree(dev);
-               return -ENODEV;
-       } else {
-               printk("registered VBI\n");
+               em28xx_errdev("unable to register vbi device\n");
+               retval = -ENODEV;
+               goto fail_unreg;
        }
 
+       if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
+               dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+                                       VFL_TYPE_RADIO, "radio");
+               if (NULL == dev->radio_dev) {
+                       em28xx_errdev("cannot allocate video_device.\n");
+                       goto fail_unreg;
+               }
+               retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+                                           radio_nr[dev->devno]);
+               if (retval < 0) {
+                       em28xx_errdev("can't register radio device\n");
+                       goto fail_unreg;
+               }
+               em28xx_info("Registered radio device as /dev/radio%d\n",
+                           dev->radio_dev->minor & 0x1f);
+       }
+
+
        if (dev->has_msp34xx) {
                /* Send a reset to other chips via gpio */
                em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
                msleep(3);
                em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
                msleep(3);
-
        }
-       video_mux(dev, 0);
 
-       mutex_unlock(&dev->lock);
+       video_mux(dev, 0);
 
        em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
                                dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
                                dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
 
+       mutex_lock(&em28xx_extension_devlist_lock);
+       if (!list_empty(&em28xx_extension_devlist)) {
+               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+                       if (ops->id)
+                               ops->init(dev);
+               }
+       }
+       mutex_unlock(&em28xx_extension_devlist_lock);
+
        return 0;
+
+fail_unreg:
+       em28xx_release_resources(dev);
+       mutex_unlock(&dev->lock);
+       kfree(dev);
+       return retval;
+}
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+       struct em28xx *dev = container_of(work,
+                            struct em28xx, request_module_wk);
+
+       if (dev->has_audio_class)
+               request_module("snd-usb-audio");
+       else
+               request_module("em28xx-alsa");
+}
+
+static void request_modules(struct em28xx *dev)
+{
+       INIT_WORK(&dev->request_module_wk, request_module_async);
+       schedule_work(&dev->request_module_wk);
 }
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
 
 /*
  * em28xx_usb_probe()
@@ -1700,7 +2007,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        struct usb_interface *uif;
        struct em28xx *dev = NULL;
        int retval = -ENODEV;
-       int model,i,nr,ifnum;
+       int i, nr, ifnum;
 
        udev = usb_get_dev(interface_to_usbdev(interface));
        ifnum = interface->altsetting[0].desc.bInterfaceNumber;
@@ -1740,8 +2047,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                return -ENODEV;
        }
 
-       model=id->driver_info;
-
        if (nr >= EM28XX_MAXBOARDS) {
                printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
                em28xx_devused&=~(1<<nr);
@@ -1757,7 +2062,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        }
 
        snprintf(dev->name, 29, "em28xx #%d", nr);
-       dev->devno=nr;
+       dev->devno = nr;
+       dev->model = id->driver_info;
+
+       /* Checks if audio is provided by some interface */
+       for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+               uif = udev->config->interface[i];
+               if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+                       dev->has_audio_class = 1;
+                       break;
+               }
+       }
+
+       printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
+                  dev->has_audio_class ? "Has" : "Doesn't have");
 
        /* compute alternate max packet sizes */
        uif = udev->actconfig->interface[0];
@@ -1784,33 +2102,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        }
 
        if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
-               model=card[nr];
-
-       if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
-               em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
-                       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
-                       "%s: workaround that.  Redirect complaints to the vendor of\n"
-                       "%s: the TV card. Generic type will be used."
-                       "%s: Best regards,\n"
-                       "%s:         -- tux\n",
-                       dev->name,dev->name,dev->name,dev->name,dev->name);
-               em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
-                       dev->name);
-               for (i = 0; i < em28xx_bcount; i++) {
-                       em28xx_errdev("    card=%d -> %s\n", i,
-                                                       em28xx_boards[i].name);
-               }
-       }
+               dev->model = card[nr];
 
        /* allocate device struct */
-       retval = em28xx_init_dev(&dev, udev, nr, model);
+       retval = em28xx_init_dev(&dev, udev, nr);
        if (retval)
                return retval;
 
-       em28xx_info("Found %s\n", em28xx_boards[model].name);
+       em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
 
        /* save our data pointer in this interface device */
        usb_set_intfdata(interface, dev);
+
+       request_modules(dev);
+
        return 0;
 }
 
@@ -1821,18 +2126,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
  */
 static void em28xx_usb_disconnect(struct usb_interface *interface)
 {
-       struct em28xx *dev = usb_get_intfdata(interface);
+       struct em28xx *dev;
+       struct em28xx_ops *ops = NULL;
+
+       dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
        if (!dev)
                return;
 
-       down_write(&em28xx_disconnect);
+       em28xx_info("disconnecting %s\n", dev->vdev->name);
 
+       /* wait until all current v4l2 io is finished then deallocate resources */
        mutex_lock(&dev->lock);
 
-       em28xx_info("disconnecting %s\n", dev->vdev->name);
-
        wake_up_interruptible_all(&dev->open);
 
        if (dev->users) {
@@ -1850,15 +2157,20 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                dev->state |= DEV_DISCONNECTED;
                em28xx_release_resources(dev);
        }
-
        mutex_unlock(&dev->lock);
 
+       mutex_lock(&em28xx_extension_devlist_lock);
+       if (!list_empty(&em28xx_extension_devlist)) {
+               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+                       ops->fini(dev);
+               }
+       }
+       mutex_unlock(&em28xx_extension_devlist_lock);
+
        if (!dev->users) {
                kfree(dev->alt_max_pkt_size);
                kfree(dev);
        }
-
-       up_write(&em28xx_disconnect);
 }
 
 static struct usb_driver em28xx_usb_driver = {
index d8fcc9e17ac004c47e35325eb1feda1812824180..f3bad0c1c51723c8d3b622ea359156f59ef52b1e 100644 (file)
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
 
-/* Boards supported by driver */
-
-#define EM2800_BOARD_UNKNOWN                   0
-#define EM2820_BOARD_UNKNOWN                   1
-#define EM2820_BOARD_TERRATEC_CINERGY_250      2
-#define EM2820_BOARD_PINNACLE_USB_2            3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
-#define EM2820_BOARD_MSI_VOX_USB_2              5
-#define EM2800_BOARD_TERRATEC_CINERGY_200       6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
-#define EM2800_BOARD_KWORLD_USB2800             8
-#define EM2820_BOARD_PINNACLE_DVC_90           9
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900   10
-#define EM2880_BOARD_TERRATEC_HYBRID_XS                11
-#define EM2820_BOARD_KWORLD_PVRTV2800RF                12
-#define EM2880_BOARD_TERRATEC_PRODIGY_XS       13
-
 #define UNSET -1
 
 /* maximum number of em28xx boards */
@@ -148,10 +131,17 @@ enum enum28xx_itype {
        EM28XX_RADIO,
 };
 
+enum em28xx_amux {
+       EM28XX_AMUX_VIDEO,
+       EM28XX_AMUX_LINE_IN,
+       EM28XX_AMUX_AC97_VIDEO,
+       EM28XX_AMUX_AC97_LINE_IN,
+};
+
 struct em28xx_input {
        enum enum28xx_itype type;
        unsigned int vmux;
-       unsigned int amux;
+       enum em28xx_amux amux;
 };
 
 #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
@@ -165,19 +155,23 @@ enum em28xx_decoder {
 struct em28xx_board {
        char *name;
        int vchannels;
-       int norm;
        int tuner_type;
 
        /* i2c flags */
-       unsigned int is_em2800;
        unsigned int tda9887_conf;
 
-       unsigned int has_tuner:1;
+       unsigned int is_em2800:1;
        unsigned int has_msp34xx:1;
+       unsigned int mts_firmware:1;
+       unsigned int has_12mhz_i2s:1;
+       unsigned int max_range_640_480:1;
+
+       unsigned int analog_gpio;
 
        enum em28xx_decoder decoder;
 
        struct em28xx_input       input[MAX_EM28XX_INPUT];
+       struct em28xx_input       radio;
 };
 
 struct em28xx_eeprom {
@@ -201,12 +195,26 @@ enum em28xx_dev_state {
        DEV_MISCONFIGURED = 0x04,
 };
 
-/* tvnorms */
-struct em28xx_tvnorm {
-       char *name;
-       v4l2_std_id id;
-       /* mode for saa7113h */
-       int mode;
+#define EM28XX_AUDIO_BUFS 5
+#define EM28XX_NUM_AUDIO_PACKETS 64
+#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
+#define EM28XX_CAPTURE_STREAM_EN 1
+#define EM28XX_AUDIO   0x10
+
+struct em28xx_audio {
+       char name[50];
+       char *transfer_buffer[EM28XX_AUDIO_BUFS];
+       struct urb *urb[EM28XX_AUDIO_BUFS];
+       struct usb_device *udev;
+       unsigned int capture_transfer_done;
+       struct snd_pcm_substream   *capture_pcm_substream;
+
+       unsigned int hwptr_done_capture;
+       struct snd_card            *sndcard;
+
+       int users, shutdown;
+       enum em28xx_stream_state capture_stream;
+       spinlock_t slock;
 };
 
 /* main device struct */
@@ -215,12 +223,17 @@ struct em28xx {
        char name[30];          /* name (including minor) of the device */
        int model;              /* index in the device_data struct */
        int devno;              /* marks the number of this device */
-       unsigned int is_em2800;
-       int video_inputs;       /* number of video inputs */
-       struct list_head        devlist;
-       unsigned int has_tuner:1;
+       unsigned int analog_gpio;
+       unsigned int is_em2800:1;
        unsigned int has_msp34xx:1;
        unsigned int has_tda9887:1;
+       unsigned int stream_on:1;       /* Locks streams */
+       unsigned int has_audio_class:1;
+       unsigned int has_12mhz_i2s:1;
+       unsigned int max_range_640_480:1;
+
+       int video_inputs;       /* number of video inputs */
+       struct list_head        devlist;
 
        u32 i2s_speed;          /* I2S speed for audio digital stream */
 
@@ -235,8 +248,7 @@ struct em28xx {
        /* video for linux */
        int users;              /* user count for exclusive use */
        struct video_device *vdev;      /* video for linux device struct */
-       struct video_picture vpic;      /* picture settings only used to init saa7113h */
-       struct em28xx_tvnorm *tvnorm;   /* selected tv norm */
+       v4l2_std_id norm;       /* selected tv norm */
        int ctl_freq;           /* selected frequency */
        unsigned int ctl_input; /* selected input */
        unsigned int ctl_ainput;        /* slected audio input */
@@ -256,17 +268,27 @@ struct em28xx {
        int vscale;             /* vertical scale factor (see datasheet) */
        int interlaced;         /* 1=interlace fileds, 0=just top fileds */
        int type;
+       unsigned int video_bytesread;   /* Number of bytes read */
+
+       unsigned long hash;     /* eeprom hash - for boards with generic ID */
+       unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */
+
+       struct em28xx_audio *adev;
 
        /* states */
        enum em28xx_dev_state state;
        enum em28xx_stream_state stream;
        enum em28xx_io_method io;
+
+       struct work_struct         request_module_wk;
+
        /* locks */
-       struct mutex lock, fileop_lock;
+       struct mutex lock;
        spinlock_t queue_lock;
        struct list_head inqueue, outqueue;
        wait_queue_head_t open, wait_frame, wait_stream;
        struct video_device *vbi_dev;
+       struct video_device *radio_dev;
 
        unsigned char eedata[256];
 
@@ -289,16 +311,27 @@ struct em28xx {
        int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
 };
 
+struct em28xx_fh {
+       struct em28xx *dev;
+       unsigned int  stream_on:1;      /* Locks streams */
+       int           radio;
+};
+
+struct em28xx_ops {
+       struct list_head next;
+       char *name;
+       int id;
+       int (*init)(struct em28xx *);
+       int (*fini)(struct em28xx *);
+};
+
 /* Provided by em28xx-i2c.c */
 
 void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
+void em28xx_do_i2c_scan(struct em28xx *dev);
 int em28xx_i2c_register(struct em28xx *dev);
 int em28xx_i2c_unregister(struct em28xx *dev);
 
-/* Provided by em28xx-input.c */
-
-void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
-
 /* Provided by em28xx-core.c */
 
 u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
@@ -314,8 +347,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
 int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
 int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
                          u8 bitmask);
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_set_audio_source(struct em28xx *dev);
 int em28xx_audio_analog_set(struct em28xx *dev);
+
 int em28xx_colorlevels_set_default(struct em28xx *dev);
 int em28xx_capture_start(struct em28xx *dev, int start);
 int em28xx_outfmt_set_yuv422(struct em28xx *dev);
@@ -324,6 +358,10 @@ int em28xx_init_isoc(struct em28xx *dev);
 void em28xx_uninit_isoc(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
 
+/* Provided by em28xx-video.c */
+int em28xx_register_extension(struct em28xx_ops *dev);
+void em28xx_unregister_extension(struct em28xx_ops *dev);
+
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device* udev,int model);
 extern void em28xx_pre_card_setup(struct em28xx *dev);
@@ -331,8 +369,20 @@ extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+
+/* Provided by em28xx-input.c */
+/* TODO: Check if the standard get_key handlers on ir-common can be used */
+int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+                                    u32 *ir_raw);
+
+/* em2800 registers */
+#define EM2800_AUDIOSRC_REG 0x08
 
 /* em28xx registers */
+#define I2C_CLK_REG    0x06
 #define CHIPID_REG     0x0a
 #define USBSUSP_REG    0x0c    /* */
 
@@ -384,9 +434,12 @@ extern const unsigned int em28xx_bcount;
 
 /* em202 registers */
 #define MASTER_AC97    0x02
+#define LINE_IN_AC97    0x10
 #define VIDEO_AC97     0x14
 
 /* register settings */
+#define EM2800_AUDIO_SRC_TUNER  0x0d
+#define EM2800_AUDIO_SRC_LINE   0x0c
 #define EM28XX_AUDIO_SRC_TUNER 0xc0
 #define EM28XX_AUDIO_SRC_LINE  0x80
 
@@ -406,22 +459,6 @@ extern const unsigned int em28xx_bcount;
        printk(KERN_WARNING "%s: "fmt,\
                        dev->name , ##arg); } while (0)
 
-inline static int em28xx_audio_source(struct em28xx *dev, int input)
-{
-       return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
-}
-
-inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
-{
-       return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
-}
-
-inline static int em28xx_audio_analog_setup(struct em28xx *dev)
-{
-       /* unmute video mixer with default volume level */
-       return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
-}
-
 inline static int em28xx_compression_disable(struct em28xx *dev)
 {
        /* side effect of disabling scaler and mixer */
@@ -497,18 +534,17 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
 /*FIXME: maxw should be dependent of alt mode */
 inline static unsigned int norm_maxw(struct em28xx *dev)
 {
-       switch(dev->model){
-               case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
-               default: return(720);
-       }
+       if (dev->max_range_640_480)
+               return 640;
+       else
+               return 720;
 }
 
 inline static unsigned int norm_maxh(struct em28xx *dev)
 {
-       switch(dev->model){
-               case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
-               default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
-       }
+       if (dev->max_range_640_480)
+               return 480;
+       else
+               return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
 }
-
 #endif
index d19d73b81edef7b37140a092b3365f2538a72480..06b6a3ae06c4c151bb8d54c04299920e11449e7a 100644 (file)
@@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
 }
 
 
-int et61x251_read_reg(struct et61x251_device* cam, u16 index)
+static int et61x251_read_reg(struct et61x251_device* cam, u16 index)
 {
        struct usb_device* udev = cam->usbdev;
        u8* buff = cam->control_buffer;
@@ -268,73 +268,6 @@ et61x251_i2c_wait(struct et61x251_device* cam,
 }
 
 
-int
-et61x251_i2c_try_read(struct et61x251_device* cam,
-                     const struct et61x251_sensor* sensor, u8 address)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x10;
-       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, sensor);
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       if (err)
-               DBG(3, "I2C read failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-
-       return err ? -1 : (int)data[0];
-}
-
-
-int
-et61x251_i2c_try_write(struct et61x251_device* cam,
-                      const struct et61x251_sensor* sensor, u8 address,
-                      u8 value)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x12;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       data[0] = value;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, sensor);
-
-       if (err)
-               DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-
-       return err ? -1 : 0;
-}
-
-
 int
 et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
                       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
@@ -387,17 +320,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
 }
 
 
-int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-{
-       return et61x251_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
-{
-       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
 /*****************************************************************************/
 
 static void et61x251_urb_complete(struct urb *urb)
@@ -675,6 +597,83 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam)
 /*****************************************************************************/
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+
+static int et61x251_i2c_try_read(struct et61x251_device* cam,
+                                const struct et61x251_sensor* sensor,
+                                u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x10;
+       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+
+       return err ? -1 : (int)data[0];
+}
+
+
+static int et61x251_i2c_try_write(struct et61x251_device* cam,
+                                 const struct et61x251_sensor* sensor,
+                                 u8 address, u8 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x12;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = value;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       if (err)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+
+       return err ? -1 : 0;
+}
+
+static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
+{
+       return et61x251_i2c_try_read(cam, &cam->sensor, address);
+}
+
+static int et61x251_i2c_write(struct et61x251_device* cam,
+                             u8 address, u8 value)
+{
+       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
+}
+
 static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
 {
        char str[5];
index e1458633062351d337f569681dc5e92870844618..71a03148cb092b17e4aa76d5f97fc176ef60f6cf 100644 (file)
@@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam,
 /*****************************************************************************/
 
 extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
-extern int et61x251_read_reg(struct et61x251_device*, u16 index);
-extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
-extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
-extern int et61x251_i2c_try_write(struct et61x251_device*,
-                                 const struct et61x251_sensor*, u8 address,
-                                 u8 value);
-extern int et61x251_i2c_try_read(struct et61x251_device*,
-                                const struct et61x251_sensor*, u8 address);
 extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
                                  u8 data2, u8 data3, u8 data4, u8 data5,
                                  u8 data6, u8 data7, u8 data8, u8 address);
index 29779d8bf7fbecbc0e33ade96d51a75ef0c30e03..9851987b95fbed200c94fa0207817271f3e728d0 100644 (file)
@@ -398,6 +398,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        case 0x7a:
        case 0x47:
        case 0x71:
+       case 0x2d:
                if (adap->id == I2C_HW_B_CX2388x) {
                        /* Handled by cx88-input */
                        name        = "CX2388x remote";
@@ -504,7 +505,7 @@ static int ir_probe(struct i2c_adapter *adap)
        */
 
        static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-       static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
+       static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
        static const int probe_em28XX[] = { 0x30, 0x47, -1 };
        static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
        static const int probe_cx23885[] = { 0x6b, -1 };
index 854cc9c30ca92bb3548aa9f5d5b77571ad7a9f52..270906fc314600107e161dde9575308c85385f1e 100644 (file)
@@ -3,6 +3,7 @@ config VIDEO_IVTV
        depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
        select I2C_ALGOBIT
        select FW_LOADER
+       select VIDEO_IR
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select VIDEO_CX2341X
@@ -12,6 +13,7 @@ config VIDEO_IVTV
        select VIDEO_SAA7127
        select VIDEO_TVAUDIO
        select VIDEO_CS53L32A
+       select VIDEO_M52790
        select VIDEO_WM8775
        select VIDEO_WM8739
        select VIDEO_VP27SMPX
index e8eefd96d8976f7eaa6e12a55e7a8d03417908fb..a0389014fa88dc8dc156263e140232794b156e45 100644 (file)
@@ -6,3 +6,8 @@ ivtv-objs       := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
 obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
index b6a8be622d3ccfdb0db39c51b369ff55792ff918..f23c6b8d6911dee0f360c60e5c745b869df95e6e 100644 (file)
@@ -23,6 +23,7 @@
 #include "ivtv-i2c.h"
 
 #include <media/msp3400.h>
+#include <media/m52790.h>
 #include <media/wm8775.h>
 #include <media/cs53l32a.h>
 #include <media/cx25840.h>
 #define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
                                MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
 
+/* usual i2c tuner addresses to probe */
+static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
+       .radio = { I2C_CLIENT_END },
+       .demod = { 0x43, I2C_CLIENT_END },
+       .tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* as above, but with possible radio tuner */
+static struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+       .radio = { 0x60, I2C_CLIENT_END },
+       .demod = { 0x43, I2C_CLIENT_END },
+       .tv    = { 0x61, I2C_CLIENT_END },
+};
+
+/* using the tda8290+75a combo */
+static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
+       .radio = { I2C_CLIENT_END },
+       .demod = { I2C_CLIENT_END },
+       .tv    = { 0x4b, I2C_CLIENT_END },
+};
+
 /********************** card configuration *******************************/
 
 /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
@@ -72,6 +94,7 @@ static const struct ivtv_card ivtv_card_pvr250 = {
                { IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
        },
        .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -126,6 +149,7 @@ static const struct ivtv_card ivtv_card_pvr350 = {
                { IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
        },
        .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+       .i2c = &ivtv_i2c_std,
 };
 
 /* PVR-350 V1 boards have a different audio tuner input and use a
@@ -157,6 +181,7 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = {
                { IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
        },
        .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -192,6 +217,7 @@ static const struct ivtv_card ivtv_card_pvr150 = {
                         CX25840_AUDIO_SERIAL, WM8775_AIN4 },
        /* apparently needed for the IR blaster */
        .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -234,6 +260,7 @@ static const struct ivtv_card ivtv_card_m179 = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
        },
        .pci_list = ivtv_pci_m179,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -275,6 +302,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
        },
        .pci_list = ivtv_pci_mpg600,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -315,6 +343,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
        },
        .pci_list = ivtv_pci_mpg160,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -350,6 +379,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
        },
        .pci_list = ivtv_pci_pg600,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -393,6 +423,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
        },
        .pci_list = ivtv_pci_avc2410,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -463,6 +494,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
                { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
        },
        .pci_list = ivtv_pci_tg5000tv,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -493,6 +525,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
                { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
        },
        .pci_list = ivtv_pci_va2000,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -537,6 +570,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
        },
        .pci_list = ivtv_pci_cx23416gyc,
+       .i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
@@ -567,6 +601,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
                { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
        },
+       .i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
@@ -596,6 +631,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
                { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
        },
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -635,6 +671,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
                { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
        },
        .pci_list = ivtv_pci_gv_mvprx,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -671,6 +708,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
                { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
        },
        .pci_list = ivtv_pci_gv_mvprx2e,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -705,6 +743,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
                { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
        },
        .pci_list = ivtv_pci_gotview_pci_dvd,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -743,6 +782,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
                { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
        },
        .pci_list = ivtv_pci_gotview_pci_dvd2,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -778,6 +818,7 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = {
                { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
        },
        .pci_list = ivtv_pci_yuan_mpc622,
+       .i2c = &ivtv_i2c_tda8290,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -819,6 +860,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
                { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
        },
        .pci_list = ivtv_pci_dctmvtvp1,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -838,7 +880,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
        .hw_video = IVTV_HW_CX25840,
        .hw_audio = IVTV_HW_CX25840,
        .hw_audio_ctrl = IVTV_HW_CX25840,
-       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+       .hw_all = IVTV_HW_CX25840,
        .video_inputs = {
                { IVTV_CARD_INPUT_SVIDEO1,    0,
                  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
@@ -847,10 +889,8 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
        .audio_inputs = {
                { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
        },
-       .tuners = {
-               { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
-       },
        .pci_list = ivtv_pci_pg600v2,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -871,17 +911,22 @@ static const struct ivtv_card ivtv_card_club3d = {
        .hw_audio_ctrl = IVTV_HW_CX25840,
        .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
        .video_inputs = {
-               { IVTV_CARD_INPUT_SVIDEO1,    0,
+               { IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+               { IVTV_CARD_INPUT_SVIDEO1,    1,
                  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
-               { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
+               { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
        },
        .audio_inputs = {
+               { IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
                { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
        },
+       .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+       .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
        .tuners = {
-               { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+               { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
        },
        .pci_list = ivtv_pci_club3d,
+       .i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -900,7 +945,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
        .hw_video = IVTV_HW_CX25840,
        .hw_audio = IVTV_HW_CX25840,
        .hw_audio_ctrl = IVTV_HW_CX25840,
-       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
        .video_inputs = {
                { IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3    },
                { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
@@ -909,10 +954,115 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
                { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
        },
        .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+       .pci_list = ivtv_pci_avertv_mce116,
+       .i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia PVR-150 Plus (M113) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
+       { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_pvr150 = {
+       .type = IVTV_CARD_AVER_PVR150PLUS,
+       .name = "AVerMedia PVR-150 Plus",
+       .v4l2_capabilities = IVTV_CAP_ENCODER,
+       .hw_video = IVTV_HW_CX25840,
+       .hw_audio = IVTV_HW_CX25840,
+       .hw_audio_ctrl = IVTV_HW_CX25840,
+       .hw_muxer = IVTV_HW_GPIO,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+       .video_inputs = {
+               { IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+               { IVTV_CARD_INPUT_SVIDEO1,    1,
+                 CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+               { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+       },
+       .audio_inputs = {
+               { IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+               { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+       },
+       .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+       .gpio_init = { .direction = 0x0800, .initial_value = 0 },
+       .gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
        .tuners = {
-               { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+               /* This card has a Partsnic PTI-5NF05 tuner */
+               { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
        },
-       .pci_list = ivtv_pci_avertv_mce116,
+       .pci_list = ivtv_pci_aver_pvr150,
+       .i2c = &ivtv_i2c_radio,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia EZMaker PCI Deluxe card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f },
+       { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ezmaker = {
+       .type = IVTV_CARD_AVER_EZMAKER,
+       .name = "AVerMedia EZMaker PCI Deluxe",
+       .v4l2_capabilities = IVTV_CAP_ENCODER,
+       .hw_video = IVTV_HW_CX25840,
+       .hw_audio = IVTV_HW_CX25840,
+       .hw_audio_ctrl = IVTV_HW_CX25840,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
+       .video_inputs = {
+               { IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3 },
+               { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+       },
+       .audio_inputs = {
+               { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 0 },
+       },
+       .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 },
+       /* Does not have a tuner */
+       .pci_list = ivtv_pci_aver_ezmaker,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* ASUS Falcon2 */
+
+static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = {
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 },
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e },
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e },
+       { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_asus_falcon2 = {
+       .type = IVTV_CARD_ASUS_FALCON2,
+       .name = "ASUS Falcon2",
+       .v4l2_capabilities = IVTV_CAP_ENCODER,
+       .hw_video = IVTV_HW_CX25840,
+       .hw_audio = IVTV_HW_CX25840,
+       .hw_audio_ctrl = IVTV_HW_CX25840,
+       .hw_muxer = IVTV_HW_M52790,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER,
+       .video_inputs = {
+               { IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+               { IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+               { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 },
+       },
+       .audio_inputs = {
+               { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER },
+               { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL,
+                       M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX },
+               { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 },
+       },
+       .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
+       .tuners = {
+               { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+       },
+       .pci_list = ivtv_pci_asus_falcon2,
+       .i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card *ivtv_card_list[] = {
@@ -937,6 +1087,9 @@ static const struct ivtv_card *ivtv_card_list[] = {
        &ivtv_card_pg600v2,
        &ivtv_card_club3d,
        &ivtv_card_avertv_mce116,
+       &ivtv_card_asus_falcon2,
+       &ivtv_card_aver_pvr150,
+       &ivtv_card_aver_ezmaker,
 
        /* Variations of standard cards but with the same PCI IDs.
           These cards must come last in this list. */
index ff46e5ae8653717d978940ccf562dc58f4b2659f..191aafdd9968fd008fbc405a2b566a03cf1ab452 100644 (file)
 #define IVTV_CARD_PG600V2           18 /* Yuan PG600V2/GotView PCI DVD Lite */
 #define IVTV_CARD_CLUB3D            19 /* Club3D ZAP-TV1x01 */
 #define IVTV_CARD_AVERTV_MCE116             20 /* AVerTV MCE 116 Plus */
-#define IVTV_CARD_LAST                      20
+#define IVTV_CARD_ASUS_FALCON2      21 /* ASUS Falcon2 */
+#define IVTV_CARD_AVER_PVR150PLUS    22 /* AVerMedia PVR-150 Plus */
+#define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
+#define IVTV_CARD_LAST                      23
 
 /* Variants of existing cards but with the same PCI IDs. The driver
    detects these based on other device information.
@@ -69,6 +72,7 @@
 #define IVTV_PCI_ID_HAUPPAUGE_ALT1     0x0270
 #define IVTV_PCI_ID_HAUPPAUGE_ALT2     0x4070
 #define IVTV_PCI_ID_ADAPTEC            0x9005
+#define IVTV_PCI_ID_ASUSTEK            0x1043
 #define IVTV_PCI_ID_AVERMEDIA          0x1461
 #define IVTV_PCI_ID_YUAN1              0x12ab
 #define IVTV_PCI_ID_YUAN2              0xff01
@@ -80,7 +84,7 @@
 #define IVTV_PCI_ID_GOTVIEW1           0xffac
 #define IVTV_PCI_ID_GOTVIEW2           0xffad
 
-/* hardware flags */
+/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */
 #define IVTV_HW_CX25840   (1 << 0)
 #define IVTV_HW_SAA7115   (1 << 1)
 #define IVTV_HW_SAA7127   (1 << 2)
 #define IVTV_HW_CS53L32A  (1 << 6)
 #define IVTV_HW_TVEEPROM  (1 << 7)
 #define IVTV_HW_SAA7114   (1 << 8)
-#define IVTV_HW_TVAUDIO   (1 << 9)
-#define IVTV_HW_UPD64031A (1 << 10)
-#define IVTV_HW_UPD6408X  (1 << 11)
-#define IVTV_HW_SAA717X   (1 << 12)
-#define IVTV_HW_WM8739    (1 << 13)
-#define IVTV_HW_VP27SMPX  (1 << 14)
+#define IVTV_HW_UPD64031A (1 << 9)
+#define IVTV_HW_UPD6408X  (1 << 10)
+#define IVTV_HW_SAA717X   (1 << 11)
+#define IVTV_HW_WM8739    (1 << 12)
+#define IVTV_HW_VP27SMPX  (1 << 13)
+#define IVTV_HW_M52790    (1 << 14)
 #define IVTV_HW_GPIO      (1 << 15)
 
 #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
@@ -230,6 +234,12 @@ struct ivtv_card_tuner {
        int         tuner;      /* tuner ID (from tuner.h) */
 };
 
+struct ivtv_card_tuner_i2c {
+       unsigned short radio[2];/* radio tuner i2c address to probe */
+       unsigned short demod[2];/* demodulator i2c address to probe */
+       unsigned short tv[4];   /* tv tuner i2c addresses to probe */
+};
+
 /* for card information/parameters */
 struct ivtv_card {
        int type;
@@ -257,6 +267,7 @@ struct ivtv_card {
        struct ivtv_gpio_audio_detect   gpio_audio_detect;
 
        struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
+       struct ivtv_card_tuner_i2c *i2c;
 
        /* list of device and subsystem vendor/devices that
           correspond to this card type. */
index 6d2dd8764f814c3ae85fc5b96d45bdc080379335..d42f120354e5b428a17edea1db256dadaf186f0e 100644 (file)
@@ -59,6 +59,7 @@
 #include <media/tveeprom.h>
 #include <media/saa7115.h>
 #include <media/v4l2-chip-ident.h>
+#include "tuner-xc2028.h"
 
 /* var to keep track of the number of array elements in use */
 int ivtv_cards_active = 0;
@@ -185,6 +186,9 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
                 "\t\t\t20 = Club3D ZAP-TV1x01\n"
                 "\t\t\t21 = AverTV MCE 116 Plus\n"
+                "\t\t\t22 = ASUS Falcon2\n"
+                "\t\t\t23 = AverMedia PVR-150 Plus\n"
+                "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
                 "\t\t\t 0 = Autodetect (default)\n"
                 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -397,6 +401,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
 
        itv->v4l2_cap = itv->card->v4l2_capabilities;
        itv->card_name = itv->card->name;
+       itv->card_i2c = itv->card->i2c;
 
        /* If this is a PVR500 then it should be possible to detect whether it is the
           first or second unit by looking at the subsystem device ID: is bit 4 is
@@ -414,7 +419,14 @@ static void ivtv_process_eeprom(struct ivtv *itv)
           This detection is needed since the eeprom reports incorrectly that a radio is
           present on the second unit. */
        if (tv.model / 1000 == 23) {
+               static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+                       .radio = { 0x60, I2C_CLIENT_END },
+                       .demod = { 0x43, I2C_CLIENT_END },
+                       .tv = { 0x61, I2C_CLIENT_END },
+               };
+
                itv->card_name = "WinTV PVR 500";
+               itv->card_i2c = &ivtv_i2c_radio;
                if (pci_slot == 8 || pci_slot == 9) {
                        int is_first = (pci_slot & 1) == 0;
 
@@ -628,10 +640,11 @@ done:
                IVTV_ERR("Defaulting to %s card\n", itv->card->name);
                IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
                IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
-               IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n");
+               IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n");
        }
        itv->v4l2_cap = itv->card->v4l2_capabilities;
        itv->card_name = itv->card->name;
+       itv->card_i2c = itv->card->i2c;
 }
 
 /* Precondition: the ivtv structure has been memset to 0. Only
@@ -695,6 +708,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        atomic_set(&itv->yuv_info.next_dma_frame, -1);
        itv->yuv_info.lace_mode = ivtv_yuv_mode;
        itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
+       itv->yuv_info.max_frames_buffered = 3;
        return 0;
 }
 
@@ -812,75 +826,61 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
        return 0;
 }
 
-static void ivtv_request_module(struct ivtv *itv, const char *name)
+static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
+               const char *name, u32 id)
 {
+       if ((hw & id) == 0)
+               return hw;
        if (request_module(name) != 0) {
                IVTV_ERR("Failed to load module %s\n", name);
-       } else {
-               IVTV_DEBUG_INFO("Loaded module %s\n", name);
+               return hw & ~id;
        }
+       IVTV_DEBUG_INFO("Loaded module %s\n", name);
+       return hw;
 }
 
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
        u32 hw = itv->card->hw_all;
-       int i;
+       unsigned i;
 
        /* load modules */
 #ifndef CONFIG_VIDEO_TUNER
-       if (hw & IVTV_HW_TUNER) {
-               if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
-                       IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
-                       itv->tunerid = 1;
-               }
-               else {
-                       ivtv_request_module(itv, "tuner");
-               }
-       }
+       hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
 #endif
 #ifndef CONFIG_VIDEO_CX25840
-       if (hw & IVTV_HW_CX25840)
-               ivtv_request_module(itv, "cx25840");
+       hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
 #endif
 #ifndef CONFIG_VIDEO_SAA711X
-       if (hw & IVTV_HW_SAA711X)
-               ivtv_request_module(itv, "saa7115");
+       hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
 #endif
 #ifndef CONFIG_VIDEO_SAA7127
-       if (hw & IVTV_HW_SAA7127)
-               ivtv_request_module(itv, "saa7127");
+       hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
 #endif
-       if (hw & IVTV_HW_SAA717X)
-               ivtv_request_module(itv, "saa717x");
+       hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
 #ifndef CONFIG_VIDEO_UPD64031A
-       if (hw & IVTV_HW_UPD64031A)
-               ivtv_request_module(itv, "upd64031a");
+       hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
 #endif
 #ifndef CONFIG_VIDEO_UPD64083
-       if (hw & IVTV_HW_UPD6408X)
-               ivtv_request_module(itv, "upd64083");
+       hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
 #endif
 #ifndef CONFIG_VIDEO_MSP3400
-       if (hw & IVTV_HW_MSP34XX)
-               ivtv_request_module(itv, "msp3400");
+       hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
 #endif
 #ifndef CONFIG_VIDEO_VP27SMPX
-       if (hw & IVTV_HW_VP27SMPX)
-               ivtv_request_module(itv, "vp27smpx");
+       hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
 #endif
-       if (hw & IVTV_HW_TVAUDIO)
-               ivtv_request_module(itv, "tvaudio");
 #ifndef CONFIG_VIDEO_WM8775
-       if (hw & IVTV_HW_WM8775)
-               ivtv_request_module(itv, "wm8775");
+       hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
 #endif
 #ifndef CONFIG_VIDEO_WM8739
-       if (hw & IVTV_HW_WM8739)
-               ivtv_request_module(itv, "wm8739");
+       hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
 #endif
 #ifndef CONFIG_VIDEO_CS53L32A
-       if (hw & IVTV_HW_CS53L32A)
-               ivtv_request_module(itv, "cs53l32a");
+       hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
+#endif
+#ifndef CONFIG_VIDEO_M52790
+       hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
 #endif
 
        /* check which i2c devices are actually found */
@@ -889,11 +889,12 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
 
                if (!(device & hw))
                        continue;
-               if (device == IVTV_HW_GPIO) {
-                       /* GPIO is always available */
-                       itv->hw_flags |= IVTV_HW_GPIO;
+               if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) {
+                       /* GPIO and TVEEPROM do not use i2c probing */
+                       itv->hw_flags |= device;
                        continue;
                }
+               ivtv_i2c_register(itv, i);
                if (ivtv_i2c_hw_addr(itv, device) > 0)
                        itv->hw_flags |= device;
        }
@@ -964,7 +965,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                                const struct pci_device_id *pci_id)
 {
        int retval = 0;
-       int yuv_buf_size;
        int vbi_buf_size;
        struct ivtv *itv;
 
@@ -979,7 +979,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        }
 
        itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
-       if (itv == 0) {
+       if (itv == NULL) {
                spin_unlock(&ivtv_cards_lock);
                return -ENOMEM;
        }
@@ -1068,9 +1068,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
 
        if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
-#ifdef CONFIG_VIDEO_TVEEPROM_MODULE
-               ivtv_request_module(itv, "tveeprom");
-#endif
                /* Based on the model number the cardtype may be changed.
                   The PCI IDs are not always reliable. */
                ivtv_process_eeprom(itv);
@@ -1111,16 +1108,19 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                itv->is_50hz = 1;
                itv->is_out_50hz = 1;
        }
+
+       itv->yuv_info.osd_full_w = 720;
+       itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480;
+       itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
+       itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
+
        itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
 
        itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
        itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
        itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000;
-
-       /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */
-       yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500;
-       itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2;
-       itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8;
+       itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000;
+       itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000;
 
        /* Setup VBI Raw Size. Should be big enough to hold PAL.
           It is possible to switch between PAL and NTSC, so we need to
@@ -1140,13 +1140,26 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        if (itv->options.radio > 0)
                itv->v4l2_cap |= V4L2_CAP_RADIO;
 
-       if (itv->options.tuner > -1 && itv->tunerid == 0) {
+       if (itv->options.tuner > -1) {
                struct tuner_setup setup;
 
                setup.addr = ADDR_UNSET;
                setup.type = itv->options.tuner;
                setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
+               setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+                       ivtv_reset_tuner_gpio : NULL;
                ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
+               if (setup.type == TUNER_XC2028) {
+                       static struct xc2028_ctrl ctrl = {
+                               .fname = XC2028_DEFAULT_FIRMWARE,
+                               .max_len = 64,
+                       };
+                       struct v4l2_priv_tun_config cfg = {
+                               .tuner = itv->options.tuner,
+                               .priv = &ctrl,
+                       };
+                       ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
+               }
        }
 
        /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
index 49ce14d14a54b69eeaa5f04ca200840030d1dad2..536140f0c19efb6eabd9f8673857c742a3a7a600 100644 (file)
@@ -65,7 +65,6 @@
 
 #include <linux/ivtv.h>
 
-
 /* Memory layout */
 #define IVTV_ENCODER_OFFSET    0x00000000
 #define IVTV_ENCODER_SIZE      0x00800000      /* Total size is 0x01000000, but only first half is used */
@@ -392,6 +391,9 @@ struct yuv_frame_info
        u32 tru_h;
        u32 offset_y;
        s32 lace_mode;
+       u32 sync_field;
+       u32 delay;
+       u32 interlaced;
 };
 
 #define IVTV_YUV_MODE_INTERLACED       0x00
@@ -403,6 +405,8 @@ struct yuv_frame_info
 #define IVTV_YUV_SYNC_ODD              0x04
 #define IVTV_YUV_SYNC_MASK             0x04
 
+#define IVTV_YUV_BUFFERS 8
+
 struct yuv_playback_info
 {
        u32 reg_2834;
@@ -461,9 +465,10 @@ struct yuv_playback_info
        u32 osd_vis_w;
        u32 osd_vis_h;
 
-       int decode_height;
+       u32 osd_full_w;
+       u32 osd_full_h;
 
-       int frame_interlaced;
+       int decode_height;
 
        int lace_mode;
        int lace_threshold;
@@ -475,16 +480,23 @@ struct yuv_playback_info
        u32 yuv_forced_update;
        int update_frame;
 
-       int sync_field[4];  /* Field to sync on */
-       int field_delay[4]; /* Flag to extend duration of previous frame */
        u8 fields_lapsed;   /* Counter used when delaying a frame */
 
-       struct yuv_frame_info new_frame_info[4];
+       struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS];
        struct yuv_frame_info old_frame_info;
        struct yuv_frame_info old_frame_info_args;
 
        void *blanking_ptr;
        dma_addr_t blanking_dmaptr;
+
+       int stream_size;
+
+       u8 draw_frame; /* PVR350 buffer to draw into */
+       u8 max_frames_buffered; /* Maximum number of frames to buffer */
+
+       struct v4l2_rect main_rect;
+       u32 v4l2_src_w;
+       u32 v4l2_src_h;
 };
 
 #define IVTV_VBI_FRAMES 32
@@ -577,13 +589,13 @@ struct ivtv {
        struct pci_dev *dev;            /* PCI device */
        const struct ivtv_card *card;   /* card information */
        const char *card_name;          /* full name of the card */
+       const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
        u8 has_cx23415;                 /* 1 if it is a cx23415 based card, 0 for cx23416 */
        u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
        u8 nof_inputs;                  /* number of video inputs */
        u8 nof_audio_inputs;            /* number of audio inputs */
        u32 v4l2_cap;                   /* V4L2 capabilities of card */
        u32 hw_flags;                   /* hardware description of the board */
-       int tunerid;                    /* userspace tuner ID for experimental Xceive tuner support */
        v4l2_std_id tuner_std;          /* the norm of the card's tuner (fixed) */
                                        /* controlling video decoder function */
        int (*video_dec_func)(struct ivtv *, unsigned int, void *);
index a200a8a95a2dc2ee125e6b32a94ab69b96727973..6fb96f19a8661dfe369f7303e6ed4e11301d3ad9 100644 (file)
@@ -542,6 +542,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        struct ivtv_open_id *id = filp->private_data;
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
+       struct yuv_playback_info *yi = &itv->yuv_info;
        struct ivtv_buffer *buf;
        struct ivtv_queue q;
        int bytes_written = 0;
@@ -580,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
 
 retry:
+       /* If possible, just DMA the entire frame - Check the data transfer size
+       since we may get here before the stream has been fully set-up */
+       if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
+               while (count >= itv->dma_data_req_size) {
+                       if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
+                               bytes_written += itv->dma_data_req_size;
+                               user_buf += itv->dma_data_req_size;
+                               count -= itv->dma_data_req_size;
+                       } else {
+                               break;
+                       }
+               }
+               if (count == 0) {
+                       IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+                       return bytes_written;
+               }
+       }
+
        for (;;) {
                /* Gather buffers */
                while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
@@ -604,9 +623,16 @@ retry:
 
        /* copy user data into buffers */
        while ((buf = ivtv_dequeue(s, &q))) {
-               /* Make sure we really got all the user data */
-               rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+               /* yuv is a pain. Don't copy more data than needed for a single
+                  frame, otherwise we lose sync with the incoming stream */
+               if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+                   yi->stream_size + count > itv->dma_data_req_size)
+                       rc  = ivtv_buf_copy_from_user(s, buf, user_buf,
+                               itv->dma_data_req_size - yi->stream_size);
+               else
+                       rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
 
+               /* Make sure we really got all the user data */
                if (rc < 0) {
                        ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
                        return rc;
@@ -615,6 +641,16 @@ retry:
                count -= rc;
                bytes_written += rc;
 
+               if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+                       yi->stream_size += rc;
+                       /* If we have a complete yuv frame, break loop now */
+                       if (yi->stream_size == itv->dma_data_req_size) {
+                               ivtv_enqueue(s, buf, &s->q_full);
+                               yi->stream_size = 0;
+                               break;
+                       }
+               }
+
                if (buf->bytesused != s->buf_size) {
                        /* incomplete, leave in q_io for next time */
                        ivtv_enqueue(s, buf, &s->q_io);
@@ -642,6 +678,9 @@ retry:
                if (s->q_full.length >= itv->dma_data_req_size) {
                        int got_sig;
 
+                       if (mode == OUT_YUV)
+                               ivtv_yuv_setup_stream_frame(itv);
+
                        prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
                        while (!(got_sig = signal_pending(current)) &&
                                        test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
@@ -922,10 +961,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
        }
 
        /* YUV or MPG Decoding Mode? */
-       if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+       if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
                clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-       else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+       } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
                set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+               /* For yuv, we need to know the dma size before we start */
+               itv->dma_data_req_size =
+                               1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+               itv->yuv_info.stream_size = 0;
+       }
        return 0;
 }
 
index 132fb5f713663769df3a99642c91078c5dcfc02b..688cd3856685f09a0374fa91f42f20efbf1fdc92 100644 (file)
@@ -22,6 +22,7 @@
 #include "ivtv-driver.h"
 #include "ivtv-cards.h"
 #include "ivtv-gpio.h"
+#include "tuner-xc2028.h"
 #include <media/tuner.h>
 
 /*
@@ -122,6 +123,29 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
        write_reg(curdir, IVTV_REG_GPIO_DIR);
 }
 
+/* Xceive tuner reset function */
+int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
+{
+       struct i2c_algo_bit_data *algo = dev;
+       struct ivtv *itv = algo->data;
+       int curdir, curout;
+
+       if (cmd != XC2028_TUNER_RESET)
+               return 0;
+       IVTV_DEBUG_INFO("Resetting tuner\n");
+       curout = read_reg(IVTV_REG_GPIO_OUT);
+       curdir = read_reg(IVTV_REG_GPIO_DIR);
+       curdir |= (1 << 12);  /* GPIO bit 12 */
+
+       curout &= ~(1 << 12);
+       write_reg(curout, IVTV_REG_GPIO_OUT);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
+
+       curout |= (1 << 12);
+       write_reg(curout, IVTV_REG_GPIO_OUT);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
+       return 0;
+}
 
 void ivtv_gpio_init(struct ivtv *itv)
 {
index 44678fe27a04397575f51bf6183d99d18f9d4777..fa5ab1eb180005049db0412df19b8279303b7aec 100644 (file)
@@ -80,6 +80,7 @@
 #endif /* I2C_ADAP_CLASS_TV_ANALOG */
 
 #define IVTV_CS53L32A_I2C_ADDR         0x11
+#define IVTV_M52790_I2C_ADDR           0x48
 #define IVTV_CX25840_I2C_ADDR          0x44
 #define IVTV_SAA7115_I2C_ADDR          0x21
 #define IVTV_SAA7127_I2C_ADDR          0x44
@@ -91,7 +92,8 @@
 #define IVTV_TEA5767_I2C_ADDR          0x60
 #define IVTV_UPD64031A_I2C_ADDR        0x12
 #define IVTV_UPD64083_I2C_ADDR                 0x5c
-#define IVTV_TDA985X_I2C_ADDR          0x5b
+#define IVTV_VP27SMPX_I2C_ADDR         0x5b
+#define IVTV_M52790_I2C_ADDR           0x48
 
 /* This array should match the IVTV_HW_ defines */
 static const u8 hw_driverids[] = {
@@ -104,18 +106,38 @@ static const u8 hw_driverids[] = {
        I2C_DRIVERID_CS53L32A,
        I2C_DRIVERID_TVEEPROM,
        I2C_DRIVERID_SAA711X,
-       I2C_DRIVERID_TVAUDIO,
        I2C_DRIVERID_UPD64031A,
        I2C_DRIVERID_UPD64083,
        I2C_DRIVERID_SAA717X,
        I2C_DRIVERID_WM8739,
        I2C_DRIVERID_VP27SMPX,
+       I2C_DRIVERID_M52790,
+       0               /* IVTV_HW_GPIO dummy driver ID */
+};
+
+/* This array should match the IVTV_HW_ defines */
+static const u8 hw_addrs[] = {
+       IVTV_CX25840_I2C_ADDR,
+       IVTV_SAA7115_I2C_ADDR,
+       IVTV_SAA7127_I2C_ADDR,
+       IVTV_MSP3400_I2C_ADDR,
+       0,
+       IVTV_WM8775_I2C_ADDR,
+       IVTV_CS53L32A_I2C_ADDR,
+       0,
+       IVTV_SAA7115_I2C_ADDR,
+       IVTV_UPD64031A_I2C_ADDR,
+       IVTV_UPD64083_I2C_ADDR,
+       IVTV_SAA717x_I2C_ADDR,
+       IVTV_WM8739_I2C_ADDR,
+       IVTV_VP27SMPX_I2C_ADDR,
+       IVTV_M52790_I2C_ADDR,
        0               /* IVTV_HW_GPIO dummy driver ID */
 };
 
 /* This array should match the IVTV_HW_ defines */
 static const char * const hw_drivernames[] = {
-       "cx2584x",
+       "cx25840",
        "saa7115",
        "saa7127",
        "msp3400",
@@ -123,31 +145,67 @@ static const char * const hw_drivernames[] = {
        "wm8775",
        "cs53l32a",
        "tveeprom",
-       "saa7114",
-       "tvaudio",
+       "saa7115",
        "upd64031a",
        "upd64083",
        "saa717x",
        "wm8739",
        "vp27smpx",
+       "m52790",
        "gpio",
 };
 
-static int attach_inform(struct i2c_client *client)
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
-       struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+       struct i2c_board_info info;
+       struct i2c_client *c;
+       u8 id;
        int i;
 
-       IVTV_DEBUG_I2C("i2c client attach\n");
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               if (itv->i2c_clients[i] == NULL) {
-                       itv->i2c_clients[i] = client;
-                       break;
-               }
-       }
+       IVTV_DEBUG_I2C("i2c client register\n");
+       if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+               return -1;
+       id = hw_driverids[idx];
+       memset(&info, 0, sizeof(info));
+       strcpy(info.driver_name, hw_drivernames[idx]);
+       info.addr = hw_addrs[idx];
+       for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
+
        if (i == I2C_CLIENTS_MAX) {
-               IVTV_ERR("Insufficient room for new I2C client\n");
+               IVTV_ERR("insufficient room for new I2C client!\n");
+               return -ENOMEM;
        }
+
+       if (id != I2C_DRIVERID_TUNER) {
+               c = i2c_new_device(&itv->i2c_adap, &info);
+               if (c->driver == NULL)
+                       i2c_unregister_device(c);
+               else
+                       itv->i2c_clients[i] = c;
+               return itv->i2c_clients[i] ? 0 : -ENODEV;
+       }
+
+       /* special tuner handling */
+       c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
+       if (c && c->driver == NULL)
+               i2c_unregister_device(c);
+       else if (c)
+               itv->i2c_clients[i++] = c;
+       c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
+       if (c && c->driver == NULL)
+               i2c_unregister_device(c);
+       else if (c)
+               itv->i2c_clients[i++] = c;
+       c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
+       if (c && c->driver == NULL)
+               i2c_unregister_device(c);
+       else if (c)
+               itv->i2c_clients[i++] = c;
+       return 0;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
        return 0;
 }
 
@@ -475,9 +533,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
        .client_register = attach_inform,
        .client_unregister = detach_inform,
        .owner = THIS_MODULE,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-       .class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
 };
 
 static void ivtv_setscl_old(void *data, int state)
@@ -525,15 +580,12 @@ static int ivtv_getsda_old(void *data)
 /* template for i2c-bit-algo */
 static struct i2c_adapter ivtv_i2c_adap_template = {
        .name = "ivtv i2c driver",
-       .id = I2C_HW_B_CX2341X,         /* algo-bit is OR'd with this */
+       .id = I2C_HW_B_CX2341X,
        .algo = NULL,                   /* set by i2c-algo-bit */
        .algo_data = NULL,              /* filled from template */
        .client_register = attach_inform,
        .client_unregister = detach_inform,
        .owner = THIS_MODULE,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-       .class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
 };
 
 static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
@@ -541,7 +593,7 @@ static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
        .setscl         = ivtv_setscl_old,
        .getsda         = ivtv_getsda_old,
        .getscl         = ivtv_getscl_old,
-       .udelay         = 5,
+       .udelay         = 10,
        .timeout        = 200,
 };
 
@@ -558,12 +610,9 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
        IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
                client = itv->i2c_clients[i];
-               if (client == NULL) {
-                       continue;
-               }
-               if (client->driver->command == NULL) {
+               if (client == NULL || client->driver == NULL ||
+                   client->driver->command == NULL)
                        continue;
-               }
                if (addr == client->addr) {
                        retval = client->driver->command(client, cmd, arg);
                        return retval;
@@ -584,7 +633,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
 
        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
                client = itv->i2c_clients[i];
-               if (client == NULL)
+               if (client == NULL || client->driver == NULL)
                        continue;
                if (id == client->driver->id) {
                        retval = client->addr;
@@ -710,6 +759,16 @@ int init_ivtv_i2c(struct ivtv *itv)
 {
        IVTV_DEBUG_I2C("i2c init\n");
 
+       /* Sanity checks for the I2C hardware arrays. They must be the
+        * same size and GPIO must be the last entry.
+        */
+       if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+           ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
+           IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+           hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+               IVTV_ERR("Mismatched I2C hardware arrays\n");
+               return -ENODEV;
+       }
        if (itv->options.newi2c > 0) {
                memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
                       sizeof(struct i2c_adapter));
@@ -718,12 +777,9 @@ int init_ivtv_i2c(struct ivtv *itv)
                       sizeof(struct i2c_adapter));
                memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
                       sizeof(struct i2c_algo_bit_data));
-               /* The mspx4xx chips need a longer delay for some reason */
-               if (itv->hw_flags & IVTV_HW_MSP34XX)
-                       itv->i2c_algo.udelay = 10;
-               itv->i2c_algo.data = itv;
-               itv->i2c_adap.algo_data = &itv->i2c_algo;
        }
+       itv->i2c_algo.data = itv;
+       itv->i2c_adap.algo_data = &itv->i2c_algo;
 
        sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
                itv->num);
index 987042c09b643fb42ef4faabbb7843359e9bdd41..022978cf533db15f0b7f81f7ac8b9c9a3aea041f 100644 (file)
@@ -33,6 +33,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
 int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
 int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
 
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv);
index fd6826f472e3c99ac50029602e0e38ffc136aba7..edef2a579617e722c5357b93775f88620faff327 100644 (file)
@@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
                fmt->fmt.pix.height = itv->main_rect.height;
                fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
                fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-               if (itv->output_mode == OUT_UDMA_YUV) {
+               if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
                        switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
                        case IVTV_YUV_MODE_INTERLACED:
                                fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
@@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
                                break;
                        }
                        fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+                       fmt->fmt.pix.bytesperline = 720;
+                       fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
+                       fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
                        /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
                        fmt->fmt.pix.sizeimage =
-                               fmt->fmt.pix.height * fmt->fmt.pix.width +
-                               fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-               }
-               else if (itv->output_mode == OUT_YUV ||
-                               streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
-                               streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+                               1080 * ((fmt->fmt.pix.height + 31) & ~31);
+               } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
                        fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
                        /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
                        fmt->fmt.pix.sizeimage =
@@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
 static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
                struct v4l2_format *fmt, int set_fmt)
 {
+       struct yuv_playback_info *yi = &itv->yuv_info;
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
        u16 set;
 
@@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
                r.width = fmt->fmt.pix.width;
                r.height = fmt->fmt.pix.height;
                ivtv_get_fmt(itv, streamtype, fmt);
-               if (itv->output_mode != OUT_UDMA_YUV) {
-                       /* TODO: would setting the rect also be valid for this mode? */
-                       fmt->fmt.pix.width = r.width;
-                       fmt->fmt.pix.height = r.height;
-               }
-               if (itv->output_mode == OUT_UDMA_YUV) {
-                       /* TODO: add checks for validity */
+               fmt->fmt.pix.width = r.width;
+               fmt->fmt.pix.height = r.height;
+               if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
                        fmt->fmt.pix.field = field;
+                       if (fmt->fmt.pix.width < 2)
+                               fmt->fmt.pix.width = 2;
+                       if (fmt->fmt.pix.width > 720)
+                               fmt->fmt.pix.width = 720;
+                       if (fmt->fmt.pix.height < 2)
+                               fmt->fmt.pix.height = 2;
+                       if (fmt->fmt.pix.height > 576)
+                               fmt->fmt.pix.height = 576;
                }
-               if (set_fmt) {
-                       if (itv->output_mode == OUT_UDMA_YUV) {
-                               switch (field) {
-                               case V4L2_FIELD_NONE:
-                                       itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
-                                       break;
-                               case V4L2_FIELD_ANY:
-                                       itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
-                                       break;
-                               case V4L2_FIELD_INTERLACED_BT:
-                                       itv->yuv_info.lace_mode =
-                                               IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
-                                       break;
-                               case V4L2_FIELD_INTERLACED_TB:
-                               default:
-                                       itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
-                                       break;
-                               }
-                               itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+               if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+                       /* Return now if we already have some frame data */
+                       if (yi->stream_size)
+                               return -EBUSY;
 
-                               /* Force update of yuv registers */
-                               itv->yuv_info.yuv_forced_update = 1;
-                               return 0;
+                       yi->v4l2_src_w = r.width;
+                       yi->v4l2_src_h = r.height;
+
+                       switch (field) {
+                       case V4L2_FIELD_NONE:
+                               yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+                               break;
+                       case V4L2_FIELD_ANY:
+                               yi->lace_mode = IVTV_YUV_MODE_AUTO;
+                               break;
+                       case V4L2_FIELD_INTERLACED_BT:
+                               yi->lace_mode =
+                                    IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+                               break;
+                       case V4L2_FIELD_INTERLACED_TB:
+                       default:
+                               yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+                               break;
                        }
+                       yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+                       if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+                               itv->dma_data_req_size =
+                                          1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+                       /* Force update of yuv registers */
+                       yi->yuv_forced_update = 1;
+                       return 0;
                }
                return 0;
        }
@@ -660,11 +673,8 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
                chip->ident = V4L2_IDENT_NONE;
                chip->revision = 0;
                if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
-                       if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
-                               struct v4l2_chip_ident *chip = arg;
-
+                       if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
                                chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
-                       }
                        return 0;
                }
                if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
@@ -688,7 +698,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
                        ivtv_reset_ir_gpio(itv);
                }
                if (val & 0x02) {
-                       itv->video_dec_func(itv, cmd, 0);
+                       itv->video_dec_func(itv, cmd, NULL);
                }
                break;
        }
@@ -703,8 +713,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 {
        struct ivtv_open_id *id = NULL;
        u32 data[CX2341X_MBOX_MAX_DATA];
+       int streamtype = 0;
 
-       if (filp) id = (struct ivtv_open_id *)filp->private_data;
+       if (filp) {
+               id = (struct ivtv_open_id *)filp->private_data;
+               streamtype = id->type;
+       }
 
        switch (cmd) {
        case VIDIOC_G_PRIORITY:
@@ -822,6 +836,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
                        cropcap->bounds.height = itv->is_50hz ? 576 : 480;
                        cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
                        cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+               } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+                       cropcap->bounds.width = itv->yuv_info.osd_full_w;
+                       cropcap->bounds.height = itv->yuv_info.osd_full_h;
+                       cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+                       cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
                } else {
                        cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
                        cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
@@ -836,10 +855,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 
                if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
                    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-                       if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-                                crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
-                               itv->main_rect = crop->c;
+                       if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+                               itv->yuv_info.main_rect = crop->c;
                                return 0;
+                       } else {
+                               if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+                                       crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+                                       itv->main_rect = crop->c;
+                                       return 0;
+                               }
                        }
                        return -EINVAL;
                }
@@ -853,7 +877,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 
                if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
                    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-                       crop->c = itv->main_rect;
+                       if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+                               crop->c = itv->yuv_info.main_rect;
+                       else
+                               crop->c = itv->main_rect;
                        return 0;
                }
                if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -864,7 +891,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
        case VIDIOC_ENUM_FMT: {
                static struct v4l2_fmtdesc formats[] = {
                        { 0, 0, 0,
-                         "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+                         "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
                          { 0, 0, 0, 0 }
                        },
                        { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
@@ -1043,6 +1070,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
                        itv->main_rect.height = itv->params.height;
                        ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
                                720, itv->main_rect.height, 0, 0);
+                       itv->yuv_info.main_rect = itv->main_rect;
+                       if (!itv->osd_info) {
+                               itv->yuv_info.osd_full_w = 720;
+                               itv->yuv_info.osd_full_h =
+                                               itv->is_out_50hz ? 576 : 480;
+                       }
                }
                break;
        }
index fd1688e4757dc1fefa51f4a49461a4af0039a3aa..65604dde972614cfb9c1926c3dcd89649cacc2cf 100644 (file)
@@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
                s->sg_pending[idx].dst = buf->dma_handle;
                s->sg_pending[idx].src = offset;
                s->sg_pending[idx].size = s->buf_size;
-               buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
+               buf->bytesused = min(size, s->buf_size);
                buf->dma_xfer_cnt = s->dma_xfer_cnt;
 
                s->q_predma.bytesused += buf->bytesused;
@@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s)
 void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
 {
        struct ivtv *itv = s->itv;
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       u8 frame = yi->draw_frame;
+       struct yuv_frame_info *f = &yi->new_frame_info[frame];
        struct ivtv_buffer *buf;
-       u32 y_size = itv->params.height * itv->params.width;
+       u32 y_size = 720 * ((f->src_h + 31) & ~31);
        u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
        int y_done = 0;
        int bytes_written = 0;
@@ -311,17 +314,42 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
        int idx = 0;
 
        IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+
+       /* Insert buffer block for YUV if needed */
+       if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
+               if (yi->blanking_dmaptr) {
+                       s->sg_pending[idx].src = yi->blanking_dmaptr;
+                       s->sg_pending[idx].dst = offset;
+                       s->sg_pending[idx].size = 720 * 16;
+               }
+               offset += 720 * 16;
+               idx++;
+       }
+
        list_for_each_entry(buf, &s->q_predma.list, list) {
                /* YUV UV Offset from Y Buffer */
-               if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
+               if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
+                               (bytes_written + buf->bytesused) >= y_size) {
+                       s->sg_pending[idx].src = buf->dma_handle;
+                       s->sg_pending[idx].dst = offset;
+                       s->sg_pending[idx].size = y_size - bytes_written;
                        offset = uv_offset;
+                       if (s->sg_pending[idx].size != buf->bytesused) {
+                               idx++;
+                               s->sg_pending[idx].src =
+                                 buf->dma_handle + s->sg_pending[idx - 1].size;
+                               s->sg_pending[idx].dst = offset;
+                               s->sg_pending[idx].size =
+                                  buf->bytesused - s->sg_pending[idx - 1].size;
+                               offset += s->sg_pending[idx].size;
+                       }
                        y_done = 1;
+               } else {
+                       s->sg_pending[idx].src = buf->dma_handle;
+                       s->sg_pending[idx].dst = offset;
+                       s->sg_pending[idx].size = buf->bytesused;
+                       offset += buf->bytesused;
                }
-               s->sg_pending[idx].src = buf->dma_handle;
-               s->sg_pending[idx].dst = offset;
-               s->sg_pending[idx].size = buf->bytesused;
-
-               offset += buf->bytesused;
                bytes_written += buf->bytesused;
 
                /* Sync SG buffers */
@@ -408,7 +436,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
                s_vbi->sg_pending_size = 0;
                s_vbi->dma_xfer_cnt++;
                set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
-               IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
+               IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
        }
 
        s->dma_xfer_cnt++;
@@ -700,12 +728,15 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
        ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
 
        if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
-               itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2;
-               itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0];
+               itv->dma_data_req_size =
+                                1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+               itv->dma_data_req_offset = data[1];
+               if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
+                       ivtv_yuv_frame_complete(itv);
                s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
        }
        else {
-               itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2];
+               itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
                itv->dma_data_req_offset = data[1];
                s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
        }
@@ -715,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
                set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
        }
        else {
+               if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+                       ivtv_yuv_setup_stream_frame(itv);
                clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
                ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
                ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
@@ -731,24 +764,26 @@ static void ivtv_irq_vsync(struct ivtv *itv)
         * one vsync per frame.
         */
        unsigned int frame = read_reg(0x28c0) & 1;
+       struct yuv_playback_info *yi = &itv->yuv_info;
        int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
+       struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
 
        if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
 
-       if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
-               ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
-                       (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
+       if (((frame ^ f->sync_field) == 0 &&
+               ((itv->last_vsync_field & 1) ^ f->sync_field)) ||
+                       (frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
                int next_dma_frame = last_dma_frame;
 
-               if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
-                       if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+               if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
+                       if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
                                write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
                                write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
                                write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
                                write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
-                               next_dma_frame = (next_dma_frame + 1) & 0x3;
-                               atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
-                               itv->yuv_info.fields_lapsed = -1;
+                               next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
+                               atomic_set(&yi->next_dma_frame, next_dma_frame);
+                               yi->fields_lapsed = -1;
                        }
                }
        }
@@ -781,20 +816,22 @@ static void ivtv_irq_vsync(struct ivtv *itv)
                }
 
                /* Check if we need to update the yuv registers */
-               if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
-                       if (!itv->yuv_info.new_frame_info[last_dma_frame].update)
-                               last_dma_frame = (last_dma_frame - 1) & 3;
-
-                       if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {
-                               itv->yuv_info.update_frame = last_dma_frame;
-                               itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
-                               itv->yuv_info.yuv_forced_update = 0;
+               if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
+                       if (!f->update) {
+                               last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
+                               f = &yi->new_frame_info[last_dma_frame];
+                       }
+
+                       if (f->src_w) {
+                               yi->update_frame = last_dma_frame;
+                               f->update = 0;
+                               yi->yuv_forced_update = 0;
                                set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
                                set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
                        }
                }
 
-               itv->yuv_info.fields_lapsed ++;
+               yi->fields_lapsed++;
        }
 }
 
index b05436da7136d04ec422e0c7c31d3ebd3abbefa8..13a6c374d2dbf0833108ff3e0367cbcca7e40f8e 100644 (file)
@@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
        return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
 }
 
-int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
 {
        return ivtv_api(priv, cmd, in, data);
 }
index 71a54eef8fc7ca8814f4ab5c6851b4b8f6e9abd1..6ef12091e3f3b010904d0901135a913195c06ae6 100644 (file)
@@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
 int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
 int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
 int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
-int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
 
 #endif
index 398bd33033ed6f77ca5291b301f96da8ff4e9211..05564919b57f680c9afc227a95447beabe38ecc7 100644 (file)
@@ -25,6 +25,7 @@
 #include "ivtv-routing.h"
 
 #include <media/msp3400.h>
+#include <media/m52790.h>
 #include <media/upd64031a.h>
 #include <media/upd64083.h>
 
    settings. */
 void ivtv_audio_set_io(struct ivtv *itv)
 {
+       const struct ivtv_card_audio_input *in;
        struct v4l2_routing route;
-       u32 audio_input;
-       int mux_input;
 
        /* Determine which input to use */
-       if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
-               audio_input = itv->card->radio_input.audio_input;
-               mux_input = itv->card->radio_input.muxer_input;
-       } else {
-               audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
-               mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
-       }
+       if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+               in = &itv->card->radio_input;
+       else
+               in = &itv->card->audio_inputs[itv->audio_input];
 
        /* handle muxer chips */
-       route.input = mux_input;
+       route.input = in->muxer_input;
        route.output = 0;
+       if (itv->card->hw_muxer & IVTV_HW_M52790)
+               route.output = M52790_OUT_STEREO;
        ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 
-       route.input = audio_input;
-       if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
+       route.input = in->audio_input;
+       route.output = 0;
+       if (itv->card->hw_audio & IVTV_HW_MSP34XX)
                route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-       }
        ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 }
 
index 74fb0e021979eec1b805c8f16b34d14f21287ba6..24d98ecf35ad13de77f4d2457de6c8ba09c9c584 100644 (file)
@@ -43,7 +43,7 @@
 #include "ivtv-cards.h"
 #include "ivtv-streams.h"
 
-static struct file_operations ivtv_v4l2_enc_fops = {
+static const struct file_operations ivtv_v4l2_enc_fops = {
       .owner = THIS_MODULE,
       .read = ivtv_v4l2_read,
       .write = ivtv_v4l2_write,
@@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = {
       .poll = ivtv_v4l2_enc_poll,
 };
 
-static struct file_operations ivtv_v4l2_dec_fops = {
+static const struct file_operations ivtv_v4l2_dec_fops = {
       .owner = THIS_MODULE,
       .read = ivtv_v4l2_read,
       .write = ivtv_v4l2_write,
@@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
                /* Initialize Digitizer for Capture */
-               itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+               itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
                ivtv_msleep_timeout(300, 1);
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-               itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
+               itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
        }
 
        /* begin_capture */
@@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
 
        IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
 
-       /* Clear Streamoff */
-       if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
-               /* Initialize Decoder */
-               /* Reprogram Decoder YUV Buffers for YUV */
-               write_reg(yuv_offset[0] >> 4, 0x82c);
-               write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
-               write_reg(yuv_offset[0] >> 4, 0x834);
-               write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
-
-               write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24);
-
-               write_reg_sync(0x00108080, 0x2898);
-               /* Enable YUV decoder output */
-               write_reg_sync(0x01, IVTV_REG_VDM);
-       }
-
        ivtv_setup_v4l2_decode_stream(s);
 
        /* set dma size to 65536 bytes */
        ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
 
+       /* Clear Streamoff */
        clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 
        /* Zero out decoder counters */
index d050de2a7229cc2e9bbf37ad77be2b30dbb60958..0f1d4cc4b4d9b49dd95f2aa7b46411f0a9769fd9 100644 (file)
@@ -22,7 +22,7 @@
 
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 1
+#define IVTV_DRIVER_VERSION_MINOR 2
 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
index 9091c4837bbca23bcb0f65ad0135537406b68bea..85183480a2259e610aaad59e4341dd4d91d4d5c4 100644 (file)
 #include "ivtv-udma.h"
 #include "ivtv-yuv.h"
 
-const u32 yuv_offset[4] = {
-       IVTV_YUV_BUFFER_OFFSET,
-       IVTV_YUV_BUFFER_OFFSET_1,
-       IVTV_YUV_BUFFER_OFFSET_2,
-       IVTV_YUV_BUFFER_OFFSET_3
+/* YUV buffer offsets */
+const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
+       0x001a8600,
+       0x00240400,
+       0x002d8200,
+       0x00370000,
+       0x00029000,
+       0x000C0E00,
+       0x006B0400,
+       0x00748200
 };
 
 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
-                                struct ivtv_dma_frame *args)
+                                 struct ivtv_dma_frame *args)
 {
        struct ivtv_dma_page_info y_dma;
        struct ivtv_dma_page_info uv_dma;
-
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       u8 frame = yi->draw_frame;
+       struct yuv_frame_info *f = &yi->new_frame_info[frame];
        int i;
        int y_pages, uv_pages;
-
        unsigned long y_buffer_offset, uv_buffer_offset;
        int y_decode_height, uv_decode_height, y_size;
-       int frame = atomic_read(&itv->yuv_info.next_fill_frame);
 
        y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
        uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
 
-       y_decode_height = uv_decode_height = args->src.height + args->src.top;
+       y_decode_height = uv_decode_height = f->src_h + f->src_y;
 
-       if (y_decode_height < 512-16)
+       if (f->offset_y)
                y_buffer_offset += 720 * 16;
 
        if (y_decode_height & 15)
@@ -60,8 +65,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 
        /* Still in USE */
        if (dma->SG_length || dma->page_count) {
-               IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
-                               dma->SG_length, dma->page_count);
+               IVTV_DEBUG_WARN
+                   ("prep_user_dma: SG_length %d page_count %d still full?\n",
+                    dma->SG_length, dma->page_count);
                return -EBUSY;
        }
 
@@ -77,8 +83,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
        dma->page_count = y_dma.page_count + uv_dma.page_count;
 
        if (y_pages + uv_pages != dma->page_count) {
-               IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
-                               y_pages + uv_pages, dma->page_count);
+               IVTV_DEBUG_WARN
+                   ("failed to map user pages, returned %d instead of %d\n",
+                    y_pages + uv_pages, dma->page_count);
 
                for (i = 0; i < dma->page_count; i++) {
                        put_page(dma->map[i]);
@@ -99,16 +106,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
        dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
 
        /* Fill SG Array with new values */
-       ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
+       ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
 
        /* If we've offset the y plane, ensure top area is blanked */
-       if (args->src.height + args->src.top < 512-16) {
-               if (itv->yuv_info.blanking_dmaptr) {
-                       dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
-                       dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
-                       dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
-                       dma->SG_length++;
-               }
+       if (f->offset_y && yi->blanking_dmaptr) {
+               dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
+               dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
+               dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
+               dma->SG_length++;
        }
 
        /* Tag SG Array with Interrupt Bit */
@@ -121,11 +126,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 /* We rely on a table held in the firmware - Quick check. */
 int ivtv_yuv_filter_check(struct ivtv *itv)
 {
-       int i, offset_y, offset_uv;
+       int i, y, uv;
 
-       for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
-               if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
-                   (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
+       for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
+               if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
+                   (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
                        IVTV_WARN ("YUV filter table not found in firmware.\n");
                        return -1;
                }
@@ -135,69 +140,67 @@ int ivtv_yuv_filter_check(struct ivtv *itv)
 
 static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
 {
-       int filter_index, filter_line;
+       u32 i, line;
 
        /* If any filter is -1, then don't update it */
        if (h_filter > -1) {
-               if (h_filter > 4) h_filter = 4;
-               filter_index = h_filter * 384;
-               filter_line = 0;
-               while (filter_line < 16) {
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
-                       filter_index += 4;
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
-                       filter_index += 4;
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
-                       filter_index += 4;
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
-                       filter_index += 4;
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
-                       write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
-                       filter_index += 8;
+               if (h_filter > 4)
+                       h_filter = 4;
+               i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
+               for (line = 0; line < 16; line++) {
+                       write_reg(read_dec(i), 0x02804);
+                       write_reg(read_dec(i), 0x0281c);
+                       i += 4;
+                       write_reg(read_dec(i), 0x02808);
+                       write_reg(read_dec(i), 0x02820);
+                       i += 4;
+                       write_reg(read_dec(i), 0x0280c);
+                       write_reg(read_dec(i), 0x02824);
+                       i += 4;
+                       write_reg(read_dec(i), 0x02810);
+                       write_reg(read_dec(i), 0x02828);
+                       i += 4;
+                       write_reg(read_dec(i), 0x02814);
+                       write_reg(read_dec(i), 0x0282c);
+                       i += 8;
                        write_reg(0, 0x02818);
                        write_reg(0, 0x02830);
-                       filter_line ++;
                }
-               IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
+               IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
        }
 
        if (v_filter_1 > -1) {
-               if (v_filter_1 > 4) v_filter_1 = 4;
-               filter_index = v_filter_1 * 192;
-               filter_line = 0;
-               while (filter_line < 16) {
-                       write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
-                       filter_index += 4;
-                       write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
-                       filter_index += 8;
+               if (v_filter_1 > 4)
+                       v_filter_1 = 4;
+               i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
+               for (line = 0; line < 16; line++) {
+                       write_reg(read_dec(i), 0x02900);
+                       i += 4;
+                       write_reg(read_dec(i), 0x02904);
+                       i += 8;
                        write_reg(0, 0x02908);
-                       filter_line ++;
                }
-               IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
+               IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
        }
 
        if (v_filter_2 > -1) {
-               if (v_filter_2 > 4) v_filter_2 = 4;
-               filter_index = v_filter_2 * 192;
-               filter_line = 0;
-               while (filter_line < 16) {
-                       write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
-                       filter_index += 4;
-                       write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
-                       filter_index += 8;
+               if (v_filter_2 > 4)
+                       v_filter_2 = 4;
+               i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
+               for (line = 0; line < 16; line++) {
+                       write_reg(read_dec(i), 0x0290c);
+                       i += 4;
+                       write_reg(read_dec(i), 0x02910);
+                       i += 8;
                        write_reg(0, 0x02914);
-                       filter_line ++;
                }
-               IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
+               IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
        }
 }
 
-static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
+static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
 {
+       struct yuv_playback_info *yi = &itv->yuv_info;
        u32 reg_2834, reg_2838, reg_283c;
        u32 reg_2844, reg_2854, reg_285c;
        u32 reg_2864, reg_2874, reg_2890;
@@ -206,18 +209,19 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
        int h_filter;
        u32 master_width;
 
-       IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
-                        window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
+       IVTV_DEBUG_WARN
+           ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
+            f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
 
        /* How wide is the src image */
-       x_cutoff  = window->src_w + window->src_x;
+       x_cutoff = f->src_w + f->src_x;
 
        /* Set the display width */
-       reg_2834 = window->dst_w;
+       reg_2834 = f->dst_w;
        reg_2838 = reg_2834;
 
        /* Set the display position */
-       reg_2890 = window->dst_x;
+       reg_2890 = f->dst_x;
 
        /* Index into the image horizontally */
        reg_2870 = 0;
@@ -228,32 +232,31 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
           Gradually adjust the offset to avoid the video 'snapping'
           left/right if it gets dragged through this region.
           Only do this if osd is full width. */
-       if (window->vis_w == 720) {
-               if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
-                       reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
-               }
-               else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
-                       reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
-               }
+       if (f->vis_w == 720) {
+               if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
+                       reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
+               else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
+                       reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
 
-               if (window->dst_w >= window->src_w)
+               if (f->dst_w >= f->src_w)
                        reg_2870 = reg_2870 << 16 | reg_2870;
                else
                        reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
        }
 
-       if (window->dst_w < window->src_w)
+       if (f->dst_w < f->src_w)
                reg_2870 = 0x000d000e - reg_2870;
        else
                reg_2870 = 0x0012000e - reg_2870;
 
        /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
-       reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
+       reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
 
-       if (window->dst_w >= window->src_w) {
+       if (f->dst_w >= f->src_w) {
                x_cutoff &= ~1;
-               master_width = (window->src_w * 0x00200000) / (window->dst_w);
-               if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
+               master_width = (f->src_w * 0x00200000) / (f->dst_w);
+               if (master_width * f->dst_w != f->src_w * 0x00200000)
+                       master_width++;
                reg_2834 = (reg_2834 << 16) | x_cutoff;
                reg_2838 = (reg_2838 << 16) | x_cutoff;
                reg_283c = master_width >> 2;
@@ -264,17 +267,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
 
                /* We also need to factor in the scaling
                   (src_w - dst_w) / (src_w / 4) */
-               if (window->dst_w > window->src_w)
-                       reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
+               if (f->dst_w > f->src_w)
+                       reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
                else
                        reg_2870_base = 0;
 
                reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
                reg_2874 = 0;
-       }
-       else if (window->dst_w < window->src_w / 2) {
-               master_width = (window->src_w * 0x00080000) / window->dst_w;
-               if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
+       } else if (f->dst_w < f->src_w / 2) {
+               master_width = (f->src_w * 0x00080000) / f->dst_w;
+               if (master_width * f->dst_w != f->src_w * 0x00080000)
+                       master_width++;
                reg_2834 = (reg_2834 << 16) | x_cutoff;
                reg_2838 = (reg_2838 << 16) | x_cutoff;
                reg_283c = master_width >> 2;
@@ -282,13 +285,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
                reg_2854 = master_width;
                reg_285c = master_width >> 1;
                reg_2864 = master_width >> 1;
-               reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
-               reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
+               reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
+               reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
                reg_2874 = 0x00000012;
-       }
-       else {
-               master_width = (window->src_w * 0x00100000) / window->dst_w;
-               if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
+       } else {
+               master_width = (f->src_w * 0x00100000) / f->dst_w;
+               if (master_width * f->dst_w != f->src_w * 0x00100000)
+                       master_width++;
                reg_2834 = (reg_2834 << 16) | x_cutoff;
                reg_2838 = (reg_2838 << 16) | x_cutoff;
                reg_283c = master_width >> 2;
@@ -296,62 +299,70 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
                reg_2854 = master_width;
                reg_285c = master_width >> 1;
                reg_2864 = master_width >> 1;
-               reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
-               reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
+               reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
+               reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
                reg_2874 = 0x00000001;
        }
 
        /* Select the horizontal filter */
-       if (window->src_w == window->dst_w) {
+       if (f->src_w == f->dst_w) {
                /* An exact size match uses filter 0 */
                h_filter = 0;
-       }
-       else {
+       } else {
                /* Figure out which filter to use */
-               h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
+               h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
                h_filter = (h_filter >> 1) + (h_filter & 1);
                /* Only an exact size match can use filter 0 */
-               if (h_filter == 0) h_filter = 1;
+               h_filter += !h_filter;
        }
 
        write_reg(reg_2834, 0x02834);
        write_reg(reg_2838, 0x02838);
-       IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838);
+       IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
+                      yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
 
        write_reg(reg_283c, 0x0283c);
        write_reg(reg_2844, 0x02844);
 
-       IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844);
+       IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
+                      yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
 
        write_reg(0x00080514, 0x02840);
        write_reg(0x00100514, 0x02848);
-       IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
+       IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
+                      yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
 
        write_reg(reg_2854, 0x02854);
-       IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
+       IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
+                      yi->reg_2854, reg_2854);
 
        write_reg(reg_285c, 0x0285c);
        write_reg(reg_2864, 0x02864);
-       IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864);
+       IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
+                      yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
 
        write_reg(reg_2874, 0x02874);
-       IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
+       IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
+                      yi->reg_2874, reg_2874);
 
        write_reg(reg_2870, 0x02870);
-       IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
+       IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
+                      yi->reg_2870, reg_2870);
 
-       write_reg( reg_2890,0x02890);
-       IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
+       write_reg(reg_2890, 0x02890);
+       IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
+                      yi->reg_2890, reg_2890);
 
        /* Only update the filter if we really need to */
-       if (h_filter != itv->yuv_info.h_filter) {
-               ivtv_yuv_filter (itv,h_filter,-1,-1);
-               itv->yuv_info.h_filter = h_filter;
+       if (h_filter != yi->h_filter) {
+               ivtv_yuv_filter(itv, h_filter, -1, -1);
+               yi->h_filter = h_filter;
        }
 }
 
-static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
+static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
 {
+       struct yuv_playback_info *yi = &itv->yuv_info;
        u32 master_height;
        u32 reg_2918, reg_291c, reg_2920, reg_2928;
        u32 reg_2930, reg_2934, reg_293c;
@@ -359,69 +370,59 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
        u32 reg_2950, reg_2954, reg_2958, reg_295c;
        u32 reg_2960, reg_2964, reg_2968, reg_296c;
        u32 reg_289c;
-       u32 src_y_major_y, src_y_minor_y;
-       u32 src_y_major_uv, src_y_minor_uv;
+       u32 src_major_y, src_minor_y;
+       u32 src_major_uv, src_minor_uv;
        u32 reg_2964_base, reg_2968_base;
        int v_filter_1, v_filter_2;
 
-       IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
-               window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
+       IVTV_DEBUG_WARN
+           ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
+            f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
 
        /* What scaling mode is being used... */
-       if (window->interlaced_y) {
-               IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
-       }
-       else {
-               IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
-       }
+       IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
+                      f->interlaced_y ? "Interlaced" : "Progressive");
 
-       if (window->interlaced_uv) {
-               IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
-       }
-       else {
-               IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
-       }
+       IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
+                      f->interlaced_uv ? "Interlaced" : "Progressive");
 
        /* What is the source video being treated as... */
-       if (itv->yuv_info.frame_interlaced) {
-               IVTV_DEBUG_WARN("Source video: Interlaced\n");
-       }
-       else {
-               IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
-       }
+       IVTV_DEBUG_WARN("Source video: %s\n",
+                       f->interlaced ? "Interlaced" : "Progressive");
 
        /* We offset into the image using two different index methods, so split
           the y source coord into two parts. */
-       if (window->src_y < 8) {
-               src_y_minor_uv = window->src_y;
-               src_y_major_uv = 0;
-       }
-       else {
-               src_y_minor_uv = 8;
-               src_y_major_uv = window->src_y - 8;
+       if (f->src_y < 8) {
+               src_minor_uv = f->src_y;
+               src_major_uv = 0;
+       } else {
+               src_minor_uv = 8;
+               src_major_uv = f->src_y - 8;
        }
 
-       src_y_minor_y = src_y_minor_uv;
-       src_y_major_y = src_y_major_uv;
+       src_minor_y = src_minor_uv;
+       src_major_y = src_major_uv;
 
-       if (window->offset_y) src_y_minor_y += 16;
+       if (f->offset_y)
+               src_minor_y += 16;
 
-       if (window->interlaced_y)
-               reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
+       if (f->interlaced_y)
+               reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
        else
-               reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
+               reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
 
-       if (window->interlaced_uv)
-               reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
+       if (f->interlaced_uv)
+               reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
        else
-               reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
+               reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
 
-       reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
-       reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
+       reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
+       reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
 
-       if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
-               master_height = (window->src_h * 0x00400000) / window->dst_h;
-               if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
+       if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
+               master_height = (f->src_h * 0x00400000) / f->dst_h;
+               if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
+                       master_height++;
                reg_2920 = master_height >> 2;
                reg_2928 = master_height >> 3;
                reg_2930 = master_height;
@@ -429,45 +430,42 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
                reg_2964_base >>= 3;
                reg_2968_base >>= 3;
                reg_296c = 0x00000000;
-       }
-       else if (window->dst_h >= window->src_h) {
-               master_height = (window->src_h * 0x00400000) / window->dst_h;
+       } else if (f->dst_h >= f->src_h) {
+               master_height = (f->src_h * 0x00400000) / f->dst_h;
                master_height = (master_height >> 1) + (master_height & 1);
                reg_2920 = master_height >> 2;
                reg_2928 = master_height >> 2;
                reg_2930 = master_height;
                reg_2940 = master_height >> 1;
                reg_296c = 0x00000000;
-               if (window->interlaced_y) {
+               if (f->interlaced_y) {
                        reg_2964_base >>= 3;
-               }
-               else {
-                       reg_296c ++;
+               } else {
+                       reg_296c++;
                        reg_2964_base >>= 2;
                }
-               if (window->interlaced_uv) reg_2928 >>= 1;
+               if (f->interlaced_uv)
+                       reg_2928 >>= 1;
                reg_2968_base >>= 3;
-       }
-       else if (window->dst_h >= window->src_h / 2) {
-               master_height = (window->src_h * 0x00200000) / window->dst_h;
+       } else if (f->dst_h >= f->src_h / 2) {
+               master_height = (f->src_h * 0x00200000) / f->dst_h;
                master_height = (master_height >> 1) + (master_height & 1);
                reg_2920 = master_height >> 2;
                reg_2928 = master_height >> 2;
                reg_2930 = master_height;
                reg_2940 = master_height;
                reg_296c = 0x00000101;
-               if (window->interlaced_y) {
+               if (f->interlaced_y) {
                        reg_2964_base >>= 2;
-               }
-               else {
-                       reg_296c ++;
+               } else {
+                       reg_296c++;
                        reg_2964_base >>= 1;
                }
-               if (window->interlaced_uv) reg_2928 >>= 1;
+               if (f->interlaced_uv)
+                       reg_2928 >>= 1;
                reg_2968_base >>= 2;
-       }
-       else {
-               master_height = (window->src_h * 0x00100000) / window->dst_h;
+       } else {
+               master_height = (f->src_h * 0x00100000) / f->dst_h;
                master_height = (master_height >> 1) + (master_height & 1);
                reg_2920 = master_height >> 2;
                reg_2928 = master_height >> 2;
@@ -480,13 +478,12 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
 
        /* FIXME These registers change depending on scaled / unscaled output
           We really need to work out what they should be */
-       if (window->src_h == window->dst_h){
+       if (f->src_h == f->dst_h) {
                reg_2934 = 0x00020000;
                reg_293c = 0x00100000;
                reg_2944 = 0x00040000;
                reg_294c = 0x000b0000;
-       }
-       else {
+       } else {
                reg_2934 = 0x00000FF0;
                reg_293c = 0x00000FF0;
                reg_2944 = 0x00000FF0;
@@ -494,34 +491,36 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
        }
 
        /* The first line to be displayed */
-       reg_2950 = 0x00010000 + src_y_major_y;
-       if (window->interlaced_y) reg_2950 += 0x00010000;
+       reg_2950 = 0x00010000 + src_major_y;
+       if (f->interlaced_y)
+               reg_2950 += 0x00010000;
        reg_2954 = reg_2950 + 1;
 
-       reg_2958 = 0x00010000 + (src_y_major_y >> 1);
-       if (window->interlaced_uv) reg_2958 += 0x00010000;
+       reg_2958 = 0x00010000 + (src_major_y >> 1);
+       if (f->interlaced_uv)
+               reg_2958 += 0x00010000;
        reg_295c = reg_2958 + 1;
 
-       if (itv->yuv_info.decode_height == 480)
+       if (yi->decode_height == 480)
                reg_289c = 0x011e0017;
        else
                reg_289c = 0x01500017;
 
-       if (window->dst_y < 0)
-               reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
+       if (f->dst_y < 0)
+               reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
        else
-               reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
+               reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
 
        /* How much of the source to decode.
           Take into account the source offset */
-       reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
-                       ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
+       reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
+               (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
 
        /* Calculate correct value for register 2964 */
-       if (window->src_h == window->dst_h)
+       if (f->src_h == f->dst_h) {
                reg_2964 = 1;
-       else {
-               reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
+       else {
+               reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
                reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
        }
        reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
@@ -536,283 +535,246 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
        /* Deviate further from what it should be. I find the flicker headache
           inducing so try to reduce it slightly. Leave 2968 as-is otherwise
           colours foul. */
-       if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
-               reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
+       if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
+               reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
 
-       if (!window->interlaced_y) reg_2964 -= 0x00010001;
-       if (!window->interlaced_uv) reg_2968 -= 0x00010001;
+       if (!f->interlaced_y)
+               reg_2964 -= 0x00010001;
+       if (!f->interlaced_uv)
+               reg_2968 -= 0x00010001;
 
        reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
        reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
 
        /* Select the vertical filter */
-       if (window->src_h == window->dst_h) {
+       if (f->src_h == f->dst_h) {
                /* An exact size match uses filter 0/1 */
                v_filter_1 = 0;
                v_filter_2 = 1;
-       }
-       else {
+       } else {
                /* Figure out which filter to use */
-               v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
+               v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
                v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
                /* Only an exact size match can use filter 0 */
-               if (v_filter_1 == 0) v_filter_1 = 1;
+               v_filter_1 += !v_filter_1;
                v_filter_2 = v_filter_1;
        }
 
        write_reg(reg_2934, 0x02934);
        write_reg(reg_293c, 0x0293c);
-       IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c);
+       IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
+                      yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
        write_reg(reg_2944, 0x02944);
        write_reg(reg_294c, 0x0294c);
-       IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c);
+       IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
+                      yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
 
        /* Ensure 2970 is 0 (does it ever change ?) */
 /*     write_reg(0,0x02970); */
-/*     IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
+/*     IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
 
        write_reg(reg_2930, 0x02938);
        write_reg(reg_2930, 0x02930);
-       IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930);
+       IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
+                      yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
 
        write_reg(reg_2928, 0x02928);
-       write_reg(reg_2928+0x514, 0x0292C);
-       IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514);
+       write_reg(reg_2928 + 0x514, 0x0292C);
+       IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
+                      yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
 
        write_reg(reg_2920, 0x02920);
-       write_reg(reg_2920+0x514, 0x02924);
-       IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920);
+       write_reg(reg_2920 + 0x514, 0x02924);
+       IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
+                      yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
 
-       write_reg (reg_2918,0x02918);
-       write_reg (reg_291c,0x0291C);
-       IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c);
+       write_reg(reg_2918, 0x02918);
+       write_reg(reg_291c, 0x0291C);
+       IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
+                      yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
 
        write_reg(reg_296c, 0x0296c);
-       IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
+       IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
+                      yi->reg_296c, reg_296c);
 
        write_reg(reg_2940, 0x02948);
        write_reg(reg_2940, 0x02940);
-       IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940);
+       IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
+                      yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
 
        write_reg(reg_2950, 0x02950);
        write_reg(reg_2954, 0x02954);
-       IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954);
+       IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
+                      yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
 
        write_reg(reg_2958, 0x02958);
        write_reg(reg_295c, 0x0295C);
-       IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c);
+       IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
+                      yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
 
        write_reg(reg_2960, 0x02960);
-       IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
+       IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
+                      yi->reg_2960, reg_2960);
 
        write_reg(reg_2964, 0x02964);
        write_reg(reg_2968, 0x02968);
-       IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968);
+       IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
+                      yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
 
-       write_reg( reg_289c,0x0289c);
-       IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
+       write_reg(reg_289c, 0x0289c);
+       IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
+                      yi->reg_289c, reg_289c);
 
        /* Only update filter 1 if we really need to */
-       if (v_filter_1 != itv->yuv_info.v_filter_1) {
-               ivtv_yuv_filter (itv,-1,v_filter_1,-1);
-               itv->yuv_info.v_filter_1 = v_filter_1;
+       if (v_filter_1 != yi->v_filter_1) {
+               ivtv_yuv_filter(itv, -1, v_filter_1, -1);
+               yi->v_filter_1 = v_filter_1;
        }
 
        /* Only update filter 2 if we really need to */
-       if (v_filter_2 != itv->yuv_info.v_filter_2) {
-               ivtv_yuv_filter (itv,-1,-1,v_filter_2);
-               itv->yuv_info.v_filter_2 = v_filter_2;
+       if (v_filter_2 != yi->v_filter_2) {
+               ivtv_yuv_filter(itv, -1, -1, v_filter_2);
+               yi->v_filter_2 = v_filter_2;
        }
-
 }
 
 /* Modify the supplied coordinate information to fit the visible osd area */
-static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
+static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
 {
-       int osd_crop, lace_threshold;
+       struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
+       int osd_crop;
        u32 osd_scale;
        u32 yuv_update = 0;
 
-       lace_threshold = itv->yuv_info.lace_threshold;
-       if (lace_threshold < 0)
-               lace_threshold = itv->yuv_info.decode_height - 1;
-
-       /* Work out the lace settings */
-       switch (itv->yuv_info.lace_mode) {
-               case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
-                       itv->yuv_info.frame_interlaced = 0;
-                       if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
-                               window->interlaced_y = 0;
-                       else
-                               window->interlaced_y = 1;
-
-                       if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
-                               window->interlaced_uv = 0;
-                       else
-                               window->interlaced_uv = 1;
-                       break;
-
-               case IVTV_YUV_MODE_AUTO:
-                       if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
-                               itv->yuv_info.frame_interlaced = 0;
-                               if ((window->tru_h < 512) ||
-                                 (window->tru_h > 576 && window->tru_h < 1021) ||
-                                 (window->tru_w > 720 && window->tru_h < 1021))
-                                       window->interlaced_y = 0;
-                               else
-                                       window->interlaced_y = 1;
-
-                               if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
-                                       window->interlaced_uv = 0;
-                               else
-                                       window->interlaced_uv = 1;
-                       }
-                       else {
-                               itv->yuv_info.frame_interlaced = 1;
-                               window->interlaced_y = 1;
-                               window->interlaced_uv = 1;
-                       }
-                       break;
-
-                       case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
-               default:
-                       itv->yuv_info.frame_interlaced = 1;
-                       window->interlaced_y = 1;
-                       window->interlaced_uv = 1;
-                       break;
-       }
-
        /* Sorry, but no negative coords for src */
-       if (window->src_x < 0) window->src_x = 0;
-       if (window->src_y < 0) window->src_y = 0;
+       if (f->src_x < 0)
+               f->src_x = 0;
+       if (f->src_y < 0)
+               f->src_y = 0;
 
        /* Can only reduce width down to 1/4 original size */
-       if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
-               window->src_x += osd_crop / 2;
-               window->src_w = (window->src_w - osd_crop) & ~3;
-               window->dst_w = window->src_w / 4;
-               window->dst_w += window->dst_w & 1;
+       if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
+               f->src_x += osd_crop / 2;
+               f->src_w = (f->src_w - osd_crop) & ~3;
+               f->dst_w = f->src_w / 4;
+               f->dst_w += f->dst_w & 1;
        }
 
        /* Can only reduce height down to 1/4 original size */
-       if (window->src_h / window->dst_h >= 2) {
-               /* Overflow may be because we're running progressive, so force mode switch */
-               window->interlaced_y = 1;
+       if (f->src_h / f->dst_h >= 2) {
+               /* Overflow may be because we're running progressive,
+                  so force mode switch */
+               f->interlaced_y = 1;
                /* Make sure we're still within limits for interlace */
-               if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
+               if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
                        /* If we reach here we'll have to force the height. */
-                       window->src_y += osd_crop / 2;
-                       window->src_h = (window->src_h - osd_crop) & ~3;
-                       window->dst_h = window->src_h / 4;
-                       window->dst_h += window->dst_h & 1;
+                       f->src_y += osd_crop / 2;
+                       f->src_h = (f->src_h - osd_crop) & ~3;
+                       f->dst_h = f->src_h / 4;
+                       f->dst_h += f->dst_h & 1;
                }
        }
 
        /* If there's nothing to safe to display, we may as well stop now */
-       if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
+       if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
+           (int)f->src_w <= 2 || (int)f->src_h <= 2) {
                return IVTV_YUV_UPDATE_INVALID;
        }
 
        /* Ensure video remains inside OSD area */
-       osd_scale = (window->src_h << 16) / window->dst_h;
+       osd_scale = (f->src_h << 16) / f->dst_h;
 
-       if ((osd_crop = window->pan_y - window->dst_y) > 0) {
+       if ((osd_crop = f->pan_y - f->dst_y) > 0) {
                /* Falls off the upper edge - crop */
-               window->src_y += (osd_scale * osd_crop) >> 16;
-               window->src_h -= (osd_scale * osd_crop) >> 16;
-               window->dst_h -= osd_crop;
-               window->dst_y = 0;
-       }
-       else {
-               window->dst_y -= window->pan_y;
+               f->src_y += (osd_scale * osd_crop) >> 16;
+               f->src_h -= (osd_scale * osd_crop) >> 16;
+               f->dst_h -= osd_crop;
+               f->dst_y = 0;
+       } else {
+               f->dst_y -= f->pan_y;
        }
 
-       if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
+       if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
                /* Falls off the lower edge - crop */
-               window->dst_h -= osd_crop;
-               window->src_h -= (osd_scale * osd_crop) >> 16;
+               f->dst_h -= osd_crop;
+               f->src_h -= (osd_scale * osd_crop) >> 16;
        }
 
-       osd_scale = (window->src_w << 16) / window->dst_w;
+       osd_scale = (f->src_w << 16) / f->dst_w;
 
-       if ((osd_crop = window->pan_x - window->dst_x) > 0) {
+       if ((osd_crop = f->pan_x - f->dst_x) > 0) {
                /* Fall off the left edge - crop */
-               window->src_x += (osd_scale * osd_crop) >> 16;
-               window->src_w -= (osd_scale * osd_crop) >> 16;
-               window->dst_w -= osd_crop;
-               window->dst_x = 0;
-       }
-       else {
-               window->dst_x -= window->pan_x;
+               f->src_x += (osd_scale * osd_crop) >> 16;
+               f->src_w -= (osd_scale * osd_crop) >> 16;
+               f->dst_w -= osd_crop;
+               f->dst_x = 0;
+       } else {
+               f->dst_x -= f->pan_x;
        }
 
-       if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
+       if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
                /* Falls off the right edge - crop */
-               window->dst_w -= osd_crop;
-               window->src_w -= (osd_scale * osd_crop) >> 16;
+               f->dst_w -= osd_crop;
+               f->src_w -= (osd_scale * osd_crop) >> 16;
        }
 
        /* The OSD can be moved. Track to it */
-       window->dst_x += itv->yuv_info.osd_x_offset;
-       window->dst_y += itv->yuv_info.osd_y_offset;
+       f->dst_x += itv->yuv_info.osd_x_offset;
+       f->dst_y += itv->yuv_info.osd_y_offset;
 
        /* Width & height for both src & dst must be even.
           Same for coordinates. */
-       window->dst_w &= ~1;
-       window->dst_x &= ~1;
+       f->dst_w &= ~1;
+       f->dst_x &= ~1;
 
-       window->src_w += window->src_x & 1;
-       window->src_x &= ~1;
+       f->src_w += f->src_x & 1;
+       f->src_x &= ~1;
 
-       window->src_w &= ~1;
-       window->dst_w &= ~1;
+       f->src_w &= ~1;
+       f->dst_w &= ~1;
 
-       window->dst_h &= ~1;
-       window->dst_y &= ~1;
+       f->dst_h &= ~1;
+       f->dst_y &= ~1;
 
-       window->src_h += window->src_y & 1;
-       window->src_y &= ~1;
+       f->src_h += f->src_y & 1;
+       f->src_y &= ~1;
 
-       window->src_h &= ~1;
-       window->dst_h &= ~1;
+       f->src_h &= ~1;
+       f->dst_h &= ~1;
 
-       /* Due to rounding, we may have reduced the output size to <1/4 of the source
-          Check again, but this time just resize. Don't change source coordinates */
-       if (window->dst_w < window->src_w / 4) {
-               window->src_w &= ~3;
-               window->dst_w = window->src_w / 4;
-               window->dst_w += window->dst_w & 1;
+       /* Due to rounding, we may have reduced the output size to <1/4 of
+          the source. Check again, but this time just resize. Don't change
+          source coordinates */
+       if (f->dst_w < f->src_w / 4) {
+               f->src_w &= ~3;
+               f->dst_w = f->src_w / 4;
+               f->dst_w += f->dst_w & 1;
        }
-       if (window->dst_h < window->src_h / 4) {
-               window->src_h &= ~3;
-               window->dst_h = window->src_h / 4;
-               window->dst_h += window->dst_h & 1;
+       if (f->dst_h < f->src_h / 4) {
+               f->src_h &= ~3;
+               f->dst_h = f->src_h / 4;
+               f->dst_h += f->dst_h & 1;
        }
 
        /* Check again. If there's nothing to safe to display, stop now */
-       if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
+       if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
+           (int)f->src_w <= 2 || (int)f->src_h <= 2) {
                return IVTV_YUV_UPDATE_INVALID;
        }
 
        /* Both x offset & width are linked, so they have to be done together */
-       if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
-           (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
-           (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
-           (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
-           (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
-           (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
+       if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
+           (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
+           (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
                yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
        }
 
-       if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
-           (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
-           (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
-           (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
-           (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
-           (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
-           (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
-           (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
-           (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
+       if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
+           (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
+           (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
+           (of->lace_mode != f->lace_mode) ||
+           (of->interlaced_y != f->interlaced_y) ||
+           (of->interlaced_uv != f->interlaced_uv)) {
                yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
        }
 
@@ -820,24 +782,24 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
 }
 
 /* Update the scaling register to the requested value */
-void ivtv_yuv_work_handler (struct ivtv *itv)
+void ivtv_yuv_work_handler(struct ivtv *itv)
 {
-       struct yuv_frame_info window;
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       struct yuv_frame_info f;
+       int frame = yi->update_frame;
        u32 yuv_update;
 
-       int frame = itv->yuv_info.update_frame;
-
-/*     IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
-       memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
+       IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
+       f = yi->new_frame_info[frame];
 
        /* Update the osd pan info */
-       window.pan_x = itv->yuv_info.osd_x_pan;
-       window.pan_y = itv->yuv_info.osd_y_pan;
-       window.vis_w = itv->yuv_info.osd_vis_w;
-       window.vis_h = itv->yuv_info.osd_vis_h;
+       f.pan_x = yi->osd_x_pan;
+       f.pan_y = yi->osd_y_pan;
+       f.vis_w = yi->osd_vis_w;
+       f.vis_h = yi->osd_vis_h;
 
        /* Calculate the display window coordinates. Exit if nothing left */
-       if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
+       if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
                return;
 
        if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
@@ -846,16 +808,15 @@ void ivtv_yuv_work_handler (struct ivtv *itv)
                write_reg(0x00108080, 0x2898);
 
                if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
-                       ivtv_yuv_handle_horizontal(itv, &window);
+                       ivtv_yuv_handle_horizontal(itv, &f);
 
                if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
-                       ivtv_yuv_handle_vertical(itv, &window);
+                       ivtv_yuv_handle_vertical(itv, &f);
        }
-
-       memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
+       yi->old_frame_info = f;
 }
 
-static void ivtv_yuv_init (struct ivtv *itv)
+static void ivtv_yuv_init(struct ivtv *itv)
 {
        struct yuv_playback_info *yi = &itv->yuv_info;
 
@@ -924,25 +885,23 @@ static void ivtv_yuv_init (struct ivtv *itv)
                if (!yi->osd_vis_w)
                        yi->osd_vis_w = 720 - yi->osd_x_offset;
 
-               if (!yi->osd_vis_h)
+               if (!yi->osd_vis_h) {
                        yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
-               else {
+               } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
                        /* If output video standard has changed, requested height may
-                       not be legal */
-                       if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
-                               IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
-                                               yi->osd_vis_h + yi->osd_y_offset,
-                                               yi->decode_height);
-                               yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
-                       }
+                          not be legal */
+                       IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+                                       yi->osd_vis_h + yi->osd_y_offset,
+                                       yi->decode_height);
+                       yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
                }
        }
 
        /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
-       yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
-       if (yi->blanking_ptr)
+       yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
+       if (yi->blanking_ptr) {
                yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
-       else {
+       else {
                yi->blanking_dmaptr = 0;
                IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
        }
@@ -954,77 +913,140 @@ static void ivtv_yuv_init (struct ivtv *itv)
        atomic_set(&yi->next_dma_frame, 0);
 }
 
-int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+/* Get next available yuv buffer on PVR350 */
+void ivtv_yuv_next_free(struct ivtv *itv)
 {
-       DEFINE_WAIT(wait);
-       int rc = 0;
-       int got_sig = 0;
-       int frame, next_fill_frame, last_fill_frame;
-       int register_update = 0;
+       int draw, display;
+       struct yuv_playback_info *yi = &itv->yuv_info;
 
-       IVTV_DEBUG_INFO("yuv_prep_frame\n");
+       if (atomic_read(&yi->next_dma_frame) == -1)
+               ivtv_yuv_init(itv);
 
-       if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
+       draw = atomic_read(&yi->next_fill_frame);
+       display = atomic_read(&yi->next_dma_frame);
 
-       frame = atomic_read(&itv->yuv_info.next_fill_frame);
-       next_fill_frame = (frame + 1) & 0x3;
-       last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
+       if (display > draw)
+               display -= IVTV_YUV_BUFFERS;
 
-       if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
-               /* Buffers are full - Overwrite the last frame */
-               next_fill_frame = frame;
-               frame = (frame - 1) & 3;
-               register_update = itv->yuv_info.new_frame_info[frame].update;
-       }
+       if (draw - display >= yi->max_frames_buffered)
+               draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
+       else
+               yi->new_frame_info[draw].update = 0;
+
+       yi->draw_frame = draw;
+}
+
+/* Set up frame according to ivtv_dma_frame parameters */
+void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       u8 frame = yi->draw_frame;
+       u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
+       struct yuv_frame_info *nf = &yi->new_frame_info[frame];
+       struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
+       int lace_threshold = yi->lace_threshold;
+
+       /* Preserve old update flag in case we're overwriting a queued frame */
+       int update = nf->update;
 
        /* Take a snapshot of the yuv coordinate information */
-       itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
-       itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
-       itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
-       itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
-       itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
-       itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
-       itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
-       itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
-       itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
-       itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
-       itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
-
-       /* Snapshot field order */
-       itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
+       nf->src_x = args->src.left;
+       nf->src_y = args->src.top;
+       nf->src_w = args->src.width;
+       nf->src_h = args->src.height;
+       nf->dst_x = args->dst.left;
+       nf->dst_y = args->dst.top;
+       nf->dst_w = args->dst.width;
+       nf->dst_h = args->dst.height;
+       nf->tru_x = args->dst.left;
+       nf->tru_w = args->src_width;
+       nf->tru_h = args->src_height;
 
        /* Are we going to offset the Y plane */
-       if (args->src.height + args->src.top < 512-16)
-               itv->yuv_info.new_frame_info[frame].offset_y = 1;
-       else
-               itv->yuv_info.new_frame_info[frame].offset_y = 0;
+       nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
 
        /* Snapshot the osd pan info */
-       itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
-       itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
-       itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
-       itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
-
-       itv->yuv_info.new_frame_info[frame].update = 0;
-       itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
-       itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
-       itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
-
-       if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
-           sizeof (itv->yuv_info.new_frame_info[frame]))) {
-               memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
-               itv->yuv_info.new_frame_info[frame].update = 1;
-/*             IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
+       nf->pan_x = yi->osd_x_pan;
+       nf->pan_y = yi->osd_y_pan;
+       nf->vis_w = yi->osd_vis_w;
+       nf->vis_h = yi->osd_vis_h;
+
+       nf->update = 0;
+       nf->interlaced_y = 0;
+       nf->interlaced_uv = 0;
+       nf->delay = 0;
+       nf->sync_field = 0;
+       nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
+
+       if (lace_threshold < 0)
+               lace_threshold = yi->decode_height - 1;
+
+       /* Work out the lace settings */
+       switch (nf->lace_mode) {
+       case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
+               nf->interlaced = 0;
+               if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
+                       nf->interlaced_y = 0;
+               else
+                       nf->interlaced_y = 1;
+
+               if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
+                       nf->interlaced_uv = 0;
+               else
+                       nf->interlaced_uv = 1;
+               break;
+
+       case IVTV_YUV_MODE_AUTO:
+               if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
+                       nf->interlaced = 0;
+                       if ((nf->tru_h < 512) ||
+                           (nf->tru_h > 576 && nf->tru_h < 1021) ||
+                           (nf->tru_w > 720 && nf->tru_h < 1021))
+                               nf->interlaced_y = 0;
+                       else
+                               nf->interlaced_y = 1;
+                       if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
+                               nf->interlaced_uv = 0;
+                       else
+                               nf->interlaced_uv = 1;
+               } else {
+                       nf->interlaced = 1;
+                       nf->interlaced_y = 1;
+                       nf->interlaced_uv = 1;
+               }
+               break;
+
+       case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
+       default:
+               nf->interlaced = 1;
+               nf->interlaced_y = 1;
+               nf->interlaced_uv = 1;
+               break;
        }
 
-       itv->yuv_info.new_frame_info[frame].update |= register_update;
+       if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
+               yi->old_frame_info_args = *nf;
+               nf->update = 1;
+               IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
+       }
 
-       /* Should this frame be delayed ? */
-       if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
-               itv->yuv_info.field_delay[frame] = 1;
-       else
-               itv->yuv_info.field_delay[frame] = 0;
+       nf->update |= update;
+       nf->sync_field = yi->lace_sync_field;
+       nf->delay = nf->sync_field != of->sync_field;
+}
 
+/* Frame is complete & ready for display */
+void ivtv_yuv_frame_complete(struct ivtv *itv)
+{
+       atomic_set(&itv->yuv_info.next_fill_frame,
+                       (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
+}
+
+int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+       DEFINE_WAIT(wait);
+       int rc = 0;
+       int got_sig = 0;
        /* DMA the frame */
        mutex_lock(&itv->udma.lock);
 
@@ -1036,10 +1058,10 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
        ivtv_udma_prepare(itv);
        prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
        /* if no UDMA is pending and no UDMA is in progress, then the DMA
-       is finished */
+          is finished */
        while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
                /* don't interrupt if the DMA is in progress but break off
-               a still pending DMA. */
+                  a still pending DMA. */
                got_sig = signal_pending(current);
                if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
                        break;
@@ -1057,99 +1079,148 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
                return -EINTR;
        }
 
-       atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
+       ivtv_yuv_frame_complete(itv);
 
        mutex_unlock(&itv->udma.lock);
        return rc;
 }
 
+/* Setup frame according to V4L2 parameters */
+void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
+{
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       struct ivtv_dma_frame dma_args;
+
+       ivtv_yuv_next_free(itv);
+
+       /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
+       dma_args.y_source = 0L;
+       dma_args.uv_source = 0L;
+       dma_args.src.left = 0;
+       dma_args.src.top = 0;
+       dma_args.src.width = yi->v4l2_src_w;
+       dma_args.src.height = yi->v4l2_src_h;
+       dma_args.dst = yi->main_rect;
+       dma_args.src_width = yi->v4l2_src_w;
+       dma_args.src_height = yi->v4l2_src_h;
+
+       /* ... and use the same setup routine as ivtv_yuv_prep_frame */
+       ivtv_yuv_setup_frame(itv, &dma_args);
+
+       if (!itv->dma_data_req_offset)
+               itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
+}
+
+/* Attempt to dma a frame from a user buffer */
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
+{
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       struct ivtv_dma_frame dma_args;
+
+       ivtv_yuv_setup_stream_frame(itv);
+
+       /* We only need to supply source addresses for this */
+       dma_args.y_source = src;
+       dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
+       return ivtv_yuv_udma_frame(itv, &dma_args);
+}
+
+/* IVTV_IOC_DMA_FRAME ioctl handler */
+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+/*     IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
+
+       ivtv_yuv_next_free(itv);
+       ivtv_yuv_setup_frame(itv, args);
+       return ivtv_yuv_udma_frame(itv, args);
+}
+
 void ivtv_yuv_close(struct ivtv *itv)
 {
+       struct yuv_playback_info *yi = &itv->yuv_info;
        int h_filter, v_filter_1, v_filter_2;
 
        IVTV_DEBUG_YUV("ivtv_yuv_close\n");
        ivtv_waitq(&itv->vsync_waitq);
 
-       atomic_set(&itv->yuv_info.next_dma_frame, -1);
-       atomic_set(&itv->yuv_info.next_fill_frame, 0);
+       atomic_set(&yi->next_dma_frame, -1);
+       atomic_set(&yi->next_fill_frame, 0);
 
        /* Reset registers we have changed so mpeg playback works */
 
        /* If we fully restore this register, the display may remain active.
           Restore, but set one bit to blank the video. Firmware will always
           clear this bit when needed, so not a problem. */
-       write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
-
-       write_reg(itv->yuv_info.reg_2834, 0x02834);
-       write_reg(itv->yuv_info.reg_2838, 0x02838);
-       write_reg(itv->yuv_info.reg_283c, 0x0283c);
-       write_reg(itv->yuv_info.reg_2840, 0x02840);
-       write_reg(itv->yuv_info.reg_2844, 0x02844);
-       write_reg(itv->yuv_info.reg_2848, 0x02848);
-       write_reg(itv->yuv_info.reg_2854, 0x02854);
-       write_reg(itv->yuv_info.reg_285c, 0x0285c);
-       write_reg(itv->yuv_info.reg_2864, 0x02864);
-       write_reg(itv->yuv_info.reg_2870, 0x02870);
-       write_reg(itv->yuv_info.reg_2874, 0x02874);
-       write_reg(itv->yuv_info.reg_2890, 0x02890);
-       write_reg(itv->yuv_info.reg_289c, 0x0289c);
-
-       write_reg(itv->yuv_info.reg_2918, 0x02918);
-       write_reg(itv->yuv_info.reg_291c, 0x0291c);
-       write_reg(itv->yuv_info.reg_2920, 0x02920);
-       write_reg(itv->yuv_info.reg_2924, 0x02924);
-       write_reg(itv->yuv_info.reg_2928, 0x02928);
-       write_reg(itv->yuv_info.reg_292c, 0x0292c);
-       write_reg(itv->yuv_info.reg_2930, 0x02930);
-       write_reg(itv->yuv_info.reg_2934, 0x02934);
-       write_reg(itv->yuv_info.reg_2938, 0x02938);
-       write_reg(itv->yuv_info.reg_293c, 0x0293c);
-       write_reg(itv->yuv_info.reg_2940, 0x02940);
-       write_reg(itv->yuv_info.reg_2944, 0x02944);
-       write_reg(itv->yuv_info.reg_2948, 0x02948);
-       write_reg(itv->yuv_info.reg_294c, 0x0294c);
-       write_reg(itv->yuv_info.reg_2950, 0x02950);
-       write_reg(itv->yuv_info.reg_2954, 0x02954);
-       write_reg(itv->yuv_info.reg_2958, 0x02958);
-       write_reg(itv->yuv_info.reg_295c, 0x0295c);
-       write_reg(itv->yuv_info.reg_2960, 0x02960);
-       write_reg(itv->yuv_info.reg_2964, 0x02964);
-       write_reg(itv->yuv_info.reg_2968, 0x02968);
-       write_reg(itv->yuv_info.reg_296c, 0x0296c);
-       write_reg(itv->yuv_info.reg_2970, 0x02970);
+       write_reg(yi->reg_2898 | 0x01000000, 0x2898);
+
+       write_reg(yi->reg_2834, 0x02834);
+       write_reg(yi->reg_2838, 0x02838);
+       write_reg(yi->reg_283c, 0x0283c);
+       write_reg(yi->reg_2840, 0x02840);
+       write_reg(yi->reg_2844, 0x02844);
+       write_reg(yi->reg_2848, 0x02848);
+       write_reg(yi->reg_2854, 0x02854);
+       write_reg(yi->reg_285c, 0x0285c);
+       write_reg(yi->reg_2864, 0x02864);
+       write_reg(yi->reg_2870, 0x02870);
+       write_reg(yi->reg_2874, 0x02874);
+       write_reg(yi->reg_2890, 0x02890);
+       write_reg(yi->reg_289c, 0x0289c);
+
+       write_reg(yi->reg_2918, 0x02918);
+       write_reg(yi->reg_291c, 0x0291c);
+       write_reg(yi->reg_2920, 0x02920);
+       write_reg(yi->reg_2924, 0x02924);
+       write_reg(yi->reg_2928, 0x02928);
+       write_reg(yi->reg_292c, 0x0292c);
+       write_reg(yi->reg_2930, 0x02930);
+       write_reg(yi->reg_2934, 0x02934);
+       write_reg(yi->reg_2938, 0x02938);
+       write_reg(yi->reg_293c, 0x0293c);
+       write_reg(yi->reg_2940, 0x02940);
+       write_reg(yi->reg_2944, 0x02944);
+       write_reg(yi->reg_2948, 0x02948);
+       write_reg(yi->reg_294c, 0x0294c);
+       write_reg(yi->reg_2950, 0x02950);
+       write_reg(yi->reg_2954, 0x02954);
+       write_reg(yi->reg_2958, 0x02958);
+       write_reg(yi->reg_295c, 0x0295c);
+       write_reg(yi->reg_2960, 0x02960);
+       write_reg(yi->reg_2964, 0x02964);
+       write_reg(yi->reg_2968, 0x02968);
+       write_reg(yi->reg_296c, 0x0296c);
+       write_reg(yi->reg_2970, 0x02970);
 
        /* Prepare to restore filters */
 
        /* First the horizontal filter */
-       if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
+       if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
                /* An exact size match uses filter 0 */
                h_filter = 0;
-       }
-       else {
+       } else {
                /* Figure out which filter to use */
-               h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
+               h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
                h_filter = (h_filter >> 1) + (h_filter & 1);
                /* Only an exact size match can use filter 0. */
-               if (h_filter < 1) h_filter = 1;
+               h_filter += !h_filter;
        }
 
        /* Now the vertical filter */
-       if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
+       if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
                /* An exact size match uses filter 0/1 */
                v_filter_1 = 0;
                v_filter_2 = 1;
-       }
-       else {
+       } else {
                /* Figure out which filter to use */
-               v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
+               v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
                v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
                /* Only an exact size match can use filter 0 */
-               if (v_filter_1 == 0) v_filter_1 = 1;
+               v_filter_1 += !v_filter_1;
                v_filter_2 = v_filter_1;
        }
 
        /* Now restore the filters */
-       ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
+       ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
 
        /* and clear a few registers */
        write_reg(0, 0x02814);
@@ -1158,19 +1229,18 @@ void ivtv_yuv_close(struct ivtv *itv)
        write_reg(0, 0x02910);
 
        /* Release the blanking buffer */
-       if (itv->yuv_info.blanking_ptr) {
-               kfree (itv->yuv_info.blanking_ptr);
-               itv->yuv_info.blanking_ptr = NULL;
-               pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+       if (yi->blanking_ptr) {
+               kfree(yi->blanking_ptr);
+               yi->blanking_ptr = NULL;
+               pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
        }
 
        /* Invalidate the old dimension information */
-       itv->yuv_info.old_frame_info.src_w = 0;
-       itv->yuv_info.old_frame_info.src_h = 0;
-       itv->yuv_info.old_frame_info_args.src_w = 0;
-       itv->yuv_info.old_frame_info_args.src_h = 0;
+       yi->old_frame_info.src_w = 0;
+       yi->old_frame_info.src_h = 0;
+       yi->old_frame_info_args.src_w = 0;
+       yi->old_frame_info_args.src_h = 0;
 
        /* All done. */
        clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
 }
-
index 3b966f0a204ab25109ba3742fb96c3601678ac3d..2fe5f1250762821741679be463580641ce77b951 100644 (file)
 #ifndef IVTV_YUV_H
 #define IVTV_YUV_H
 
-/* Buffers on hardware offsets */
-#define IVTV_YUV_BUFFER_OFFSET    0x001a8600   /* First YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400   /* Second YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200   /* Third YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000   /* Fourth YUV Buffer */
 #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400      /* Offset to UV Buffer */
 
 /* Offset to filter table in firmware */
 #define IVTV_YUV_UPDATE_VERTICAL    0x02
 #define IVTV_YUV_UPDATE_INVALID     0x04
 
-extern const u32 yuv_offset[4];
+extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
 
 int ivtv_yuv_filter_check(struct ivtv *itv);
+void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
+void ivtv_yuv_frame_complete(struct ivtv *itv);
 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
 void ivtv_yuv_close(struct ivtv *itv);
-void ivtv_yuv_work_handler (struct ivtv *itv);
+void ivtv_yuv_work_handler(struct ivtv *itv);
 
 #endif
index 52ffd154a3d80bbb21eb0514c7603c4368040c3d..3b23fc05f7c4331dc1d15b61af39a3cb1d3133da 100644 (file)
@@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
 
        ivtvfb_set_display_window(itv, &ivtv_window);
 
+       /* Pass screen size back to yuv handler */
+       itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
+       itv->yuv_info.osd_full_h = ivtv_osd.lines;
+
        /* Force update of yuv registers */
        itv->yuv_info.yuv_forced_update = 1;
 
@@ -1053,7 +1057,7 @@ static int ivtvfb_init_card(struct ivtv *itv)
        }
 
        itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
-       if (itv->osd_info == 0) {
+       if (itv->osd_info == NULL) {
                IVTVFB_ERR("Failed to allocate memory for osd_info\n");
                return -ENOMEM;
        }
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
new file mode 100644 (file)
index 0000000..d4bf14c
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * m52790 i2c ivtv driver.
+ * Copyright (C) 2007  Hans Verkuil
+ *
+ * A/V source switching Mitsubishi M52790SP/FP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/m52790.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
+
+MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+
+struct m52790_state {
+       u16 input;
+       u16 output;
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int m52790_write(struct i2c_client *client)
+{
+       struct m52790_state *state = i2c_get_clientdata(client);
+       u8 sw1 = (state->input | state->output) & 0xff;
+       u8 sw2 = (state->input | state->output) >> 8;
+
+       return i2c_smbus_write_byte_data(client, sw1, sw2);
+}
+
+static int m52790_command(struct i2c_client *client, unsigned int cmd,
+                           void *arg)
+{
+       struct m52790_state *state = i2c_get_clientdata(client);
+       struct v4l2_routing *route = arg;
+
+       /* Note: audio and video are linked and cannot be switched separately.
+          So audio and video routing commands are identical for this chip.
+          In theory the video amplifier and audio modes could be handled
+          separately for the output, but that seems to be overkill right now.
+          The same holds for implementing an audio mute control, this is now
+          part of the audio output routing. The normal case is that another
+          chip takes care of the actual muting so making it part of the
+          output routing seems to be the right thing to do for now. */
+       switch (cmd) {
+       case VIDIOC_INT_G_AUDIO_ROUTING:
+       case VIDIOC_INT_G_VIDEO_ROUTING:
+               route->input = state->input;
+               route->output = state->output;
+               break;
+
+       case VIDIOC_INT_S_AUDIO_ROUTING:
+       case VIDIOC_INT_S_VIDEO_ROUTING:
+               state->input = route->input;
+               state->output = route->output;
+               m52790_write(client);
+               break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (!v4l2_chip_match_i2c_client(client,
+                                       reg->match_type, reg->match_chip))
+                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if (reg->reg != 0)
+                       return -EINVAL;
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = state->input | state->output;
+               else {
+                       state->input = reg->val & 0x0303;
+                       state->output = reg->val & ~0x0303;
+                       m52790_write(client);
+               }
+               break;
+       }
+#endif
+
+       case VIDIOC_G_CHIP_IDENT:
+               return v4l2_chip_ident_i2c_client(client, arg,
+                               V4L2_IDENT_M52790, 0);
+
+       case VIDIOC_LOG_STATUS:
+               v4l_info(client, "Switch 1: %02x\n",
+                               (state->input | state->output) & 0xff);
+               v4l_info(client, "Switch 2: %02x\n",
+                               (state->input | state->output) >> 8);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+static int m52790_probe(struct i2c_client *client)
+{
+       struct m52790_state *state;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       snprintf(client->name, sizeof(client->name) - 1, "m52790");
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL);
+       if (state == NULL)
+               return -ENOMEM;
+
+       state->input = M52790_IN_TUNER;
+       state->output = M52790_OUT_STEREO;
+       i2c_set_clientdata(client, state);
+       m52790_write(client);
+       return 0;
+}
+
+static int m52790_remove(struct i2c_client *client)
+{
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "m52790",
+       .driverid = I2C_DRIVERID_M52790,
+       .command = m52790_command,
+       .probe = m52790_probe,
+       .remove = m52790_remove,
+};
+
index c3116329043276640c28e6aa9ccf3ca064a25f43..3d51fa0a52b6132c6b09859c691c466e97e0964e 100644 (file)
@@ -2023,7 +2023,7 @@ static int __init meye_init(void)
        if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)
                gbufsize = MEYE_MAX_BUFSIZE;
        gbufsize = PAGE_ALIGN(gbufsize);
-       printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)"
+       printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) "
                         "for capture\n",
                         gbuffers,
                         gbufsize / 1024, gbuffers * gbufsize / 1024);
index c0c87e06259b9c599c62e03ab26e577e28e5c78e..7a11f3159e32b755a3a435b6872590b35f0dc845 100644 (file)
@@ -42,7 +42,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 
@@ -53,6 +54,7 @@
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/tvaudio.h>
 #include <media/msp3400.h>
 #include <linux/kthread.h>
@@ -71,7 +73,8 @@ int msp_debug;                 /* msp_debug output */
 int msp_once;           /* no continous stereo monitoring */
 int msp_amsound;        /* hard-wire AM sound at 6.5 Hz (france),
                            the autoscan seems work well only with FM... */
-int msp_standard = 1;    /* Override auto detect of audio msp_standard, if needed. */
+int msp_standard = 1;    /* Override auto detect of audio msp_standard,
+                           if needed. */
 int msp_dolby;
 
 int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
@@ -81,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
 module_param(opmode,           int, 0444);
 
 /* read-write */
-module_param_named(once,msp_once,                      bool, 0644);
-module_param_named(debug,msp_debug,                    int,  0644);
-module_param_named(stereo_threshold,msp_stereo_thresh, int,  0644);
-module_param_named(standard,msp_standard,              int,  0644);
-module_param_named(amsound,msp_amsound,                bool, 0644);
-module_param_named(dolby,msp_dolby,                    bool, 0644);
+module_param_named(once, msp_once,                      bool, 0644);
+module_param_named(debug, msp_debug,                    int,  0644);
+module_param_named(stereo_threshold, msp_stereo_thresh, int,  0644);
+module_param_named(standard, msp_standard,              int,  0644);
+module_param_named(amsound, msp_amsound,                bool, 0644);
+module_param_named(dolby, msp_dolby,                    bool, 0644);
 
 MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
 MODULE_PARM_DESC(once, "No continuous stereo monitoring");
@@ -160,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
                schedule_timeout_interruptible(msecs_to_jiffies(10));
        }
        if (err == 3) {
-               v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+               v4l_warn(client, "resetting chip, sound will go off.\n");
                msp_reset(client);
                return -1;
        }
        retval = read[0] << 8 | read[1];
-       v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+       v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n",
+                       dev, addr, retval);
        return retval;
 }
 
@@ -190,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
        buffer[3] = val  >> 8;
        buffer[4] = val  &  0xff;
 
-       v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
+       v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n",
+                       dev, addr, val);
        for (err = 0; err < 3; err++) {
                if (i2c_master_send(client, buffer, 5) == 5)
                        break;
@@ -199,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
                schedule_timeout_interruptible(msecs_to_jiffies(10));
        }
        if (err == 3) {
-               v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+               v4l_warn(client, "resetting chip, sound will go off.\n");
                msp_reset(client);
                return -1;
        }
@@ -273,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
                state->acb = 0xf60; /* Mute Input and SCART 1 Output */
 
        v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n",
-                                               scart_names[in], out, state->acb);
+                                       scart_names[in], out, state->acb);
        msp_write_dsp(client, 0x13, state->acb);
 
        /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
@@ -292,7 +297,8 @@ void msp_set_audio(struct i2c_client *client)
                val = (state->volume * 0x7f / 65535) << 8;
 
        v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
-               state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no",
+               state->muted ? "on" : "off",
+               state->scan_in_progress ? "yes" : "no",
                state->volume);
 
        msp_write_dsp(client, 0x0000, val);
@@ -681,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a);
 
                switch (*a) {
-                       case 1024000:
-                               state->i2s_mode = 0;
-                               break;
-                       case 2048000:
-                               state->i2s_mode = 1;
-                               break;
-                       default:
-                               return -EINVAL;
+               case 1024000:
+                       state->i2s_mode = 0;
+                       break;
+               case 2048000:
+                       state->i2s_mode = 1;
+                       break;
+               default:
+                       return -EINVAL;
                }
                break;
        }
@@ -698,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                struct v4l2_queryctrl *qc = arg;
 
                switch (qc->id) {
-                       case V4L2_CID_AUDIO_VOLUME:
-                       case V4L2_CID_AUDIO_MUTE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               break;
+               case V4L2_CID_AUDIO_VOLUME:
+               case V4L2_CID_AUDIO_MUTE:
+                       return v4l2_ctrl_query_fill_std(qc);
+               default:
+                       break;
                }
                if (!state->has_sound_processing)
                        return -EINVAL;
                switch (qc->id) {
-                       case V4L2_CID_AUDIO_LOUDNESS:
-                       case V4L2_CID_AUDIO_BALANCE:
-                       case V4L2_CID_AUDIO_BASS:
-                       case V4L2_CID_AUDIO_TREBLE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               return -EINVAL;
+               case V4L2_CID_AUDIO_LOUDNESS:
+               case V4L2_CID_AUDIO_BALANCE:
+               case V4L2_CID_AUDIO_BASS:
+               case V4L2_CID_AUDIO_TREBLE:
+                       return v4l2_ctrl_query_fill_std(qc);
+               default:
+                       return -EINVAL;
                }
        }
 
@@ -735,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                state->volume, state->muted ? " (muted)" : "");
                if (state->has_sound_processing) {
                        v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
-                                       state->balance, state->bass, state->treble,
+                                       state->balance, state->bass,
+                                       state->treble,
                                        state->loudness ? "on" : "off");
                }
                switch (state->mode) {
                case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
                case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
-               case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
+               case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
                case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
                case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
                case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
@@ -772,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        }
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2);
+               return v4l2_chip_ident_i2c_client(client, arg, state->ident,
+                               (state->rev1 << 16) | state->rev2);
 
        default:
                /* unknown */
@@ -783,7 +791,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static int msp_suspend(struct i2c_client *client, pm_message_t state)
 {
-
        v4l_dbg(1, msp_debug, client, "suspend\n");
        msp_reset(client);
        return 0;
@@ -791,7 +798,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state)
 
 static int msp_resume(struct i2c_client *client)
 {
-
        v4l_dbg(1, msp_debug, client, "resume\n");
        msp_wake_thread(client);
        return 0;
@@ -799,11 +805,8 @@ static int msp_resume(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver;
-
-static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+static int msp_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct msp_state *state;
        int (*thread_func)(void *data) = NULL;
        int msp_hard;
@@ -812,26 +815,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
        int msp_product, msp_prod_hi, msp_prod_lo;
        int msp_rom;
 
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
        snprintf(client->name, sizeof(client->name) - 1, "msp3400");
 
        if (msp_reset(client) == -1) {
                v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
-               kfree(client);
-               return 0;
+               return -ENODEV;
        }
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (!state) {
-               kfree(client);
+       if (!state)
                return -ENOMEM;
-       }
 
        i2c_set_clientdata(client, state);
 
@@ -853,12 +846,13 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
        state->rev1 = msp_read_dsp(client, 0x1e);
        if (state->rev1 != -1)
                state->rev2 = msp_read_dsp(client, 0x1f);
-       v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
+       v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n",
+                       state->rev1, state->rev2);
        if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
-               v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n");
+               v4l_dbg(1, msp_debug, client,
+                               "not an msp3400 (cannot read chip version)\n");
                kfree(state);
-               kfree(client);
-               return 0;
+               return -ENODEV;
        }
 
        msp_set_audio(client);
@@ -874,37 +868,55 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
                        msp_family, msp_product,
                        msp_revision, msp_hard, msp_rom);
        /* Rev B=2, C=3, D=4, G=7 */
-       state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@';
+       state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
+                       msp_revision - '@';
 
        /* Has NICAM support: all mspx41x and mspx45x products have NICAM */
-       state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
+       state->has_nicam =
+               msp_prod_hi == 1 || msp_prod_hi == 5;
        /* Has radio support: was added with revision G */
-       state->has_radio = msp_revision >= 'G';
+       state->has_radio =
+               msp_revision >= 'G';
        /* Has headphones output: not for stripped down products */
-       state->has_headphones = msp_prod_lo < 5;
+       state->has_headphones =
+               msp_prod_lo < 5;
        /* Has scart2 input: not in stripped down products of the '3' family */
-       state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7;
+       state->has_scart2 =
+               msp_family >= 4 || msp_prod_lo < 7;
        /* Has scart3 input: not in stripped down products of the '3' family */
-       state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5;
+       state->has_scart3 =
+               msp_family >= 4 || msp_prod_lo < 5;
        /* Has scart4 input: not in pre D revisions, not in stripped D revs */
-       state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
-       /* Has scart2 output: not in stripped down products of the '3' family */
-       state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
+       state->has_scart4 =
+               msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+       /* Has scart2 output: not in stripped down products of
+        * the '3' family */
+       state->has_scart2_out =
+               msp_family >= 4 || msp_prod_lo < 5;
        /* Has scart2 a volume control? Not in pre-D revisions. */
-       state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out;
+       state->has_scart2_out_volume =
+               msp_revision > 'C' && state->has_scart2_out;
        /* Has a configurable i2s out? */
-       state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
-       /* Has subwoofer output: not in pre-D revs and not in stripped down products */
-       state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
-       /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
-          stripped down products */
-       state->has_sound_processing = msp_prod_lo < 7;
+       state->has_i2s_conf =
+               msp_revision >= 'G' && msp_prod_lo < 7;
+       /* Has subwoofer output: not in pre-D revs and not in stripped down
+        * products */
+       state->has_subwoofer =
+               msp_revision >= 'D' && msp_prod_lo < 5;
+       /* Has soundprocessing (bass/treble/balance/loudness/equalizer):
+        *  not in stripped down products */
+       state->has_sound_processing =
+               msp_prod_lo < 7;
        /* Has Virtual Dolby Surround: only in msp34x1 */
-       state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+       state->has_virtual_dolby_surround =
+               msp_revision == 'G' && msp_prod_lo == 1;
        /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
-       state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
-       /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
-       state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
+       state->has_dolby_pro_logic =
+               msp_revision == 'G' && msp_prod_lo == 2;
+       /* The msp343xG supports BTSC only and cannot do Automatic Standard
+        * Detection. */
+       state->force_btsc =
+               msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
 
        state->opmode = opmode;
        if (state->opmode == OPMODE_AUTO) {
@@ -919,32 +931,33 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
        }
 
        /* hello world :-) */
-       v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
+       v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+                       client->addr << 1, client->adapter->name);
        v4l_info(client, "%s ", client->name);
        if (state->has_nicam && state->has_radio)
-               printk("supports nicam and radio, ");
+               printk(KERN_CONT "supports nicam and radio, ");
        else if (state->has_nicam)
-               printk("supports nicam, ");
+               printk(KERN_CONT "supports nicam, ");
        else if (state->has_radio)
-               printk("supports radio, ");
-       printk("mode is ");
+               printk(KERN_CONT "supports radio, ");
+       printk(KERN_CONT "mode is ");
 
        /* version-specific initialization */
        switch (state->opmode) {
        case OPMODE_MANUAL:
-               printk("manual");
+               printk(KERN_CONT "manual");
                thread_func = msp3400c_thread;
                break;
        case OPMODE_AUTODETECT:
-               printk("autodetect");
+               printk(KERN_CONT "autodetect");
                thread_func = msp3410d_thread;
                break;
        case OPMODE_AUTOSELECT:
-               printk("autodetect and autoselect");
+               printk(KERN_CONT "autodetect and autoselect");
                thread_func = msp34xxg_thread;
                break;
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
 
        /* startup control thread if needed */
        if (thread_func) {
@@ -954,24 +967,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
                        v4l_warn(client, "kernel_thread() failed\n");
                msp_wake_thread(client);
        }
-
-       /* done */
-       i2c_attach_client(client);
-
        return 0;
 }
 
-static int msp_probe(struct i2c_adapter *adapter)
-{
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, msp_attach);
-       return 0;
-}
-
-static int msp_detach(struct i2c_client *client)
+static int msp_remove(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
-       int err;
 
        /* shutdown control thread */
        if (state->kthread) {
@@ -980,43 +981,22 @@ static int msp_detach(struct i2c_client *client)
        }
        msp_reset(client);
 
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
        kfree(state);
-       kfree(client);
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .id             = I2C_DRIVERID_MSP3400,
-       .attach_adapter = msp_probe,
-       .detach_client  = msp_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "msp3400",
+       .driverid = I2C_DRIVERID_MSP3400,
+       .command = msp_command,
+       .probe = msp_probe,
+       .remove = msp_remove,
        .suspend = msp_suspend,
-       .resume  = msp_resume,
-       .command        = msp_command,
-       .driver = {
-               .name    = "msp3400",
-       },
+       .resume = msp_resume,
 };
 
-static int __init msp3400_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit msp3400_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(msp3400_init_module);
-module_exit(msp3400_cleanup_module);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
index d5ee2629121e93794b28680ecdc7b4e1e1eab106..61ec794a737e2f438072a06e9e0272bb274e2a3f 100644 (file)
@@ -15,7 +15,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 
@@ -78,37 +79,37 @@ static struct msp3400c_init_data_dem {
                {75, 19, 36, 35, 39, 40},
                MSP_CARRIER(5.5), MSP_CARRIER(5.5),
                0x00d0, 0x0500, 0x0020, 0x3000
-       },    /* AM (for carrier detect / msp3410) */
+       }, {    /* AM (for carrier detect / msp3410) */
                {-1, -1, -8, 2, 59, 126},
                {-1, -1, -8, 2, 59, 126},
                MSP_CARRIER(5.5), MSP_CARRIER(5.5),
                0x00d0, 0x0100, 0x0020, 0x3000
-       },    /* FM Radio */
+       }, {    /* FM Radio */
                {-8, -8, 4, 6, 78, 107},
                {-8, -8, 4, 6, 78, 107},
                MSP_CARRIER(10.7), MSP_CARRIER(10.7),
                0x00d0, 0x0480, 0x0020, 0x3000
-       },    /* Terrestial FM-mono + FM-stereo */
+       }, {    /* Terrestial FM-mono + FM-stereo */
                {3, 18, 27, 48, 66, 72},
                {3, 18, 27, 48, 66, 72},
                MSP_CARRIER(5.5), MSP_CARRIER(5.5),
                0x00d0, 0x0480, 0x0030, 0x3000
-       },    /* Sat FM-mono */
+       }, {    /* Sat FM-mono */
                { 1, 9, 14, 24, 33, 37},
                { 3, 18, 27, 48, 66, 72},
                MSP_CARRIER(6.5), MSP_CARRIER(6.5),
                0x00c6, 0x0480, 0x0000, 0x3000
-       },    /* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+       }, {    /* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
                {-2, -8, -10, 10, 50, 86},
                {3, 18, 27, 48, 66, 72},
                MSP_CARRIER(5.5), MSP_CARRIER(5.5),
                0x00d0, 0x0040, 0x0120, 0x3000
-       },    /* NICAM/FM -- I (6.0/6.552) */
+       }, {    /* NICAM/FM -- I (6.0/6.552) */
                {2, 4, -6, -4, 40, 94},
                {3, 18, 27, 48, 66, 72},
                MSP_CARRIER(6.0), MSP_CARRIER(6.0),
                0x00d0, 0x0040, 0x0120, 0x3000
-       },    /* NICAM/AM -- L (6.5/5.85) */
+       }, {    /* NICAM/AM -- L (6.5/5.85) */
                {-2, -8, -10, 10, 50, 86},
                {-4, -12, -9, 23, 79, 126},
                MSP_CARRIER(6.5), MSP_CARRIER(6.5),
@@ -224,7 +225,9 @@ void msp3400c_set_mode(struct i2c_client *client, int mode)
    nor do they support stereo BTSC. */
 static void msp3400c_set_audmode(struct i2c_client *client)
 {
-       static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" };
+       static char *strmode[] = {
+               "mono", "stereo", "lang2", "lang1", "lang1+lang2"
+       };
        struct msp_state *state = i2c_get_clientdata(client);
        char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
                strmode[state->audmode] : "unknown";
@@ -298,19 +301,23 @@ static void msp3400c_set_audmode(struct i2c_client *client)
        case MSP_MODE_FM_NICAM1:
        case MSP_MODE_FM_NICAM2:
        case MSP_MODE_AM_NICAM:
-               v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
+               v4l_dbg(1, msp_debug, client,
+                       "NICAM set_audmode: %s\n", modestr);
                if (state->nicam_on)
                        src = 0x0100;  /* NICAM */
                break;
        case MSP_MODE_BTSC:
-               v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
+               v4l_dbg(1, msp_debug, client,
+                       "BTSC set_audmode: %s\n", modestr);
                break;
        case MSP_MODE_EXTERN:
-               v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
+               v4l_dbg(1, msp_debug, client,
+                       "extern set_audmode: %s\n", modestr);
                src = 0x0200;  /* SCART */
                break;
        case MSP_MODE_FM_RADIO:
-               v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
+               v4l_dbg(1, msp_debug, client,
+                       "FM-Radio set_audmode: %s\n", modestr);
                break;
        default:
                v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
@@ -342,7 +349,8 @@ static void msp3400c_set_audmode(struct i2c_client *client)
                src |= 0x0010;
                break;
        }
-       v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
+       v4l_dbg(1, msp_debug, client,
+               "set_audmode final source/matrix = 0x%x\n", src);
 
        msp_set_source(client, src);
 }
@@ -351,22 +359,26 @@ static void msp3400c_print_mode(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
-       if (state->main == state->second) {
-               v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n",
-                      state->main / 910000, (state->main / 910) % 1000);
-       } else {
-               v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n",
-                      state->main / 910000, (state->main / 910) % 1000);
-       }
+       if (state->main == state->second)
+               v4l_dbg(1, msp_debug, client,
+                       "mono sound carrier: %d.%03d MHz\n",
+                       state->main / 910000, (state->main / 910) % 1000);
+       else
+               v4l_dbg(1, msp_debug, client,
+                       "main sound carrier: %d.%03d MHz\n",
+                       state->main / 910000, (state->main / 910) % 1000);
        if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
-               v4l_dbg(1, msp_debug, client, "NICAM/FM carrier  : %d.%03d MHz\n",
-                      state->second / 910000, (state->second/910) % 1000);
+               v4l_dbg(1, msp_debug, client,
+                       "NICAM/FM carrier  : %d.%03d MHz\n",
+                       state->second / 910000, (state->second/910) % 1000);
        if (state->mode == MSP_MODE_AM_NICAM)
-               v4l_dbg(1, msp_debug, client, "NICAM/AM carrier  : %d.%03d MHz\n",
-                      state->second / 910000, (state->second / 910) % 1000);
+               v4l_dbg(1, msp_debug, client,
+                       "NICAM/AM carrier  : %d.%03d MHz\n",
+                       state->second / 910000, (state->second / 910) % 1000);
        if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
-               v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n",
-                      state->second / 910000, (state->second / 910) % 1000);
+               v4l_dbg(1, msp_debug, client,
+                       "FM-stereo carrier : %d.%03d MHz\n",
+                       state->second / 910000, (state->second / 910) % 1000);
        }
 }
 
@@ -385,7 +397,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
                val = msp_read_dsp(client, 0x18);
                if (val > 32767)
                        val -= 65536;
-               v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
+               v4l_dbg(2, msp_debug, client,
+                       "stereo detect register: %d\n", val);
                if (val > 8192) {
                        rxsubchans = V4L2_TUNER_SUB_STEREO;
                } else if (val < -4096) {
@@ -430,7 +443,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
        }
        if (rxsubchans != state->rxsubchans) {
                update = 1;
-               v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
+               v4l_dbg(1, msp_debug, client,
+                       "watch: rxsubchans %02x => %02x\n",
                        state->rxsubchans, rxsubchans);
                state->rxsubchans = rxsubchans;
        }
@@ -452,9 +466,8 @@ static void watch_stereo(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
-       if (msp_detect_stereo(client)) {
+       if (msp_detect_stereo(client))
                msp_set_audmode(client);
-       }
 
        if (msp_once)
                state->watch_stereo = 0;
@@ -465,7 +478,7 @@ int msp3400c_thread(void *data)
        struct i2c_client *client = data;
        struct msp_state *state = i2c_get_clientdata(client);
        struct msp3400c_carrier_detect *cd;
-       int count, max1, max2, val1, val2, val, this;
+       int count, max1, max2, val1, val2, val, i;
 
 
        v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
@@ -475,7 +488,7 @@ int msp3400c_thread(void *data)
                msp_sleep(state, -1);
                v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
 
-       restart:
+restart:
                v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
                state->restart = 0;
                if (kthread_should_stop())
@@ -483,7 +496,8 @@ int msp3400c_thread(void *data)
 
                if (state->radio || MSP_MODE_EXTERN == state->mode) {
                        /* no carrier scan, just unmute */
-                       v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+                       v4l_dbg(1, msp_debug, client,
+                               "thread: no carrier scan\n");
                        state->scan_in_progress = 0;
                        msp_set_audio(client);
                        continue;
@@ -514,16 +528,17 @@ int msp3400c_thread(void *data)
                        v4l_dbg(1, msp_debug, client, "AM sound override\n");
                }
 
-               for (this = 0; this < count; this++) {
-                       msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
-                       if (msp_sleep(state,100))
+               for (i = 0; i < count; i++) {
+                       msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
+                       if (msp_sleep(state, 100))
                                goto restart;
                        val = msp_read_dsp(client, 0x1b);
                        if (val > 32767)
                                val -= 65536;
                        if (val1 < val)
-                               val1 = val, max1 = this;
-                       v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
+                               val1 = val, max1 = i;
+                       v4l_dbg(1, msp_debug, client,
+                               "carrier1 val: %5d / %s\n", val, cd[i].name);
                }
 
                /* carrier detect pass #2 -- second (stereo) carrier */
@@ -550,16 +565,17 @@ int msp3400c_thread(void *data)
                        count = 0;
                        max2 = 0;
                }
-               for (this = 0; this < count; this++) {
-                       msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
-                       if (msp_sleep(state,100))
+               for (i = 0; i < count; i++) {
+                       msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
+                       if (msp_sleep(state, 100))
                                goto restart;
                        val = msp_read_dsp(client, 0x1b);
                        if (val > 32767)
                                val -= 65536;
                        if (val2 < val)
-                               val2 = val, max2 = this;
-                       v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
+                               val2 = val, max2 = i;
+                       v4l_dbg(1, msp_debug, client,
+                               "carrier2 val: %5d / %s\n", val, cd[i].name);
                }
 
                /* program the msp3400 according to the results */
@@ -611,7 +627,7 @@ int msp3400c_thread(void *data)
                        break;
                case 0: /* 4.5 */
                default:
-               no_second:
+no_second:
                        state->second = msp3400c_carrier_detect_main[max1].cdo;
                        msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
                        break;
@@ -632,7 +648,8 @@ int msp3400c_thread(void *data)
                while (state->watch_stereo) {
                        if (msp_sleep(state, count ? 1000 : 5000))
                                goto restart;
-                       if (count) count--;
+                       if (count)
+                               count--;
                        watch_stereo(client);
                }
        }
@@ -651,10 +668,10 @@ int msp3410d_thread(void *data)
        set_freezable();
        for (;;) {
                v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
-               msp_sleep(state,-1);
+               msp_sleep(state, -1);
                v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
 
-       restart:
+restart:
                v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
                state->restart = 0;
                if (kthread_should_stop())
@@ -662,7 +679,8 @@ int msp3410d_thread(void *data)
 
                if (state->mode == MSP_MODE_EXTERN) {
                        /* no carrier scan needed, just unmute */
-                       v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+                       v4l_dbg(1, msp_debug, client,
+                               "thread: no carrier scan\n");
                        state->scan_in_progress = 0;
                        msp_set_audio(client);
                        continue;
@@ -673,7 +691,8 @@ int msp3410d_thread(void *data)
                msp_set_audio(client);
 
                /* start autodetect. Note: autodetect is not supported for
-                  NTSC-M and radio, hence we force the standard in those cases. */
+                  NTSC-M and radio, hence we force the standard in those
+                  cases. */
                if (state->radio)
                        std = 0x40;
                else
@@ -686,8 +705,9 @@ int msp3410d_thread(void *data)
                        goto restart;
 
                if (msp_debug)
-                       v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
-                              msp_standard_std_name(std), std);
+                       v4l_dbg(2, msp_debug, client,
+                               "setting standard: %s (0x%04x)\n",
+                               msp_standard_std_name(std), std);
 
                if (std != 1) {
                        /* programmed some specific mode */
@@ -703,7 +723,8 @@ int msp3410d_thread(void *data)
                                val = msp_read_dem(client, 0x7e);
                                if (val < 0x07ff)
                                        break;
-                               v4l_dbg(2, msp_debug, client, "detection still in progress\n");
+                               v4l_dbg(2, msp_debug, client,
+                                       "detection still in progress\n");
                        }
                }
                for (i = 0; msp_stdlist[i].name != NULL; i++)
@@ -716,12 +737,13 @@ int msp3410d_thread(void *data)
                state->std = val;
                state->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-               if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
-                               (val != 0x0009)) {
+               if (msp_amsound && !state->radio &&
+                   (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) {
                        /* autodetection has failed, let backup */
                        v4l_dbg(1, msp_debug, client, "autodetection failed,"
                                " switching to backup standard: %s (0x%04x)\n",
-                               msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
+                               msp_stdlist[8].name ?
+                                       msp_stdlist[8].name : "unknown", val);
                        state->std = val = 0x0009;
                        msp_write_dem(client, 0x20, val);
                }
@@ -786,7 +808,8 @@ int msp3410d_thread(void *data)
                while (state->watch_stereo) {
                        if (msp_sleep(state, count ? 1000 : 5000))
                                goto restart;
-                       if (count) count--;
+                       if (count)
+                               count--;
                        watch_stereo(client);
                }
        }
@@ -872,8 +895,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
        else
                source = (in << 8) | matrix;
 
-       v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
-                       in, source, reg);
+       v4l_dbg(1, msp_debug, client,
+               "set source to %d (0x%x) for output %02x\n", in, source, reg);
        msp_write_dsp(client, reg, source);
 }
 
@@ -948,7 +971,7 @@ int msp34xxg_thread(void *data)
                msp_sleep(state, -1);
                v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
 
-       restart:
+restart:
                v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
                state->restart = 0;
                if (kthread_should_stop())
@@ -956,7 +979,8 @@ int msp34xxg_thread(void *data)
 
                if (state->mode == MSP_MODE_EXTERN) {
                        /* no carrier scan needed, just unmute */
-                       v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+                       v4l_dbg(1, msp_debug, client,
+                               "thread: no carrier scan\n");
                        state->scan_in_progress = 0;
                        msp_set_audio(client);
                        continue;
@@ -972,7 +996,8 @@ int msp34xxg_thread(void *data)
                        goto unmute;
 
                /* watch autodetect */
-               v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
+               v4l_dbg(1, msp_debug, client,
+                       "started autodetect, waiting for result\n");
                for (i = 0; i < 10; i++) {
                        if (msp_sleep(state, 100))
                                goto restart;
@@ -983,15 +1008,18 @@ int msp34xxg_thread(void *data)
                                state->std = val;
                                break;
                        }
-                       v4l_dbg(2, msp_debug, client, "detection still in progress\n");
+                       v4l_dbg(2, msp_debug, client,
+                               "detection still in progress\n");
                }
                if (state->std == 1) {
-                       v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
+                       v4l_dbg(1, msp_debug, client,
+                               "detection still in progress after 10 tries. giving up.\n");
                        continue;
                }
 
-       unmute:
-               v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
+unmute:
+               v4l_dbg(1, msp_debug, client,
+                       "detected standard: %s (0x%04x)\n",
                        msp_standard_std_name(state->std), state->std);
 
                if (state->std == 9) {
@@ -1046,9 +1074,11 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
                if (state->std == 0x20)
                        state->rxsubchans |= V4L2_TUNER_SUB_SAP;
                else
-                       state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       state->rxsubchans =
+                               V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
        }
-       v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+       v4l_dbg(1, msp_debug, client,
+               "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
                status, is_stereo, is_bilingual, state->rxsubchans);
        return (oldrx != state->rxsubchans);
 }
index f49d1f4c40db11cf43650e767848ba9310c23845..b630c26cfe856b9b45ead161d34ee013fddbeadc 100644 (file)
@@ -14,7 +14,7 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "mt20xx "
+#define PREFIX "mt20xx"
 
 /* ---------------------------------------------------------------------- */
 
index d0c2cd7854303fc8167a8203f85ee7f30493a27b..6fc1b8be1a1ff7811e458d2c4128876ddc974ad7 100644 (file)
@@ -5,6 +5,10 @@ config VIDEO_PVRUSB2
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select VIDEO_CX2341X
+       select VIDEO_SAA711X
+       select VIDEO_CX25840
+       select VIDEO_MSP3400
+       select VIDEO_WM8775
        ---help---
          This is a video4linux driver for Conexant 23416 based
          usb2 personal video recorder devices.
@@ -12,32 +16,29 @@ config VIDEO_PVRUSB2
          To compile this driver as a module, choose M here: the
          module will be called pvrusb2
 
-config VIDEO_PVRUSB2_29XXX
-       bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
+config VIDEO_PVRUSB2_ONAIR_CREATOR
+       bool "pvrusb2 driver support for OnAir Creator model"
        depends on VIDEO_PVRUSB2 && EXPERIMENTAL
        select VIDEO_SAA711X
-       select VIDEO_MSP3400
+       select VIDEO_CS53L32A
        ---help---
-         This option enables support for WinTV-PVR USB2 devices whose
-         model number is of the form "29xxx" (leading prefix of "29"
-         followed by 3 digits).
-         To see if you may need this option, examine the white
-         sticker on the underside of your device.
+
+         This option enables support for the OnAir Creator USB tuner
+         device.  This is a hybrid device, however currently only
+         analog mode is supported.
 
          If you are in doubt, say Y.
 
-config VIDEO_PVRUSB2_24XXX
-       bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+config VIDEO_PVRUSB2_ONAIR_USB2
+       bool "pvrusb2 driver support for OnAir USB2 model"
        depends on VIDEO_PVRUSB2 && EXPERIMENTAL
-       select VIDEO_CX25840
-       select VIDEO_WM8775
+       select VIDEO_SAA711X
+       select VIDEO_CS53L32A
        ---help---
-         This option enables inclusion of additional logic to operate
-         newer WinTV-PVR USB2 devices whose model number is of the
-         form "24xxx" (leading prefix of "24" followed by 3 digits).
-         To see if you may need this option, examine the white
-         sticker on the underside of your device.  Enabling this
-         option will not harm support for older devices.
+
+         This option enables support for the OnAir USB2 tuner device
+         (also known as the Sasem tuner).  This is a hybrid device,
+         however currently only analog mode is supported.
 
          If you are in doubt, say Y.
 
index 69b3e43cd0ebb8175cd3b5f465186947a7092955..47284e55864808a12be78b854b99cf7946c3a577 100644 (file)
@@ -6,7 +6,7 @@ pvrusb2-objs    := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
                   pvrusb2-encoder.o pvrusb2-video-v4l.o \
                   pvrusb2-eeprom.o pvrusb2-tuner.o \
                   pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
-                  pvrusb2-ctrl.o pvrusb2-std.o \
+                  pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
                   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
                   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
                   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
index 379645e481c6ff830cab9e7dcaec13758c8131ec..9a7c8e9c3e8ba3ef33ab19b4f449e64791c43a79 100644 (file)
@@ -35,34 +35,58 @@ struct pvr2_msp3400_handler {
 };
 
 
+
+struct routing_scheme {
+       const int *def;
+       unsigned int cnt;
+};
+
+static const int routing_scheme0[] = {
+       [PVR2_CVAL_INPUT_TV]        = MSP_INPUT_DEFAULT,
+       [PVR2_CVAL_INPUT_RADIO]     = MSP_INPUT(MSP_IN_SCART2,
+                                               MSP_IN_TUNER1,
+                                               MSP_DSP_IN_SCART,
+                                               MSP_DSP_IN_SCART),
+       [PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1,
+                                               MSP_IN_TUNER1,
+                                               MSP_DSP_IN_SCART,
+                                               MSP_DSP_IN_SCART),
+       [PVR2_CVAL_INPUT_SVIDEO]    = MSP_INPUT(MSP_IN_SCART1,
+                                               MSP_IN_TUNER1,
+                                               MSP_DSP_IN_SCART,
+                                               MSP_DSP_IN_SCART),
+};
+
+static const struct routing_scheme routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
+               .def = routing_scheme0,
+               .cnt = ARRAY_SIZE(routing_scheme0),
+       },
+};
+
 /* This function selects the correct audio input source */
 static void set_stereo(struct pvr2_msp3400_handler *ctxt)
 {
        struct pvr2_hdw *hdw = ctxt->hdw;
        struct v4l2_routing route;
+       const struct routing_scheme *sp;
+       unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
 
-       route.input = MSP_INPUT_DEFAULT;
-       route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-       switch (hdw->input_val) {
-       case PVR2_CVAL_INPUT_TV:
-               break;
-       case PVR2_CVAL_INPUT_RADIO:
-               /* Assume that msp34xx also handle FM decoding, in which case
-                  we're still using the tuner. */
-               /* HV: actually it is more likely to be the SCART2 input if
-                  the ivtv experience is any indication. */
-               route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
-                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
-               break;
-       case PVR2_CVAL_INPUT_SVIDEO:
-       case PVR2_CVAL_INPUT_COMPOSITE:
-               /* SCART 1 input */
-               route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
-                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
-               break;
+       if ((sid < ARRAY_SIZE(routing_schemes)) &&
+           ((sp = routing_schemes + sid) != 0) &&
+           (hdw->input_val >= 0) &&
+           (hdw->input_val < sp->cnt)) {
+               route.input = sp->def[hdw->input_val];
+       } else {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
+                          " Invalid routing scheme (%u) and/or input (%d)",
+                          sid,hdw->input_val);
+               return;
        }
+       route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
        pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
 }
 
index 22719ba861aceb2d0e0c3f2b70b467b39ef26de9..9d94aed2e12dcacb2f66cbf339db899fbd1ba18d 100644 (file)
 
 static void pvr2_context_destroy(struct pvr2_context *mp)
 {
-       if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
        pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
-       if (mp->workqueue) {
-               flush_workqueue(mp->workqueue);
-               destroy_workqueue(mp->workqueue);
-       }
+       if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
        kfree(mp);
 }
 
 
-static void pvr2_context_trigger_poll(struct pvr2_context *mp)
-{
-       queue_work(mp->workqueue,&mp->workpoll);
-}
-
-
-static void pvr2_context_poll(struct work_struct *work)
-{
-       struct pvr2_context *mp =
-               container_of(work, struct pvr2_context, workpoll);
-       pvr2_context_enter(mp); do {
-               pvr2_hdw_poll(mp->hdw);
-       } while (0); pvr2_context_exit(mp);
-}
-
-
-static void pvr2_context_setup(struct work_struct *work)
+static void pvr2_context_state_check(struct pvr2_context *mp)
 {
-       struct pvr2_context *mp =
-               container_of(work, struct pvr2_context, workinit);
+       if (mp->init_flag) return;
+
+       switch (pvr2_hdw_get_state(mp->hdw)) {
+       case PVR2_STATE_WARM: break;
+       case PVR2_STATE_ERROR: break;
+       case PVR2_STATE_READY: break;
+       case PVR2_STATE_RUN: break;
+       default: return;
+       }
 
        pvr2_context_enter(mp); do {
-               if (!pvr2_hdw_dev_ok(mp->hdw)) break;
-               pvr2_hdw_setup(mp->hdw);
-               pvr2_hdw_setup_poll_trigger(
-                       mp->hdw,
-                       (void (*)(void *))pvr2_context_trigger_poll,
-                       mp);
-               if (!pvr2_hdw_dev_ok(mp->hdw)) break;
-               if (!pvr2_hdw_init_ok(mp->hdw)) break;
+               mp->init_flag = !0;
                mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
                if (mp->setup_func) {
                        mp->setup_func(mp);
                }
        } while (0); pvr2_context_exit(mp);
-}
+ }
 
 
 struct pvr2_context *pvr2_context_create(
@@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create(
                mp = NULL;
                goto done;
        }
-
-       mp->workqueue = create_singlethread_workqueue("pvrusb2");
-       INIT_WORK(&mp->workinit, pvr2_context_setup);
-       INIT_WORK(&mp->workpoll, pvr2_context_poll);
-       queue_work(mp->workqueue,&mp->workinit);
+       pvr2_hdw_set_state_callback(mp->hdw,
+                                   (void (*)(void *))pvr2_context_state_check,
+                                   mp);
+       pvr2_context_state_check(mp);
  done:
        return mp;
 }
index 6327fa1f7e4f24864a6377aa2090f4ab96a19119..a04187a932251dd86b11020916f55c31c3da51c5 100644 (file)
@@ -45,14 +45,11 @@ struct pvr2_context {
        struct pvr2_context_stream video_stream;
        struct mutex mutex;
        int disconnect_flag;
+       int init_flag;
 
        /* Called after pvr2_context initialization is complete */
        void (*setup_func)(struct pvr2_context *);
 
-       /* Work queue overhead for out-of-line processing */
-       struct workqueue_struct *workqueue;
-       struct work_struct workinit;
-       struct work_struct workpoll;
 };
 
 struct pvr2_channel {
index e8a9252c7df6a2250cb301f7c8f792fd50527c5f..ffdc45c324e5d24936de4557da279af46314ee8d 100644 (file)
@@ -49,34 +49,89 @@ struct pvr2_v4l_cx2584x {
 };
 
 
+struct routing_scheme_item {
+       int vid;
+       int aud;
+};
+
+struct routing_scheme {
+       const struct routing_scheme_item *def;
+       unsigned int cnt;
+};
+
+static const struct routing_scheme_item routing_scheme0[] = {
+       [PVR2_CVAL_INPUT_TV] = {
+               .vid = CX25840_COMPOSITE7,
+               .aud = CX25840_AUDIO8,
+       },
+       [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+               .vid = CX25840_COMPOSITE3,
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+       [PVR2_CVAL_INPUT_COMPOSITE] = {
+               .vid = CX25840_COMPOSITE3,
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+       [PVR2_CVAL_INPUT_SVIDEO] = {
+               .vid = CX25840_SVIDEO1,
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+};
+
+/* Specific to gotview device */
+static const struct routing_scheme_item routing_schemegv[] = {
+       [PVR2_CVAL_INPUT_TV] = {
+               .vid = CX25840_COMPOSITE2,
+               .aud = CX25840_AUDIO5,
+       },
+       [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+               .vid = CX25840_COMPOSITE1,
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+       [PVR2_CVAL_INPUT_COMPOSITE] = {
+               .vid = CX25840_COMPOSITE1,
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+       [PVR2_CVAL_INPUT_SVIDEO] = {
+               .vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4),
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+};
+
+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 void set_input(struct pvr2_v4l_cx2584x *ctxt)
 {
        struct pvr2_hdw *hdw = ctxt->hdw;
        struct v4l2_routing route;
        enum cx25840_video_input vid_input;
        enum cx25840_audio_input aud_input;
+       const struct routing_scheme *sp;
+       unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
        memset(&route,0,sizeof(route));
 
-       switch(hdw->input_val) {
-       case PVR2_CVAL_INPUT_TV:
-               vid_input = CX25840_COMPOSITE7;
-               aud_input = CX25840_AUDIO8;
-               break;
-       case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
-       case PVR2_CVAL_INPUT_COMPOSITE:
-               vid_input = CX25840_COMPOSITE3;
-               aud_input = CX25840_AUDIO_SERIAL;
-               break;
-       case PVR2_CVAL_INPUT_SVIDEO:
-               vid_input = CX25840_SVIDEO1;
-               aud_input = CX25840_AUDIO_SERIAL;
-               break;
-       default:
-               // Just set it to be composite input for now...
-               vid_input = CX25840_COMPOSITE3;
-               aud_input = CX25840_AUDIO_SERIAL;
-               break;
+       if ((sid < ARRAY_SIZE(routing_schemes)) &&
+           ((sp = routing_schemes + sid) != 0) &&
+           (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 {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "*** WARNING *** i2c cx2584x set_input:"
+                          " Invalid routing scheme (%u) and/or input (%d)",
+                          sid,hdw->input_val);
+               return;
        }
 
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
@@ -140,7 +195,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
 static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
 {
        ctxt->client->handler = NULL;
-       ctxt->hdw->decoder_ctrl = NULL;
+       pvr2_hdw_set_decoder(ctxt->hdw,NULL);
        kfree(ctxt);
 }
 
@@ -241,7 +296,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
        ctxt->client = cp;
        ctxt->hdw = hdw;
        ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
-       hdw->decoder_ctrl = &ctxt->ctrl;
+       pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
        cp->handler = &ctxt->handler;
        {
                /*
index da6441b88f31af8ebae32a62533f9d6330f2823c..fca49d8a9311e70544e89b5cd713fc677d91cf05 100644 (file)
@@ -34,25 +34,26 @@ extern int pvrusb2_debug;
 #define PVR2_TRACE_INIT       (1 <<  5) /* misc initialization steps */
 #define PVR2_TRACE_START_STOP (1 <<  6) /* Streaming start / stop */
 #define PVR2_TRACE_CTL        (1 <<  7) /* commit of control changes */
-#define PVR2_TRACE_DEBUG      (1 <<  8) /* Temporary debug code */
-#define PVR2_TRACE_EEPROM     (1 <<  9) /* eeprom parsing / report */
-#define PVR2_TRACE_STRUCT     (1 << 10) /* internal struct creation */
-#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
-#define PVR2_TRACE_CREG       (1 << 12) /* Main critical region entry / exit */
-#define PVR2_TRACE_SYSFS      (1 << 13) /* Sysfs driven I/O */
-#define PVR2_TRACE_FIRMWARE   (1 << 14) /* firmware upload actions */
-#define PVR2_TRACE_CHIPS      (1 << 15) /* chip broadcast operation */
-#define PVR2_TRACE_I2C        (1 << 16) /* I2C related stuff */
-#define PVR2_TRACE_I2C_CMD    (1 << 17) /* Software commands to I2C modules */
-#define PVR2_TRACE_I2C_CORE   (1 << 18) /* I2C core debugging */
-#define PVR2_TRACE_I2C_TRAF   (1 << 19) /* I2C traffic through the adapter */
-#define PVR2_TRACE_V4LIOCTL   (1 << 20) /* v4l ioctl details */
-#define PVR2_TRACE_ENCODER    (1 << 21) /* mpeg2 encoder operation */
-#define PVR2_TRACE_BUF_POOL   (1 << 22) /* Track buffer pool management */
-#define PVR2_TRACE_BUF_FLOW   (1 << 23) /* Track buffer flow in system */
-#define PVR2_TRACE_DATA_FLOW  (1 << 24) /* Track data flow */
-#define PVR2_TRACE_DEBUGIFC   (1 << 25) /* Debug interface actions */
-#define PVR2_TRACE_GPIO       (1 << 26) /* GPIO state bit changes */
+#define PVR2_TRACE_STATE      (1 <<  8) /* Device state changes */
+#define PVR2_TRACE_STBITS     (1 <<  9) /* Individual bit state changes */
+#define PVR2_TRACE_EEPROM     (1 << 10) /* eeprom parsing / report */
+#define PVR2_TRACE_STRUCT     (1 << 11) /* internal struct creation */
+#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
+#define PVR2_TRACE_CREG       (1 << 13) /* Main critical region entry / exit */
+#define PVR2_TRACE_SYSFS      (1 << 14) /* Sysfs driven I/O */
+#define PVR2_TRACE_FIRMWARE   (1 << 15) /* firmware upload actions */
+#define PVR2_TRACE_CHIPS      (1 << 16) /* chip broadcast operation */
+#define PVR2_TRACE_I2C        (1 << 17) /* I2C related stuff */
+#define PVR2_TRACE_I2C_CMD    (1 << 18) /* Software commands to I2C modules */
+#define PVR2_TRACE_I2C_CORE   (1 << 19) /* I2C core debugging */
+#define PVR2_TRACE_I2C_TRAF   (1 << 20) /* I2C traffic through the adapter */
+#define PVR2_TRACE_V4LIOCTL   (1 << 21) /* v4l ioctl details */
+#define PVR2_TRACE_ENCODER    (1 << 22) /* mpeg2 encoder operation */
+#define PVR2_TRACE_BUF_POOL   (1 << 23) /* Track buffer pool management */
+#define PVR2_TRACE_BUF_FLOW   (1 << 24) /* Track buffer flow in system */
+#define PVR2_TRACE_DATA_FLOW  (1 << 25) /* Track data flow */
+#define PVR2_TRACE_DEBUGIFC   (1 << 26) /* Debug interface actions */
+#define PVR2_TRACE_GPIO       (1 << 27) /* GPIO state bit changes */
 
 
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
index 6f135f4a2497d89d55d760d6f6f812cc87a5253f..b0687430fdd421fc8798ecb4bde590512b42f2d5 100644 (file)
@@ -31,14 +31,6 @@ struct debugifc_mask_item {
        unsigned long msk;
 };
 
-static struct debugifc_mask_item mask_items[] = {
-       {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
-       {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
-       {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
-       {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
-       {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
-};
-
 
 static unsigned int debugifc_count_whitespace(const char *buf,
                                              unsigned int count)
@@ -148,134 +140,14 @@ static int debugifc_match_keyword(const char *buf,unsigned int count,
 }
 
 
-static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
-{
-       struct debugifc_mask_item *mip;
-       unsigned int idx;
-       for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
-               mip = mask_items + idx;
-               if (debugifc_match_keyword(buf,count,mip->name)) {
-                       return mip->msk;
-               }
-       }
-       return 0;
-}
-
-
-static int debugifc_print_mask(char *buf,unsigned int sz,
-                              unsigned long msk,unsigned long val)
-{
-       struct debugifc_mask_item *mip;
-       unsigned int idx;
-       int bcnt = 0;
-       int ccnt;
-       for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
-               mip = mask_items + idx;
-               if (!(mip->msk & msk)) continue;
-               ccnt = scnprintf(buf,sz,"%s%c%s",
-                                (bcnt ? " " : ""),
-                                ((mip->msk & val) ? '+' : '-'),
-                                mip->name);
-               sz -= ccnt;
-               buf += ccnt;
-               bcnt += ccnt;
-       }
-       return bcnt;
-}
-
-static unsigned int debugifc_parse_subsys_mask(const char *buf,
-                                              unsigned int count,
-                                              unsigned long *mskPtr,
-                                              unsigned long *valPtr)
-{
-       const char *wptr;
-       unsigned int consume_cnt = 0;
-       unsigned int scnt;
-       unsigned int wlen;
-       int mode;
-       unsigned long m1,msk,val;
-
-       msk = 0;
-       val = 0;
-
-       while (count) {
-               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
-               if (!scnt) break;
-               consume_cnt += scnt; count -= scnt; buf += scnt;
-               if (!wptr) break;
-
-               mode = 0;
-               if (wlen) switch (wptr[0]) {
-               case '+':
-                       wptr++;
-                       wlen--;
-                       break;
-               case '-':
-                       mode = 1;
-                       wptr++;
-                       wlen--;
-                       break;
-               }
-               if (!wlen) continue;
-               m1 = debugifc_find_mask(wptr,wlen);
-               if (!m1) break;
-               msk |= m1;
-               if (!mode) val |= m1;
-       }
-       *mskPtr = msk;
-       *valPtr = val;
-       return consume_cnt;
-}
-
-
 int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
 {
        int bcnt = 0;
        int ccnt;
-       struct pvr2_hdw_debug_info dbg;
-
-       pvr2_hdw_get_debug_info(hdw,&dbg);
-
-       ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
-                        (dbg.big_lock_held ? "held" : "free"),
-                        (dbg.ctl_lock_held ? "held" : "free"));
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       if (dbg.ctl_lock_held) {
-               ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
-                                " cmd_wlen=%d cmd_rlen=%d"
-                                " wpend=%d rpend=%d tmout=%d rstatus=%d"
-                                " wstatus=%d",
-                                dbg.cmd_debug_state,dbg.cmd_code,
-                                dbg.cmd_debug_write_len,
-                                dbg.cmd_debug_read_len,
-                                dbg.cmd_debug_write_pend,
-                                dbg.cmd_debug_read_pend,
-                                dbg.cmd_debug_timeout,
-                                dbg.cmd_debug_rstatus,
-                                dbg.cmd_debug_wstatus);
-               bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       }
-       ccnt = scnprintf(buf,acnt,"\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(
-               buf,acnt,"driver flags: %s %s %s\n",
-               (dbg.flag_init_ok ? "initialized" : "uninitialized"),
-               (dbg.flag_ok ? "ok" : "fail"),
-               (dbg.flag_disconnected ? "disconnected" : "connected"));
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+       ccnt = scnprintf(buf,acnt,"Driver state info:\n");
        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
+       ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-
        ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
        ccnt = pvr2_i2c_report(hdw,buf,acnt);
@@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
 {
        int bcnt = 0;
        int ccnt;
-       unsigned long msk;
        int ret;
        u32 gpio_dir,gpio_in,gpio_out;
 
@@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
                         pvr2_hdw_get_streaming(hdw) ? "on" : "off");
        bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 
-       msk = pvr2_hdw_subsys_get(hdw);
-       ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = debugifc_print_mask(buf,acnt,msk,msk);
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-
-       msk = pvr2_hdw_subsys_stream_get(hdw);
-       ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = debugifc_print_mask(buf,acnt,msk,msk);
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-       ccnt = scnprintf(buf,acnt,"\n");
-       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-
        return bcnt;
 }
 
@@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
                        return pvr2_upload_firmware2(hdw);
                } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
                        return pvr2_hdw_cmd_decoder_reset(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"worker")) {
+                       return pvr2_hdw_untrip(hdw);
                }
                return -EINVAL;
-       } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
-               unsigned long msk = 0;
-               unsigned long val = 0;
-               if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
-                       pvr2_trace(PVR2_TRACE_DEBUGIFC,
-                                  "debugifc parse error on subsys mask");
-                       return -EINVAL;
-               }
-               pvr2_hdw_subsys_bit_chg(hdw,msk,val);
-               return 0;
-       } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
-               unsigned long msk = 0;
-               unsigned long val = 0;
-               if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
-                       pvr2_trace(PVR2_TRACE_DEBUGIFC,
-                                  "debugifc parse error on stream mask");
-                       return -EINVAL;
-               }
-               pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
-               return 0;
        } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
                scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
                if (!scnt) return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
new file mode 100644 (file)
index 0000000..4df6d6d
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2007 Mike Isely <isely@pobox.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
+ *
+ *  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
+ *
+ */
+
+/*
+
+This source file should encompass ALL per-device type information for the
+driver.  To define a new device, add elements to the pvr2_device_table and
+pvr2_device_desc structures.
+
+*/
+
+#include "pvrusb2-devattr.h"
+#include <linux/usb.h>
+/* This is needed in order to pull in tuner type ids... */
+#include <linux/i2c.h>
+#include <media/tuner.h>
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 29xxx */
+
+static const char *pvr2_client_29xxx[] = {
+       "msp3400",
+       "saa7115",
+       "tuner",
+};
+
+static const char *pvr2_fw1_names_29xxx[] = {
+               "v4l-pvrusb2-29xxx-01.fw",
+};
+
+static const struct pvr2_device_desc pvr2_device_29xxx = {
+               .description = "WinTV PVR USB2 Model Category 29xxxx",
+               .shortname = "29xxx",
+               .client_modules.lst = pvr2_client_29xxx,
+               .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
+               .fx2_firmware.lst = pvr2_fw1_names_29xxx,
+               .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
+               .flag_has_hauppauge_rom = !0,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 24xxx */
+
+static const char *pvr2_client_24xxx[] = {
+       "cx25840",
+       "tuner",
+       "wm8775",
+};
+
+static const char *pvr2_fw1_names_24xxx[] = {
+               "v4l-pvrusb2-24xxx-01.fw",
+};
+
+static const struct pvr2_device_desc pvr2_device_24xxx = {
+               .description = "WinTV PVR USB2 Model Category 24xxxx",
+               .shortname = "24xxx",
+               .client_modules.lst = pvr2_client_24xxx,
+               .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
+               .fx2_firmware.lst = pvr2_fw1_names_24xxx,
+               .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
+               .flag_has_cx25840 = !0,
+               .flag_has_wm8775 = !0,
+               .flag_has_hauppauge_rom = !0,
+               .flag_has_hauppauge_custom_ir = !0,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* GOTVIEW USB2.0 DVD2 */
+
+static const char *pvr2_client_gotview_2[] = {
+       "cx25840",
+       "tuner",
+};
+
+static const struct pvr2_device_desc pvr2_device_gotview_2 = {
+               .description = "Gotview USB 2.0 DVD 2",
+               .shortname = "gv2",
+               .client_modules.lst = pvr2_client_gotview_2,
+               .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+               .flag_has_cx25840 = !0,
+               .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
+};
+
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
+/*------------------------------------------------------------------------*/
+/* OnAir Creator */
+
+static const char *pvr2_client_onair_creator[] = {
+       "saa7115",
+       "tuner",
+       "cs53l32a",
+};
+
+static const struct pvr2_device_desc pvr2_device_onair_creator = {
+               .description = "OnAir Creator Hybrid USB tuner",
+               .shortname = "oac",
+               .client_modules.lst = pvr2_client_onair_creator,
+               .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
+               .default_tuner_type = TUNER_LG_TDVS_H06XF,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+#endif
+
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
+/*------------------------------------------------------------------------*/
+/* OnAir USB 2.0 */
+
+static const char *pvr2_client_onair_usb2[] = {
+       "saa7115",
+       "tuner",
+       "cs53l32a",
+};
+
+static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
+               .description = "OnAir USB2 Hybrid USB tuner",
+               .shortname = "oa2",
+               .client_modules.lst = pvr2_client_onair_usb2,
+               .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
+               .default_tuner_type = TUNER_PHILIPS_ATSC,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+#endif
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 75xxx */
+
+static const char *pvr2_client_75xxx[] = {
+       "cx25840",
+       "tuner",
+};
+
+static const char *pvr2_fw1_names_75xxx[] = {
+               "v4l-pvrusb2-73xxx-01.fw",
+};
+
+static const struct pvr2_device_desc pvr2_device_75xxx = {
+               .description = "WinTV PVR USB2 Model Category 75xxxx",
+               .shortname = "75xxx",
+               .client_modules.lst = pvr2_client_75xxx,
+               .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+               .fx2_firmware.lst = pvr2_fw1_names_75xxx,
+               .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+               .flag_has_cx25840 = !0,
+               .flag_has_hauppauge_rom = !0,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+               .default_std_mask = V4L2_STD_NTSC_M,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+
+struct usb_device_id pvr2_device_table[] = {
+       { USB_DEVICE(0x2040, 0x2900),
+         .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
+       { USB_DEVICE(0x2040, 0x2400),
+         .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
+       { USB_DEVICE(0x1164, 0x0622),
+         .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
+       { USB_DEVICE(0x11ba, 0x1003),
+         .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
+#endif
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
+       { USB_DEVICE(0x11ba, 0x1001),
+         .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
+#endif
+       { USB_DEVICE(0x2040, 0x7500),
+         .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
new file mode 100644 (file)
index 0000000..64b467f
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef __PVRUSB2_DEVATTR_H
+#define __PVRUSB2_DEVATTR_H
+
+#include <linux/mod_devicetable.h>
+#include <linux/videodev2.h>
+
+/*
+
+  This header defines structures used to describe attributes of a device.
+
+*/
+
+
+struct pvr2_string_table {
+       const char **lst;
+       unsigned int cnt;
+};
+
+#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
+#define PVR2_ROUTING_SCHEME_GOTVIEW 1
+
+/* This describes a particular hardware type (except for the USB device ID
+   which must live in a separate structure due to environmental
+   constraints).  See the top of pvrusb2-hdw.c for where this is
+   instantiated. */
+struct pvr2_device_desc {
+       /* Single line text description of hardware */
+       const char *description;
+
+       /* Single token identifier for hardware */
+       const char *shortname;
+
+       /* List of additional client modules we need to load */
+       struct pvr2_string_table client_modules;
+
+       /* List of FX2 firmware file names we should search; if empty then
+          FX2 firmware check / load is skipped and we assume the device
+          was initialized from internal ROM. */
+       struct pvr2_string_table fx2_firmware;
+
+       /* Signal routing scheme used by device, contains one of
+          PVR2_ROUTING_SCHEME_XXX.  Schemes have to be defined as we
+          encounter them.  This is an arbitrary integer scheme id; its
+          meaning is contained entirely within the driver and is
+          interpreted by logic which must send commands to the chip-level
+          drivers (search for things which touch this field). */
+       unsigned int signal_routing_scheme;
+
+       /* V4L tuner type ID to use with this device (only used if the
+          driver could not discover the type any other way). */
+       int default_tuner_type;
+
+       /* Initial standard bits to use for this device, if not zero.
+          Anything set here is also implied as an available standard.
+          Note: This is ignored if overridden on the module load line via
+          the video_std module option. */
+       v4l2_std_id default_std_mask;
+
+       /* If set, we don't bother trying to load cx23416 firmware. */
+       char flag_skip_cx23416_firmware;
+
+       /* Device has a hauppauge eeprom which we can interrogate. */
+       char flag_has_hauppauge_rom;
+
+       /* Device does not require a powerup command to be issued. */
+       char flag_no_powerup;
+
+       /* Device has a cx25840 - this enables special additional logic to
+          handle it. */
+       char flag_has_cx25840;
+
+       /* Device has a wm8775 - this enables special additional logic to
+          ensure that it is found. */
+       char flag_has_wm8775;
+
+       /* Device has IR hardware that can be faked into looking like a
+          normal Hauppauge i2c IR receiver.  This is currently very
+          specific to the 24xxx device, where Hauppauge had replaced their
+          'standard' I2C IR receiver with a bunch of FPGA logic controlled
+          directly via the FX2.  Turning this on tells the pvrusb2 driver
+          to virtualize the presence of the non-existant IR receiver chip and
+          implement the virtual receiver in terms of appropriate FX2
+          commands. */
+       char flag_has_hauppauge_custom_ir;
+};
+
+extern struct usb_device_id pvr2_device_table[];
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
index 45cbca0143ca7a62ad4fe7356cb04e87e94f97d1..5ef005947b04f2bd2bbeed76562b13056872b84c 100644 (file)
@@ -144,6 +144,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
        trace_eeprom("serial_number=%d",tvdata.serial_number);
        trace_eeprom("rev_str=%s",tvdata.rev_str);
        hdw->tuner_type = tvdata.tuner_type;
+       hdw->tuner_updated = !0;
        hdw->serial_number = tvdata.serial_number;
        hdw->std_mask_eeprom = tvdata.tuner_formats;
 
index 205087a3e136fa226cc52495c5055b7121da5b10..64062879981e4297db9f8386c68306c15e61c616 100644 (file)
@@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
    cx2341x.ko to write to our encoder (by handing it a pointer to this
    function).  For earlier kernels this doesn't really matter. */
 static int pvr2_encoder_cmd(void *ctxt,
-                           int cmd,
+                           u32 cmd,
                            int arg_cnt_send,
                            int arg_cnt_recv,
                            u32 *argp)
@@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt,
 
        LOCK_TAKE(hdw->ctl_lock); do {
 
-               if (!hdw->flag_encoder_ok) {
+               if (!hdw->state_encoder_ok) {
                        ret = -EIO;
                        break;
                }
@@ -278,12 +278,15 @@ static int pvr2_encoder_cmd(void *ctxt,
                        ret = -EBUSY;
                }
                if (ret) {
-                       hdw->flag_encoder_ok = 0;
+                       hdw->state_encoder_ok = 0;
+                       pvr2_trace(PVR2_TRACE_STBITS,
+                                  "State bit %s <-- %s",
+                                  "state_encoder_ok",
+                                  (hdw->state_encoder_ok ? "true" : "false"));
                        pvr2_trace(
                                PVR2_TRACE_ERROR_LEGS,
                                "Giving up on command."
-                               "  It is likely that"
-                               " this is a bad idea...");
+                               "  This is normally recovered by the driver.");
                        break;
                }
                wrData[0] = 0x7;
@@ -366,13 +369,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
 
        /* This ENC_MISC(3,encMisc3Arg) command is critical - without
           it there will eventually be video corruption.  Also, the
-          29xxx case is strange - the Windows driver is passing 1
-          regardless of device type but if we have 1 for 29xxx device
-          the video turns sluggish.  */
-       switch (hdw->hdw_type) {
-       case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
-       case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
-       default: break;
+          saa7115 case is strange - the Windows driver is passing 1
+          regardless of device type but if we have 1 for saa7115
+          devices the video turns sluggish.  */
+       if (hdw->hdw_desc->flag_has_cx25840) {
+               encMisc3Arg = 1;
+       } else {
+               encMisc3Arg = 0;
        }
        ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
                                 encMisc3Arg,0,0);
@@ -394,6 +397,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
        return ret;
 }
 
+int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
+{
+       int ret;
+       ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+                            (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
+                            &hdw->enc_ctl_state);
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Error from cx2341x module code=%d",ret);
+       } else {
+               memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
+                      sizeof(struct cx2341x_mpeg_params));
+               hdw->enc_cur_valid = !0;
+       }
+       return ret;
+}
+
+
 int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 {
        int ret;
@@ -412,7 +433,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 
        /* saa7115: 0xf0 */
        val = 0xf0;
-       if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+       if (hdw->hdw_desc->flag_has_cx25840) {
                /* ivtv cx25840: 0x140 */
                val = 0x140;
        }
@@ -436,18 +457,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
                return ret;
        }
 
-       ret = cx2341x_update(hdw,pvr2_encoder_cmd,
-                            (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
-                            &hdw->enc_ctl_state);
-       if (ret) {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "Error from cx2341x module code=%d",ret);
-               return ret;
-       }
-
-       ret = 0;
+       ret = pvr2_encoder_adjust(hdw);
+       if (ret) return ret;
 
-       if (!ret) ret = pvr2_encoder_vcmd(
+       ret = pvr2_encoder_vcmd(
                hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
        if (ret) {
@@ -456,10 +469,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
                return ret;
        }
 
-       hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-       memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
-              sizeof(struct cx2341x_mpeg_params));
-       hdw->enc_cur_valid = !0;
        return 0;
 }
 
@@ -478,7 +487,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
        pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
                          hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
 
-       switch (hdw->config) {
+       switch (hdw->active_stream_type) {
        case pvr2_config_vbi:
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
                                           0x01,0x14);
@@ -492,9 +501,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
                                           0,0x13);
                break;
        }
-       if (!status) {
-               hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
-       }
        return status;
 }
 
@@ -505,7 +511,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
        /* mask all interrupts */
        pvr2_write_register(hdw, 0x0048, 0xffffffff);
 
-       switch (hdw->config) {
+       switch (hdw->active_stream_type) {
        case pvr2_config_vbi:
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
                                           0x01,0x01,0x14);
@@ -526,9 +532,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
        pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
        pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
 
-       if (!status) {
-               hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
-       }
        return status;
 }
 
index 01b5a0b89c03893d3d30f34759ad803e777b522b..54caf2e3c428adadc7ff16b76261ffeac60a95c1 100644 (file)
@@ -25,6 +25,7 @@
 
 struct pvr2_hdw;
 
+int pvr2_encoder_adjust(struct pvr2_hdw *);
 int pvr2_encoder_configure(struct pvr2_hdw *);
 int pvr2_encoder_start(struct pvr2_hdw *);
 int pvr2_encoder_stop(struct pvr2_hdw *);
index f873994b088ce3287a7a5b1bfdb4763b0f818fb6..d7a216b41b7235b14bcd364ef82dc3c946a2b97b 100644 (file)
 
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <linux/workqueue.h>
 #include <linux/mutex.h>
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-io.h"
 #include <media/cx2341x.h>
+#include "pvrusb2-devattr.h"
 
 /* Legal values for PVR2_CID_HSM */
 #define PVR2_CVAL_HSM_FAIL 0
@@ -161,10 +163,6 @@ struct pvr2_decoder_ctrl {
 #define FW1_STATE_RELOAD 3
 #define FW1_STATE_OK 4
 
-/* Known major hardware variants, keyed from device ID */
-#define PVR2_HDW_TYPE_29XXX 0
-#define PVR2_HDW_TYPE_24XXX 1
-
 typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
 #define PVR2_I2C_FUNC_CNT 128
 
@@ -176,8 +174,15 @@ struct pvr2_hdw {
        struct usb_device *usb_dev;
        struct usb_interface *usb_intf;
 
-       /* Device type, one of PVR2_HDW_TYPE_xxxxx */
-       unsigned int hdw_type;
+       /* Device description, anything that must adjust behavior based on
+          device specific info will use information held here. */
+       const struct pvr2_device_desc *hdw_desc;
+
+       /* Kernel worker thread handling */
+       struct workqueue_struct *workqueue;
+       struct work_struct workpoll;     /* Update driver state */
+       struct work_struct worki2csync;  /* Update i2c clients */
+       struct work_struct workinit;     /* Driver initialization sequence */
 
        /* Video spigot */
        struct pvr2_stream *vid_stream;
@@ -186,9 +191,6 @@ struct pvr2_hdw {
        struct mutex big_lock_mutex;
        int big_lock_held;  /* For debugging */
 
-       void (*poll_trigger_func)(void *);
-       void *poll_trigger_data;
-
        char name[32];
 
        /* I2C stuff */
@@ -215,9 +217,9 @@ struct pvr2_hdw {
        struct urb *ctl_read_urb;
        unsigned char *ctl_write_buffer;
        unsigned char *ctl_read_buffer;
-       volatile int ctl_write_pend_flag;
-       volatile int ctl_read_pend_flag;
-       volatile int ctl_timeout_flag;
+       int ctl_write_pend_flag;
+       int ctl_read_pend_flag;
+       int ctl_timeout_flag;
        struct completion ctl_done;
        unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
        int cmd_debug_state;               // Low level command debugging info
@@ -225,14 +227,48 @@ struct pvr2_hdw {
        unsigned int cmd_debug_write_len;  //
        unsigned int cmd_debug_read_len;   //
 
+       /* Bits of state that describe what is going on with various parts
+          of the driver. */
+       int state_encoder_ok;         /* Encoder is operational */
+       int state_encoder_run;        /* Encoder is running */
+       int state_encoder_config;     /* Encoder is configured */
+       int state_encoder_waitok;     /* Encoder pre-wait done */
+       int state_decoder_run;        /* Decoder is running */
+       int state_usbstream_run;      /* FX2 is streaming */
+       int state_decoder_quiescent;  /* Decoder idle for > 50msec */
+       int state_pipeline_config;    /* Pipeline is configured */
+       int state_pipeline_req;                /* Somebody wants to stream */
+       int state_pipeline_pause;              /* Pipeline must be paused */
+       int state_pipeline_idle;               /* Pipeline not running */
+
+       /* This is the master state of the driver.  It is the combined
+          result of other bits of state.  Examining this will indicate the
+          overall state of the driver.  Values here are one of
+          PVR2_STATE_xxxx */
+       unsigned int master_state;
+
+       /* True if states must be re-evaluated */
+       int state_stale;
+
+       void (*state_func)(void *);
+       void *state_data;
+
+       /* Timer for measuring decoder settling time */
+       struct timer_list quiescent_timer;
+
+       /* Timer for measuring encoder pre-wait time */
+       struct timer_list encoder_wait_timer;
+
+       /* Place to block while waiting for state changes */
+       wait_queue_head_t state_wait_data;
+
+
        int flag_ok;            /* device in known good state */
        int flag_disconnected;  /* flag_ok == 0 due to disconnect */
        int flag_init_ok;       /* true if structure is fully initialized */
-       int flag_streaming_enabled; /* true if streaming should be on */
        int fw1_state;          /* current situation with fw1 */
-       int flag_encoder_ok;    /* True if encoder is healthy */
-
-       int flag_decoder_is_tuned;
+       int flag_decoder_missed;/* We've noticed missing decoder */
+       int flag_tripped;       /* Indicates overall failure to start */
 
        struct pvr2_decoder_ctrl *decoder_ctrl;
 
@@ -241,12 +277,6 @@ struct pvr2_hdw {
        unsigned int fw_size;
        int fw_cpu_flag; /* True if we are dealing with the CPU */
 
-       // Which subsystem pieces have been enabled / configured
-       unsigned long subsys_enabled_mask;
-
-       // Which subsystems are manipulated to enable streaming
-       unsigned long subsys_stream_mask;
-
        // True if there is a request to trigger logging of state in each
        // module.
        int log_requested;
@@ -296,13 +326,16 @@ struct pvr2_hdw {
        /* Location of eeprom or a negative number if none */
        int eeprom_addr;
 
-       enum pvr2_config config;
+       enum pvr2_config active_stream_type;
+       enum pvr2_config desired_stream_type;
 
        /* Control state needed for cx2341x module */
        struct cx2341x_mpeg_params enc_cur_state;
        struct cx2341x_mpeg_params enc_ctl_state;
        /* True if an encoder attribute has changed */
        int enc_stale;
+       /* True if an unsafe encoder attribute has changed */
+       int enc_unsafe_stale;
        /* True if enc_cur_state is valid */
        int enc_cur_valid;
 
@@ -332,6 +365,7 @@ struct pvr2_hdw {
 
 /* This function gets the current frequency */
 unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
 
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
 
index 402c59488253768ce077708c8787711886988aa1..41ae980405edfac42a38cc22449389a68fe9658c 100644 (file)
 #define TV_MIN_FREQ     55250000L
 #define TV_MAX_FREQ    850000000L
 
-struct usb_device_id pvr2_device_table[] = {
-       [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
-       [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, pvr2_device_table);
-
-static const char *pvr2_device_names[] = {
-       [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
-       [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
-};
-
-struct pvr2_string_table {
-       const char **lst;
-       unsigned int cnt;
-};
-
-// Names of other client modules to request for 24xxx model hardware
-static const char *pvr2_client_24xxx[] = {
-       "cx25840",
-       "tuner",
-       "wm8775",
-};
-
-// Names of other client modules to request for 29xxx model hardware
-static const char *pvr2_client_29xxx[] = {
-       "msp3400",
-       "saa7115",
-       "tuner",
-};
-
-static struct pvr2_string_table pvr2_client_lists[] = {
-       [PVR2_HDW_TYPE_29XXX] = {
-               pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
-       },
-       [PVR2_HDW_TYPE_24XXX] = {
-               pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
-       },
-};
-
 static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
 static DEFINE_MUTEX(pvr2_unit_mtx);
 
@@ -246,32 +205,46 @@ static const char *control_values_hsm[] = {
 };
 
 
-static const char *control_values_subsystem[] = {
-       [PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",
-       [PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
-       [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
-       [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
-       [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
+static const char *pvr2_state_names[] = {
+       [PVR2_STATE_NONE] =    "none",
+       [PVR2_STATE_DEAD] =    "dead",
+       [PVR2_STATE_COLD] =    "cold",
+       [PVR2_STATE_WARM] =    "warm",
+       [PVR2_STATE_ERROR] =   "error",
+       [PVR2_STATE_READY] =   "ready",
+       [PVR2_STATE_RUN] =     "run",
 };
 
+
+static void pvr2_hdw_state_sched(struct pvr2_hdw *);
+static int pvr2_hdw_state_eval(struct pvr2_hdw *);
 static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
+static void pvr2_hdw_worker_i2c(struct work_struct *work);
+static void pvr2_hdw_worker_poll(struct work_struct *work);
+static void pvr2_hdw_worker_init(struct work_struct *work);
+static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
+static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
+static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
-static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
+static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
-static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
-static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
-                                           unsigned long msk,
-                                           unsigned long val);
-static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
-                                                  unsigned long msk,
-                                                  unsigned long val);
+static void pvr2_hdw_quiescent_timeout(unsigned long);
+static void pvr2_hdw_encoder_wait_timeout(unsigned long);
 static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
                                unsigned int timeout,int probe_fl,
                                void *write_data,unsigned int write_len,
                                void *read_data,unsigned int read_len);
 
+
+static void trace_stbit(const char *name,int val)
+{
+       pvr2_trace(PVR2_TRACE_STBITS,
+                  "State bit %s <-- %s",
+                  name,(val ? "true" : "false"));
+}
+
 static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
 {
        struct pvr2_hdw *hdw = cptr->hdw;
@@ -380,8 +353,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
 
 static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
 {
-       /* Actual minimum depends on device type. */
-       if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+       /* Actual minimum depends on device digitizer type. */
+       if (cptr->hdw->hdw_desc->flag_has_cx25840) {
                *vp = 75;
        } else {
                *vp = 17;
@@ -480,6 +453,7 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
 static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
 {
        cptr->hdw->enc_stale = 0;
+       cptr->hdw->enc_unsafe_stale = 0;
 }
 
 static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
@@ -502,6 +476,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
 static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
 {
        int ret;
+       struct pvr2_hdw *hdw = cptr->hdw;
        struct v4l2_ext_controls cs;
        struct v4l2_ext_control c1;
        memset(&cs,0,sizeof(cs));
@@ -510,10 +485,22 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
        cs.count = 1;
        c1.id = cptr->info->v4l_id;
        c1.value = v;
-       ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
+       ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
+                               hdw->state_encoder_run, &cs,
                                VIDIOC_S_EXT_CTRLS);
+       if (ret == -EBUSY) {
+               /* Oops.  cx2341x is telling us it's not safe to change
+                  this control while we're capturing.  Make a note of this
+                  fact so that the pipeline will be stopped the next time
+                  controls are committed.  Then go on ahead and store this
+                  change anyway. */
+               ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
+                                       0, &cs,
+                                       VIDIOC_S_EXT_CTRLS);
+               if (!ret) hdw->enc_unsafe_stale = !0;
+       }
        if (ret) return ret;
-       cptr->hdw->enc_stale = !0;
+       hdw->enc_stale = !0;
        return 0;
 }
 
@@ -544,7 +531,13 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
 
 static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
 {
-       *vp = cptr->hdw->flag_streaming_enabled;
+       *vp = cptr->hdw->state_pipeline_req;
+       return 0;
+}
+
+static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->master_state;
        return 0;
 }
 
@@ -657,29 +650,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
        return 0;
 }
 
-static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
-{
-       *vp = cptr->hdw->subsys_enabled_mask;
-       return 0;
-}
-
-static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
-{
-       pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
-       return 0;
-}
-
-static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
-{
-       *vp = cptr->hdw->subsys_stream_mask;
-       return 0;
-}
-
-static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
-{
-       pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
-       return 0;
-}
 
 static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
 {
@@ -914,6 +884,11 @@ static const struct pvr2_ctl_info control_defs[] = {
                .name = "usb_speed",
                .get_value = ctrl_hsm_get,
                DEFENUM(control_values_hsm),
+       },{
+               .desc = "Master State",
+               .name = "master_state",
+               .get_value = ctrl_masterstate_get,
+               DEFENUM(pvr2_state_names),
        },{
                .desc = "Signal Present",
                .name = "signal_present",
@@ -954,20 +929,6 @@ static const struct pvr2_ctl_info control_defs[] = {
                .val_to_sym = ctrl_std_val_to_sym,
                .sym_to_val = ctrl_std_sym_to_val,
                .type = pvr2_ctl_bitmask,
-       },{
-               .desc = "Subsystem enabled mask",
-               .name = "debug_subsys_mask",
-               .skip_init = !0,
-               .get_value = ctrl_subsys_get,
-               .set_value = ctrl_subsys_set,
-               DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
-       },{
-               .desc = "Subsystem stream mask",
-               .name = "debug_subsys_stream_mask",
-               .skip_init = !0,
-               .get_value = ctrl_subsys_stream_get,
-               .set_value = ctrl_subsys_stream_set,
-               DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
        },{
                .desc = "Video Standard Name",
                .name = "video_standard",
@@ -1129,25 +1090,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
        unsigned int pipe;
        int ret;
        u16 address;
-       static const char *fw_files_29xxx[] = {
-               "v4l-pvrusb2-29xxx-01.fw",
-       };
-       static const char *fw_files_24xxx[] = {
-               "v4l-pvrusb2-24xxx-01.fw",
-       };
-       static const struct pvr2_string_table fw_file_defs[] = {
-               [PVR2_HDW_TYPE_29XXX] = {
-                       fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
-               },
-               [PVR2_HDW_TYPE_24XXX] = {
-                       fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
-               },
-       };
 
-       if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
-           (!fw_file_defs[hdw->hdw_type].lst)) {
+       if (!hdw->hdw_desc->fx2_firmware.cnt) {
                hdw->fw1_state = FW1_STATE_OK;
-               return 0;
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Connected device type defines"
+                          " no firmware to upload; ignoring firmware");
+               return -ENOTTY;
        }
 
        hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1155,8 +1104,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
        trace_firmware("pvr2_upload_firmware1");
 
        ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
-                                  fw_file_defs[hdw->hdw_type].cnt,
-                                  fw_file_defs[hdw->hdw_type].lst);
+                                  hdw->hdw_desc->fx2_firmware.cnt,
+                                  hdw->hdw_desc->fx2_firmware.lst);
        if (ret < 0) {
                if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
                return ret;
@@ -1231,8 +1180,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                CX2341X_FIRM_ENC_FILENAME,
        };
 
-       if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
-           (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
+       if (hdw->hdw_desc->flag_skip_cx23416_firmware) {
                return 0;
        }
 
@@ -1248,8 +1196,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
           time we configure the encoder, then we'll fully configure it. */
        hdw->enc_cur_valid = 0;
 
-       hdw->flag_encoder_ok = 0;
-
        /* First prepare firmware loading */
        ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
        ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1347,293 +1293,129 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload post-proc failure");
-       } else {
-               hdw->flag_encoder_ok = !0;
-               hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
        }
        return ret;
 }
 
 
-#define FIRMWARE_RECOVERY_BITS \
-       ((1<<PVR2_SUBSYS_B_ENC_CFG) | \
-        (1<<PVR2_SUBSYS_B_ENC_RUN) | \
-        (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
-        (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
-
-/*
-
-  This single function is key to pretty much everything.  The pvrusb2
-  device can logically be viewed as a series of subsystems which can be
-  stopped / started or unconfigured / configured.  To get things streaming,
-  one must configure everything and start everything, but there may be
-  various reasons over time to deconfigure something or stop something.
-  This function handles all of this activity.  Everything EVERYWHERE that
-  must affect a subsystem eventually comes here to do the work.
-
-  The current state of all subsystems is represented by a single bit mask,
-  known as subsys_enabled_mask.  The bit positions are defined by the
-  PVR2_SUBSYS_xxxx macros, with one subsystem per bit position.  At any
-  time the set of configured or active subsystems can be queried just by
-  looking at that mask.  To change bits in that mask, this function here
-  must be called.  The "msk" argument indicates which bit positions to
-  change, and the "val" argument defines the new values for the positions
-  defined by "msk".
-
-  There is a priority ordering of starting / stopping things, and for
-  multiple requested changes, this function implements that ordering.
-  (Thus we will act on a request to load encoder firmware before we
-  configure the encoder.)  In addition to priority ordering, there is a
-  recovery strategy implemented here.  If a particular step fails and we
-  detect that failure, this function will clear the affected subsystem bits
-  and restart.  Thus we have a means for recovering from a dead encoder:
-  Clear all bits that correspond to subsystems that we need to restart /
-  reconfigure and start over.
-
-*/
-static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
-                                           unsigned long msk,
-                                           unsigned long val)
-{
-       unsigned long nmsk;
-       unsigned long vmsk;
-       int ret;
-       unsigned int tryCount = 0;
-
-       if (!hdw->flag_ok) return;
-
-       msk &= PVR2_SUBSYS_ALL;
-       nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
-       nmsk &= PVR2_SUBSYS_ALL;
-
-       for (;;) {
-               tryCount++;
-               if (!((nmsk ^ hdw->subsys_enabled_mask) &
-                     PVR2_SUBSYS_ALL)) break;
-               if (tryCount > 4) {
-                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                  "Too many retries when configuring device;"
-                                  " giving up");
-                       pvr2_hdw_render_useless(hdw);
-                       break;
-               }
-               if (tryCount > 1) {
-                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                  "Retrying device reconfiguration");
-               }
-               pvr2_trace(PVR2_TRACE_INIT,
-                          "subsys mask changing 0x%lx:0x%lx"
-                          " from 0x%lx to 0x%lx",
-                          msk,val,hdw->subsys_enabled_mask,nmsk);
-
-               vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
-                       hdw->subsys_enabled_mask;
-               if (vmsk) {
-                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " pvr2_encoder_stop");
-                               ret = pvr2_encoder_stop(hdw);
-                               if (ret) {
-                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                                  "Error recovery initiated");
-                                       hdw->subsys_enabled_mask &=
-                                               ~FIRMWARE_RECOVERY_BITS;
-                                       continue;
-                               }
-                       }
-                       if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " pvr2_hdw_cmd_usbstream(0)");
-                               pvr2_hdw_cmd_usbstream(hdw,0);
-                       }
-                       if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " decoder disable");
-                               if (hdw->decoder_ctrl) {
-                                       hdw->decoder_ctrl->enable(
-                                               hdw->decoder_ctrl->ctxt,0);
-                               } else {
-                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                                  "WARNING:"
-                                                  " No decoder present");
-                               }
-                               hdw->subsys_enabled_mask &=
-                                       ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
-                       }
-                       if (vmsk & PVR2_SUBSYS_CFG_ALL) {
-                               hdw->subsys_enabled_mask &=
-                                       ~(vmsk & PVR2_SUBSYS_CFG_ALL);
-                       }
-               }
-               vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
-               if (vmsk) {
-                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " pvr2_upload_firmware2");
-                               ret = pvr2_upload_firmware2(hdw);
-                               if (ret) {
-                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                                  "Failure uploading encoder"
-                                                  " firmware");
-                                       pvr2_hdw_render_useless(hdw);
-                                       break;
-                               }
-                       }
-                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " pvr2_encoder_configure");
-                               ret = pvr2_encoder_configure(hdw);
-                               if (ret) {
-                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                                  "Error recovery initiated");
-                                       hdw->subsys_enabled_mask &=
-                                               ~FIRMWARE_RECOVERY_BITS;
-                                       continue;
-                               }
-                       }
-                       if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " decoder enable");
-                               if (hdw->decoder_ctrl) {
-                                       hdw->decoder_ctrl->enable(
-                                               hdw->decoder_ctrl->ctxt,!0);
-                               } else {
-                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                                  "WARNING:"
-                                                  " No decoder present");
-                               }
-                               hdw->subsys_enabled_mask |=
-                                       (1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
-                       }
-                       if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " pvr2_hdw_cmd_usbstream(1)");
-                               pvr2_hdw_cmd_usbstream(hdw,!0);
-                       }
-                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
-                               pvr2_trace(PVR2_TRACE_CTL,
-                                          "/*---TRACE_CTL----*/"
-                                          " pvr2_encoder_start");
-                               ret = pvr2_encoder_start(hdw);
-                               if (ret) {
-                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                                  "Error recovery initiated");
-                                       hdw->subsys_enabled_mask &=
-                                               ~FIRMWARE_RECOVERY_BITS;
-                                       continue;
-                               }
-                       }
-               }
+static const char *pvr2_get_state_name(unsigned int st)
+{
+       if (st < ARRAY_SIZE(pvr2_state_names)) {
+               return pvr2_state_names[st];
        }
+       return "???";
 }
 
-
-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
-                            unsigned long msk,unsigned long val)
+static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
 {
-       LOCK_TAKE(hdw->big_lock); do {
-               pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
-       } while (0); LOCK_GIVE(hdw->big_lock);
+       if (!hdw->decoder_ctrl) {
+               if (!hdw->flag_decoder_missed) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "WARNING: No decoder present");
+                       hdw->flag_decoder_missed = !0;
+                       trace_stbit("flag_decoder_missed",
+                                   hdw->flag_decoder_missed);
+               }
+               return -EIO;
+       }
+       hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
+       return 0;
 }
 
 
-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
+void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
 {
-       return hdw->subsys_enabled_mask;
+       if (hdw->decoder_ctrl == ptr) return;
+       hdw->decoder_ctrl = ptr;
+       if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
+               hdw->flag_decoder_missed = 0;
+               trace_stbit("flag_decoder_missed",
+                           hdw->flag_decoder_missed);
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Decoder has appeared");
+               pvr2_hdw_state_sched(hdw);
+       }
 }
 
 
-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
+int pvr2_hdw_get_state(struct pvr2_hdw *hdw)
 {
-       return hdw->subsys_stream_mask;
+       return hdw->master_state;
 }
 
 
-static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
-                                                  unsigned long msk,
-                                                  unsigned long val)
+static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw)
 {
-       unsigned long val2;
-       msk &= PVR2_SUBSYS_ALL;
-       val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
-       pvr2_trace(PVR2_TRACE_INIT,
-                  "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
-                  msk,val,hdw->subsys_stream_mask,val2);
-       hdw->subsys_stream_mask = val2;
+       if (!hdw->flag_tripped) return 0;
+       hdw->flag_tripped = 0;
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "Clearing driver error statuss");
+       return !0;
 }
 
 
-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
-                                   unsigned long msk,
-                                   unsigned long val)
+int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
 {
+       int fl;
        LOCK_TAKE(hdw->big_lock); do {
-               pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
+               fl = pvr2_hdw_untrip_unlocked(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
+       if (fl) pvr2_hdw_state_sched(hdw);
+       return 0;
 }
 
 
-static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
+const char *pvr2_hdw_get_state_name(unsigned int id)
 {
-       if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
-       if (enableFl) {
-               pvr2_trace(PVR2_TRACE_START_STOP,
-                          "/*--TRACE_STREAM--*/ enable");
-               pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
-       } else {
-               pvr2_trace(PVR2_TRACE_START_STOP,
-                          "/*--TRACE_STREAM--*/ disable");
-               pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
-       }
-       if (!hdw->flag_ok) return -EIO;
-       hdw->flag_streaming_enabled = enableFl != 0;
-       return 0;
+       if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
+       return pvr2_state_names[id];
 }
 
 
 int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
 {
-       return hdw->flag_streaming_enabled != 0;
+       return hdw->state_pipeline_req != 0;
 }
 
 
 int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
 {
-       int ret;
+       int ret,st;
        LOCK_TAKE(hdw->big_lock); do {
-               ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
+               pvr2_hdw_untrip_unlocked(hdw);
+               if ((!enable_flag) != !(hdw->state_pipeline_req)) {
+                       hdw->state_pipeline_req = enable_flag != 0;
+                       pvr2_trace(PVR2_TRACE_START_STOP,
+                                  "/*--TRACE_STREAM--*/ %s",
+                                  enable_flag ? "enable" : "disable");
+               }
+               pvr2_hdw_state_sched(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
-       return ret;
-}
-
-
-static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
-                                           enum pvr2_config config)
-{
-       unsigned long sm = hdw->subsys_enabled_mask;
-       if (!hdw->flag_ok) return -EIO;
-       pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
-       hdw->config = config;
-       pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
+       if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret;
+       if (enable_flag) {
+               while ((st = hdw->master_state) != PVR2_STATE_RUN) {
+                       if (st != PVR2_STATE_READY) return -EIO;
+                       if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret;
+               }
+       }
        return 0;
 }
 
 
 int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
 {
-       int ret;
-       if (!hdw->flag_ok) return -EIO;
+       int fl;
        LOCK_TAKE(hdw->big_lock);
-       ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
+       if ((fl = (hdw->desired_stream_type != config)) != 0) {
+               hdw->desired_stream_type = config;
+               hdw->state_pipeline_config = 0;
+               trace_stbit("state_pipeline_config",
+                           hdw->state_pipeline_config);
+               pvr2_hdw_state_sched(hdw);
+       }
        LOCK_GIVE(hdw->big_lock);
-       return ret;
+       if (fl) return 0;
+       return pvr2_hdw_wait(hdw,0);
 }
 
 
@@ -1646,6 +1428,7 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw)
        }
        if (tp < 0) return -EINVAL;
        hdw->tuner_type = tp;
+       hdw->tuner_updated = !0;
        return 0;
 }
 
@@ -1656,8 +1439,9 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
        int tp = 0;
        if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
                tp = video_std[unit_number];
+               if (tp) return tp;
        }
-       return tp;
+       return 0;
 }
 
 
@@ -1731,7 +1515,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = {
        },
        {       /* PAL(D/D1/K) */
                .pat = V4L2_STD_DK,
-               .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
+               .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
        },
 };
 
@@ -1739,18 +1523,20 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
 {
        char buf[40];
        unsigned int bcnt;
-       v4l2_std_id std1,std2;
+       v4l2_std_id std1,std2,std3;
 
        std1 = get_default_standard(hdw);
+       std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask;
 
        bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
        pvr2_trace(PVR2_TRACE_STD,
-                  "Supported video standard(s) reported by eeprom: %.*s",
+                  "Supported video standard(s) reported available"
+                  " in hardware: %.*s",
                   bcnt,buf);
 
        hdw->std_mask_avail = hdw->std_mask_eeprom;
 
-       std2 = std1 & ~hdw->std_mask_avail;
+       std2 = (std1|std3) & ~hdw->std_mask_avail;
        if (std2) {
                bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
                pvr2_trace(PVR2_TRACE_STD,
@@ -1772,6 +1558,16 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
                pvr2_hdw_internal_find_stdenum(hdw);
                return;
        }
+       if (std3) {
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3);
+               pvr2_trace(PVR2_TRACE_STD,
+                          "Initial video standard"
+                          " (determined by device type): %.*s",bcnt,buf);
+               hdw->std_mask_cur = std3;
+               hdw->std_dirty = !0;
+               pvr2_hdw_internal_find_stdenum(hdw);
+               return;
+       }
 
        {
                unsigned int idx;
@@ -1816,8 +1612,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        unsigned int idx;
        struct pvr2_ctrl *cptr;
        int reloadFl = 0;
-       if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
-           (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+       if (hdw->hdw_desc->fx2_firmware.cnt) {
                if (!reloadFl) {
                        reloadFl =
                                (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
@@ -1853,25 +1648,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        }
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
-       if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
-               for (idx = 0;
-                    idx < pvr2_client_lists[hdw->hdw_type].cnt;
-                    idx++) {
-                       request_module(
-                               pvr2_client_lists[hdw->hdw_type].lst[idx]);
-               }
+       for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
+               request_module(hdw->hdw_desc->client_modules.lst[idx]);
        }
 
-       if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
-           (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+       if (!hdw->hdw_desc->flag_no_powerup) {
                pvr2_hdw_cmd_powerup(hdw);
                if (!pvr2_hdw_dev_ok(hdw)) return;
-
-               if (pvr2_upload_firmware2(hdw)){
-                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
-                       pvr2_hdw_render_useless(hdw);
-                       return;
-               }
        }
 
        // This step MUST happen after the earlier powerup step.
@@ -1899,15 +1682,22 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        // thread-safe against the normal pvr2_send_request() mechanism.
        // (We should make it thread safe).
 
-       ret = pvr2_hdw_get_eeprom_addr(hdw);
-       if (!pvr2_hdw_dev_ok(hdw)) return;
-       if (ret < 0) {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "Unable to determine location of eeprom, skipping");
-       } else {
-               hdw->eeprom_addr = ret;
-               pvr2_eeprom_analyze(hdw);
+       if (hdw->hdw_desc->flag_has_hauppauge_rom) {
+               ret = pvr2_hdw_get_eeprom_addr(hdw);
                if (!pvr2_hdw_dev_ok(hdw)) return;
+               if (ret < 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Unable to determine location of eeprom,"
+                                  " skipping");
+               } else {
+                       hdw->eeprom_addr = ret;
+                       pvr2_eeprom_analyze(hdw);
+                       if (!pvr2_hdw_dev_ok(hdw)) return;
+               }
+       } else {
+               hdw->tuner_type = hdw->hdw_desc->default_tuner_type;
+               hdw->tuner_updated = !0;
+               hdw->std_mask_eeprom = V4L2_STD_ALL;
        }
 
        pvr2_hdw_setup_std(hdw);
@@ -1918,14 +1708,12 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                           hdw->tuner_type);
        }
 
-       hdw->tuner_updated = !0;
        pvr2_i2c_core_check_stale(hdw);
        hdw->tuner_updated = 0;
 
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
-       pvr2_hdw_commit_ctl_internal(hdw);
-       if (!pvr2_hdw_dev_ok(hdw)) return;
+       pvr2_hdw_commit_setup(hdw);
 
        hdw->vid_stream = pvr2_stream_create();
        if (!pvr2_hdw_dev_ok(hdw)) return;
@@ -1945,25 +1733,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
-       /* Make sure everything is up to date */
-       pvr2_i2c_core_sync(hdw);
-
-       if (!pvr2_hdw_dev_ok(hdw)) return;
-
        hdw->flag_init_ok = !0;
+
+       pvr2_hdw_state_sched(hdw);
 }
 
 
-int pvr2_hdw_setup(struct pvr2_hdw *hdw)
+/* Set up the structure and attempt to put the device into a usable state.
+   This can be a time-consuming operation, which is why it is not done
+   internally as part of the create() step. */
+static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
 {
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
-       LOCK_TAKE(hdw->big_lock); do {
+       do {
                pvr2_hdw_setup_low(hdw);
                pvr2_trace(PVR2_TRACE_INIT,
                           "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
-                          hdw,hdw->flag_ok,hdw->flag_init_ok);
+                          hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok);
                if (pvr2_hdw_dev_ok(hdw)) {
-                       if (pvr2_hdw_init_ok(hdw)) {
+                       if (hdw->flag_init_ok) {
                                pvr2_trace(
                                        PVR2_TRACE_INFO,
                                        "Device initialization"
@@ -2013,9 +1801,8 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw)
                                " the pvrusb2 device"
                                " in order to recover.");
                }
-       } while (0); LOCK_GIVE(hdw->big_lock);
+       } while (0);
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
-       return hdw->flag_init_ok;
 }
 
 
@@ -2026,24 +1813,32 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 {
        unsigned int idx,cnt1,cnt2;
        struct pvr2_hdw *hdw;
-       unsigned int hdw_type;
        int valid_std_mask;
        struct pvr2_ctrl *cptr;
+       const struct pvr2_device_desc *hdw_desc;
        __u8 ifnum;
        struct v4l2_queryctrl qctrl;
        struct pvr2_ctl_info *ciptr;
 
-       hdw_type = devid - pvr2_device_table;
-       if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "Bogus device type of %u reported",hdw_type);
-               return NULL;
-       }
+       hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
 
        hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
-                  hdw,pvr2_device_names[hdw_type]);
+                  hdw,hdw_desc->description);
        if (!hdw) goto fail;
+
+       init_timer(&hdw->quiescent_timer);
+       hdw->quiescent_timer.data = (unsigned long)hdw;
+       hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout;
+
+       init_timer(&hdw->encoder_wait_timer);
+       hdw->encoder_wait_timer.data = (unsigned long)hdw;
+       hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
+
+       hdw->master_state = PVR2_STATE_DEAD;
+
+       init_waitqueue_head(&hdw->state_wait_data);
+
        hdw->tuner_signal_stale = !0;
        cx2341x_fill_defaults(&hdw->enc_ctl_state);
 
@@ -2052,7 +1847,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
                                GFP_KERNEL);
        if (!hdw->controls) goto fail;
-       hdw->hdw_type = hdw_type;
+       hdw->hdw_desc = hdw_desc;
        for (idx = 0; idx < hdw->control_cnt; idx++) {
                cptr = hdw->controls + idx;
                cptr->hdw = hdw;
@@ -2184,18 +1979,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
        hdw->name[cnt1] = 0;
 
+       hdw->workqueue = create_singlethread_workqueue(hdw->name);
+       INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
+       INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
+       INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
+
        pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
                   hdw->unit_number,hdw->name);
 
        hdw->tuner_type = -1;
        hdw->flag_ok = !0;
-       /* Initialize the mask of subsystems that we will shut down when we
-          stop streaming. */
-       hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
-       hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-
-       pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
-                  hdw->subsys_stream_mask);
 
        hdw->usb_intf = intf;
        hdw->usb_dev = interface_to_usbdev(intf);
@@ -2211,15 +2004,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        mutex_init(&hdw->ctl_lock_mutex);
        mutex_init(&hdw->big_lock_mutex);
 
+       queue_work(hdw->workqueue,&hdw->workinit);
        return hdw;
  fail:
        if (hdw) {
+               del_timer_sync(&hdw->quiescent_timer);
+               del_timer_sync(&hdw->encoder_wait_timer);
+               if (hdw->workqueue) {
+                       flush_workqueue(hdw->workqueue);
+                       destroy_workqueue(hdw->workqueue);
+                       hdw->workqueue = NULL;
+               }
                usb_free_urb(hdw->ctl_read_urb);
                usb_free_urb(hdw->ctl_write_urb);
                kfree(hdw->ctl_read_buffer);
                kfree(hdw->ctl_write_buffer);
                kfree(hdw->controls);
                kfree(hdw->mpeg_ctrl_info);
+               kfree(hdw->std_defs);
+               kfree(hdw->std_enum_names);
                kfree(hdw);
        }
        return NULL;
@@ -2250,10 +2053,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
                kfree(hdw->ctl_write_buffer);
                hdw->ctl_write_buffer = NULL;
        }
-       pvr2_hdw_render_useless_unlocked(hdw);
        hdw->flag_disconnected = !0;
        hdw->usb_dev = NULL;
        hdw->usb_intf = NULL;
+       pvr2_hdw_render_useless(hdw);
 }
 
 
@@ -2262,6 +2065,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
 {
        if (!hdw) return;
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
+       del_timer_sync(&hdw->quiescent_timer);
+       del_timer_sync(&hdw->encoder_wait_timer);
+       if (hdw->workqueue) {
+               flush_workqueue(hdw->workqueue);
+               destroy_workqueue(hdw->workqueue);
+               hdw->workqueue = NULL;
+       }
        if (hdw->fw_buffer) {
                kfree(hdw->fw_buffer);
                hdw->fw_buffer = NULL;
@@ -2290,12 +2100,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
 }
 
 
-int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
-{
-       return hdw->flag_init_ok;
-}
-
-
 int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
 {
        return (hdw && hdw->flag_ok);
@@ -2473,17 +2277,11 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
 }
 
 
-/* Commit all control changes made up to this point.  Subsystems can be
-   indirectly affected by these changes.  For a given set of things being
-   committed, we'll clear the affected subsystem bits and then once we're
-   done committing everything we'll make a request to restore the subsystem
-   state(s) back to their previous value before this function was called.
-   Thus we can automatically reconfigure affected pieces of the driver as
-   controls are changed. */
-static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+/* Figure out if we need to commit control changes.  If so, mark internal
+   state flags to indicate this fact and return true.  Otherwise do nothing
+   else and return false. */
+static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
 {
-       unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
-       unsigned long stale_subsys_mask = 0;
        unsigned int idx;
        struct pvr2_ctrl *cptr;
        int value;
@@ -2518,6 +2316,25 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
                return 0;
        }
 
+       hdw->state_pipeline_config = 0;
+       trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
+       pvr2_hdw_state_sched(hdw);
+
+       return !0;
+}
+
+
+/* Perform all operations needed to commit all control changes.  This must
+   be performed in synchronization with the pipeline state and is thus
+   expected to be called as part of the driver's worker thread.  Return
+   true if commit successful, otherwise return false to indicate that
+   commit isn't possible at this time. */
+static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+       struct pvr2_ctrl *cptr;
+       int disruptive_change;
+
        /* When video standard changes, reset the hres and vres values -
           but if the user has pending changes there, then let the changes
           take priority. */
@@ -2536,24 +2353,26 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
                }
        }
 
-       if (hdw->std_dirty ||
-           hdw->enc_stale ||
-           hdw->srate_dirty ||
-           hdw->res_ver_dirty ||
-           hdw->res_hor_dirty ||
-           0) {
-               /* If any of this changes, then the encoder needs to be
-                  reconfigured, and we need to reset the stream. */
-               stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-       }
-
-       if (hdw->input_dirty) {
-               /* pk: If input changes to or from radio, then the encoder
-                  needs to be restarted (for ENC_MUTE_VIDEO to work) */
-               stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+       /* If any of the below has changed, then we can't do the update
+          while the pipeline is running.  Pipeline must be paused first
+          and decoder -> encoder connection be made quiescent before we
+          can proceed. */
+       disruptive_change =
+               (hdw->std_dirty ||
+                hdw->enc_unsafe_stale ||
+                hdw->srate_dirty ||
+                hdw->res_ver_dirty ||
+                hdw->res_hor_dirty ||
+                hdw->input_dirty ||
+                (hdw->active_stream_type != hdw->desired_stream_type));
+       if (disruptive_change && !hdw->state_pipeline_idle) {
+               /* Pipeline is not idle; we can't proceed.  Arrange to
+                  cause pipeline to stop so that we can try this again
+                  later.... */
+               hdw->state_pipeline_pause = !0;
+               return 0;
        }
 
-
        if (hdw->srate_dirty) {
                /* Write new sample rate into control structure since
                 * the master copy is stale.  We must track srate
@@ -2582,51 +2401,88 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
                cptr->info->clear_dirty(cptr);
        }
 
+       if (hdw->active_stream_type != hdw->desired_stream_type) {
+               /* Handle any side effects of stream config here */
+               hdw->active_stream_type = hdw->desired_stream_type;
+       }
+
        /* Now execute i2c core update */
        pvr2_i2c_core_sync(hdw);
 
-       pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
-       pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
+       if (hdw->state_encoder_run) {
+               /* If encoder isn't running, then this will get worked out
+                  later when we start the encoder. */
+               if (pvr2_encoder_adjust(hdw) < 0) return !0;
+       }
 
-       return 0;
+       hdw->state_pipeline_config = !0;
+       trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
+       return !0;
 }
 
 
 int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
 {
+       int fl;
+       LOCK_TAKE(hdw->big_lock);
+       fl = pvr2_hdw_commit_setup(hdw);
+       LOCK_GIVE(hdw->big_lock);
+       if (!fl) return 0;
+       return pvr2_hdw_wait(hdw,0);
+}
+
+
+static void pvr2_hdw_worker_i2c(struct work_struct *work)
+{
+       struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
        LOCK_TAKE(hdw->big_lock); do {
-               pvr2_hdw_commit_ctl_internal(hdw);
+               pvr2_i2c_core_sync(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
-       return 0;
 }
 
 
-void pvr2_hdw_poll(struct pvr2_hdw *hdw)
+static void pvr2_hdw_worker_poll(struct work_struct *work)
 {
+       int fl = 0;
+       struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll);
        LOCK_TAKE(hdw->big_lock); do {
-               pvr2_i2c_core_sync(hdw);
+               fl = pvr2_hdw_state_eval(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
+       if (fl && hdw->state_func) {
+               hdw->state_func(hdw->state_data);
+       }
 }
 
 
-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
-                                void (*func)(void *),
-                                void *data)
+static void pvr2_hdw_worker_init(struct work_struct *work)
 {
+       struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
        LOCK_TAKE(hdw->big_lock); do {
-               hdw->poll_trigger_func = func;
-               hdw->poll_trigger_data = data;
+               pvr2_hdw_setup(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
 }
 
 
-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
+static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
 {
-       if (hdw->poll_trigger_func) {
-               hdw->poll_trigger_func(hdw->poll_trigger_data);
-       }
+       return wait_event_interruptible(
+               hdw->state_wait_data,
+               (hdw->state_stale == 0) &&
+               (!state || (hdw->master_state != state)));
 }
 
+
+void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
+                                void (*callback_func)(void *),
+                                void *callback_data)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               hdw->state_data = callback_data;
+               hdw->state_func = callback_func;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 {
@@ -2634,6 +2490,18 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 }
 
 
+const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw)
+{
+       return hdw->hdw_desc->description;
+}
+
+
+const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw)
+{
+       return hdw->hdw_desc->shortname;
+}
+
+
 int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 {
        int result;
@@ -2689,6 +2557,7 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
                pvr2_i2c_core_sync(hdw);
                pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
                cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
+               pvr2_hdw_state_log_state(hdw);
                printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);
        } while (0); LOCK_GIVE(hdw->big_lock);
 }
@@ -2959,7 +2828,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
                           " without lock!!");
                return -EDEADLK;
        }
-       if ((!hdw->flag_ok) && !probe_fl) {
+       if (!hdw->flag_ok && !probe_fl) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "Attempted to execute control transfer"
                           " when device not ok");
@@ -3167,7 +3036,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 
        hdw->cmd_debug_state = 0;
        if ((status < 0) && (!probe_fl)) {
-               pvr2_hdw_render_useless_unlocked(hdw);
+               pvr2_hdw_render_useless(hdw);
        }
        return status;
 }
@@ -3227,24 +3096,17 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
 }
 
 
-static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
+void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
 {
        if (!hdw->flag_ok) return;
-       pvr2_trace(PVR2_TRACE_INIT,"render_useless");
-       hdw->flag_ok = 0;
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "Device being rendered inoperable");
        if (hdw->vid_stream) {
                pvr2_stream_setup(hdw->vid_stream,NULL,0,0);
        }
-       hdw->flag_streaming_enabled = 0;
-       hdw->subsys_enabled_mask = 0;
-}
-
-
-void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
-{
-       LOCK_TAKE(hdw->ctl_lock);
-       pvr2_hdw_render_useless_unlocked(hdw);
-       LOCK_GIVE(hdw->ctl_lock);
+       hdw->flag_ok = 0;
+       trace_stbit("flag_ok",hdw->flag_ok);
+       pvr2_hdw_state_sched(hdw);
 }
 
 
@@ -3299,7 +3161,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
        int status;
        LOCK_TAKE(hdw->ctl_lock); do {
                pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
-               hdw->flag_ok = !0;
                hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
                status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
        } while (0); LOCK_GIVE(hdw->ctl_lock);
@@ -3349,26 +3210,473 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
                        (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
                status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
        } while (0); LOCK_GIVE(hdw->ctl_lock);
-       if (!status) {
-               hdw->subsys_enabled_mask =
-                       ((hdw->subsys_enabled_mask &
-                         ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
-                        (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
-       }
        return status;
 }
 
 
-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
-                            struct pvr2_hdw_debug_info *ptr)
+/* Evaluate whether or not state_encoder_ok can change */
+static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_encoder_ok) return 0;
+       if (hdw->flag_tripped) return 0;
+       if (hdw->state_encoder_run) return 0;
+       if (hdw->state_encoder_config) return 0;
+       if (hdw->state_decoder_run) return 0;
+       if (hdw->state_usbstream_run) return 0;
+       if (pvr2_upload_firmware2(hdw) < 0) {
+               hdw->flag_tripped = !0;
+               trace_stbit("flag_tripped",hdw->flag_tripped);
+               return !0;
+       }
+       hdw->state_encoder_ok = !0;
+       trace_stbit("state_encoder_ok",hdw->state_encoder_ok);
+       return !0;
+}
+
+
+/* Evaluate whether or not state_encoder_config can change */
+static int state_eval_encoder_config(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_encoder_config) {
+               if (hdw->state_encoder_ok) {
+                       if (hdw->state_pipeline_req &&
+                           !hdw->state_pipeline_pause) return 0;
+               }
+               hdw->state_encoder_config = 0;
+               hdw->state_encoder_waitok = 0;
+               trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
+               /* paranoia - solve race if timer just completed */
+               del_timer_sync(&hdw->encoder_wait_timer);
+       } else {
+               if (!hdw->state_encoder_ok ||
+                   !hdw->state_pipeline_idle ||
+                   hdw->state_pipeline_pause ||
+                   !hdw->state_pipeline_req ||
+                   !hdw->state_pipeline_config) {
+                       /* We must reset the enforced wait interval if
+                          anything has happened that might have disturbed
+                          the encoder.  This should be a rare case. */
+                       if (timer_pending(&hdw->encoder_wait_timer)) {
+                               del_timer_sync(&hdw->encoder_wait_timer);
+                       }
+                       if (hdw->state_encoder_waitok) {
+                               /* Must clear the state - therefore we did
+                                  something to a state bit and must also
+                                  return true. */
+                               hdw->state_encoder_waitok = 0;
+                               trace_stbit("state_encoder_waitok",
+                                           hdw->state_encoder_waitok);
+                               return !0;
+                       }
+                       return 0;
+               }
+               if (!hdw->state_encoder_waitok) {
+                       if (!timer_pending(&hdw->encoder_wait_timer)) {
+                               /* waitok flag wasn't set and timer isn't
+                                  running.  Check flag once more to avoid
+                                  a race then start the timer.  This is
+                                  the point when we measure out a minimal
+                                  quiet interval before doing something to
+                                  the encoder. */
+                               if (!hdw->state_encoder_waitok) {
+                                       hdw->encoder_wait_timer.expires =
+                                               jiffies + (HZ*50/1000);
+                                       add_timer(&hdw->encoder_wait_timer);
+                               }
+                       }
+                       /* We can't continue until we know we have been
+                          quiet for the interval measured by this
+                          timer. */
+                       return 0;
+               }
+               pvr2_encoder_configure(hdw);
+               if (hdw->state_encoder_ok) hdw->state_encoder_config = !0;
+       }
+       trace_stbit("state_encoder_config",hdw->state_encoder_config);
+       return !0;
+}
+
+
+/* Evaluate whether or not state_encoder_run can change */
+static int state_eval_encoder_run(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_encoder_run) {
+               if (hdw->state_encoder_ok) {
+                       if (hdw->state_decoder_run) return 0;
+                       if (pvr2_encoder_stop(hdw) < 0) return !0;
+               }
+               hdw->state_encoder_run = 0;
+       } else {
+               if (!hdw->state_encoder_ok) return 0;
+               if (!hdw->state_decoder_run) return 0;
+               if (pvr2_encoder_start(hdw) < 0) return !0;
+               hdw->state_encoder_run = !0;
+       }
+       trace_stbit("state_encoder_run",hdw->state_encoder_run);
+       return !0;
+}
+
+
+/* Timeout function for quiescent timer. */
+static void pvr2_hdw_quiescent_timeout(unsigned long data)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       hdw->state_decoder_quiescent = !0;
+       trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
+       hdw->state_stale = !0;
+       queue_work(hdw->workqueue,&hdw->workpoll);
+}
+
+
+/* Timeout function for encoder wait timer. */
+static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       hdw->state_encoder_waitok = !0;
+       trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
+       hdw->state_stale = !0;
+       queue_work(hdw->workqueue,&hdw->workpoll);
+}
+
+
+/* Evaluate whether or not state_decoder_run can change */
+static int state_eval_decoder_run(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_decoder_run) {
+               if (hdw->state_encoder_ok) {
+                       if (hdw->state_pipeline_req &&
+                           !hdw->state_pipeline_pause) return 0;
+               }
+               if (!hdw->flag_decoder_missed) {
+                       pvr2_decoder_enable(hdw,0);
+               }
+               hdw->state_decoder_quiescent = 0;
+               hdw->state_decoder_run = 0;
+               /* paranoia - solve race if timer just completed */
+               del_timer_sync(&hdw->quiescent_timer);
+       } else {
+               if (!hdw->state_decoder_quiescent) {
+                       if (!timer_pending(&hdw->quiescent_timer)) {
+                               /* We don't do something about the
+                                  quiescent timer until right here because
+                                  we also want to catch cases where the
+                                  decoder was already not running (like
+                                  after initialization) as opposed to
+                                  knowing that we had just stopped it.
+                                  The second flag check is here to cover a
+                                  race - the timer could have run and set
+                                  this flag just after the previous check
+                                  but before we did the pending check. */
+                               if (!hdw->state_decoder_quiescent) {
+                                       hdw->quiescent_timer.expires =
+                                               jiffies + (HZ*50/1000);
+                                       add_timer(&hdw->quiescent_timer);
+                               }
+                       }
+                       /* Don't allow decoder to start again until it has
+                          been quiesced first.  This little detail should
+                          hopefully further stabilize the encoder. */
+                       return 0;
+               }
+               if (!hdw->state_pipeline_req ||
+                   hdw->state_pipeline_pause ||
+                   !hdw->state_pipeline_config ||
+                   !hdw->state_encoder_config ||
+                   !hdw->state_encoder_ok) return 0;
+               del_timer_sync(&hdw->quiescent_timer);
+               if (hdw->flag_decoder_missed) return 0;
+               if (pvr2_decoder_enable(hdw,!0) < 0) return 0;
+               hdw->state_decoder_quiescent = 0;
+               hdw->state_decoder_run = !0;
+       }
+       trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
+       trace_stbit("state_decoder_run",hdw->state_decoder_run);
+       return !0;
+}
+
+
+/* Evaluate whether or not state_usbstream_run can change */
+static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_usbstream_run) {
+               if (hdw->state_encoder_ok) {
+                       if (hdw->state_encoder_run) return 0;
+               }
+               pvr2_hdw_cmd_usbstream(hdw,0);
+               hdw->state_usbstream_run = 0;
+       } else {
+               if (!hdw->state_encoder_ok ||
+                   !hdw->state_encoder_run ||
+                   !hdw->state_pipeline_req ||
+                   hdw->state_pipeline_pause) return 0;
+               if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
+               hdw->state_usbstream_run = !0;
+       }
+       trace_stbit("state_usbstream_run",hdw->state_usbstream_run);
+       return !0;
+}
+
+
+/* Attempt to configure pipeline, if needed */
+static int state_eval_pipeline_config(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_pipeline_config ||
+           hdw->state_pipeline_pause) return 0;
+       pvr2_hdw_commit_execute(hdw);
+       return !0;
+}
+
+
+/* Update pipeline idle and pipeline pause tracking states based on other
+   inputs.  This must be called whenever the other relevant inputs have
+   changed. */
+static int state_update_pipeline_state(struct pvr2_hdw *hdw)
+{
+       unsigned int st;
+       int updatedFl = 0;
+       /* Update pipeline state */
+       st = !(hdw->state_encoder_run ||
+              hdw->state_decoder_run ||
+              hdw->state_usbstream_run ||
+              (!hdw->state_decoder_quiescent));
+       if (!st != !hdw->state_pipeline_idle) {
+               hdw->state_pipeline_idle = st;
+               updatedFl = !0;
+       }
+       if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) {
+               hdw->state_pipeline_pause = 0;
+               updatedFl = !0;
+       }
+       return updatedFl;
+}
+
+
+typedef int (*state_eval_func)(struct pvr2_hdw *);
+
+/* Set of functions to be run to evaluate various states in the driver. */
+const static state_eval_func eval_funcs[] = {
+       state_eval_pipeline_config,
+       state_eval_encoder_ok,
+       state_eval_encoder_config,
+       state_eval_decoder_run,
+       state_eval_encoder_run,
+       state_eval_usbstream_run,
+};
+
+
+/* Process various states and return true if we did anything interesting. */
+static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
+{
+       unsigned int i;
+       int state_updated = 0;
+       int check_flag;
+
+       if (!hdw->state_stale) return 0;
+       if ((hdw->fw1_state != FW1_STATE_OK) ||
+           !hdw->flag_ok) {
+               hdw->state_stale = 0;
+               return !0;
+       }
+       /* This loop is the heart of the entire driver.  It keeps trying to
+          evaluate various bits of driver state until nothing changes for
+          one full iteration.  Each "bit of state" tracks some global
+          aspect of the driver, e.g. whether decoder should run, if
+          pipeline is configured, usb streaming is on, etc.  We separately
+          evaluate each of those questions based on other driver state to
+          arrive at the correct running configuration. */
+       do {
+               check_flag = 0;
+               state_update_pipeline_state(hdw);
+               /* Iterate over each bit of state */
+               for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) {
+                       if ((*eval_funcs[i])(hdw)) {
+                               check_flag = !0;
+                               state_updated = !0;
+                               state_update_pipeline_state(hdw);
+                       }
+               }
+       } while (check_flag && hdw->flag_ok);
+       hdw->state_stale = 0;
+       trace_stbit("state_stale",hdw->state_stale);
+       return state_updated;
+}
+
+
+static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
+                                            char *buf,unsigned int acnt)
+{
+       switch (which) {
+       case 0:
+               return scnprintf(
+                       buf,acnt,
+                       "driver:%s%s%s%s%s",
+                       (hdw->flag_ok ? " <ok>" : " <fail>"),
+                       (hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
+                       (hdw->flag_disconnected ? " <disconnected>" :
+                        " <connected>"),
+                       (hdw->flag_tripped ? " <tripped>" : ""),
+                       (hdw->flag_decoder_missed ? " <no decoder>" : ""));
+       case 1:
+               return scnprintf(
+                       buf,acnt,
+                       "pipeline:%s%s%s%s",
+                       (hdw->state_pipeline_idle ? " <idle>" : ""),
+                       (hdw->state_pipeline_config ?
+                        " <configok>" : " <stale>"),
+                       (hdw->state_pipeline_req ? " <req>" : ""),
+                       (hdw->state_pipeline_pause ? " <pause>" : ""));
+       case 2:
+               return scnprintf(
+                       buf,acnt,
+                       "worker:%s%s%s%s%s%s",
+                       (hdw->state_decoder_run ?
+                        " <decode:run>" :
+                        (hdw->state_decoder_quiescent ?
+                         "" : " <decode:stop>")),
+                       (hdw->state_decoder_quiescent ?
+                        " <decode:quiescent>" : ""),
+                       (hdw->state_encoder_ok ?
+                        "" : " <encode:init>"),
+                       (hdw->state_encoder_run ?
+                        " <encode:run>" : " <encode:stop>"),
+                       (hdw->state_encoder_config ?
+                        " <encode:configok>" :
+                        (hdw->state_encoder_waitok ?
+                         "" : " <encode:wait>")),
+                       (hdw->state_usbstream_run ?
+                        " <usb:run>" : " <usb:stop>"));
+               break;
+       case 3:
+               return scnprintf(
+                       buf,acnt,
+                       "state: %s",
+                       pvr2_get_state_name(hdw->master_state));
+               break;
+       default: break;
+       }
+       return 0;
+}
+
+
+unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+                                  char *buf,unsigned int acnt)
+{
+       unsigned int bcnt,ccnt,idx;
+       bcnt = 0;
+       LOCK_TAKE(hdw->big_lock);
+       for (idx = 0; ; idx++) {
+               ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt);
+               if (!ccnt) break;
+               bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+               if (!acnt) break;
+               buf[0] = '\n'; ccnt = 1;
+               bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       }
+       LOCK_GIVE(hdw->big_lock);
+       return bcnt;
+}
+
+
+static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
+{
+       char buf[128];
+       unsigned int idx,ccnt;
+
+       for (idx = 0; ; idx++) {
+               ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
+               if (!ccnt) break;
+               printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
+       }
+}
+
+
+/* Evaluate and update the driver's current state, taking various actions
+   as appropriate for the update. */
+static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
+{
+       unsigned int st;
+       int state_updated = 0;
+       int callback_flag = 0;
+
+       pvr2_trace(PVR2_TRACE_STBITS,
+                  "Drive state check START");
+       if (pvrusb2_debug & PVR2_TRACE_STBITS) {
+               pvr2_hdw_state_log_state(hdw);
+       }
+
+       /* Process all state and get back over disposition */
+       state_updated = pvr2_hdw_state_update(hdw);
+
+       /* Update master state based upon all other states. */
+       if (!hdw->flag_ok) {
+               st = PVR2_STATE_DEAD;
+       } else if (hdw->fw1_state != FW1_STATE_OK) {
+               st = PVR2_STATE_COLD;
+       } else if (!hdw->state_encoder_ok) {
+               st = PVR2_STATE_WARM;
+       } else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
+               st = PVR2_STATE_ERROR;
+       } else if (hdw->state_encoder_run &&
+                  hdw->state_decoder_run &&
+                  hdw->state_usbstream_run) {
+               st = PVR2_STATE_RUN;
+       } else {
+               st = PVR2_STATE_READY;
+       }
+       if (hdw->master_state != st) {
+               pvr2_trace(PVR2_TRACE_STATE,
+                          "Device state change from %s to %s",
+                          pvr2_get_state_name(hdw->master_state),
+                          pvr2_get_state_name(st));
+               hdw->master_state = st;
+               state_updated = !0;
+               callback_flag = !0;
+       }
+       if (state_updated) {
+               /* Trigger anyone waiting on any state changes here. */
+               wake_up(&hdw->state_wait_data);
+       }
+
+       if (pvrusb2_debug & PVR2_TRACE_STBITS) {
+               pvr2_hdw_state_log_state(hdw);
+       }
+       pvr2_trace(PVR2_TRACE_STBITS,
+                  "Drive state check DONE callback=%d",callback_flag);
+
+       return callback_flag;
+}
+
+
+/* Cause kernel thread to check / update driver state */
+static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_stale) return;
+       hdw->state_stale = !0;
+       trace_stbit("state_stale",hdw->state_stale);
+       queue_work(hdw->workqueue,&hdw->workpoll);
+}
+
+
+void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
+                                     struct pvr2_hdw_debug_info *ptr)
 {
        ptr->big_lock_held = hdw->big_lock_held;
        ptr->ctl_lock_held = hdw->ctl_lock_held;
-       ptr->flag_ok = hdw->flag_ok;
        ptr->flag_disconnected = hdw->flag_disconnected;
        ptr->flag_init_ok = hdw->flag_init_ok;
-       ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
-       ptr->subsys_flags = hdw->subsys_enabled_mask;
+       ptr->flag_ok = hdw->flag_ok;
+       ptr->fw1_state = hdw->fw1_state;
+       ptr->flag_decoder_missed = hdw->flag_decoder_missed;
+       ptr->flag_tripped = hdw->flag_tripped;
+       ptr->state_encoder_ok = hdw->state_encoder_ok;
+       ptr->state_encoder_run = hdw->state_encoder_run;
+       ptr->state_decoder_run = hdw->state_decoder_run;
+       ptr->state_usbstream_run = hdw->state_usbstream_run;
+       ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
+       ptr->state_pipeline_config = hdw->state_pipeline_config;
+       ptr->state_pipeline_req = hdw->state_pipeline_req;
+       ptr->state_pipeline_pause = hdw->state_pipeline_pause;
+       ptr->state_pipeline_idle = hdw->state_pipeline_idle;
        ptr->cmd_debug_state = hdw->cmd_debug_state;
        ptr->cmd_code = hdw->cmd_debug_code;
        ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
@@ -3381,6 +3689,15 @@ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
 }
 
 
+void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
+                                   struct pvr2_hdw_debug_info *ptr)
+{
+       LOCK_TAKE(hdw->ctl_lock); do {
+               pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+}
+
+
 int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
 {
        return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
index e2f9d5e4cb653c191f1a07ed94bf14a5799d3a4f..3ad7a13d6c391839a3135e117ae1102c20a888b1 100644 (file)
 #define PVR2_CVAL_INPUT_COMPOSITE 2
 #define PVR2_CVAL_INPUT_RADIO 3
 
-/* Subsystem definitions - these are various pieces that can be
-   independently stopped / started.  Usually you don't want to mess with
-   this directly (let the driver handle things itself), but it is useful
-   for debugging. */
-#define PVR2_SUBSYS_B_ENC_FIRMWARE        0
-#define PVR2_SUBSYS_B_ENC_CFG             1
-#define PVR2_SUBSYS_B_DIGITIZER_RUN       2
-#define PVR2_SUBSYS_B_USBSTREAM_RUN       3
-#define PVR2_SUBSYS_B_ENC_RUN             4
-
-#define PVR2_SUBSYS_CFG_ALL ( \
-       (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
-       (1 << PVR2_SUBSYS_B_ENC_CFG) )
-#define PVR2_SUBSYS_RUN_ALL ( \
-       (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
-       (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
-       (1 << PVR2_SUBSYS_B_ENC_RUN) )
-#define PVR2_SUBSYS_ALL ( \
-       PVR2_SUBSYS_CFG_ALL | \
-       PVR2_SUBSYS_RUN_ALL )
-
 enum pvr2_config {
        pvr2_config_empty,    /* No configuration */
        pvr2_config_mpeg,     /* Encoded / compressed video */
@@ -79,8 +58,41 @@ enum pvr2_v4l_type {
        pvr2_v4l_type_radio,
 };
 
+/* Major states that we can be in:
+ *
+ *  DEAD - Device is in an unusable state and cannot be recovered.  This
+ *  can happen if we completely lose the ability to communicate with it
+ *  (but it might still on the bus).  In this state there's nothing we can
+ *  do; it must be replugged in order to recover.
+ *
+ *  COLD - Device is in an unusuable state, needs microcontroller firmware.
+ *
+ *  WARM - We can communicate with the device and the proper
+ *  microcontroller firmware is running, but other device initialization is
+ *  still needed (e.g. encoder firmware).
+ *
+ *  ERROR - A problem prevents capture operation (e.g. encoder firmware
+ *  missing).
+ *
+ *  READY - Device is operational, but not streaming.
+ *
+ *  RUN - Device is streaming.
+ *
+ */
+#define PVR2_STATE_NONE 0
+#define PVR2_STATE_DEAD 1
+#define PVR2_STATE_COLD 2
+#define PVR2_STATE_WARM 3
+#define PVR2_STATE_ERROR 4
+#define PVR2_STATE_READY 5
+#define PVR2_STATE_RUN 6
+
+/* Translate configuration enum to a string label */
 const char *pvr2_config_get_name(enum pvr2_config);
 
+/* Translate a master state enum to a string label */
+const char *pvr2_hdw_get_state_name(unsigned int);
+
 struct pvr2_hdw;
 
 /* Create and return a structure for interacting with the underlying
@@ -88,28 +100,13 @@ struct pvr2_hdw;
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                 const struct usb_device_id *devid);
 
-/* Poll for background activity (if any) */
-void pvr2_hdw_poll(struct pvr2_hdw *);
-
-/* Trigger a poll to take place later at a convenient time */
-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
-
-/* Register a callback used to trigger a future poll */
-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
-                                void (*func)(void *),
-                                void *data);
-
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *);
 
-/* Set up the structure and attempt to put the device into a usable state.
-   This can be a time-consuming operation, which is why it is not done
-   internally as part of the create() step.  Return value is exactly the
-   same as pvr2_hdw_init_ok(). */
-int pvr2_hdw_setup(struct pvr2_hdw *);
-
-/* Initialization succeeded */
-int pvr2_hdw_init_ok(struct pvr2_hdw *);
+/* Register a function to be called whenever the master state changes. */
+void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
+                                void (*callback_func)(void *),
+                                void *callback_data);
 
 /* Return true if in the ready (normal) state */
 int pvr2_hdw_dev_ok(struct pvr2_hdw *);
@@ -161,12 +158,21 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
 /* Query device and see if it thinks it is on a high-speed USB link */
 int pvr2_hdw_is_hsm(struct pvr2_hdw *);
 
+/* Return a string token representative of the hardware type */
+const char *pvr2_hdw_get_type(struct pvr2_hdw *);
+
+/* Return a single line description of the hardware type */
+const char *pvr2_hdw_get_desc(struct pvr2_hdw *);
+
 /* Turn streaming on/off */
 int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
 
 /* Find out if streaming is on */
 int pvr2_hdw_get_streaming(struct pvr2_hdw *);
 
+/* Retrieve driver overall state */
+int pvr2_hdw_get_state(struct pvr2_hdw *);
+
 /* Configure the type of stream to generate */
 int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
 
@@ -177,26 +183,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
 int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
                               unsigned int idx);
 
-/* Enable / disable various pieces of hardware.  Items to change are
-   identified by bit positions within msk, and new state for each item is
-   identified by corresponding bit positions within val. */
-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
-                            unsigned long msk,unsigned long val);
-
-/* Retrieve mask indicating which pieces of hardware are currently enabled
-   / configured. */
-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
-
-/* Adjust mask of what get shut down when streaming is stopped.  This is a
-   debugging aid. */
-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
-                                   unsigned long msk,unsigned long val);
-
-/* Retrieve mask indicating which pieces of hardware are disabled when
-   streaming is turned off. */
-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
-
-
 /* Enable / disable retrieval of CPU firmware or prom contents.  This must
    be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
    this may prevent the device from running (and leaving this mode may
@@ -253,6 +239,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
 /* Execute a USB-commanded device reset */
 void pvr2_hdw_device_reset(struct pvr2_hdw *);
 
+/* Reset worker's error trapping circuit breaker */
+int pvr2_hdw_untrip(struct pvr2_hdw *);
+
 /* Execute hard reset command (after this point it's likely that the
    encoder will have to be reconfigured).  This also clears the "useless"
    state. */
@@ -275,11 +264,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
 struct pvr2_hdw_debug_info {
        int big_lock_held;
        int ctl_lock_held;
-       int flag_ok;
        int flag_disconnected;
        int flag_init_ok;
-       int flag_streaming_enabled;
-       unsigned long subsys_flags;
+       int flag_ok;
+       int fw1_state;
+       int flag_decoder_missed;
+       int flag_tripped;
+       int state_encoder_ok;
+       int state_encoder_run;
+       int state_decoder_run;
+       int state_usbstream_run;
+       int state_decoder_quiescent;
+       int state_pipeline_config;
+       int state_pipeline_req;
+       int state_pipeline_pause;
+       int state_pipeline_idle;
        int cmd_debug_state;
        int cmd_debug_write_len;
        int cmd_debug_read_len;
@@ -295,8 +294,20 @@ struct pvr2_hdw_debug_info {
    diagnosing lockups.  Note that this operation is completed without any
    kind of locking and so it is not atomic and may yield inconsistent
    results.  This is *purely* a debugging aid. */
-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
-                            struct pvr2_hdw_debug_info *);
+void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
+                                     struct pvr2_hdw_debug_info *);
+
+/* Intrusively retrieve internal state info - this is useful for
+   diagnosing overall driver state.  This operation synchronizes against
+   the overall driver mutex - so if there are locking problems this will
+   likely hang!  This is *purely* a debugging aid. */
+void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
+                                   struct pvr2_hdw_debug_info *);
+
+/* Report out several lines of text that describes driver internal state.
+   Results are written into the passed-in buffer. */
+unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+                                  char *buf_ptr,unsigned int buf_size);
 
 /* Cause modules to log their state once */
 void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
@@ -306,9 +317,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
    a debugging aid. */
 int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
 
-/* List of device types that we can match */
-extern struct usb_device_id pvr2_device_table[];
-
 #endif /* __PVRUSB2_HDW_H */
 
 /*
index c817c864e6a020b94ee5039744190fe4193c2642..62867fa3517ae4cd201b2971372aa180ccf716d8 100644 (file)
@@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
                list_add_tail(&cp->list,&hdw->i2c_clients);
                hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
        } while (0); mutex_unlock(&hdw->i2c_list_lock);
-       if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
+       if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
        return 0;
 }
 
@@ -980,14 +980,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
                printk(KERN_INFO "%s: IR disabled\n",hdw->name);
                hdw->i2c_func[0x18] = i2c_black_hole;
        } else if (ir_mode[hdw->unit_number] == 1) {
-               if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+               if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) {
                        hdw->i2c_func[0x18] = i2c_24xxx_ir;
                }
        }
-       if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
-               hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+       if (hdw->hdw_desc->flag_has_cx25840) {
                hdw->i2c_func[0x44] = i2c_hack_cx25840;
        }
+       if (hdw->hdw_desc->flag_has_wm8775) {
+               hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+       }
 
        // Configure the adapter and set up everything else related to it.
        memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
index 11b3b2e84b9092da3983fab9ab130a8f485a85d8..b63b2265503ac174a335e1ca23c5a560e8d1c31c 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/videodev2.h>
 
 #include "pvrusb2-hdw.h"
+#include "pvrusb2-devattr.h"
 #include "pvrusb2-context.h"
 #include "pvrusb2-debug.h"
 #include "pvrusb2-v4l2.h"
@@ -148,11 +149,6 @@ static void __exit pvr_exit(void)
 module_init(pvr_init);
 module_exit(pvr_exit);
 
-/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
-   MODULE_DEVICE_TABLE().  We have to declare that attribute there
-   because that's where the device table actually is now and it seems
-   that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
-   is used on what ends up being an external symbol. */
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
index 63e55bb59fcbc9f698600f613459c505d56cd91c..da309288daa4c603fd92b6dbd33e3eca5a6a6508 100644 (file)
@@ -50,6 +50,10 @@ struct std_name {
         V4L2_STD_NTSC_M_KR| \
         V4L2_STD_NTSC_443)
 
+#define CSTD_ATSC \
+       (V4L2_STD_ATSC_8_VSB| \
+        V4L2_STD_ATSC_16_VSB)
+
 #define CSTD_SECAM \
        (V4L2_STD_SECAM_B| \
         V4L2_STD_SECAM_D| \
@@ -82,6 +86,7 @@ static const struct std_name std_groups[] = {
        {"PAL",CSTD_PAL},
        {"NTSC",CSTD_NTSC},
        {"SECAM",CSTD_SECAM},
+       {"ATSC",CSTD_ATSC},
 };
 
 /* Mapping of standard bits to modulation system */
@@ -104,6 +109,8 @@ static const struct std_name std_items[] = {
        {"N",TSTD_N},
        {"Nc",TSTD_Nc},
        {"60",TSTD_60},
+       {"8VSB",V4L2_STD_ATSC_8_VSB},
+       {"16VSB",V4L2_STD_ATSC_16_VSB},
 };
 
 
index 3c57a7d8200bfd9724c96f50707e217b50fbb4b1..7a1cd878e31a70f8423bbdf6810914fa2ec3192c 100644 (file)
@@ -43,10 +43,14 @@ struct pvr2_sysfs {
        struct device_attribute attr_v4l_radio_minor_number;
        struct device_attribute attr_unit_number;
        struct device_attribute attr_bus_info;
+       struct device_attribute attr_hdw_name;
+       struct device_attribute attr_hdw_desc;
        int v4l_minor_number_created_ok;
        int v4l_radio_minor_number_created_ok;
        int unit_number_created_ok;
        int bus_info_created_ok;
+       int hdw_name_created_ok;
+       int hdw_desc_created_ok;
 };
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
@@ -712,6 +716,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
        pvr2_sysfs_tear_down_debugifc(sfp);
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
        pvr2_sysfs_tear_down_controls(sfp);
+       if (sfp->hdw_desc_created_ok) {
+               device_remove_file(sfp->class_dev,
+                                  &sfp->attr_hdw_desc);
+       }
+       if (sfp->hdw_name_created_ok) {
+               device_remove_file(sfp->class_dev,
+                                  &sfp->attr_hdw_name);
+       }
        if (sfp->bus_info_created_ok) {
                device_remove_file(sfp->class_dev,
                                         &sfp->attr_bus_info);
@@ -758,6 +770,28 @@ static ssize_t bus_info_show(struct device *class_dev,
 }
 
 
+static ssize_t hdw_name_show(struct device *class_dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%s\n",
+                        pvr2_hdw_get_type(sfp->channel.hdw));
+}
+
+
+static ssize_t hdw_desc_show(struct device *class_dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%s\n",
+                        pvr2_hdw_get_desc(sfp->channel.hdw));
+}
+
+
 static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
                                           struct device_attribute *attr,
                                           char *buf)
@@ -871,6 +905,32 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
                sfp->bus_info_created_ok = !0;
        }
 
+       sfp->attr_hdw_name.attr.name = "device_hardware_type";
+       sfp->attr_hdw_name.attr.mode = S_IRUGO;
+       sfp->attr_hdw_name.show = hdw_name_show;
+       sfp->attr_hdw_name.store = NULL;
+       ret = device_create_file(sfp->class_dev,
+                                &sfp->attr_hdw_name);
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: device_create_file error: %d\n",
+                      __FUNCTION__, ret);
+       } else {
+               sfp->hdw_name_created_ok = !0;
+       }
+
+       sfp->attr_hdw_desc.attr.name = "device_hardware_description";
+       sfp->attr_hdw_desc.attr.mode = S_IRUGO;
+       sfp->attr_hdw_desc.show = hdw_desc_show;
+       sfp->attr_hdw_desc.store = NULL;
+       ret = device_create_file(sfp->class_dev,
+                                &sfp->attr_hdw_desc);
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: device_create_file error: %d\n",
+                      __FUNCTION__, ret);
+       } else {
+               sfp->hdw_desc_created_ok = !0;
+       }
+
        pvr2_sysfs_add_controls(sfp);
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
        pvr2_sysfs_add_debugifc(sfp);
index 7a596ea7cfe698bc59d7f39299845d73e91dfd1c..8f0587ebd4bd8609b4e97f785f3641f176b01344 100644 (file)
@@ -205,6 +205,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
                strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
                        sizeof(cap->bus_info));
+               strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
 
                ret = 0;
                break;
@@ -1015,10 +1016,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
        sp = fh->dev_info->stream->stream;
        pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
        pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
-       pvr2_hdw_set_streaming(hdw,!0);
-       ret = pvr2_ioread_set_enabled(fh->rhp,!0);
-
-       return ret;
+       if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
+       return pvr2_ioread_set_enabled(fh->rhp,!0);
 }
 
 
index 61efa6f02200e74dee598bf1d1ee765aed3faea9..7c47345501b610ea988f349f935de29666415193 100644 (file)
@@ -49,29 +49,50 @@ struct pvr2_v4l_decoder {
 };
 
 
+struct routing_scheme {
+       const int *def;
+       unsigned int cnt;
+};
+
+
+static const int routing_scheme0[] = {
+       [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
+       /* In radio mode, we mute the video, but point at one
+          spot just to stay consistent */
+       [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
+       [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5,
+       [PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2,
+};
+
+static const struct routing_scheme routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
+               .def = routing_scheme0,
+               .cnt = ARRAY_SIZE(routing_scheme0),
+       },
+};
+
 static void set_input(struct pvr2_v4l_decoder *ctxt)
 {
        struct pvr2_hdw *hdw = ctxt->hdw;
        struct v4l2_routing route;
+       const struct routing_scheme *sp;
+       unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
-       switch(hdw->input_val) {
-       case PVR2_CVAL_INPUT_TV:
-               route.input = SAA7115_COMPOSITE4;
-               break;
-       case PVR2_CVAL_INPUT_COMPOSITE:
-               route.input = SAA7115_COMPOSITE5;
-               break;
-       case PVR2_CVAL_INPUT_SVIDEO:
-               route.input = SAA7115_SVIDEO2;
-               break;
-       case PVR2_CVAL_INPUT_RADIO:
-               // In radio mode, we mute the video, but point at one
-               // spot just to stay consistent
-               route.input = SAA7115_COMPOSITE5;
-       default:
+
+       if ((sid < ARRAY_SIZE(routing_schemes)) &&
+           ((sp = routing_schemes + sid) != 0) &&
+           (hdw->input_val >= 0) &&
+           (hdw->input_val < sp->cnt)) {
+               route.input = sp->def[hdw->input_val];
+       } else {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "*** WARNING *** i2c v4l2 set_input:"
+                          " Invalid routing scheme (%u) and/or input (%d)",
+                          sid,hdw->input_val);
                return;
        }
+
        route.output = 0;
        pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
 }
@@ -129,7 +150,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
 static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
 {
        ctxt->client->handler = NULL;
-       ctxt->hdw->decoder_ctrl = NULL;
+       pvr2_hdw_set_decoder(ctxt->hdw,NULL);
        kfree(ctxt);
 }
 
@@ -217,7 +238,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
        ctxt->client = cp;
        ctxt->hdw = hdw;
        ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
-       hdw->decoder_ctrl = &ctxt->ctrl;
+       pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
        cp->handler = &ctxt->handler;
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
                   cp->client->addr);
index 2d18f00698214565603d486847dacd4e2345b4b6..41e5e518a47e21926245fc8deca0d115f2edf8dc 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/saa7115.h>
 #include <asm/div64.h>
 
@@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
-static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct saa711x_state *state = i2c_get_clientdata(client);
 
@@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa711x;
-
-static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
+static int saa7115_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct saa711x_state *state;
        int     i;
        char    name[17];
        u8 chip_id;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_saa711x;
        snprintf(client->name, sizeof(client->name) - 1, "saa7115");
 
        for (i = 0; i < 0x0f; i++) {
@@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
        /* Check whether this chip is part of the saa711x series */
        if (memcmp(name, "1f711", 5)) {
                v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
-                       address << 1, name);
-               kfree(client);
-               return 0;
+                       client->addr << 1, name);
+               return -ENODEV;
        }
 
        snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
-       v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
+       v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
 
        state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
        i2c_set_clientdata(client, state);
        if (state == NULL) {
-               kfree(client);
                return -ENOMEM;
        }
        state->input = -1;
@@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
        saa711x_writeregs(client, saa7115_init_misc);
        saa711x_set_v4lstd(client, V4L2_STD_NTSC);
 
-       i2c_attach_client(client);
-
        v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
                saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
-
        return 0;
 }
 
-static int saa711x_probe(struct i2c_adapter *adapter)
-{
-       if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
-               return i2c_probe(adapter, &addr_data, &saa711x_attach);
-       return 0;
-}
+/* ----------------------------------------------------------------------- */
 
-static int saa711x_detach(struct i2c_client *client)
+static int saa7115_remove(struct i2c_client *client)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(state);
-       kfree(client);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver_saa711x = {
-       .driver = {
-               .name = "saa7115",
-       },
-       .id = I2C_DRIVERID_SAA711X,
-       .attach_adapter = saa711x_probe,
-       .detach_client = saa711x_detach,
-       .command = saa711x_command,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7115",
+       .driverid = I2C_DRIVERID_SAA711X,
+       .command = saa7115_command,
+       .probe = saa7115_probe,
+       .remove = saa7115_remove,
+       .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
 };
 
-
-static int __init saa711x_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver_saa711x);
-}
-
-static void __exit saa711x_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver_saa711x);
-}
-
-module_init(saa711x_init_module);
-module_exit(saa711x_cleanup_module);
index e35ef321ec717b7da3b1a8e0ef0fa2eb424df718..06c88db656b41d4a8a94dc67ef9814c4fe852e50 100644 (file)
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/saa7127.h>
 
-static int debug = 0;
-static int test_image = 0;
+static int debug;
+static int test_image;
 
 MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
@@ -68,10 +69,6 @@ module_param(test_image, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (0-2)");
 MODULE_PARM_DESC(test_image, "test_image (0-1)");
 
-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 /*
  * SAA7127 registers
@@ -360,9 +357,10 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
        if (enable && (data->field != 0 || data->line != 21))
                return -EINVAL;
        if (state->cc_enable != enable) {
-               v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off");
+               v4l_dbg(1, debug, client,
+                       "Turn CC %s\n", enable ? "on" : "off");
                saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
-                               (state->xds_enable << 7) | (enable << 6) | 0x11);
+                       (state->xds_enable << 7) | (enable << 6) | 0x11);
                state->cc_enable = enable;
        }
        if (!enable)
@@ -420,7 +418,8 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 
        saa7127_write(client, 0x26, data->data[0]);
        saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
-       v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+       v4l_dbg(1, debug, client,
+               "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
        state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
        return 0;
 }
@@ -507,7 +506,8 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
        default:
                return -EINVAL;
        }
-       v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]);
+       v4l_dbg(1, debug, client,
+               "Selecting %s output type\n", output_strs[output]);
 
        /* Configure Encoder */
        saa7127_write(client, 0x2d, state->reg_2d);
@@ -569,12 +569,10 @@ static int saa7127_command(struct i2c_client *client,
        {
                int rc = 0;
 
-               if (state->input_type != route->input) {
+               if (state->input_type != route->input)
                        rc = saa7127_set_input_type(client, route->input);
-               }
-               if (rc == 0 && state->output_type != route->output) {
+               if (rc == 0 && state->output_type != route->output)
                        rc = saa7127_set_output_type(client, route->output);
-               }
                return rc;
        }
 
@@ -620,7 +618,8 @@ static int saa7127_command(struct i2c_client *client,
        {
                struct v4l2_register *reg = arg;
 
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+               if (!v4l2_chip_match_i2c_client(client,
+                                       reg->match_type, reg->match_chip))
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -637,16 +636,16 @@ static int saa7127_command(struct i2c_client *client,
                struct v4l2_sliced_vbi_data *data = arg;
 
                switch (data->id) {
-                       case V4L2_SLICED_WSS_625:
-                               return saa7127_set_wss(client, data);
-                       case V4L2_SLICED_VPS:
-                               return saa7127_set_vps(client, data);
-                       case V4L2_SLICED_CAPTION_525:
-                               if (data->field == 0)
-                                       return saa7127_set_cc(client, data);
-                               return saa7127_set_xds(client, data);
-                       default:
-                               return -EINVAL;
+               case V4L2_SLICED_WSS_625:
+                       return saa7127_set_wss(client, data);
+               case V4L2_SLICED_VPS:
+                       return saa7127_set_vps(client, data);
+               case V4L2_SLICED_CAPTION_525:
+                       if (data->field == 0)
+                               return saa7127_set_cc(client, data);
+                       return saa7127_set_xds(client, data);
+               default:
+                       return -EINVAL;
                }
                break;
        }
@@ -662,31 +661,20 @@ static int saa7127_command(struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7127;
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+static int saa7127_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct saa7127_state *state;
        struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
        int read_result = 0;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_saa7127;
        snprintf(client->name, sizeof(client->name) - 1, "saa7127");
 
-       v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1);
+       v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
+                       client->addr << 1);
 
        /* First test register 0: Bits 5-7 are a version ID (should be 0),
           and bit 2 should also be 0.
@@ -696,15 +684,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
        if ((saa7127_read(client, 0) & 0xe4) != 0 ||
                        (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
                v4l_dbg(1, debug, client, "saa7127 not found\n");
-               kfree(client);
-               return 0;
+               return -ENODEV;
        }
        state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
 
-       if (state == NULL) {
-               kfree(client);
-               return (-ENOMEM);
-       }
+       if (state == NULL)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, state);
 
@@ -718,91 +703,48 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
        saa7127_set_wss(client, &vbi);
        saa7127_set_cc(client, &vbi);
        saa7127_set_xds(client, &vbi);
-       if (test_image == 1) {
+       if (test_image == 1)
                /* The Encoder has an internal Colorbar generator */
                /* This can be used for debugging */
                saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
-       } else {
+       else
                saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
-       }
        saa7127_set_video_enable(client, 1);
 
        /* Detect if it's an saa7129 */
        read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
        saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
        if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
-               v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+               v4l_info(client, "saa7129 found @ 0x%x (%s)\n",
+                               client->addr << 1, client->adapter->name);
                saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
                saa7127_write_inittab(client, saa7129_init_config_extra);
                state->ident = V4L2_IDENT_SAA7129;
        } else {
-               v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+               v4l_info(client, "saa7127 found @ 0x%x (%s)\n",
+                               client->addr << 1, client->adapter->name);
                state->ident = V4L2_IDENT_SAA7127;
        }
-
-       i2c_attach_client(client);
-
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_probe(struct i2c_adapter *adapter)
+static int saa7127_remove(struct i2c_client *client)
 {
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, saa7127_attach);
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_detach(struct i2c_client *client)
-{
-       struct saa7127_state *state = i2c_get_clientdata(client);
-       int err;
-
        /* Turn off TV output */
        saa7127_set_video_enable(client, 0);
-
-       err = i2c_detach_client(client);
-
-       if (err) {
-               return err;
-       }
-
-       kfree(state);
-       kfree(client);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7127 = {
-       .driver = {
-               .name = "saa7127",
-       },
-       .id = I2C_DRIVERID_SAA7127,
-       .attach_adapter = saa7127_probe,
-       .detach_client = saa7127_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7127",
+       .driverid = I2C_DRIVERID_SAA7127,
        .command = saa7127_command,
+       .probe = saa7127_probe,
+       .remove = saa7127_remove,
 };
 
-
-/* ----------------------------------------------------------------------- */
-
-static int __init saa7127_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver_saa7127);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void __exit saa7127_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver_saa7127);
-}
-
-/* ----------------------------------------------------------------------- */
-
-module_init(saa7127_init_module);
-module_exit(saa7127_cleanup_module);
index 3aa8cb2b860ae3d570ca051a275cea1bff9942e2..96bc3b1298a2564389b262e843b49622da4fde44 100644 (file)
@@ -4,6 +4,7 @@ config VIDEO_SAA7134
        select VIDEOBUF_DMA_SG
        select VIDEO_IR
        select VIDEO_TUNER
+       select VIDEO_TVEEPROM
        select CRC32
        ---help---
          This is a video4linux driver for Philips SAA713x based
@@ -23,18 +24,6 @@ config VIDEO_SAA7134_ALSA
          To compile this driver as a module, choose M here: the
          module will be called saa7134-alsa.
 
-config VIDEO_SAA7134_OSS
-       tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)"
-       depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA
-       ---help---
-         This is a video4linux driver for direct (DMA) audio in
-         Philips SAA713x based TV cards using OSS
-
-         This is deprecated in favor of the ALSA module
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa7134-oss.
-
 config VIDEO_SAA7134_DVB
        tristate "DVB/ATSC Support for saa7134 based TV cards"
        depends on VIDEO_SAA7134 && DVB_CORE
index c85c8a8ec36119b0f3714d6c8b440b70004d18ae..9aff937ba7a5232ab506d8f1e0617f5089be3726 100644 (file)
@@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
                                saa6752hs.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
-obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o
 
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
index 4878f3067787e5e046f3625e0510471cf6e38b0c..ba2531034a91264f763d53daabab533a98469bcb 100644 (file)
@@ -1077,24 +1077,14 @@ static int saa7134_alsa_init(void)
        struct saa7134_dev *dev = NULL;
        struct list_head *list;
 
-       if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
-               saa7134_dmasound_init = alsa_device_init;
-               saa7134_dmasound_exit = alsa_device_exit;
-       } else {
-               printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n");
-               return -EBUSY;
-       }
+       saa7134_dmasound_init = alsa_device_init;
+       saa7134_dmasound_exit = alsa_device_exit;
 
        printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
 
        list_for_each(list,&saa7134_devlist) {
                dev = list_entry(list, struct saa7134_dev, devlist);
-               if (dev->dmasound.priv_data == NULL) {
-                       alsa_device_init(dev);
-               } else {
-                       printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
-                       return -EBUSY;
-               }
+               alsa_device_init(dev);
        }
 
        if (dev == NULL)
index 98c1b084a7160eeaeb18b7033c670cb3668a1ece..7d7f383b404f93b3e25e3b54854b40d596bfbaaa 100644 (file)
@@ -26,6 +26,7 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 #include <media/v4l2-common.h>
+#include <media/tveeprom.h>
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -349,6 +350,10 @@ struct saa7134_board saa7134_boards[] = {
                        .name = name_radio,
                        .amux = LINE2,
                },
+              .mute = {
+                      .name = name_mute,
+                      .amux = TV,
+              },
        },
        [SAA7134_BOARD_TVSTATION_RDS] = {
                /* Typhoon TV Tuner RDS: Art.Nr. 50694 */
@@ -565,6 +570,10 @@ struct saa7134_board saa7134_boards[] = {
                .radio = {
                        .name   = name_radio,
                        .amux   = LINE2,
+              },
+              .mute = {
+                      .name = name_mute,
+                      .amux = TV,
                },
        },
        [SAA7134_BOARD_TYPHOON_90031] = {
@@ -3553,6 +3562,356 @@ struct saa7134_board saa7134_boards[] = {
                        .tv     = 1,
                }},
        },
+       [SAA7134_BOARD_BEHOLD_401] = {
+               .name           = "Beholder BeholdTV 401",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FQ1216ME,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }},
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_403] = {
+               .name           = "Beholder BeholdTV 403",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FQ1216ME,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 1,
+                       .amux   = LINE1,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }},
+       },
+       [SAA7134_BOARD_BEHOLD_403FM] = {
+               .name           = "Beholder BeholdTV 403 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FQ1216ME,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 1,
+                       .amux   = LINE1,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_405] = {
+               .name           = "Beholder BeholdTV 405",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }},
+       },
+       [SAA7134_BOARD_BEHOLD_405FM] = {
+               /* Sergey <skiv@orel.ru> */
+               .name           = "Beholder BeholdTV 405 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_407] = {
+               .name           = "Beholder BeholdTV 407",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask = 0xc0c000,
+               .inputs = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0xc0c000,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+                       .gpio = 0xc0c000,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv = 1,
+                       .gpio = 0xc0c000,
+               }},
+       },
+       [SAA7134_BOARD_BEHOLD_407FM] = {
+               .name           = "Beholder BeholdTV 407 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask = 0xc0c000,
+               .inputs = {{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0xc0c000,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+                       .gpio = 0xc0c000,
+               },{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv = 1,
+                       .gpio = 0xc0c000,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0xc0c000,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_409] = {
+               .name           = "Beholder BeholdTV 409",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+       },
+       [SAA7134_BOARD_BEHOLD_505FM] = {
+               .name           = "Beholder BeholdTV 505 FM/RDS",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_507_9FM] = {
+               .name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+                       .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+               .name           = "Beholder BeholdTV Columbus TVFM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_ALPS_TSBE5_PAL,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607_9FM] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 / BeholdTV 609",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_M6] = {
+               /* Igor Kuznetsov <igk@igk.ru> */
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV M6 / BeholdTV M6 Extra",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+               .mpeg  = SAA7134_MPEG_EMPRESS,
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4033,7 +4392,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x1462,
-               .subdevice    = 0x6231,
+               .subdevice    = 0x6231, /* tda8275a, ks003 IR */
+               .driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1462,
+               .subdevice    = 0x8624, /* tda8275, ks003 IR */
                .driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -4203,12 +4568,42 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1043,
                .subdevice    = 0x4876,
                .driver_data  = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6700,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x0070,
                .subdevice    = 0x6701,
                .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6702,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6703,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6704,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6705,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -4287,6 +4682,162 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0xf01d, /* AVerTV DVB-T Super 007 */
                .driver_data  = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4016,
+               .driver_data  = SAA7134_BOARD_BEHOLD_401,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4036,
+               .driver_data  = SAA7134_BOARD_BEHOLD_403,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4037,
+               .driver_data  = SAA7134_BOARD_BEHOLD_403FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4050,
+               .driver_data  = SAA7134_BOARD_BEHOLD_405,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4051,
+               .driver_data  = SAA7134_BOARD_BEHOLD_405FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4070,
+               .driver_data  = SAA7134_BOARD_BEHOLD_407,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4071,
+               .driver_data  = SAA7134_BOARD_BEHOLD_407FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x4090,
+               .driver_data  = SAA7134_BOARD_BEHOLD_409,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x5051,
+               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x505B,
+               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x5050,
+               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x5071,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x507B,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x5070,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x5090,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0000,
+               .subdevice    = 0x5201,
+               .driver_data  = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6070,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6071,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6072,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6073,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6090,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6091,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6092,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6093,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6190,
+               .driver_data  = SAA7134_BOARD_BEHOLD_M6,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace,
+               .subdevice    = 0x6193,
+               .driver_data  = SAA7134_BOARD_BEHOLD_M6,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -4351,6 +4902,34 @@ static void board_flyvideo(struct saa7134_dev *dev)
 
 /* ----------------------------------------------------------- */
 
+static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
+{
+       struct tveeprom tv;
+
+       tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+       /* Make sure we support the board model */
+       switch (tv.model) {
+       case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+       case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+       case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+       case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
+       case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
+       case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+       case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+               break;
+       default:
+               printk(KERN_WARNING "%s: warning: "
+                      "unknown hauppauge model #%d\n", dev->name, tv.model);
+               break;
+       }
+
+       printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+              dev->name, tv.model);
+}
+
+/* ----------------------------------------------------------- */
+
 int saa7134_board_init1(struct saa7134_dev *dev)
 {
        /* Always print gpio, often manufacturers encode tuner type and other info. */
@@ -4406,6 +4985,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
        case SAA7134_BOARD_10MOONSTVMASTER3:
+       case SAA7134_BOARD_BEHOLD_401:
+       case SAA7134_BOARD_BEHOLD_403:
+       case SAA7134_BOARD_BEHOLD_403FM:
+       case SAA7134_BOARD_BEHOLD_405:
+       case SAA7134_BOARD_BEHOLD_405FM:
+       case SAA7134_BOARD_BEHOLD_407:
+       case SAA7134_BOARD_BEHOLD_407FM:
+       case SAA7134_BOARD_BEHOLD_409:
+       case SAA7134_BOARD_BEHOLD_505FM:
+       case SAA7134_BOARD_BEHOLD_507_9FM:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4445,6 +5034,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
                break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+       case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
                /* power-up tuner chip */
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
@@ -4466,6 +5056,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+       case SAA7134_BOARD_BEHOLD_607_9FM:
+       case SAA7134_BOARD_BEHOLD_M6:
                dev->has_remote = SAA7134_REMOTE_I2C;
                break;
        case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -4477,6 +5069,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_AVERMEDIA_M102:
                /* enable tuner */
+              dev->has_remote = SAA7134_REMOTE_GPIO;
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
                break;
@@ -4570,8 +5163,17 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 
                printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
                if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
-                       dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE;
-                       saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf);
+                       struct v4l2_priv_tun_config tda9887_cfg;
+
+                       tda9887_cfg.tuner = TUNER_TDA9887;
+                       tda9887_cfg.priv  = &dev->tda9887_conf;
+
+                       dev->tda9887_conf = TDA9887_PRESENT      |
+                                           TDA9887_PORT1_ACTIVE |
+                                           TDA9887_PORT2_ACTIVE;
+
+                       saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+                                                &tda9887_cfg);
                }
 
                tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
@@ -4601,7 +5203,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_PHILIPS_TIGER:
        case SAA7134_BOARD_PHILIPS_TIGER_S:
-       case SAA7134_BOARD_AVERMEDIA_SUPER_007:
                {
                u8 data[] = { 0x3c, 0x33, 0x60};
                struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
@@ -4622,13 +5223,16 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                }
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+               hauppauge_eeprom(dev, dev->eedata+0x80);
+               /* break intentionally omitted */
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
        case SAA7134_BOARD_KWORLD_DVBT_210:
        case SAA7134_BOARD_TEVION_DVBT_220RF:
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
        case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
        case SAA7134_BOARD_MEDION_MD8800_QUADRO:
-       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+       case SAA7134_BOARD_AVERMEDIA_SUPER_007:
                /* this is a hybrid board, initialize to analog mode
                 * and configure firmware eeprom address
                 */
index 4fd187ac9d7088378498f408c1b2efa2e732c142..52baa4f7f7dda1d235431b867000366bf60b9625 100644 (file)
@@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_unmap(q, dma);
        videobuf_dma_free(dma);
-       buf->vb.state = STATE_NEEDS_INIT;
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 /* ------------------------------------------------------------------ */
@@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
                        buf->activate(dev,buf,NULL);
                } else if (list_empty(&q->queue)) {
                        list_add_tail(&buf->vb.queue,&q->queue);
-                       buf->vb.state = STATE_QUEUED;
+                       buf->vb.state = VIDEOBUF_QUEUED;
                } else {
                        next = list_entry(q->queue.next,struct saa7134_buf,
                                          vb.queue);
@@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
                }
        } else {
                list_add_tail(&buf->vb.queue,&q->queue);
-               buf->vb.state = STATE_QUEUED;
+               buf->vb.state = VIDEOBUF_QUEUED;
        }
        return 0;
 }
@@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data)
           try to start over with the next one. */
        if (q->curr) {
                dprintk("timeout on %p\n",q->curr);
-               saa7134_buffer_finish(dev,q,STATE_ERROR);
+               saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR);
        }
        saa7134_buffer_next(dev,q);
        spin_unlock_irqrestore(&dev->slock,flags);
@@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data)
 
 /* resends a current buffer in queue after resume */
 
-int saa7134_buffer_requeue(struct saa7134_dev *dev,
-                        struct saa7134_dmaqueue *q)
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+                                 struct saa7134_dmaqueue *q)
 {
        struct saa7134_buf *buf, *next;
 
@@ -834,6 +834,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
        vfd->minor   = -1;
        vfd->dev     = &dev->pci->dev;
        vfd->release = video_device_release;
+       vfd->debug   = video_debug;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
                 dev->name, type, saa7134_boards[dev->board].name);
        return vfd;
@@ -1052,7 +1053,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
               dev->name,dev->video_dev->minor & 0x1f);
 
-       dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi");
+       dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
+       dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT;
+
        err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
                                    vbi_nr[dev->nr]);
        if (err < 0)
@@ -1181,8 +1184,13 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
        saa_writel(SAA7134_IRQ2, 0);
        saa_writel(SAA7134_MAIN_CTRL, 0);
 
-       synchronize_irq(pci_dev->irq);
        dev->insuspend = 1;
+       synchronize_irq(pci_dev->irq);
+
+       /* ACK interrupts once more, just in case,
+               since the IRQ handler won't ack them anymore*/
+
+       saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
 
        /* Disable timeout timers - if we have active buffers, we will
           fill them on resume*/
@@ -1194,20 +1202,19 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
        if (dev->remote)
                saa7134_ir_stop(dev);
 
-       pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
        pci_save_state(pci_dev);
+       pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
 
-    return 0;
+       return 0;
 }
 
 static int saa7134_resume(struct pci_dev *pci_dev)
 {
-
        struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
-       unsigned int flags;
+       unsigned long flags;
 
-       pci_restore_state(pci_dev);
        pci_set_power_state(pci_dev, PCI_D0);
+       pci_restore_state(pci_dev);
 
        /* Do things that are done in saa7134_initdev ,
                except of initializing memory structures.*/
@@ -1223,6 +1230,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
                saa7134_ir_start(dev, dev->remote);
        saa7134_hw_enable1(dev);
 
+       msleep(100);
 
        saa7134_board_init2(dev);
 
@@ -1230,10 +1238,13 @@ static int saa7134_resume(struct pci_dev *pci_dev)
        saa7134_set_tvnorm_hw(dev);
        saa7134_tvaudio_setmute(dev);
        saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+       saa7134_tvaudio_init(dev);
        saa7134_tvaudio_do_scan(dev);
        saa7134_enable_i2s(dev);
        saa7134_hw_enable2(dev);
 
+       saa7134_irq_video_signalchange(dev);
+
        /*resume unfinished buffer(s)*/
        spin_lock_irqsave(&dev->slock, flags);
        saa7134_buffer_requeue(dev, &dev->video_q);
@@ -1247,6 +1258,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
 
        /* start DMA now*/
        dev->insuspend = 0;
+       smp_wmb();
        saa7134_set_dmabits(dev);
        spin_unlock_irqrestore(&dev->slock, flags);
 
index e1ab099ec4c62ecdf2fdebc4a018bb27e96f1272..a9ca5730826f6d9c5ce46d2363ffc86e36609072 100644 (file)
@@ -1073,14 +1073,21 @@ static int dvb_init(struct saa7134_dev *dev)
 
 static int dvb_fini(struct saa7134_dev *dev)
 {
-       static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+       /* FIXME: I suspect that this code is bogus, since the entry for
+          Pinnacle 300I DVB-T PAL already defines the proper init to allow
+          the detection of mt2032 (TDA9887_PORT2_INACTIVE)
+        */
+       if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
+               struct v4l2_priv_tun_config tda9887_cfg;
+               static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv  = &on;
 
-       switch (dev->board) {
-       case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
                /* otherwise we don't detect the tuner on next insmod */
-               saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
-               break;
-       };
+               saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
+       }
+
        videobuf_dvb_unregister(&dev->dvb);
        return 0;
 }
index 9322f44865b8341ee74976b76c0fb107e1bf0088..b1b01fa867203ff03a98673e3d7fddfc70e7334a 100644 (file)
@@ -161,152 +161,176 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
  * video_generic_ioctl (and maybe others).  userspace
  * copying is done already, arg is a kernel pointer.
  */
-static int ts_do_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, void *arg)
+
+static int empress_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
 {
-       struct saa7134_dev *dev = file->private_data;
-       struct v4l2_ext_controls *ctrls = arg;
-
-       if (debug > 1)
-               v4l_print_ioctl(dev->name,cmd);
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->driver, "saa7134");
-               strlcpy(cap->card, saa7134_boards[dev->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = SAA7134_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
-               return 0;
-       }
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       strcpy(cap->driver, "saa7134");
+       strlcpy(cap->card, saa7134_boards[dev->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->version = SAA7134_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
+       return 0;
+}
 
-       /* --- input switching --------------------------------------- */
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
+static int empress_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       if (i->index != 0)
+               return -EINVAL;
 
-               if (i->index != 0)
-                       return -EINVAL;
-               i->type = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(i->name,"CCIR656");
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = 0;
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               int *i = arg;
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       strcpy(i->name, "CCIR656");
 
-               if (*i != 0)
-                       return -EINVAL;
-               return 0;
-       }
-       /* --- capture ioctls ---------------------------------------- */
-
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               int index;
-
-               index = f->index;
-               if (index != 0)
-                       return -EINVAL;
-
-               memset(f,0,sizeof(*f));
-               f->index = index;
-               strlcpy(f->description, "MPEG TS", sizeof(f->description));
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               f->pixelformat = V4L2_PIX_FMT_MPEG;
-               return 0;
-       }
+       return 0;
+}
 
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
+static int empress_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
 
-               memset(f,0,sizeof(*f));
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+static int empress_s_input(struct file *file, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
 
-               saa7134_i2c_call_clients(dev, cmd, arg);
-               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-               f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
-               return 0;
-       }
+       return 0;
+}
 
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
+static int empress_enum_fmt_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index != 0)
+               return -EINVAL;
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                   return -EINVAL;
+       strlcpy(f->description, "MPEG TS", sizeof(f->description));
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
 
-               saa7134_i2c_call_clients(dev, cmd, arg);
-               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-               f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
-               return 0;
-       }
+       return 0;
+}
 
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(&dev->empress_tsq,arg);
+static int empress_g_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(&dev->empress_tsq,arg);
+       saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
 
-       case VIDIOC_QBUF:
-               return videobuf_qbuf(&dev->empress_tsq,arg);
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
 
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(&dev->empress_tsq,arg,
-                                     file->f_flags & O_NONBLOCK);
+       return 0;
+}
 
-       case VIDIOC_STREAMON:
-               return videobuf_streamon(&dev->empress_tsq);
+static int empress_s_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-       case VIDIOC_STREAMOFF:
-               return videobuf_streamoff(&dev->empress_tsq);
+       saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
 
-       case VIDIOC_QUERYCTRL:
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_CTRL:
-               return saa7134_common_ioctl(dev, cmd, arg);
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
 
-       case VIDIOC_S_EXT_CTRLS:
-               /* count == 0 is abused in saa6752hs.c, so that special
-                  case is handled here explicitly. */
-               if (ctrls->count == 0)
-                       return 0;
-               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-                       return -EINVAL;
-               saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
-               ts_init_encoder(dev);
-               return 0;
-       case VIDIOC_G_EXT_CTRLS:
-               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-                       return -EINVAL;
-               saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+       return 0;
+}
+
+
+static int empress_reqbufs(struct file *file, void *priv,
+                                       struct v4l2_requestbuffers *p)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       return videobuf_reqbufs(&dev->empress_tsq, p);
+}
+
+static int empress_querybuf(struct file *file, void *priv,
+                                       struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       return videobuf_querybuf(&dev->empress_tsq, b);
+}
+
+static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       return videobuf_qbuf(&dev->empress_tsq, b);
+}
+
+static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       return videobuf_dqbuf(&dev->empress_tsq, b,
+                               file->f_flags & O_NONBLOCK);
+}
+
+static int empress_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       return videobuf_streamon(&dev->empress_tsq);
+}
+
+static int empress_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       return videobuf_streamoff(&dev->empress_tsq);
+}
+
+static int empress_s_ext_ctrls(struct file *file, void *priv,
+                              struct v4l2_ext_controls *ctrls)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       /* count == 0 is abused in saa6752hs.c, so that special
+               case is handled here explicitly. */
+       if (ctrls->count == 0)
                return 0;
 
-       default:
-               return -ENOIOCTLCMD;
-       }
+       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+
+       saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
+       ts_init_encoder(dev);
+
        return 0;
 }
 
-static int ts_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg)
+static int empress_g_ext_ctrls(struct file *file, void *priv,
+                              struct v4l2_ext_controls *ctrls)
 {
-       return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+       saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+
+       return 0;
 }
 
 static const struct file_operations ts_fops =
@@ -317,7 +341,7 @@ static const struct file_operations ts_fops =
        .read     = ts_read,
        .poll     = ts_poll,
        .mmap     = ts_mmap,
-       .ioctl    = ts_ioctl,
+       .ioctl    = video_ioctl2,
        .llseek   = no_llseek,
 };
 
@@ -330,6 +354,29 @@ static struct video_device saa7134_empress_template =
        .type2         = 0 /* FIXME */,
        .fops          = &ts_fops,
        .minor         = -1,
+
+       .vidioc_querycap                = empress_querycap,
+       .vidioc_enum_fmt_cap            = empress_enum_fmt_cap,
+       .vidioc_s_fmt_cap               = empress_s_fmt_cap,
+       .vidioc_g_fmt_cap               = empress_g_fmt_cap,
+       .vidioc_reqbufs                 = empress_reqbufs,
+       .vidioc_querybuf                = empress_querybuf,
+       .vidioc_qbuf                    = empress_qbuf,
+       .vidioc_dqbuf                   = empress_dqbuf,
+       .vidioc_streamon                = empress_streamon,
+       .vidioc_streamoff               = empress_streamoff,
+       .vidioc_s_ext_ctrls             = empress_s_ext_ctrls,
+       .vidioc_g_ext_ctrls             = empress_g_ext_ctrls,
+       .vidioc_enum_input              = empress_enum_input,
+       .vidioc_g_input                 = empress_g_input,
+       .vidioc_s_input                 = empress_s_input,
+
+       .vidioc_queryctrl               = saa7134_queryctrl,
+       .vidioc_g_ctrl                  = saa7134_g_ctrl,
+       .vidioc_s_ctrl                  = saa7134_s_ctrl,
+
+       .tvnorms                        = SAA7134_NORMS,
+       .current_norm                   = V4L2_STD_PAL,
 };
 
 static void empress_signal_update(struct work_struct *work)
index 6deaad1a5480c34471c0b4a728719c3e4d452d0e..d3322c3018f2d6a7887584926005c025778f5b3d 100644 (file)
@@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client)
 {
        struct saa7134_dev *dev = client->adapter->algo_data;
        int tuner = dev->tuner_type;
-       int conf  = dev->tda9887_conf;
        struct tuner_setup tun_setup;
 
        d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
@@ -335,6 +334,7 @@ static int attach_inform(struct i2c_client *client)
                case 0x7a:
                case 0x47:
                case 0x71:
+               case 0x2d:
                {
                        struct IR_i2c *ir = i2c_get_clientdata(client);
                        d1printk("%s i2c IR detected (%s).\n",
@@ -360,7 +360,6 @@ static int attach_inform(struct i2c_client *client)
        }
 
        if (tuner != UNSET) {
-
                tun_setup.type = tuner;
                tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
                tun_setup.config = saa7134_boards[dev->board].tuner_config;
@@ -372,9 +371,18 @@ static int attach_inform(struct i2c_client *client)
 
                        client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
                }
+
+               if (tuner == TUNER_TDA9887) {
+                       struct v4l2_priv_tun_config tda9887_cfg;
+
+                       tda9887_cfg.tuner = TUNER_TDA9887;
+                       tda9887_cfg.priv = &dev->tda9887_conf;
+
+                       client->driver->command(client, TUNER_SET_CONFIG,
+                                               &tda9887_cfg);
+               }
        }
 
-       client->driver->command(client, TDA9887_SET_CONFIG, &conf);
 
        return 0;
 }
@@ -432,6 +440,7 @@ static char *i2c_devs[128] = {
        [ 0xa0 >> 1 ] = "eeprom",
        [ 0xc0 >> 1 ] = "tuner (analog)",
        [ 0x86 >> 1 ] = "tda9887",
+       [ 0x5a >> 1 ] = "remote control",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
index 3abaa1b8ac9d76b834b3eb61be7b1f337cd5ab9a..0db955c2d9b9e0983c55e1eeca336201fc708664 100644 (file)
@@ -49,9 +49,14 @@ module_param(repeat_delay, int, 0644);
 MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
 static int repeat_period = 33;
 module_param(repeat_period, int, 0644);
-MODULE_PARM_DESC(repeat_period, "repeat period between"
+MODULE_PARM_DESC(repeat_period, "repeat period between "
     "keypresses when key is down");
 
+static unsigned int disable_other_ir;
+module_param(disable_other_ir, int, 0644);
+MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
+    "alternative remotes from other manufacturers");
+
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
@@ -154,6 +159,45 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
+
+static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char data[12];
+       u32 gpio;
+
+       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+
+       /* rising SAA7134_GPIO_GPRESCAN reads the status */
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+       if (0x400000 & ~gpio)
+               return 0; /* No button press */
+
+       ir->c.addr = 0x5a >> 1;
+
+       if (12 != i2c_master_recv(&ir->c, data, 12)) {
+               i2cdprintk("read error\n");
+               return -EIO;
+       }
+       /* IR of this card normally decode signals NEC-standard from
+        * - Sven IHOO MT 5.1R remote. xxyye718
+        * - Sven DVD HD-10xx remote. xxyyf708
+        * - BBK ...
+        * - mayby others
+        * So, skip not our, if disable full codes mode.
+        */
+       if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
+               return 0;
+
+       *ir_key = data[9];
+       *ir_raw = data[9];
+
+       return 1;
+}
+
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
        struct card_ir *ir = dev->remote;
@@ -260,6 +304,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+       case SAA7134_BOARD_AVERMEDIA_M102:
                ir_codes     = ir_codes_avermedia;
                mask_keycode = 0x0007C8;
                mask_keydown = 0x000010;
@@ -287,6 +332,16 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
        case SAA7134_BOARD_BEHOLD_409FM:
+       case SAA7134_BOARD_BEHOLD_401:
+       case SAA7134_BOARD_BEHOLD_403:
+       case SAA7134_BOARD_BEHOLD_403FM:
+       case SAA7134_BOARD_BEHOLD_405:
+       case SAA7134_BOARD_BEHOLD_405FM:
+       case SAA7134_BOARD_BEHOLD_407:
+       case SAA7134_BOARD_BEHOLD_407FM:
+       case SAA7134_BOARD_BEHOLD_409:
+       case SAA7134_BOARD_BEHOLD_505FM:
+       case SAA7134_BOARD_BEHOLD_507_9FM:
                ir_codes     = ir_codes_manli;
                mask_keycode = 0x001f00;
                mask_keyup   = 0x004000;
@@ -457,6 +512,12 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
                ir->get_key   = get_key_hvr1110;
                ir->ir_codes  = ir_codes_hauppauge_new;
                break;
+       case SAA7134_BOARD_BEHOLD_607_9FM:
+       case SAA7134_BOARD_BEHOLD_M6:
+               snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
+               ir->get_key   = get_key_beholdm6xx;
+               ir->ir_codes  = ir_codes_behold;
+               break;
        default:
                dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
                break;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
deleted file mode 100644 (file)
index aedf046..0000000
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
- *
- * device driver for philips saa7134 based TV cards
- * oss dsp interface
- *
- * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *     2005 conversion to standalone module:
- *         Ricardo Cerqueira <v4l@cerqueira.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-
-#include "saa7134-reg.h"
-#include "saa7134.h"
-
-/* ------------------------------------------------------------------ */
-
-static unsigned int debug  = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages [oss]");
-
-static unsigned int rate  = 0;
-module_param(rate, int, 0444);
-MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
-
-static unsigned int dsp_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s).");
-module_param_array(dsp_nr,   int, NULL, 0444);
-
-static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s).");
-module_param_array(mixer_nr, int, NULL, 0444);
-
-#define dprintk(fmt, arg...)   if (debug) \
-       printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
-
-
-/* ------------------------------------------------------------------ */
-
-static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
-{
-       if (blksize < 0x100)
-               blksize = 0x100;
-       if (blksize > 0x10000)
-               blksize = 0x10000;
-
-       if (blocks < 2)
-               blocks = 2;
-       if ((blksize * blocks) > 1024*1024)
-               blocks = 1024*1024 / blksize;
-
-       dev->dmasound.blocks  = blocks;
-       dev->dmasound.blksize = blksize;
-       dev->dmasound.bufsize = blksize * blocks;
-
-       dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
-               blocks,blksize,blksize * blocks / 1024);
-       return 0;
-}
-
-static int dsp_buffer_init(struct saa7134_dev *dev)
-{
-       int err;
-
-       BUG_ON(!dev->dmasound.bufsize);
-       videobuf_dma_init(&dev->dmasound.dma);
-       err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
-                                      (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
-       if (0 != err)
-               return err;
-       return 0;
-}
-
-static int dsp_buffer_free(struct saa7134_dev *dev)
-{
-       BUG_ON(!dev->dmasound.blksize);
-       videobuf_dma_free(&dev->dmasound.dma);
-       dev->dmasound.blocks  = 0;
-       dev->dmasound.blksize = 0;
-       dev->dmasound.bufsize = 0;
-       return 0;
-}
-
-static void dsp_dma_start(struct saa7134_dev *dev)
-{
-       dev->dmasound.dma_blk     = 0;
-       dev->dmasound.dma_running = 1;
-       saa7134_set_dmabits(dev);
-}
-
-static void dsp_dma_stop(struct saa7134_dev *dev)
-{
-       dev->dmasound.dma_blk     = -1;
-       dev->dmasound.dma_running = 0;
-       saa7134_set_dmabits(dev);
-}
-
-static int dsp_rec_start(struct saa7134_dev *dev)
-{
-       int err, bswap, sign;
-       u32 fmt, control;
-       unsigned long flags;
-
-       /* prepare buffer */
-       if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma)))
-               return err;
-       if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
-               goto fail1;
-       if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
-                                             dev->dmasound.dma.sglist,
-                                             dev->dmasound.dma.sglen,
-                                             0)))
-               goto fail2;
-
-       /* sample format */
-       switch (dev->dmasound.afmt) {
-       case AFMT_U8:
-       case AFMT_S8:     fmt = 0x00;  break;
-       case AFMT_U16_LE:
-       case AFMT_U16_BE:
-       case AFMT_S16_LE:
-       case AFMT_S16_BE: fmt = 0x01;  break;
-       default:
-               err = -EINVAL;
-               goto fail2;
-       }
-
-       switch (dev->dmasound.afmt) {
-       case AFMT_S8:
-       case AFMT_S16_LE:
-       case AFMT_S16_BE: sign = 1; break;
-       default:          sign = 0; break;
-       }
-
-       switch (dev->dmasound.afmt) {
-       case AFMT_U16_BE:
-       case AFMT_S16_BE: bswap = 1; break;
-       default:          bswap = 0; break;
-       }
-
-       switch (dev->pci->device) {
-       case PCI_DEVICE_ID_PHILIPS_SAA7134:
-               if (1 == dev->dmasound.channels)
-                       fmt |= (1 << 3);
-               if (2 == dev->dmasound.channels)
-                       fmt |= (3 << 3);
-               if (sign)
-                       fmt |= 0x04;
-               fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
-
-               saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
-               saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
-               saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
-               saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
-
-               break;
-       case PCI_DEVICE_ID_PHILIPS_SAA7133:
-       case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               if (1 == dev->dmasound.channels)
-                       fmt |= (1 << 4);
-               if (2 == dev->dmasound.channels)
-                       fmt |= (2 << 4);
-               if (!sign)
-                       fmt |= 0x04;
-               saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
-               saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
-               break;
-       }
-       dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
-               dev->dmasound.afmt, dev->dmasound.channels, fmt,
-               bswap ? 'b' : '-');
-
-       /* dma: setup channel 6 (= AUDIO) */
-       control = SAA7134_RS_CONTROL_BURST_16 |
-               SAA7134_RS_CONTROL_ME |
-               (dev->dmasound.pt.dma >> 12);
-       if (bswap)
-               control |= SAA7134_RS_CONTROL_BSWAP;
-       saa_writel(SAA7134_RS_BA1(6),0);
-       saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
-       saa_writel(SAA7134_RS_PITCH(6),0);
-       saa_writel(SAA7134_RS_CONTROL(6),control);
-
-       /* start dma */
-       dev->dmasound.recording_on = 1;
-       spin_lock_irqsave(&dev->slock,flags);
-       dsp_dma_start(dev);
-       spin_unlock_irqrestore(&dev->slock,flags);
-       return 0;
-
- fail2:
-       saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
- fail1:
-       videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
-       return err;
-}
-
-static int dsp_rec_stop(struct saa7134_dev *dev)
-{
-       unsigned long flags;
-
-       dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
-
-       /* stop dma */
-       dev->dmasound.recording_on = 0;
-       spin_lock_irqsave(&dev->slock,flags);
-       dsp_dma_stop(dev);
-       spin_unlock_irqrestore(&dev->slock,flags);
-
-       /* unlock buffer */
-       saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
-       videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
-       return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int dsp_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct saa7134_dev *dev;
-       int err;
-
-       list_for_each_entry(dev, &saa7134_devlist, devlist)
-               if (dev->dmasound.minor_dsp == minor)
-                       goto found;
-       return -ENODEV;
- found:
-
-       mutex_lock(&dev->dmasound.lock);
-       err = -EBUSY;
-       if (dev->dmasound.users_dsp)
-               goto fail1;
-       dev->dmasound.users_dsp++;
-       file->private_data = dev;
-
-       dev->dmasound.afmt        = AFMT_U8;
-       dev->dmasound.channels    = 1;
-       dev->dmasound.read_count  = 0;
-       dev->dmasound.read_offset = 0;
-       dsp_buffer_conf(dev,PAGE_SIZE,64);
-       err = dsp_buffer_init(dev);
-       if (0 != err)
-               goto fail2;
-
-       mutex_unlock(&dev->dmasound.lock);
-       return 0;
-
- fail2:
-       dev->dmasound.users_dsp--;
- fail1:
-       mutex_unlock(&dev->dmasound.lock);
-       return err;
-}
-
-static int dsp_release(struct inode *inode, struct file *file)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       mutex_lock(&dev->dmasound.lock);
-       if (dev->dmasound.recording_on)
-               dsp_rec_stop(dev);
-       dsp_buffer_free(dev);
-       dev->dmasound.users_dsp--;
-       file->private_data = NULL;
-       mutex_unlock(&dev->dmasound.lock);
-       return 0;
-}
-
-static ssize_t dsp_read(struct file *file, char __user *buffer,
-                       size_t count, loff_t *ppos)
-{
-       struct saa7134_dev *dev = file->private_data;
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned int bytes;
-       unsigned long flags;
-       int err,ret = 0;
-
-       add_wait_queue(&dev->dmasound.wq, &wait);
-       mutex_lock(&dev->dmasound.lock);
-       while (count > 0) {
-               /* wait for data if needed */
-               if (0 == dev->dmasound.read_count) {
-                       if (!dev->dmasound.recording_on) {
-                               err = dsp_rec_start(dev);
-                               if (err < 0) {
-                                       if (0 == ret)
-                                               ret = err;
-                                       break;
-                               }
-                       }
-                       if (dev->dmasound.recording_on &&
-                           !dev->dmasound.dma_running) {
-                               /* recover from overruns */
-                               spin_lock_irqsave(&dev->slock,flags);
-                               dsp_dma_start(dev);
-                               spin_unlock_irqrestore(&dev->slock,flags);
-                       }
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (0 == ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       mutex_unlock(&dev->dmasound.lock);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (0 == dev->dmasound.read_count)
-                               schedule();
-                       set_current_state(TASK_RUNNING);
-                       mutex_lock(&dev->dmasound.lock);
-                       if (signal_pending(current)) {
-                               if (0 == ret)
-                                       ret = -EINTR;
-                               break;
-                       }
-               }
-
-               /* copy data to userspace */
-               bytes = count;
-               if (bytes > dev->dmasound.read_count)
-                       bytes = dev->dmasound.read_count;
-               if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
-                       bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
-               if (copy_to_user(buffer + ret,
-                                dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
-                                bytes)) {
-                       if (0 == ret)
-                               ret = -EFAULT;
-                       break;
-               }
-
-               ret   += bytes;
-               count -= bytes;
-               dev->dmasound.read_count  -= bytes;
-               dev->dmasound.read_offset += bytes;
-               if (dev->dmasound.read_offset == dev->dmasound.bufsize)
-                       dev->dmasound.read_offset = 0;
-       }
-       mutex_unlock(&dev->dmasound.lock);
-       remove_wait_queue(&dev->dmasound.wq, &wait);
-       return ret;
-}
-
-static ssize_t dsp_write(struct file *file, const char __user *buffer,
-                        size_t count, loff_t *ppos)
-{
-       return -EINVAL;
-}
-
-static const char *osspcm_ioctls[] = {
-       "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
-       "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
-       "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
-       "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
-       "SETDUPLEX", "GETODELAY"
-};
-#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
-
-static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
-{
-       char *dir;
-
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:              dir = "--"; break;
-       case _IOC_READ:              dir = "r-"; break;
-       case _IOC_WRITE:             dir = "-w"; break;
-       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-       default:                     dir = "??"; break;
-       }
-       switch (_IOC_TYPE(cmd)) {
-       case 'P':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
-                      name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
-                      osspcm_ioctls[_IOC_NR(cmd)] : "???");
-               break;
-       case 'M':
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
-                      name, cmd, dir, _IOC_NR(cmd));
-               break;
-       default:
-               printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-                      name, cmd, dir, _IOC_NR(cmd));
-       }
-}
-
-static int dsp_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg)
-{
-       struct saa7134_dev *dev = file->private_data;
-       void __user *argp = (void __user *) arg;
-       int __user *p = argp;
-       int val = 0;
-
-       if (debug > 1)
-               saa7134_oss_print_ioctl(dev->name,cmd);
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, p);
-       case SNDCTL_DSP_GETCAPS:
-               return 0;
-
-       case SNDCTL_DSP_SPEED:
-               if (get_user(val, p))
-                       return -EFAULT;
-               /* fall through */
-       case SOUND_PCM_READ_RATE:
-               return put_user(dev->dmasound.rate, p);
-
-       case SNDCTL_DSP_STEREO:
-               if (get_user(val, p))
-                       return -EFAULT;
-               mutex_lock(&dev->dmasound.lock);
-               dev->dmasound.channels = val ? 2 : 1;
-               if (dev->dmasound.recording_on) {
-                       dsp_rec_stop(dev);
-                       dsp_rec_start(dev);
-               }
-               mutex_unlock(&dev->dmasound.lock);
-               return put_user(dev->dmasound.channels-1, p);
-
-       case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (val != 1 && val != 2)
-                       return -EINVAL;
-               mutex_lock(&dev->dmasound.lock);
-               dev->dmasound.channels = val;
-               if (dev->dmasound.recording_on) {
-                       dsp_rec_stop(dev);
-                       dsp_rec_start(dev);
-               }
-               mutex_unlock(&dev->dmasound.lock);
-               /* fall through */
-       case SOUND_PCM_READ_CHANNELS:
-               return put_user(dev->dmasound.channels, p);
-
-       case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-               return put_user(AFMT_U8     | AFMT_S8     |
-                               AFMT_U16_LE | AFMT_U16_BE |
-                               AFMT_S16_LE | AFMT_S16_BE, p);
-
-       case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
-               if (get_user(val, p))
-                       return -EFAULT;
-               switch (val) {
-               case AFMT_QUERY:
-                       /* nothing to do */
-                       break;
-               case AFMT_U8:
-               case AFMT_S8:
-               case AFMT_U16_LE:
-               case AFMT_U16_BE:
-               case AFMT_S16_LE:
-               case AFMT_S16_BE:
-                       mutex_lock(&dev->dmasound.lock);
-                       dev->dmasound.afmt = val;
-                       if (dev->dmasound.recording_on) {
-                               dsp_rec_stop(dev);
-                               dsp_rec_start(dev);
-                       }
-                       mutex_unlock(&dev->dmasound.lock);
-                       return put_user(dev->dmasound.afmt, p);
-               default:
-                       return -EINVAL;
-               }
-
-       case SOUND_PCM_READ_BITS:
-               switch (dev->dmasound.afmt) {
-               case AFMT_U8:
-               case AFMT_S8:
-                       return put_user(8, p);
-               case AFMT_U16_LE:
-               case AFMT_U16_BE:
-               case AFMT_S16_LE:
-               case AFMT_S16_BE:
-                       return put_user(16, p);
-               default:
-                       return -EINVAL;
-               }
-
-       case SNDCTL_DSP_NONBLOCK:
-               file->f_flags |= O_NONBLOCK;
-               return 0;
-
-       case SNDCTL_DSP_RESET:
-               mutex_lock(&dev->dmasound.lock);
-               if (dev->dmasound.recording_on)
-                       dsp_rec_stop(dev);
-               mutex_unlock(&dev->dmasound.lock);
-               return 0;
-       case SNDCTL_DSP_GETBLKSIZE:
-               return put_user(dev->dmasound.blksize, p);
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (dev->dmasound.recording_on)
-                       return -EBUSY;
-               dsp_buffer_free(dev);
-               /* used to be arg >> 16 instead of val >> 16; fixed */
-               dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff);
-               dsp_buffer_init(dev);
-               return 0;
-
-       case SNDCTL_DSP_SYNC:
-               /* NOP */
-               return 0;
-
-       case SNDCTL_DSP_GETISPACE:
-       {
-               audio_buf_info info;
-               info.fragsize   = dev->dmasound.blksize;
-               info.fragstotal = dev->dmasound.blocks;
-               info.bytes      = dev->dmasound.read_count;
-               info.fragments  = info.bytes / info.fragsize;
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       default:
-               return -EINVAL;
-       }
-}
-
-static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct saa7134_dev *dev = file->private_data;
-       unsigned int mask = 0;
-
-       poll_wait(file, &dev->dmasound.wq, wait);
-
-       if (0 == dev->dmasound.read_count) {
-               mutex_lock(&dev->dmasound.lock);
-               if (!dev->dmasound.recording_on)
-                       dsp_rec_start(dev);
-               mutex_unlock(&dev->dmasound.lock);
-       } else
-               mask |= (POLLIN | POLLRDNORM);
-       return mask;
-}
-
-const struct file_operations saa7134_dsp_fops = {
-       .owner   = THIS_MODULE,
-       .open    = dsp_open,
-       .release = dsp_release,
-       .read    = dsp_read,
-       .write   = dsp_write,
-       .ioctl   = dsp_ioctl,
-       .poll    = dsp_poll,
-       .llseek  = no_llseek,
-};
-
-/* ------------------------------------------------------------------ */
-
-static int
-mixer_recsrc_7134(struct saa7134_dev *dev)
-{
-       int analog_io,rate;
-
-       switch (dev->dmasound.input) {
-       case TV:
-               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
-               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
-               break;
-       case LINE1:
-       case LINE2:
-       case LINE2_LEFT:
-               analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
-               rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
-               saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
-               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
-               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
-               break;
-       }
-       return 0;
-}
-
-static int
-mixer_recsrc_7133(struct saa7134_dev *dev)
-{
-       u32 anabar, xbarin;
-
-       xbarin = 0x03; // adc
-    anabar = 0;
-       switch (dev->dmasound.input) {
-       case TV:
-               xbarin = 0; // Demodulator
-       anabar = 2; // DACs
-               break;
-       case LINE1:
-               anabar = 0;  // aux1, aux1
-               break;
-       case LINE2:
-       case LINE2_LEFT:
-               anabar = 9;  // aux2, aux2
-               break;
-       }
-    /* output xbar always main channel */
-       saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10);
-       saa_dsp_writel(dev, 0x464 >> 2, xbarin);
-       saa_writel(0x594 >> 2, anabar);
-
-       return 0;
-}
-
-static int
-mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
-{
-       static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
-
-       dev->dmasound.count++;
-       dev->dmasound.input = src;
-       dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
-
-       switch (dev->pci->device) {
-       case PCI_DEVICE_ID_PHILIPS_SAA7134:
-               mixer_recsrc_7134(dev);
-               break;
-       case PCI_DEVICE_ID_PHILIPS_SAA7133:
-       case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               mixer_recsrc_7133(dev);
-               break;
-       }
-       return 0;
-}
-
-static int
-mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
-{
-       switch (dev->pci->device) {
-       case PCI_DEVICE_ID_PHILIPS_SAA7134:
-               switch (src) {
-               case TV:
-                       /* nothing */
-                       break;
-               case LINE1:
-                       saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
-                                  (100 == level) ? 0x00 : 0x10);
-                       break;
-               case LINE2:
-               case LINE2_LEFT:
-                       saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
-                                  (100 == level) ? 0x00 : 0x20);
-                       break;
-               }
-               break;
-       case PCI_DEVICE_ID_PHILIPS_SAA7133:
-       case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               /* nothing */
-               break;
-       }
-       return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct saa7134_dev *dev;
-
-       list_for_each_entry(dev, &saa7134_devlist, devlist)
-               if (dev->dmasound.minor_mixer == minor) {
-                       file->private_data = dev;
-                       return 0;
-               }
-       return -ENODEV;
-}
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
-       file->private_data = NULL;
-       return 0;
-}
-
-static int mixer_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg)
-{
-       struct saa7134_dev *dev = file->private_data;
-       enum saa7134_audio_in input;
-       int val,ret;
-       void __user *argp = (void __user *) arg;
-       int __user *p = argp;
-
-       if (debug > 1)
-               saa7134_oss_print_ioctl(dev->name,cmd);
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, p);
-       case SOUND_MIXER_INFO:
-       {
-               mixer_info info;
-               memset(&info,0,sizeof(info));
-               strlcpy(info.id,   "TV audio", sizeof(info.id));
-               strlcpy(info.name, dev->name,  sizeof(info.name));
-               info.modify_counter = dev->dmasound.count;
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       case SOUND_OLD_MIXER_INFO:
-       {
-               _old_mixer_info info;
-               memset(&info,0,sizeof(info));
-               strlcpy(info.id,   "TV audio", sizeof(info.id));
-               strlcpy(info.name, dev->name,  sizeof(info.name));
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       case MIXER_READ(SOUND_MIXER_CAPS):
-               return put_user(SOUND_CAP_EXCL_INPUT, p);
-       case MIXER_READ(SOUND_MIXER_STEREODEVS):
-               return put_user(0, p);
-       case MIXER_READ(SOUND_MIXER_RECMASK):
-       case MIXER_READ(SOUND_MIXER_DEVMASK):
-               val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
-               if (32000 == dev->dmasound.rate)
-                       val |= SOUND_MASK_VIDEO;
-               return put_user(val, p);
-
-       case MIXER_WRITE(SOUND_MIXER_RECSRC):
-               if (get_user(val, p))
-                       return -EFAULT;
-               input = dev->dmasound.input;
-               if (32000 == dev->dmasound.rate  &&
-                   val & SOUND_MASK_VIDEO  &&  dev->dmasound.input != TV)
-                       input = TV;
-               if (val & SOUND_MASK_LINE1  &&  dev->dmasound.input != LINE1)
-                       input = LINE1;
-               if (val & SOUND_MASK_LINE2  &&  dev->dmasound.input != LINE2)
-                       input = LINE2;
-               if (input != dev->dmasound.input)
-                       mixer_recsrc(dev,input);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_RECSRC):
-               switch (dev->dmasound.input) {
-               case TV:    ret = SOUND_MASK_VIDEO; break;
-               case LINE1: ret = SOUND_MASK_LINE1; break;
-               case LINE2: ret = SOUND_MASK_LINE2; break;
-               default:    ret = 0;
-               }
-               return put_user(ret, p);
-
-       case MIXER_WRITE(SOUND_MIXER_VIDEO):
-       case MIXER_READ(SOUND_MIXER_VIDEO):
-               if (32000 != dev->dmasound.rate)
-                       return -EINVAL;
-               return put_user(100 | 100 << 8, p);
-
-       case MIXER_WRITE(SOUND_MIXER_LINE1):
-               if (get_user(val, p))
-                       return -EFAULT;
-               val &= 0xff;
-               val = (val <= 50) ? 50 : 100;
-               dev->dmasound.line1 = val;
-               mixer_level(dev,LINE1,dev->dmasound.line1);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_LINE1):
-               return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
-
-       case MIXER_WRITE(SOUND_MIXER_LINE2):
-               if (get_user(val, p))
-                       return -EFAULT;
-               val &= 0xff;
-               val = (val <= 50) ? 50 : 100;
-               dev->dmasound.line2 = val;
-               mixer_level(dev,LINE2,dev->dmasound.line2);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_LINE2):
-               return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
-
-       default:
-               return -EINVAL;
-       }
-}
-
-const struct file_operations saa7134_mixer_fops = {
-       .owner   = THIS_MODULE,
-       .open    = mixer_open,
-       .release = mixer_release,
-       .ioctl   = mixer_ioctl,
-       .llseek  = no_llseek,
-};
-
-/* ------------------------------------------------------------------ */
-
-static irqreturn_t saa7134_oss_irq(int irq, void *dev_id)
-{
-       struct saa7134_dmasound *dmasound = dev_id;
-       struct saa7134_dev *dev = dmasound->priv_data;
-       unsigned long report, status;
-       int loop, handled = 0;
-
-       for (loop = 0; loop < 10; loop++) {
-               report = saa_readl(SAA7134_IRQ_REPORT);
-               status = saa_readl(SAA7134_IRQ_STATUS);
-
-               if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
-                       handled = 1;
-                       saa_writel(SAA7134_IRQ_REPORT,report);
-                       saa7134_irq_oss_done(dev, status);
-               } else {
-                       goto out;
-               }
-       }
-
-       if (loop == 10) {
-               dprintk("error! looping IRQ!");
-       }
-out:
-       return IRQ_RETVAL(handled);
-}
-
-int saa7134_oss_init1(struct saa7134_dev *dev)
-{
-
-       if ((request_irq(dev->pci->irq, saa7134_oss_irq,
-                        IRQF_SHARED | IRQF_DISABLED, dev->name,
-                       (void*) &dev->dmasound)) < 0)
-               return -1;
-
-       /* general */
-       mutex_init(&dev->dmasound.lock);
-       init_waitqueue_head(&dev->dmasound.wq);
-
-       switch (dev->pci->device) {
-       case PCI_DEVICE_ID_PHILIPS_SAA7133:
-       case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               saa_writel(0x588 >> 2, 0x00000fff);
-               saa_writel(0x58c >> 2, 0x00543210);
-               saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
-               break;
-       }
-
-       /* dsp */
-       dev->dmasound.rate = 32000;
-       if (rate)
-               dev->dmasound.rate = rate;
-       dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
-
-       /* mixer */
-       dev->dmasound.line1 = 50;
-       dev->dmasound.line2 = 50;
-       mixer_level(dev,LINE1,dev->dmasound.line1);
-       mixer_level(dev,LINE2,dev->dmasound.line2);
-       mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
-
-       return 0;
-}
-
-int saa7134_oss_fini(struct saa7134_dev *dev)
-{
-       /* nothing */
-       return 0;
-}
-
-void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
-{
-       int next_blk, reg = 0;
-
-       spin_lock(&dev->slock);
-       if (UNSET == dev->dmasound.dma_blk) {
-               dprintk("irq: recording stopped\n");
-               goto done;
-       }
-       if (0 != (status & 0x0f000000))
-               dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
-       if (0 == (status & 0x10000000)) {
-               /* odd */
-               if (0 == (dev->dmasound.dma_blk & 0x01))
-                       reg = SAA7134_RS_BA1(6);
-       } else {
-               /* even */
-               if (1 == (dev->dmasound.dma_blk & 0x01))
-                       reg = SAA7134_RS_BA2(6);
-       }
-       if (0 == reg) {
-               dprintk("irq: field oops [%s]\n",
-                       (status & 0x10000000) ? "even" : "odd");
-               goto done;
-       }
-       if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
-               dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
-                       dev->dmasound.bufsize);
-               dsp_dma_stop(dev);
-               goto done;
-       }
-
-       /* next block addr */
-       next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
-       saa_writel(reg,next_blk * dev->dmasound.blksize);
-       if (debug > 2)
-               dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
-                       (status & 0x10000000) ? "even" : "odd ", next_blk,
-                       next_blk * dev->dmasound.blksize);
-
-       /* update status & wake waiting readers */
-       dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
-       dev->dmasound.read_count += dev->dmasound.blksize;
-       wake_up(&dev->dmasound.wq);
-
- done:
-       spin_unlock(&dev->slock);
-}
-
-static int saa7134_dsp_create(struct saa7134_dev *dev)
-{
-       int err;
-
-       err = dev->dmasound.minor_dsp =
-               register_sound_dsp(&saa7134_dsp_fops,
-                                  dsp_nr[dev->nr]);
-       if (err < 0) {
-               goto fail;
-       }
-       printk(KERN_INFO "%s: registered device dsp%d\n",
-              dev->name,dev->dmasound.minor_dsp >> 4);
-
-       err = dev->dmasound.minor_mixer =
-               register_sound_mixer(&saa7134_mixer_fops,
-                                    mixer_nr[dev->nr]);
-       if (err < 0)
-               goto fail;
-       printk(KERN_INFO "%s: registered device mixer%d\n",
-              dev->name,dev->dmasound.minor_mixer >> 4);
-
-       return 0;
-
-fail:
-       unregister_sound_dsp(dev->dmasound.minor_dsp);
-       return 0;
-
-
-}
-
-static int oss_device_init(struct saa7134_dev *dev)
-{
-       dev->dmasound.priv_data = dev;
-       saa7134_oss_init1(dev);
-       saa7134_dsp_create(dev);
-       return 1;
-}
-
-static int oss_device_exit(struct saa7134_dev *dev)
-{
-
-       unregister_sound_mixer(dev->dmasound.minor_mixer);
-       unregister_sound_dsp(dev->dmasound.minor_dsp);
-
-       saa7134_oss_fini(dev);
-
-       if (dev->pci->irq > 0) {
-               synchronize_irq(dev->pci->irq);
-               free_irq(dev->pci->irq,&dev->dmasound);
-       }
-
-       dev->dmasound.priv_data = NULL;
-       return 1;
-}
-
-static int saa7134_oss_init(void)
-{
-       struct saa7134_dev *dev = NULL;
-       struct list_head *list;
-
-       if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
-               saa7134_dmasound_init = oss_device_init;
-               saa7134_dmasound_exit = oss_device_exit;
-       } else {
-               printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n");
-               return -EBUSY;
-       }
-
-       printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n");
-
-
-       list_for_each(list,&saa7134_devlist) {
-               dev = list_entry(list, struct saa7134_dev, devlist);
-               if (dev->dmasound.priv_data == NULL) {
-                       oss_device_init(dev);
-               } else {
-                       printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name);
-                       return -EBUSY;
-               }
-       }
-
-       if (dev == NULL)
-               printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n");
-
-       return 0;
-
-}
-
-static void saa7134_oss_exit(void)
-{
-       struct saa7134_dev *dev;
-
-       list_for_each_entry(dev, &saa7134_devlist, devlist) {
-               /* Device isn't registered by OSS, probably ALSA's */
-               if (!dev->dmasound.minor_dsp)
-                       continue;
-
-               oss_device_exit(dev);
-       }
-
-       saa7134_dmasound_init = NULL;
-       saa7134_dmasound_exit = NULL;
-
-       printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
-
-       return;
-}
-
-/* We initialize this late, to make sure the sound system is up and running */
-late_initcall(saa7134_oss_init);
-module_exit(saa7134_oss_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 4b63ad3e84664ec566a4b5f22c7e87690603434c..f1b8fcaeb43acc6ecddf2ae62c25aefafb117a76 100644 (file)
@@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev,
 {
 
        dprintk("buffer_activate [%p]",buf);
-       buf->vb.state = STATE_ACTIVE;
+       buf->vb.state = VIDEOBUF_ACTIVE;
        buf->top_seen = 0;
 
        if (NULL == next)
@@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                saa7134_dma_free(q,buf);
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
                buf->vb.width  = llength;
@@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
        saa_writel(SAA7134_RS_CONTROL(5),control);
 
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
        buf->vb.field = field;
        return 0;
@@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
                        if ((status & 0x100000) != 0x100000)
                                goto done;
                }
-               saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
+               saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE);
        }
        saa7134_buffer_next(dev,&dev->ts_q);
 
index f8e304c7623277b0aa43354e01459aeace8f72a2..4e9810469ae309c0ac41917c2764a7977301658e 100644 (file)
@@ -163,32 +163,6 @@ static struct saa7134_tvaudio tvaudio[] = {
 
 /* ------------------------------------------------------------------ */
 
-static void tvaudio_init(struct saa7134_dev *dev)
-{
-       int clock = saa7134_boards[dev->board].audio_clock;
-
-       if (UNSET != audio_clock_override)
-               clock = audio_clock_override;
-
-       /* init all audio registers */
-       saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
-       if (need_resched())
-               schedule();
-       else
-               udelay(10);
-
-       saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
-       saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
-       saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
-       /* frame locked audio is mandatory for NICAM */
-       saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
-
-       saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
-       saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
-       saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
-       saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
-}
-
 static u32 tvaudio_carr2reg(u32 carrier)
 {
        u64 a = carrier;
@@ -517,9 +491,13 @@ static int tvaudio_thread(void *data)
                dev->thread.scan1 = dev->thread.scan2;
                dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
                dev->tvaudio  = NULL;
-               tvaudio_init(dev);
+
+               saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
+               saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
+
                if (dev->ctl_automute)
                        dev->automute = 1;
+
                mute_input_7134(dev);
 
                /* give the tuner some time */
@@ -784,27 +762,15 @@ static int mute_input_7133(struct saa7134_dev *dev)
 static int tvaudio_thread_ddep(void *data)
 {
        struct saa7134_dev *dev = data;
-       u32 value, norms, clock;
+       u32 value, norms;
 
 
        set_freezable();
-
-       clock = saa7134_boards[dev->board].audio_clock;
-       if (UNSET != audio_clock_override)
-               clock = audio_clock_override;
-       saa_writel(0x598 >> 2, clock);
-
-       /* unmute */
-       saa_dsp_writel(dev, 0x474 >> 2, 0x00);
-       saa_dsp_writel(dev, 0x450 >> 2, 0x00);
-
        for (;;) {
                tvaudio_sleep(dev,-1);
                if (kthread_should_stop())
                        goto done;
-
        restart:
-
                try_to_freeze();
 
                dev->thread.scan1 = dev->thread.scan2;
@@ -978,6 +944,38 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
        return retval;
 }
 
+void saa7134_tvaudio_init(struct saa7134_dev *dev)
+{
+       int clock = saa7134_boards[dev->board].audio_clock;
+
+       if (UNSET != audio_clock_override)
+               clock = audio_clock_override;
+
+       switch (dev->pci->device) {
+       case PCI_DEVICE_ID_PHILIPS_SAA7134:
+               /* init all audio registers */
+               saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
+               if (need_resched())
+                       schedule();
+               else
+                       udelay(10);
+
+               saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
+               saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
+               saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
+               /* frame locked audio is mandatory for NICAM */
+               saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
+               saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
+               saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
+               break;
+       case PCI_DEVICE_ID_PHILIPS_SAA7133:
+       case PCI_DEVICE_ID_PHILIPS_SAA7135:
+               saa_writel(0x598 >> 2, clock);
+               saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+               saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+       }
+}
+
 int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 {
        int (*my_thread)(void *data) = NULL;
@@ -994,6 +992,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 
        dev->thread.thread = NULL;
        if (my_thread) {
+               saa7134_tvaudio_init(dev);
                /* start tvaudio thread */
                dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
                if (IS_ERR(dev->thread.thread)) {
index 81a2aedeff5c4d6218fdb94baece6850edac2ddb..f0d5ed9c2b0666e1152611f3325f89a6d8914182 100644 (file)
@@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev,
        unsigned long control,base;
 
        dprintk("buffer_activate [%p]\n",buf);
-       buf->vb.state = STATE_ACTIVE;
+       buf->vb.state = VIDEOBUF_ACTIVE;
        buf->top_seen = 0;
 
        task_init(dev,buf,TASK_A);
@@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q,
        if (buf->vb.size != size)
                saa7134_dma_free(q,buf);
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
                buf->vb.width  = llength;
@@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                if (err)
                        goto oops;
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
        buf->vb.field = field;
        return 0;
@@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
                        goto done;
 
                dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
-               saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE);
+               saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE);
        }
        saa7134_buffer_next(dev,&dev->vbi_q);
 
index 6396d9b5c0636ced4538fc47460078b54ec0c6d3..1184d359e848be291d62ac6786f0526845f15d1c 100644 (file)
@@ -38,7 +38,7 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int video_debug   = 0;
+unsigned int video_debug;
 static unsigned int gbuffers      = 8;
 static unsigned int noninterlaced = 0;
 static unsigned int gbufsize      = 720*576*4;
@@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644);
 MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
 
 
-#define dprintk(fmt, arg...)   if (video_debug) \
+#define dprintk(fmt, arg...)   if (video_debug&0x04) \
        printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
 
 /* ------------------------------------------------------------------ */
@@ -540,9 +540,8 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 
 /* ------------------------------------------------------------------ */
 
-void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 {
-
        dprintk("set tv norm = %s\n",norm->name);
        dev->tvnorm = norm;
 
@@ -561,7 +560,6 @@ void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
        dev->crop_current = dev->crop_defrect;
 
        saa7134_set_tvnorm_hw(dev);
-
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
@@ -945,7 +943,7 @@ static int buffer_activate(struct saa7134_dev *dev,
        unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
 
        dprintk("buffer_activate buf=%p\n",buf);
-       buf->vb.state = STATE_ACTIVE;
+       buf->vb.state = VIDEOBUF_ACTIVE;
        buf->top_seen = 0;
 
        set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
@@ -1054,7 +1052,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                saa7134_dma_free(q,buf);
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
                buf->vb.width  = fh->width;
@@ -1074,7 +1072,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                if (err)
                        goto oops;
        }
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
        return 0;
 
@@ -1119,8 +1117,10 @@ static struct videobuf_queue_ops video_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
+int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
 {
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
        const struct v4l2_queryctrl* ctrl;
 
        ctrl = ctrl_by_id(c->id);
@@ -1165,17 +1165,27 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_ctrl);
 
-static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                      struct v4l2_control *c)
+int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
 {
        const struct v4l2_queryctrl* ctrl;
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
        unsigned long flags;
        int restart_overlay = 0;
+       int err = -EINVAL;
+
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
+
+       mutex_lock(&dev->lock);
 
        ctrl = ctrl_by_id(c->id);
        if (NULL == ctrl)
-               return -EINVAL;
+               goto error;
+
        dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_BOOLEAN:
@@ -1236,18 +1246,26 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                restart_overlay = 1;
                break;
        case V4L2_CID_PRIVATE_AUTOMUTE:
+       {
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv = &dev->tda9887_conf;
+
                dev->ctl_automute = c->value;
                if (dev->tda9887_conf) {
                        if (dev->ctl_automute)
                                dev->tda9887_conf |= TDA9887_AUTOMUTE;
                        else
                                dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
-                       saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG,
-                                                &dev->tda9887_conf);
+
+                       saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+                                                &tda9887_cfg);
                }
                break;
+       }
        default:
-               return -EINVAL;
+               goto error;
        }
        if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock,flags);
@@ -1255,8 +1273,13 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
                start_preview(dev,fh);
                spin_unlock_irqrestore(&dev->slock,flags);
        }
-       return 0;
+       err = 0;
+
+error:
+       mutex_unlock(&dev->lock);
+       return err;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_ctrl);
 
 /* ------------------------------------------------------------------ */
 
@@ -1413,8 +1436,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                return POLLERR;
 
        poll_wait(file, &buf->done, wait);
-       if (buf->state == STATE_DONE ||
-           buf->state == STATE_ERROR)
+       if (buf->state == VIDEOBUF_DONE ||
+           buf->state == VIDEOBUF_ERROR)
                return POLLIN|POLLRDNORM;
        return 0;
 }
@@ -1478,8 +1501,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
 
 /* ------------------------------------------------------------------ */
 
-static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
+                                               struct v4l2_format *f)
 {
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
        struct saa7134_tvnorm *norm = dev->tvnorm;
 
        f->fmt.vbi.sampling_rate = 6750000 * 4;
@@ -1492,837 +1518,805 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
        f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
        f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
 
+       return 0;
 }
 
-static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                        struct v4l2_format *f)
+static int saa7134_g_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
-               f->fmt.pix.width        = fh->width;
-               f->fmt.pix.height       = fh->height;
-               f->fmt.pix.field        = fh->cap.field;
-               f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.width * fh->fmt->depth) >> 3;
-               f->fmt.pix.sizeimage =
-                       f->fmt.pix.height * f->fmt.pix.bytesperline;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               if (saa7134_no_overlay > 0) {
-                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-                       return -EINVAL;
-               }
-               f->fmt.win = fh->win;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               saa7134_vbi_fmt(dev,f);
-               return 0;
-       default:
-               return -EINVAL;
-       }
+       struct saa7134_fh *fh = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->cap.field;
+       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       return 0;
 }
 
-static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                          struct v4l2_format *f)
+static int saa7134_g_fmt_overlay(struct file *file, void *priv,
+                               struct v4l2_format *f)
 {
-       int err;
+       struct saa7134_fh *fh = priv;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               struct saa7134_format *fmt;
-               enum v4l2_field field;
-               unsigned int maxw, maxh;
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
+       }
+       f->fmt.win = fh->win;
 
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
+       return 0;
+}
 
-               field = f->fmt.pix.field;
-               maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
-               maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+static int saa7134_try_fmt_cap(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_format *fmt;
+       enum v4l2_field field;
+       unsigned int maxw, maxh;
 
-               if (V4L2_FIELD_ANY == field) {
-                       field = (f->fmt.pix.height > maxh/2)
-                               ? V4L2_FIELD_INTERLACED
-                               : V4L2_FIELD_BOTTOM;
-               }
-               switch (field) {
-               case V4L2_FIELD_TOP:
-               case V4L2_FIELD_BOTTOM:
-                       maxh = maxh / 2;
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       break;
-               default:
-                       return -EINVAL;
-               }
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
 
-               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;
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.width * fmt->depth) >> 3;
-               f->fmt.pix.sizeimage =
-                       f->fmt.pix.height * f->fmt.pix.bytesperline;
+       field = f->fmt.pix.field;
+       maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+       maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
 
-               return 0;
+       if (V4L2_FIELD_ANY == field) {
+               field = (f->fmt.pix.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
        }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               if (saa7134_no_overlay > 0) {
-                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-                       return -EINVAL;
-               }
-               err = verify_preview(dev,&f->fmt.win);
-               if (0 != err)
-                       return err;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               saa7134_vbi_fmt(dev,f);
-               return 0;
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
        default:
                return -EINVAL;
        }
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.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;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
 }
 
-static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-                        struct v4l2_format *f)
+static int saa7134_try_fmt_overlay(struct file *file, void *priv,
+                                               struct v4l2_format *f)
 {
-       unsigned long flags;
-       int err;
-
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               err = saa7134_try_fmt(dev,fh,f);
-               if (0 != err)
-                       return err;
-
-               fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
-               fh->width     = f->fmt.pix.width;
-               fh->height    = f->fmt.pix.height;
-               fh->cap.field = f->fmt.pix.field;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               if (saa7134_no_overlay > 0) {
-                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-                       return -EINVAL;
-               }
-               err = verify_preview(dev,&f->fmt.win);
-               if (0 != err)
-                       return err;
-
-               mutex_lock(&dev->lock);
-               fh->win    = f->fmt.win;
-               fh->nclips = f->fmt.win.clipcount;
-               if (fh->nclips > 8)
-                       fh->nclips = 8;
-               if (copy_from_user(fh->clips,f->fmt.win.clips,
-                                  sizeof(struct v4l2_clip)*fh->nclips)) {
-                       mutex_unlock(&dev->lock);
-                       return -EFAULT;
-               }
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (res_check(fh, RESOURCE_OVERLAY)) {
-                       spin_lock_irqsave(&dev->slock,flags);
-                       stop_preview(dev,fh);
-                       start_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-               }
-               mutex_unlock(&dev->lock);
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               saa7134_vbi_fmt(dev,f);
-               return 0;
-       default:
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
+
+       return verify_preview(dev, &f->fmt.win);
 }
 
-int saa7134_common_ioctl(struct saa7134_dev *dev,
-                        unsigned int cmd, void *arg)
+static int saa7134_s_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
+       struct saa7134_fh *fh = priv;
        int err;
 
-       switch (cmd) {
-       case VIDIOC_QUERYCTRL:
-       {
-               const struct v4l2_queryctrl *ctrl;
-               struct v4l2_queryctrl *c = arg;
+       err = saa7134_try_fmt_cap(file, priv, f);
+       if (0 != err)
+               return err;
 
-               if ((c->id <  V4L2_CID_BASE ||
-                    c->id >= V4L2_CID_LASTP1) &&
-                   (c->id <  V4L2_CID_PRIVATE_BASE ||
-                    c->id >= V4L2_CID_PRIVATE_LASTP1))
-                       return -EINVAL;
-               ctrl = ctrl_by_id(c->id);
-               *c = (NULL != ctrl) ? *ctrl : no_ctrl;
-               return 0;
+       fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->width     = f->fmt.pix.width;
+       fh->height    = f->fmt.pix.height;
+       fh->cap.field = f->fmt.pix.field;
+       return 0;
+}
+
+static int saa7134_s_fmt_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int err;
+       unsigned int flags;
+
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
        }
-       case VIDIOC_G_CTRL:
-               return get_control(dev,arg);
-       case VIDIOC_S_CTRL:
-       {
-               mutex_lock(&dev->lock);
-               err = set_control(dev,NULL,arg);
-               mutex_unlock(&dev->lock);
+       err = verify_preview(dev, &f->fmt.win);
+       if (0 != err)
                return err;
-       }
-       /* --- input switching --------------------------------------- */
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-               unsigned int n;
 
-               n = i->index;
-               if (n >= SAA7134_INPUT_MAX)
-                       return -EINVAL;
-               if (NULL == card_in(dev,i->index).name)
-                       return -EINVAL;
-               memset(i,0,sizeof(*i));
-               i->index = n;
-               i->type  = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(i->name,card_in(dev,n).name);
-               if (card_in(dev,n).tv)
-                       i->type = V4L2_INPUT_TYPE_TUNER;
-               i->audioset = 1;
-               if (n == dev->ctl_input) {
-                       int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
-                       int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
-
-                       if (0 != (v1 & 0x40))
-                               i->status |= V4L2_IN_ST_NO_H_LOCK;
-                       if (0 != (v2 & 0x40))
-                               i->status |= V4L2_IN_ST_NO_SYNC;
-                       if (0 != (v2 & 0x0e))
-                               i->status |= V4L2_IN_ST_MACROVISION;
-               }
-               for (n = 0; n < TVNORMS; n++)
-                       i->std |= tvnorms[n].id;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = dev->ctl_input;
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               int *i = arg;
+       mutex_lock(&dev->lock);
 
-               if (*i < 0  ||  *i >= SAA7134_INPUT_MAX)
-                       return -EINVAL;
-               if (NULL == card_in(dev,*i).name)
-                       return -EINVAL;
-               mutex_lock(&dev->lock);
-               video_mux(dev,*i);
+       fh->win    = f->fmt.win;
+       fh->nclips = f->fmt.win.clipcount;
+
+       if (fh->nclips > 8)
+               fh->nclips = 8;
+
+       if (copy_from_user(fh->clips, f->fmt.win.clips,
+                          sizeof(struct v4l2_clip)*fh->nclips)) {
                mutex_unlock(&dev->lock);
-               return 0;
+               return -EFAULT;
        }
 
+       if (res_check(fh, RESOURCE_OVERLAY)) {
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev, fh);
+               start_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
        }
+
+       mutex_unlock(&dev->lock);
        return 0;
 }
-EXPORT_SYMBOL(saa7134_common_ioctl);
 
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others).  userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c)
 {
-       struct saa7134_fh *fh = file->private_data;
+       const struct v4l2_queryctrl *ctrl;
+
+       if ((c->id <  V4L2_CID_BASE ||
+            c->id >= V4L2_CID_LASTP1) &&
+           (c->id <  V4L2_CID_PRIVATE_BASE ||
+            c->id >= V4L2_CID_PRIVATE_LASTP1))
+               return -EINVAL;
+       ctrl = ctrl_by_id(c->id);
+       *c = (NULL != ctrl) ? *ctrl : no_ctrl;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_queryctrl);
+
+static int saa7134_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       unsigned int n;
+
+       n = i->index;
+       if (n >= SAA7134_INPUT_MAX)
+               return -EINVAL;
+       if (NULL == card_in(dev, i->index).name)
+               return -EINVAL;
+       memset(i, 0, sizeof(*i));
+       i->index = n;
+       i->type  = V4L2_INPUT_TYPE_CAMERA;
+       strcpy(i->name, card_in(dev, n).name);
+       if (card_in(dev, n).tv)
+               i->type = V4L2_INPUT_TYPE_TUNER;
+       i->audioset = 1;
+       if (n == dev->ctl_input) {
+               int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+               int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+               if (0 != (v1 & 0x40))
+                       i->status |= V4L2_IN_ST_NO_H_LOCK;
+               if (0 != (v2 & 0x40))
+                       i->status |= V4L2_IN_ST_NO_SYNC;
+               if (0 != (v2 & 0x0e))
+                       i->status |= V4L2_IN_ST_MACROVISION;
+       }
+       i->std = SAA7134_NORMS;
+       return 0;
+}
+
+static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       *i = dev->ctl_input;
+       return 0;
+}
+
+static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
-       unsigned long flags;
        int err;
 
-       if (video_debug > 1)
-               v4l_print_ioctl(dev->name,cmd);
-
-       switch (cmd) {
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-               err = v4l2_prio_check(&dev->prio,&fh->prio);
-               if (0 != err)
-                       return err;
-       }
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-               unsigned int tuner_type = dev->tuner_type;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->driver, "saa7134");
-               strlcpy(cap->card, saa7134_boards[dev->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = SAA7134_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_VBI_CAPTURE |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING |
-                       V4L2_CAP_TUNER;
-               if (saa7134_no_overlay <= 0) {
-                       cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
-               }
+       if (i < 0  ||  i >= SAA7134_INPUT_MAX)
+               return -EINVAL;
+       if (NULL == card_in(dev, i).name)
+               return -EINVAL;
+       mutex_lock(&dev->lock);
+       video_mux(dev, i);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
 
-               if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
-                       cap->capabilities &= ~V4L2_CAP_TUNER;
+static int saa7134_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
+       unsigned int tuner_type = dev->tuner_type;
+
+       strcpy(cap->driver, "saa7134");
+       strlcpy(cap->card, saa7134_boards[dev->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->version = SAA7134_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_VBI_CAPTURE |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING |
+               V4L2_CAP_TUNER;
+       if (saa7134_no_overlay <= 0)
+               cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+       if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+               cap->capabilities &= ~V4L2_CAP_TUNER;
                return 0;
-       }
+}
 
-       /* --- tv standards ------------------------------------------ */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-               unsigned int i;
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       unsigned long flags;
+       unsigned int i;
+       v4l2_std_id fixup;
+       int err;
 
-               i = e->index;
-               if (i >= TVNORMS)
-                       return -EINVAL;
-               err = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                              tvnorms[e->index].name);
-               e->index = i;
-               if (err < 0)
-                       return err;
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               *id = dev->tvnorm->id;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               unsigned int i;
-               v4l2_std_id fixup;
+       for (i = 0; i < TVNORMS; i++)
+               if (*id == tvnorms[i].id)
+                       break;
 
+       if (i == TVNORMS)
                for (i = 0; i < TVNORMS; i++)
-                       if (*id == tvnorms[i].id)
+                       if (*id & tvnorms[i].id)
                                break;
-               if (i == TVNORMS)
-                       for (i = 0; i < TVNORMS; i++)
-                               if (*id & tvnorms[i].id)
-                                       break;
-               if (i == TVNORMS)
-                       return -EINVAL;
-               if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
-                       if (secam[0] == 'L' || secam[0] == 'l') {
-                               if (secam[1] == 'C' || secam[1] == 'c')
-                                       fixup = V4L2_STD_SECAM_LC;
-                               else
-                                       fixup = V4L2_STD_SECAM_L;
-                       } else {
-                               if (secam[0] == 'D' || secam[0] == 'd')
-                                       fixup = V4L2_STD_SECAM_DK;
-                               else
-                                       fixup = V4L2_STD_SECAM;
-                       }
-                       for (i = 0; i < TVNORMS; i++)
-                               if (fixup == tvnorms[i].id)
-                                       break;
+       if (i == TVNORMS)
+               return -EINVAL;
+
+       if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+               if (secam[0] == 'L' || secam[0] == 'l') {
+                       if (secam[1] == 'C' || secam[1] == 'c')
+                               fixup = V4L2_STD_SECAM_LC;
+                       else
+                               fixup = V4L2_STD_SECAM_L;
+               } else {
+                       if (secam[0] == 'D' || secam[0] == 'd')
+                               fixup = V4L2_STD_SECAM_DK;
+                       else
+                               fixup = V4L2_STD_SECAM;
                }
-               mutex_lock(&dev->lock);
-               if (res_check(fh, RESOURCE_OVERLAY)) {
-                       spin_lock_irqsave(&dev->slock,flags);
-                       stop_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock, flags);
-
-                       set_tvnorm(dev,&tvnorms[i]);
-
-                       spin_lock_irqsave(&dev->slock, flags);
-                       start_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-               } else
-                       set_tvnorm(dev,&tvnorms[i]);
-               saa7134_tvaudio_do_scan(dev);
-               mutex_unlock(&dev->lock);
-               return 0;
+               for (i = 0; i < TVNORMS; i++)
+                       if (fixup == tvnorms[i].id)
+                               break;
        }
 
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cap = arg;
+       *id = tvnorms[i].id;
 
-               if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
-               cap->bounds  = dev->crop_bounds;
-               cap->defrect = dev->crop_defrect;
-               cap->pixelaspect.numerator   = 1;
-               cap->pixelaspect.denominator = 1;
-               if (dev->tvnorm->id & V4L2_STD_525_60) {
-                       cap->pixelaspect.numerator   = 11;
-                       cap->pixelaspect.denominator = 10;
-               }
-               if (dev->tvnorm->id & V4L2_STD_625_50) {
-                       cap->pixelaspect.numerator   = 54;
-                       cap->pixelaspect.denominator = 59;
-               }
-               return 0;
-       }
+       mutex_lock(&dev->lock);
+       if (res_check(fh, RESOURCE_OVERLAY)) {
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
 
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop * crop = arg;
+               set_tvnorm(dev, &tvnorms[i]);
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
-               crop->c = dev->crop_current;
-               return 0;
-       }
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *crop = arg;
-               struct v4l2_rect *b = &dev->crop_bounds;
+               spin_lock_irqsave(&dev->slock, flags);
+               start_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
+       } else
+               set_tvnorm(dev, &tvnorms[i]);
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-                       return -EINVAL;
-               if (crop->c.height < 0)
-                       return -EINVAL;
-               if (crop->c.width < 0)
-                       return -EINVAL;
+       saa7134_tvaudio_do_scan(dev);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
 
-               if (res_locked(fh->dev,RESOURCE_OVERLAY))
-                       return -EBUSY;
-               if (res_locked(fh->dev,RESOURCE_VIDEO))
-                       return -EBUSY;
+static int saa7134_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cap)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (crop->c.top < b->top)
-                       crop->c.top = b->top;
-               if (crop->c.top > b->top + b->height)
-                       crop->c.top = b->top + b->height;
-               if (crop->c.height > b->top - crop->c.top + b->height)
-                       crop->c.height = b->top - crop->c.top + b->height;
-
-               if (crop->c.left < b->left)
-                       crop->c.left = b->left;
-               if (crop->c.left > b->left + b->width)
-                       crop->c.left = b->left + b->width;
-               if (crop->c.width > b->left - crop->c.left + b->width)
-                       crop->c.width = b->left - crop->c.left + b->width;
-
-               dev->crop_current = crop->c;
-               return 0;
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
+       cap->bounds  = dev->crop_bounds;
+       cap->defrect = dev->crop_defrect;
+       cap->pixelaspect.numerator   = 1;
+       cap->pixelaspect.denominator = 1;
+       if (dev->tvnorm->id & V4L2_STD_525_60) {
+               cap->pixelaspect.numerator   = 11;
+               cap->pixelaspect.denominator = 10;
+       }
+       if (dev->tvnorm->id & V4L2_STD_625_50) {
+               cap->pixelaspect.numerator   = 54;
+               cap->pixelaspect.denominator = 59;
        }
+       return 0;
+}
 
-       /* --- tuner ioctls ------------------------------------------ */
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               int n;
+static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (0 != t->index)
-                       return -EINVAL;
-               memset(t,0,sizeof(*t));
-               for (n = 0; n < SAA7134_INPUT_MAX; n++)
-                       if (card_in(dev,n).tv)
-                               break;
-               if (NULL != card_in(dev,n).name) {
-                       strcpy(t->name, "Television");
-                       t->type = V4L2_TUNER_ANALOG_TV;
-                       t->capability = V4L2_TUNER_CAP_NORM |
-                               V4L2_TUNER_CAP_STEREO |
-                               V4L2_TUNER_CAP_LANG1 |
-                               V4L2_TUNER_CAP_LANG2;
-                       t->rangehigh = 0xffffffffUL;
-                       t->rxsubchans = saa7134_tvaudio_getstereo(dev);
-                       t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-               }
-               if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
-                       t->signal = 0xffff;
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               int rx,mode;
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
+       crop->c = dev->crop_current;
+       return 0;
+}
 
-               mode = dev->thread.mode;
-               if (UNSET == mode) {
-                       rx   = saa7134_tvaudio_getstereo(dev);
-                       mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-               }
-               if (mode != t->audmode) {
-                       dev->thread.mode = t->audmode;
-               }
-               return 0;
-       }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+       struct v4l2_rect *b = &dev->crop_bounds;
 
-               memset(f,0,sizeof(*f));
-               f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               f->frequency = dev->ctl_freq;
-               return 0;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+               return -EINVAL;
+       if (crop->c.height < 0)
+               return -EINVAL;
+       if (crop->c.width < 0)
+               return -EINVAL;
 
-               if (0 != f->tuner)
-                       return -EINVAL;
-               if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
-                       return -EINVAL;
-               if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
-                       return -EINVAL;
-               mutex_lock(&dev->lock);
-               dev->ctl_freq = f->frequency;
+       if (res_locked(fh->dev, RESOURCE_OVERLAY))
+               return -EBUSY;
+       if (res_locked(fh->dev, RESOURCE_VIDEO))
+               return -EBUSY;
+
+       if (crop->c.top < b->top)
+               crop->c.top = b->top;
+       if (crop->c.top > b->top + b->height)
+               crop->c.top = b->top + b->height;
+       if (crop->c.height > b->top - crop->c.top + b->height)
+               crop->c.height = b->top - crop->c.top + b->height;
+
+       if (crop->c.left < b->left)
+               crop->c.left = b->left;
+       if (crop->c.left > b->left + b->width)
+               crop->c.left = b->left + b->width;
+       if (crop->c.width > b->left - crop->c.left + b->width)
+               crop->c.width = b->left - crop->c.left + b->width;
+
+       dev->crop_current = crop->c;
+       return 0;
+}
 
-               saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
+static int saa7134_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int n;
 
-               saa7134_tvaudio_do_scan(dev);
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
+       if (0 != t->index)
+               return -EINVAL;
+       memset(t, 0, sizeof(*t));
+       for (n = 0; n < SAA7134_INPUT_MAX; n++)
+               if (card_in(dev, n).tv)
+                       break;
+       if (NULL != card_in(dev, n).name) {
+               strcpy(t->name, "Television");
+               t->type = V4L2_TUNER_ANALOG_TV;
+               t->capability = V4L2_TUNER_CAP_NORM |
+                       V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_LANG1 |
+                       V4L2_TUNER_CAP_LANG2;
+               t->rangehigh = 0xffffffffUL;
+               t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+               t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+       }
+       if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+               t->signal = 0xffff;
+       return 0;
+}
 
-       /* --- control ioctls ---------------------------------------- */
-       case VIDIOC_ENUMINPUT:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_QUERYCTRL:
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_CTRL:
-               return saa7134_common_ioctl(dev, cmd, arg);
+static int saa7134_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int rx, mode, err;
 
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               memset(a,0,sizeof(*a));
-               strcpy(a->name,"audio");
-               return 0;
-       }
-       case VIDIOC_S_AUDIO:
-               return 0;
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_captureparm *parm = arg;
-               memset(parm,0,sizeof(*parm));
-               return 0;
+       mode = dev->thread.mode;
+       if (UNSET == mode) {
+               rx   = saa7134_tvaudio_getstereo(dev);
+               mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
        }
+       if (mode != t->audmode)
+               dev->thread.mode = t->audmode;
 
-       case VIDIOC_G_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
+       return 0;
+}
 
-               *p = v4l2_prio_max(&dev->prio);
-               return 0;
-       }
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *prio = arg;
+static int saa7134_g_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-               return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
-       }
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->frequency = dev->ctl_freq;
 
-       /* --- preview ioctls ---------------------------------------- */
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int index;
-
-               index = f->index;
-               type  = f->type;
-               switch (type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (saa7134_no_overlay > 0) {
-                               printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-                               return -EINVAL;
-                       }
-                       if (index >= FORMATS)
-                               return -EINVAL;
-                       if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
-                           formats[index].planar)
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index = index;
-                       f->type  = type;
-                       strlcpy(f->description,formats[index].name,sizeof(f->description));
-                       f->pixelformat = formats[index].fourcc;
-                       break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       if (0 != index)
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index = index;
-                       f->type  = type;
-                       f->pixelformat = V4L2_PIX_FMT_GREY;
-                       strcpy(f->description,"vbi data");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       }
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
+       return 0;
+}
 
-               *fb = dev->ovbuf;
-               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-               return 0;
-       }
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
-               struct saa7134_format *fmt;
+static int saa7134_s_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int err;
 
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
+       err = v4l2_prio_check(&dev->prio, &fh->prio);
+       if (0 != err)
+               return err;
 
-               /* check args */
-               fmt = format_by_fourcc(fb->fmt.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
+       if (0 != f->tuner)
+               return -EINVAL;
+       if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+               return -EINVAL;
+       if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+               return -EINVAL;
+       mutex_lock(&dev->lock);
+       dev->ctl_freq = f->frequency;
 
-               /* ok, accept it */
-               dev->ovbuf = *fb;
-               dev->ovfmt = fmt;
-               if (0 == dev->ovbuf.fmt.bytesperline)
-                       dev->ovbuf.fmt.bytesperline =
-                               dev->ovbuf.fmt.width*fmt->depth/8;
-               return 0;
+       saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+
+       saa7134_tvaudio_do_scan(dev);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       strcpy(a->name, "audio");
+       return 0;
+}
+
+static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+       return 0;
+}
+
+static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+
+       *p = v4l2_prio_max(&dev->prio);
+       return 0;
+}
+
+static int saa7134_s_priority(struct file *file, void *f,
+                                       enum v4l2_priority prio)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+
+       return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+}
+
+static int saa7134_enum_fmt_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index >= FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+static int saa7134_enum_fmt_overlay(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (saa7134_no_overlay > 0) {
+               printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+               return -EINVAL;
        }
-       case VIDIOC_OVERLAY:
-       {
-               int *on = arg;
 
-               if (*on) {
-                       if (saa7134_no_overlay > 0) {
-                               printk ("no_overlay\n");
-                               return -EINVAL;
-                       }
+       if ((f->index >= FORMATS) || formats[f->index].planar)
+               return -EINVAL;
 
-                       if (!res_get(dev,fh,RESOURCE_OVERLAY))
-                               return -EBUSY;
-                       spin_lock_irqsave(&dev->slock,flags);
-                       start_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-               }
-               if (!*on) {
-                       if (!res_check(fh, RESOURCE_OVERLAY))
-                               return -EINVAL;
-                       spin_lock_irqsave(&dev->slock,flags);
-                       stop_preview(dev,fh);
-                       spin_unlock_irqrestore(&dev->slock,flags);
-                       res_free(dev,fh,RESOURCE_OVERLAY);
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+static int saa7134_enum_fmt_vbi(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (0 != f->index)
+               return -EINVAL;
+
+       f->pixelformat = V4L2_PIX_FMT_GREY;
+       strcpy(f->description, "vbi data");
+
+       return 0;
+}
+
+static int saa7134_g_fbuf(struct file *file, void *f,
+                               struct v4l2_framebuffer *fb)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+
+       *fb = dev->ovbuf;
+       fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+       return 0;
+}
+
+static int saa7134_s_fbuf(struct file *file, void *f,
+                                       struct v4l2_framebuffer *fb)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_format *fmt;
+
+       if (!capable(CAP_SYS_ADMIN) &&
+          !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       /* check args */
+       fmt = format_by_fourcc(fb->fmt.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       /* ok, accept it */
+       dev->ovbuf = *fb;
+       dev->ovfmt = fmt;
+       if (0 == dev->ovbuf.fmt.bytesperline)
+               dev->ovbuf.fmt.bytesperline =
+                       dev->ovbuf.fmt.width*fmt->depth/8;
+       return 0;
+}
+
+static int saa7134_overlay(struct file *file, void *f, unsigned int on)
+{
+       struct saa7134_fh *fh = f;
+       struct saa7134_dev *dev = fh->dev;
+       unsigned long flags;
+
+       if (on) {
+               if (saa7134_no_overlay > 0) {
+                       dprintk("no_overlay\n");
+                       return -EINVAL;
                }
-               return 0;
-       }
 
-       /* --- capture ioctls ---------------------------------------- */
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return saa7134_g_fmt(dev,fh,f);
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return saa7134_s_fmt(dev,fh,f);
+               if (!res_get(dev, fh, RESOURCE_OVERLAY))
+                       return -EBUSY;
+               spin_lock_irqsave(&dev->slock, flags);
+               start_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
        }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return saa7134_try_fmt(dev,fh,f);
+       if (!on) {
+               if (!res_check(fh, RESOURCE_OVERLAY))
+                       return -EINVAL;
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev, fh);
+               spin_unlock_irqrestore(&dev->slock, flags);
+               res_free(dev, fh, RESOURCE_OVERLAY);
        }
+       return 0;
+}
+
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCGMBUF:
-               return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+       struct saa7134_fh *fh = file->private_data;
+       return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
+}
 #endif
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(saa7134_queue(fh),arg);
 
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(saa7134_queue(fh),arg);
+static int saa7134_reqbufs(struct file *file, void *priv,
+                                       struct v4l2_requestbuffers *p)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_reqbufs(saa7134_queue(fh), p);
+}
 
-       case VIDIOC_QBUF:
-               return videobuf_qbuf(saa7134_queue(fh),arg);
+static int saa7134_querybuf(struct file *file, void *priv,
+                                       struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_querybuf(saa7134_queue(fh), b);
+}
 
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(saa7134_queue(fh),arg,
-                                     file->f_flags & O_NONBLOCK);
+static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_qbuf(saa7134_queue(fh), b);
+}
 
-       case VIDIOC_STREAMON:
-       {
-               int res = saa7134_resource(fh);
+static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       struct saa7134_fh *fh = priv;
+       return videobuf_dqbuf(saa7134_queue(fh), b,
+                               file->f_flags & O_NONBLOCK);
+}
 
-               if (!res_get(dev,fh,res))
-                       return -EBUSY;
-               return videobuf_streamon(saa7134_queue(fh));
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int res = saa7134_resource(fh);
+static int saa7134_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int res = saa7134_resource(fh);
 
-               err = videobuf_streamoff(saa7134_queue(fh));
-               if (err < 0)
-                       return err;
-               res_free(dev,fh,res);
-               return 0;
-       }
+       if (!res_get(dev, fh, res))
+               return -EBUSY;
 
-       default:
-               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                 video_do_ioctl);
-       }
+       return videobuf_streamon(saa7134_queue(fh));
+}
+
+static int saa7134_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       int err;
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       int res = saa7134_resource(fh);
+
+       err = videobuf_streamoff(saa7134_queue(fh));
+       if (err < 0)
+               return err;
+       res_free(dev, fh, res);
        return 0;
 }
 
-static int video_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int saa7134_g_parm(struct file *file, void *fh,
+                               struct v4l2_streamparm *parm)
 {
-       return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+       return 0;
 }
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+static int radio_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *cap)
 {
        struct saa7134_fh *fh = file->private_data;
        struct saa7134_dev *dev = fh->dev;
 
-       if (video_debug > 1)
-               v4l_print_ioctl(dev->name,cmd);
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->driver, "saa7134");
-               strlcpy(cap->card, saa7134_boards[dev->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = SAA7134_VERSION_CODE;
-               cap->capabilities = V4L2_CAP_TUNER;
-               return 0;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       strcpy(cap->driver, "saa7134");
+       strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->version = SAA7134_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
 
-               if (0 != t->index)
-                       return -EINVAL;
+static int radio_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
 
-               memset(t,0,sizeof(*t));
-               strcpy(t->name, "Radio");
-               t->type = V4L2_TUNER_RADIO;
+       if (0 != t->index)
+               return -EINVAL;
 
-               saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-               if (dev->input->amux == TV) {
-                       t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
-                       t->rxsubchans = (saa_readb(0x529) & 0x08) ?
-                                       V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
-               }
-               return 0;
+       memset(t, 0, sizeof(*t));
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
+
+       saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+       if (dev->input->amux == TV) {
+               t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+               t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+                               V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
        }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       return 0;
+}
+static int radio_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct saa7134_fh *fh = file->private_data;
+       struct saa7134_dev *dev = fh->dev;
 
-               if (0 != t->index)
-                       return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
 
-               saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
+       saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+       return 0;
+}
 
-               return 0;
-       }
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
+static int radio_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       if (i->index != 0)
+               return -EINVAL;
 
-               if (i->index != 0)
-                       return -EINVAL;
-               strcpy(i->name,"Radio");
-               i->type = V4L2_INPUT_TYPE_TUNER;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = 0;
-               return 0;
-       }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+       strcpy(i->name, "Radio");
+       i->type = V4L2_INPUT_TYPE_TUNER;
 
-               memset(a,0,sizeof(*a));
-               strcpy(a->name,"Radio");
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-               *id = 0;
-               return 0;
-       }
-       case VIDIOC_S_AUDIO:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_STD:
-               return 0;
+       return 0;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               const struct v4l2_queryctrl *ctrl;
-               struct v4l2_queryctrl *c = arg;
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
 
-               if (c->id <  V4L2_CID_BASE ||
-                   c->id >= V4L2_CID_LASTP1)
-                       return -EINVAL;
-               if (c->id == V4L2_CID_AUDIO_MUTE) {
-                       ctrl = ctrl_by_id(c->id);
-                       *c = *ctrl;
-               } else
-                       *c = no_ctrl;
-               return 0;
-       }
+static int radio_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       memset(a, 0, sizeof(*a));
+       strcpy(a->name, "Radio");
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_CTRL:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-               return video_do_ioctl(inode,file,cmd,arg);
+static int radio_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return 0;
+}
 
-       default:
-               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                 radio_do_ioctl);
-       }
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
        return 0;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
 {
-       return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+       return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       const struct v4l2_queryctrl *ctrl;
+
+       if (c->id <  V4L2_CID_BASE ||
+           c->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       if (c->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl = ctrl_by_id(c->id);
+               *c = *ctrl;
+       } else
+               *c = no_ctrl;
+       return 0;
 }
 
 static const struct file_operations video_fops =
@@ -2333,7 +2327,7 @@ static const struct file_operations video_fops =
        .read     = video_read,
        .poll     = video_poll,
        .mmap     = video_mmap,
-       .ioctl    = video_ioctl,
+       .ioctl    = video_ioctl2,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
 };
@@ -2343,7 +2337,7 @@ static const struct file_operations radio_fops =
        .owner    = THIS_MODULE,
        .open     = video_open,
        .release  = video_release,
-       .ioctl    = radio_ioctl,
+       .ioctl    = video_ioctl2,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek   = no_llseek,
 };
@@ -2353,27 +2347,79 @@ static const struct file_operations radio_fops =
 
 struct video_device saa7134_video_template =
 {
-       .name          = "saa7134-video",
-       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-                        VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-       .fops          = &video_fops,
-       .minor         = -1,
-};
-
-struct video_device saa7134_vbi_template =
-{
-       .name          = "saa7134-vbi",
-       .type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
-       .fops          = &video_fops,
-       .minor         = -1,
+       .name                           = "saa7134-video",
+       .type                           = VID_TYPE_CAPTURE|VID_TYPE_TUNER |
+                                       VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+       .fops                           = &video_fops,
+       .minor                          = -1,
+       .vidioc_querycap                = saa7134_querycap,
+       .vidioc_enum_fmt_cap            = saa7134_enum_fmt_cap,
+       .vidioc_g_fmt_cap               = saa7134_g_fmt_cap,
+       .vidioc_try_fmt_cap             = saa7134_try_fmt_cap,
+       .vidioc_s_fmt_cap               = saa7134_s_fmt_cap,
+       .vidioc_enum_fmt_overlay        = saa7134_enum_fmt_overlay,
+       .vidioc_g_fmt_overlay           = saa7134_g_fmt_overlay,
+       .vidioc_try_fmt_overlay         = saa7134_try_fmt_overlay,
+       .vidioc_s_fmt_overlay           = saa7134_s_fmt_overlay,
+       .vidioc_enum_fmt_vbi            = saa7134_enum_fmt_vbi,
+       .vidioc_g_fmt_vbi               = saa7134_try_get_set_fmt_vbi,
+       .vidioc_try_fmt_vbi             = saa7134_try_get_set_fmt_vbi,
+       .vidioc_s_fmt_vbi               = saa7134_try_get_set_fmt_vbi,
+       .vidioc_g_audio                 = saa7134_g_audio,
+       .vidioc_s_audio                 = saa7134_s_audio,
+       .vidioc_cropcap                 = saa7134_cropcap,
+       .vidioc_reqbufs                 = saa7134_reqbufs,
+       .vidioc_querybuf                = saa7134_querybuf,
+       .vidioc_qbuf                    = saa7134_qbuf,
+       .vidioc_dqbuf                   = saa7134_dqbuf,
+       .vidioc_s_std                   = saa7134_s_std,
+       .vidioc_enum_input              = saa7134_enum_input,
+       .vidioc_g_input                 = saa7134_g_input,
+       .vidioc_s_input                 = saa7134_s_input,
+       .vidioc_queryctrl               = saa7134_queryctrl,
+       .vidioc_g_ctrl                  = saa7134_g_ctrl,
+       .vidioc_s_ctrl                  = saa7134_s_ctrl,
+       .vidioc_streamon                = saa7134_streamon,
+       .vidioc_streamoff               = saa7134_streamoff,
+       .vidioc_g_tuner                 = saa7134_g_tuner,
+       .vidioc_s_tuner                 = saa7134_s_tuner,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf                    = vidiocgmbuf,
+#endif
+       .vidioc_g_crop                  = saa7134_g_crop,
+       .vidioc_s_crop                  = saa7134_s_crop,
+       .vidioc_g_fbuf                  = saa7134_g_fbuf,
+       .vidioc_s_fbuf                  = saa7134_s_fbuf,
+       .vidioc_overlay                 = saa7134_overlay,
+       .vidioc_g_priority              = saa7134_g_priority,
+       .vidioc_s_priority              = saa7134_s_priority,
+       .vidioc_g_parm                  = saa7134_g_parm,
+       .vidioc_g_frequency             = saa7134_g_frequency,
+       .vidioc_s_frequency             = saa7134_s_frequency,
+       .tvnorms                        = SAA7134_NORMS,
+       .current_norm                   = V4L2_STD_PAL,
 };
 
 struct video_device saa7134_radio_template =
 {
-       .name          = "saa7134-radio",
-       .type          = VID_TYPE_TUNER,
-       .fops          = &radio_fops,
-       .minor         = -1,
+       .name                   = "saa7134-radio",
+       .type                   = VID_TYPE_TUNER,
+       .fops                   = &radio_fops,
+       .minor                  = -1,
+       .vidioc_querycap        = radio_querycap,
+       .vidioc_g_tuner         = radio_g_tuner,
+       .vidioc_enum_input      = radio_enum_input,
+       .vidioc_g_audio         = radio_g_audio,
+       .vidioc_s_tuner         = radio_s_tuner,
+       .vidioc_s_audio         = radio_s_audio,
+       .vidioc_s_input         = radio_s_input,
+       .vidioc_s_std           = radio_s_std,
+       .vidioc_queryctrl       = radio_queryctrl,
+       .vidioc_g_input         = radio_g_input,
+       .vidioc_g_ctrl          = saa7134_g_ctrl,
+       .vidioc_s_ctrl          = saa7134_s_ctrl,
+       .vidioc_g_frequency     = saa7134_g_frequency,
+       .vidioc_s_frequency     = saa7134_s_frequency,
 };
 
 int saa7134_video_init1(struct saa7134_dev *dev)
@@ -2511,7 +2557,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
                                goto done;
                }
                dev->video_q.curr->vb.field_count = dev->video_fieldcount;
-               saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE);
+               saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
        }
        saa7134_buffer_next(dev,&dev->video_q);
 
index 66a390c321a706079c9ef82bc8168d25b2a31b19..ce450304fb5364503c7c42433927148954e211a0 100644 (file)
@@ -240,6 +240,19 @@ struct saa7134_format {
 #define SAA7134_BOARD_SABRENT_TV_PCB05     115
 #define SAA7134_BOARD_10MOONSTVMASTER3     116
 #define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
+#define SAA7134_BOARD_BEHOLD_401       118
+#define SAA7134_BOARD_BEHOLD_403       119
+#define SAA7134_BOARD_BEHOLD_403FM     120
+#define SAA7134_BOARD_BEHOLD_405       121
+#define SAA7134_BOARD_BEHOLD_405FM     122
+#define SAA7134_BOARD_BEHOLD_407       123
+#define SAA7134_BOARD_BEHOLD_407FM     124
+#define SAA7134_BOARD_BEHOLD_409       125
+#define SAA7134_BOARD_BEHOLD_505FM     126
+#define SAA7134_BOARD_BEHOLD_507_9FM   127
+#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
+#define SAA7134_BOARD_BEHOLD_607_9FM   129
+#define SAA7134_BOARD_BEHOLD_M6                130
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -481,7 +494,7 @@ struct saa7134_dev {
        /* i2c i/o */
        struct i2c_adapter         i2c_adap;
        struct i2c_client          i2c_client;
-       unsigned char              eedata[128];
+       unsigned char              eedata[256];
 
        /* video overlay */
        struct v4l2_framebuffer    ovbuf;
@@ -566,6 +579,12 @@ struct saa7134_dev {
 
 #define saa_wait(us) { udelay(us); }
 
+#define SAA7134_NORMS  (\
+               V4L2_STD_PAL    | V4L2_STD_PAL_N | \
+               V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+               V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
+               V4L2_STD_PAL_60)
+
 /* ----------------------------------------------------------- */
 /* saa7134-core.c                                              */
 
@@ -596,9 +615,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
 void saa7134_buffer_timeout(unsigned long data);
 void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
 
-int saa7134_buffer_requeue(struct saa7134_dev *dev,
-                        struct saa7134_dmaqueue *q);
-
 int saa7134_set_dmabits(struct saa7134_dev *dev);
 
 extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
@@ -628,16 +644,17 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
 /* ----------------------------------------------------------- */
 /* saa7134-video.c                                             */
 
+extern unsigned int video_debug;
 extern struct video_device saa7134_video_template;
 extern struct video_device saa7134_radio_template;
 
-void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
+int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c);
+int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c);
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
+
 int saa7134_videoport_init(struct saa7134_dev *dev);
 void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
 
-int saa7134_common_ioctl(struct saa7134_dev *dev,
-                        unsigned int cmd, void *arg);
-
 int saa7134_video_init1(struct saa7134_dev *dev);
 int saa7134_video_init2(struct saa7134_dev *dev);
 void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
@@ -682,6 +699,7 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
 void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
 int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
 
+void saa7134_tvaudio_init(struct saa7134_dev *dev);
 int saa7134_tvaudio_init2(struct saa7134_dev *dev);
 int saa7134_tvaudio_fini(struct saa7134_dev *dev);
 int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
index a56d16f69c713550ff58d1a85115ccafc06f1fa4..7ecd5a90c7c9c13c39ef470b4f86d71a0e4b1d74 100644 (file)
@@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \
                sn9c102_hv7131r.o \
                sn9c102_mi0343.o \
                sn9c102_mi0360.o \
+               sn9c102_mt9v111.o \
                sn9c102_ov7630.o \
                sn9c102_ov7660.o \
                sn9c102_pas106b.o \
index 511847912c485fbb2ec85a125e1bd9a29032dd5b..c40ba3adab21ccc24ff8ab27a3f6ffeef1bb04a1 100644 (file)
@@ -47,7 +47,7 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.47"
+#define SN9C102_MODULE_VERSION  "1:1.47pre49"
 #define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
 
 /*****************************************************************************/
@@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->fops = &sn9c102_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
 
        init_completion(&cam->probe);
 
@@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
+       video_set_drvdata(cam->v4ldev, cam);
        cam->module_param.force_munmap = force_munmap[dev_nr];
        cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
index 916054faf9be46d62e083a4ffb670c40d32b582c..35223e0d7e49bb09deada63abd58f8428a59e18b 100644 (file)
@@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
 extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
+extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
@@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
        &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
        &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
        &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
        &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
        &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
        &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
new file mode 100644 (file)
index 0000000..3b98ac3
--- /dev/null
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static int mt9v111_init(struct sn9c102_device *cam)
+{
+       struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+       int err = 0;
+
+       err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
+                                      {0x00, 0x03}, {0x1a, 0x04},
+                                      {0x1f, 0x05}, {0x20, 0x06},
+                                      {0x1f, 0x07}, {0x81, 0x08},
+                                      {0x5c, 0x09}, {0x00, 0x0a},
+                                      {0x00, 0x0b}, {0x00, 0x0c},
+                                      {0x00, 0x0d}, {0x00, 0x0e},
+                                      {0x00, 0x0f}, {0x03, 0x10},
+                                      {0x00, 0x11}, {0x00, 0x12},
+                                      {0x02, 0x13}, {0x14, 0x14},
+                                      {0x28, 0x15}, {0x1e, 0x16},
+                                      {0xe2, 0x17}, {0x06, 0x18},
+                                      {0x00, 0x19}, {0x00, 0x1a},
+                                      {0x00, 0x1b}, {0x08, 0x20},
+                                      {0x39, 0x21}, {0x51, 0x22},
+                                      {0x63, 0x23}, {0x73, 0x24},
+                                      {0x82, 0x25}, {0x8f, 0x26},
+                                      {0x9b, 0x27}, {0xa7, 0x28},
+                                      {0xb1, 0x29}, {0xbc, 0x2a},
+                                      {0xc6, 0x2b}, {0xcf, 0x2c},
+                                      {0xd8, 0x2d}, {0xe1, 0x2e},
+                                      {0xea, 0x2f}, {0xf2, 0x30},
+                                      {0x13, 0x84}, {0x00, 0x85},
+                                      {0x25, 0x86}, {0x00, 0x87},
+                                      {0x07, 0x88}, {0x00, 0x89},
+                                      {0xee, 0x8a}, {0x0f, 0x8b},
+                                      {0xe5, 0x8c}, {0x0f, 0x8d},
+                                      {0x2e, 0x8e}, {0x00, 0x8f},
+                                      {0x30, 0x90}, {0x00, 0x91},
+                                      {0xd4, 0x92}, {0x0f, 0x93},
+                                      {0xfc, 0x94}, {0x0f, 0x95},
+                                      {0x14, 0x96}, {0x00, 0x97},
+                                      {0x00, 0x98}, {0x60, 0x99},
+                                      {0x07, 0x9a}, {0x40, 0x9b},
+                                      {0x20, 0x9c}, {0x00, 0x9d},
+                                      {0x00, 0x9e}, {0x00, 0x9f},
+                                      {0x2d, 0xc0}, {0x2d, 0xc1},
+                                      {0x3a, 0xc2}, {0x05, 0xc3},
+                                      {0x04, 0xc4}, {0x3f, 0xc5},
+                                      {0x00, 0xc6}, {0x00, 0xc7},
+                                      {0x50, 0xc8}, {0x3c, 0xc9},
+                                      {0x28, 0xca}, {0xd8, 0xcb},
+                                      {0x14, 0xcc}, {0xec, 0xcd},
+                                      {0x32, 0xce}, {0xdd, 0xcf},
+                                      {0x2d, 0xd0}, {0xdd, 0xd1},
+                                      {0x6a, 0xd2}, {0x50, 0xd3},
+                                      {0x60, 0xd4}, {0x00, 0xd5},
+                                      {0x00, 0xd6});
+
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
+                                        0x00, 0x01, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+                                        0x00, 0x01, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+                                        0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
+                                        0x04, 0x80, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
+                                        0x00, 0x04, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
+                                        0x00, 0x08, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02,
+                                        0x00, 0x16, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
+                                        0x01, 0xe7, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
+                                        0x02, 0x87, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
+                                        0x00, 0x40, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
+                                        0x00, 0x09, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07,
+                                        0x30, 0x02, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c,
+                                        0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12,
+                                        0x00, 0xb0, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13,
+                                        0x00, 0x7c, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e,
+                                        0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
+                                        0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
+                                        0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
+                                        0x00, 0x04, 0, 0);
+
+       return err;
+}
+
+static int mt9v111_get_ctrl(struct sn9c102_device *cam,
+                           struct v4l2_control *ctrl)
+{
+       struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+       u8 data[2];
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
+                                            data) < 0)
+                       return -EIO;
+               ctrl->value = data[1] & 0x80 ? 1 : 0;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+static int mt9v111_set_ctrl(struct sn9c102_device *cam,
+                           const struct v4l2_control *ctrl)
+{
+       struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+                                                0x20,
+                                                ctrl->value ? 0x80 : 0x00,
+                                                ctrl->value ? 0x80 : 0x00, 0,
+                                                0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+static int mt9v111_set_crop(struct sn9c102_device *cam,
+                           const struct v4l2_rect *rect)
+{
+       struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+       int err = 0;
+       u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2;
+
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+static int mt9v111_set_pix_format(struct sn9c102_device *cam,
+                                 const struct v4l2_pix_format *pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+               err += sn9c102_write_reg(cam, 0xb4, 0x17);
+       } else {
+               err += sn9c102_write_reg(cam, 0xe2, 0x17);
+       }
+
+       return err;
+}
+
+
+static const struct sn9c102_sensor mt9v111 = {
+       .name = "MT9V111",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x5c,
+       .init = &mt9v111_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical mirror",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &mt9v111_get_ctrl,
+       .set_ctrl = &mt9v111_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &mt9v111_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &mt9v111_set_pix_format
+};
+
+
+int sn9c102_probe_mt9v111(struct sn9c102_device *cam)
+{
+       u8 data[2];
+       int err = 0;
+
+       err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+                                       {0x29, 0x01}, {0x42, 0x17},
+                                       {0x62, 0x17}, {0x08, 0x01});
+       err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4,
+                                        mt9v111.i2c_slave_id, 0x01, 0x00,
+                                        0x04, 0, 0);
+       if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111,
+                                           mt9v111.i2c_slave_id, 0x36, 2,
+                                           data) < 0)
+               return -EIO;
+
+       if (data[0] != 0x82 || data[1] != 0x3a)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &mt9v111);
+
+       return 0;
+}
diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c
new file mode 100644 (file)
index 0000000..4a9a0b6
--- /dev/null
@@ -0,0 +1,578 @@
+/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams)
+ *
+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
+ *
+ * Some parts derived from ov7670.c:
+ * Copyright 2006 One Laptop Per Child Association, Inc.  Written
+ * by Jonathan Corbet with substantial inspiration from Mark
+ * McClelland's ovcamchip code.
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Controlling the sensor via the STK1125 vendor specific control interface:
+ * The camera uses an OmniVision sensor and the stk1125 provides an
+ * SCCB(i2c)-USB bridge which let us program the sensor.
+ * In my case the sensor id is 0x9652, it can be read from sensor's register
+ * 0x0A and 0x0B as follows:
+ * - read register #R:
+ *   output #R to index 0x0208
+ *   output 0x0070 to index 0x0200
+ *   input 1 byte from index 0x0201 (some kind of status register)
+ *     until its value is 0x01
+ *   input 1 byte from index 0x0209. This is the value of #R
+ * - write value V to register #R
+ *   output #R to index 0x0204
+ *   output V to index 0x0205
+ *   output 0x0005 to index 0x0200
+ *   input 1 byte from index 0x0201 until its value becomes 0x04
+ */
+
+/* It seems the i2c bus is controlled with these registers */
+
+#include "stk-webcam.h"
+
+#define STK_IIC_BASE           (0x0200)
+#  define STK_IIC_OP           (STK_IIC_BASE)
+#    define STK_IIC_OP_TX      (0x05)
+#    define STK_IIC_OP_RX      (0x70)
+#  define STK_IIC_STAT         (STK_IIC_BASE+1)
+#    define STK_IIC_STAT_TX_OK (0x04)
+#    define STK_IIC_STAT_RX_OK (0x01)
+/* I don't know what does this register.
+ * when it is 0x00 or 0x01, we cannot talk to the sensor,
+ * other values work */
+#  define STK_IIC_ENABLE       (STK_IIC_BASE+2)
+#    define STK_IIC_ENABLE_NO  (0x00)
+/* This is what the driver writes in windows */
+#    define STK_IIC_ENABLE_YES (0x1e)
+/*
+ * Address of the slave. Seems like the binary driver look for the
+ * sensor in multiple places, attempting a reset sequence.
+ * We only know about the ov9650
+ */
+#  define STK_IIC_ADDR         (STK_IIC_BASE+3)
+#  define STK_IIC_TX_INDEX     (STK_IIC_BASE+4)
+#  define STK_IIC_TX_VALUE     (STK_IIC_BASE+5)
+#  define STK_IIC_RX_INDEX     (STK_IIC_BASE+8)
+#  define STK_IIC_RX_VALUE     (STK_IIC_BASE+9)
+
+#define MAX_RETRIES            (50)
+
+#define SENSOR_ADDRESS         (0x60)
+
+/* From ov7670.c (These registers aren't fully accurate) */
+
+/* Registers */
+#define REG_GAIN       0x00    /* Gain lower 8 bits (rest in vref) */
+#define REG_BLUE       0x01    /* blue gain */
+#define REG_RED                0x02    /* red gain */
+#define REG_VREF       0x03    /* Pieces of GAIN, VSTART, VSTOP */
+#define REG_COM1       0x04    /* Control 1 */
+#define  COM1_CCIR656    0x40  /* CCIR656 enable */
+#define  COM1_QFMT       0x20  /* QVGA/QCIF format */
+#define  COM1_SKIP_0     0x00  /* Do not skip any row */
+#define  COM1_SKIP_2     0x04  /* Skip 2 rows of 4 */
+#define  COM1_SKIP_3     0x08  /* Skip 3 rows of 4 */
+#define REG_BAVE       0x05    /* U/B Average level */
+#define REG_GbAVE      0x06    /* Y/Gb Average level */
+#define REG_AECHH      0x07    /* AEC MS 5 bits */
+#define REG_RAVE       0x08    /* V/R Average level */
+#define REG_COM2       0x09    /* Control 2 */
+#define  COM2_SSLEEP     0x10  /* Soft sleep mode */
+#define REG_PID                0x0a    /* Product ID MSB */
+#define REG_VER                0x0b    /* Product ID LSB */
+#define REG_COM3       0x0c    /* Control 3 */
+#define  COM3_SWAP       0x40    /* Byte swap */
+#define  COM3_SCALEEN    0x08    /* Enable scaling */
+#define  COM3_DCWEN      0x04    /* Enable downsamp/crop/window */
+#define REG_COM4       0x0d    /* Control 4 */
+#define REG_COM5       0x0e    /* All "reserved" */
+#define REG_COM6       0x0f    /* Control 6 */
+#define REG_AECH       0x10    /* More bits of AEC value */
+#define REG_CLKRC      0x11    /* Clock control */
+#define   CLK_PLL        0x80    /* Enable internal PLL */
+#define   CLK_EXT        0x40    /* Use external clock directly */
+#define   CLK_SCALE      0x3f    /* Mask for internal clock scale */
+#define REG_COM7       0x12    /* Control 7 */
+#define   COM7_RESET     0x80    /* Register reset */
+#define   COM7_FMT_MASK          0x38
+#define   COM7_FMT_SXGA          0x00
+#define   COM7_FMT_VGA   0x40
+#define          COM7_FMT_CIF    0x20    /* CIF format */
+#define   COM7_FMT_QVGA          0x10    /* QVGA format */
+#define   COM7_FMT_QCIF          0x08    /* QCIF format */
+#define          COM7_RGB        0x04    /* bits 0 and 2 - RGB format */
+#define          COM7_YUV        0x00    /* YUV */
+#define          COM7_BAYER      0x01    /* Bayer format */
+#define          COM7_PBAYER     0x05    /* "Processed bayer" */
+#define REG_COM8       0x13    /* Control 8 */
+#define   COM8_FASTAEC   0x80    /* Enable fast AGC/AEC */
+#define   COM8_AECSTEP   0x40    /* Unlimited AEC step size */
+#define   COM8_BFILT     0x20    /* Band filter enable */
+#define   COM8_AGC       0x04    /* Auto gain enable */
+#define   COM8_AWB       0x02    /* White balance enable */
+#define   COM8_AEC       0x01    /* Auto exposure enable */
+#define REG_COM9       0x14    /* Control 9  - gain ceiling */
+#define REG_COM10      0x15    /* Control 10 */
+#define   COM10_HSYNC    0x40    /* HSYNC instead of HREF */
+#define   COM10_PCLK_HB          0x20    /* Suppress PCLK on horiz blank */
+#define   COM10_HREF_REV  0x08   /* Reverse HREF */
+#define   COM10_VS_LEAD          0x04    /* VSYNC on clock leading edge */
+#define   COM10_VS_NEG   0x02    /* VSYNC negative */
+#define   COM10_HS_NEG   0x01    /* HSYNC negative */
+#define REG_HSTART     0x17    /* Horiz start high bits */
+#define REG_HSTOP      0x18    /* Horiz stop high bits */
+#define REG_VSTART     0x19    /* Vert start high bits */
+#define REG_VSTOP      0x1a    /* Vert stop high bits */
+#define REG_PSHFT      0x1b    /* Pixel delay after HREF */
+#define REG_MIDH       0x1c    /* Manuf. ID high */
+#define REG_MIDL       0x1d    /* Manuf. ID low */
+#define REG_MVFP       0x1e    /* Mirror / vflip */
+#define   MVFP_MIRROR    0x20    /* Mirror image */
+#define   MVFP_FLIP      0x10    /* Vertical flip */
+
+#define REG_AEW                0x24    /* AGC upper limit */
+#define REG_AEB                0x25    /* AGC lower limit */
+#define REG_VPT                0x26    /* AGC/AEC fast mode op region */
+#define REG_ADVFL      0x2d    /* Insert dummy lines (LSB) */
+#define REG_ADVFH      0x2e    /* Insert dummy lines (MSB) */
+#define REG_HSYST      0x30    /* HSYNC rising edge delay */
+#define REG_HSYEN      0x31    /* HSYNC falling edge delay */
+#define REG_HREF       0x32    /* HREF pieces */
+#define REG_TSLB       0x3a    /* lots of stuff */
+#define   TSLB_YLAST     0x04    /* UYVY or VYUY - see com13 */
+#define   TSLB_BYTEORD   0x08    /* swap bytes in 16bit mode? */
+#define REG_COM11      0x3b    /* Control 11 */
+#define   COM11_NIGHT    0x80    /* NIght mode enable */
+#define   COM11_NMFR     0x60    /* Two bit NM frame rate */
+#define   COM11_HZAUTO   0x10    /* Auto detect 50/60 Hz */
+#define          COM11_50HZ      0x08    /* Manual 50Hz select */
+#define   COM11_EXP      0x02
+#define REG_COM12      0x3c    /* Control 12 */
+#define   COM12_HREF     0x80    /* HREF always */
+#define REG_COM13      0x3d    /* Control 13 */
+#define   COM13_GAMMA    0x80    /* Gamma enable */
+#define          COM13_UVSAT     0x40    /* UV saturation auto adjustment */
+#define          COM13_CMATRIX   0x10    /* Enable color matrix for RGB or YUV */
+#define   COM13_UVSWAP   0x01    /* V before U - w/TSLB */
+#define REG_COM14      0x3e    /* Control 14 */
+#define   COM14_DCWEN    0x10    /* DCW/PCLK-scale enable */
+#define REG_EDGE       0x3f    /* Edge enhancement factor */
+#define REG_COM15      0x40    /* Control 15 */
+#define   COM15_R10F0    0x00    /* Data range 10 to F0 */
+#define          COM15_R01FE     0x80    /*            01 to FE */
+#define   COM15_R00FF    0xc0    /*            00 to FF */
+#define   COM15_RGB565   0x10    /* RGB565 output */
+#define   COM15_RGBFIXME         0x20    /* FIXME  */
+#define   COM15_RGB555   0x30    /* RGB555 output */
+#define REG_COM16      0x41    /* Control 16 */
+#define   COM16_AWBGAIN   0x08   /* AWB gain enable */
+#define REG_COM17      0x42    /* Control 17 */
+#define   COM17_AECWIN   0xc0    /* AEC window - must match COM4 */
+#define   COM17_CBAR     0x08    /* DSP Color bar */
+
+/*
+ * This matrix defines how the colors are generated, must be
+ * tweaked to adjust hue and saturation.
+ *
+ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
+ *
+ * They are nine-bit signed quantities, with the sign bit
+ * stored in 0x58.  Sign for v-red is bit 0, and up from there.
+ */
+#define        REG_CMATRIX_BASE 0x4f
+#define   CMATRIX_LEN 6
+#define REG_CMATRIX_SIGN 0x58
+
+
+#define REG_BRIGHT     0x55    /* Brightness */
+#define REG_CONTRAS    0x56    /* Contrast control */
+
+#define REG_GFIX       0x69    /* Fix gain control */
+
+#define REG_RGB444     0x8c    /* RGB 444 control */
+#define   R444_ENABLE    0x02    /* Turn on RGB444, overrides 5x5 */
+#define   R444_RGBX      0x01    /* Empty nibble at end */
+
+#define REG_HAECC1     0x9f    /* Hist AEC/AGC control 1 */
+#define REG_HAECC2     0xa0    /* Hist AEC/AGC control 2 */
+
+#define REG_BD50MAX    0xa5    /* 50hz banding step limit */
+#define REG_HAECC3     0xa6    /* Hist AEC/AGC control 3 */
+#define REG_HAECC4     0xa7    /* Hist AEC/AGC control 4 */
+#define REG_HAECC5     0xa8    /* Hist AEC/AGC control 5 */
+#define REG_HAECC6     0xa9    /* Hist AEC/AGC control 6 */
+#define REG_HAECC7     0xaa    /* Hist AEC/AGC control 7 */
+#define REG_BD60MAX    0xab    /* 60hz banding step limit */
+
+
+
+
+/* Returns 0 if OK */
+int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
+{
+       int i = 0;
+       int tmpval = 0;
+
+       if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg))
+               return 1;
+       if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val))
+               return 1;
+       if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX))
+               return 1;
+       do {
+               if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
+                       return 1;
+               i++;
+       } while (tmpval == 0 && i < MAX_RETRIES);
+       if (tmpval != STK_IIC_STAT_TX_OK) {
+               if (tmpval)
+                       STK_ERROR("stk_sensor_outb failed, status=0x%02x\n",
+                               tmpval);
+               return 1;
+       } else
+               return 0;
+}
+
+int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
+{
+       int i = 0;
+       int tmpval = 0;
+
+       if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg))
+               return 1;
+       if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX))
+               return 1;
+       do {
+               if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
+                       return 1;
+               i++;
+       } while (tmpval == 0 && i < MAX_RETRIES);
+       if (tmpval != STK_IIC_STAT_RX_OK) {
+               if (tmpval)
+                       STK_ERROR("stk_sensor_inb failed, status=0x%02x\n",
+                               tmpval);
+               return 1;
+       }
+
+       if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval))
+               return 1;
+
+       *val = (u8) tmpval;
+       return 0;
+}
+
+static int stk_sensor_write_regvals(struct stk_camera *dev,
+               struct regval *rv)
+{
+       int ret;
+       if (rv == NULL)
+               return 0;
+       while (rv->reg != 0xff || rv->val != 0xff) {
+               ret = stk_sensor_outb(dev, rv->reg, rv->val);
+               if (ret != 0)
+                       return ret;
+               rv++;
+       }
+       return 0;
+}
+
+int stk_sensor_sleep(struct stk_camera *dev)
+{
+       u8 tmp;
+       return stk_sensor_inb(dev, REG_COM2, &tmp)
+               || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP);
+}
+
+int stk_sensor_wakeup(struct stk_camera *dev)
+{
+       u8 tmp;
+       return stk_sensor_inb(dev, REG_COM2, &tmp)
+               || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP);
+}
+
+static struct regval ov_initvals[] = {
+       {REG_CLKRC, CLK_PLL},
+       {REG_COM11, 0x01},
+       {0x6a, 0x7d},
+       {REG_AECH, 0x40},
+       {REG_GAIN, 0x00},
+       {REG_BLUE, 0x80},
+       {REG_RED, 0x80},
+       /* Do not enable fast AEC for now */
+       /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/
+       {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},
+       {0x39, 0x50}, {0x38, 0x93},
+       {0x37, 0x00}, {0x35, 0x81},
+       {REG_COM5, 0x20},
+       {REG_COM1, 0x00},
+       {REG_COM3, 0x00},
+       {REG_COM4, 0x00},
+       {REG_PSHFT, 0x00},
+       {0x16, 0x07},
+       {0x33, 0xe2}, {0x34, 0xbf},
+       {REG_COM16, 0x00},
+       {0x96, 0x04},
+       /* Gamma curve values */
+/*     { 0x7a, 0x20 },         { 0x7b, 0x10 },
+       { 0x7c, 0x1e },         { 0x7d, 0x35 },
+       { 0x7e, 0x5a },         { 0x7f, 0x69 },
+       { 0x80, 0x76 },         { 0x81, 0x80 },
+       { 0x82, 0x88 },         { 0x83, 0x8f },
+       { 0x84, 0x96 },         { 0x85, 0xa3 },
+       { 0x86, 0xaf },         { 0x87, 0xc4 },
+       { 0x88, 0xd7 },         { 0x89, 0xe8 },
+*/
+       {REG_GFIX, 0x40},
+       {0x8e, 0x00},
+       {REG_COM12, 0x73},
+       {0x8f, 0xdf}, {0x8b, 0x06},
+       {0x8c, 0x20},
+       {0x94, 0x88}, {0x95, 0x88},
+/*     {REG_COM15, 0xc1}, TODO */
+       {0x29, 0x3f},
+       {REG_COM6, 0x42},
+       {REG_BD50MAX, 0x80},
+       {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92},
+       {REG_BD60MAX, 0x0a},
+       {0x90, 0x00}, {0x91, 0x00},
+       {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00},
+       {REG_AEW, 0x68}, {REG_AEB, 0x5c},
+       {REG_VPT, 0xc3},
+       {REG_COM9, 0x2e},
+       {0x2a, 0x00}, {0x2b, 0x00},
+
+       {0xff, 0xff}, /* END MARKER */
+};
+
+/* Probe the I2C bus and initialise the sensor chip */
+int stk_sensor_init(struct stk_camera *dev)
+{
+       u8 idl = 0;
+       u8 idh = 0;
+
+       if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
+               || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
+               || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
+               STK_ERROR("Sensor resetting failed\n");
+               return -ENODEV;
+       }
+       msleep(10);
+       /* Read the manufacturer ID: ov = 0x7FA2 */
+       if (stk_sensor_inb(dev, REG_MIDH, &idh)
+           || stk_sensor_inb(dev, REG_MIDL, &idl)) {
+               STK_ERROR("Strange error reading sensor ID\n");
+               return -ENODEV;
+       }
+       if (idh != 0x7F || idl != 0xA2) {
+               STK_ERROR("Huh? you don't have a sensor from ovt\n");
+               return -ENODEV;
+       }
+       if (stk_sensor_inb(dev, REG_PID, &idh)
+           || stk_sensor_inb(dev, REG_VER, &idl)) {
+               STK_ERROR("Could not read sensor model\n");
+               return -ENODEV;
+       }
+       stk_sensor_write_regvals(dev, ov_initvals);
+       msleep(10);
+       STK_INFO("OmniVision sensor detected, id %02X%02X"
+               " at address %x\n", idh, idl, SENSOR_ADDRESS);
+       return 0;
+}
+
+/* V4L2_PIX_FMT_UYVY */
+static struct regval ov_fmt_uyvy[] = {
+       {REG_TSLB, TSLB_YLAST|0x08 },
+       { 0x4f, 0x80 },         /* "matrix coefficient 1" */
+       { 0x50, 0x80 },         /* "matrix coefficient 2" */
+       { 0x51, 0    },         /* vb */
+       { 0x52, 0x22 },         /* "matrix coefficient 4" */
+       { 0x53, 0x5e },         /* "matrix coefficient 5" */
+       { 0x54, 0x80 },         /* "matrix coefficient 6" */
+       {REG_COM13, COM13_UVSAT|COM13_CMATRIX},
+       {REG_COM15, COM15_R00FF },
+       {0xff, 0xff}, /* END MARKER */
+};
+
+/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
+static struct regval ov_fmt_rgbr[] = {
+       { REG_RGB444, 0 },      /* No RGB444 please */
+       {REG_TSLB, 0x00},
+       { REG_COM1, 0x0 },
+       { REG_COM9, 0x38 },     /* 16x gain ceiling; 0x8 is reserved bit */
+       { 0x4f, 0xb3 },         /* "matrix coefficient 1" */
+       { 0x50, 0xb3 },         /* "matrix coefficient 2" */
+       { 0x51, 0    },         /* vb */
+       { 0x52, 0x3d },         /* "matrix coefficient 4" */
+       { 0x53, 0xa7 },         /* "matrix coefficient 5" */
+       { 0x54, 0xe4 },         /* "matrix coefficient 6" */
+       { REG_COM13, COM13_GAMMA },
+       { REG_COM15, COM15_RGB565|COM15_R00FF },
+       { 0xff, 0xff },
+};
+
+/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */
+static struct regval ov_fmt_rgbp[] = {
+       { REG_RGB444, 0 },      /* No RGB444 please */
+       {REG_TSLB, TSLB_BYTEORD },
+       { REG_COM1, 0x0 },
+       { REG_COM9, 0x38 },     /* 16x gain ceiling; 0x8 is reserved bit */
+       { 0x4f, 0xb3 },         /* "matrix coefficient 1" */
+       { 0x50, 0xb3 },         /* "matrix coefficient 2" */
+       { 0x51, 0    },         /* vb */
+       { 0x52, 0x3d },         /* "matrix coefficient 4" */
+       { 0x53, 0xa7 },         /* "matrix coefficient 5" */
+       { 0x54, 0xe4 },         /* "matrix coefficient 6" */
+       { REG_COM13, COM13_GAMMA },
+       { REG_COM15, COM15_RGB565|COM15_R00FF },
+       { 0xff, 0xff },
+};
+
+/* V4L2_PIX_FMT_SRGGB8 */
+static struct regval ov_fmt_bayer[] = {
+       /* This changes color order */
+       {REG_TSLB, 0x40}, /* BGGR */
+       /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */
+       {REG_COM15, COM15_R00FF },
+       {0xff, 0xff}, /* END MARKER */
+};
+/*
+ * Store a set of start/stop values into the camera.
+ */
+static int stk_sensor_set_hw(struct stk_camera *dev,
+               int hstart, int hstop, int vstart, int vstop)
+{
+       int ret;
+       unsigned char v;
+/*
+ * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of
+ * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is
+ * a mystery "edge offset" value in the top two bits of href.
+ */
+       ret =  stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff);
+       ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff);
+       ret += stk_sensor_inb(dev, REG_HREF, &v);
+       v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
+       msleep(10);
+       ret += stk_sensor_outb(dev, REG_HREF, v);
+/*
+ * Vertical: similar arrangement (note: this is different from ov7670.c)
+ */
+       ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff);
+       ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff);
+       ret += stk_sensor_inb(dev, REG_VREF, &v);
+       v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7);
+       msleep(10);
+       ret += stk_sensor_outb(dev, REG_VREF, v);
+       return ret;
+}
+
+
+int stk_sensor_configure(struct stk_camera *dev)
+{
+       int com7;
+       /*
+        * We setup the sensor to output dummy lines in low-res modes,
+        * so we don't get absurdly hight framerates.
+        */
+       unsigned dummylines;
+       int flip;
+       struct regval *rv;
+
+       switch (dev->vsettings.mode) {
+       case MODE_QCIF: com7 = COM7_FMT_QCIF;
+               dummylines = 604;
+               break;
+       case MODE_QVGA: com7 = COM7_FMT_QVGA;
+               dummylines = 267;
+               break;
+       case MODE_CIF: com7 = COM7_FMT_CIF;
+               dummylines = 412;
+               break;
+       case MODE_VGA: com7 = COM7_FMT_VGA;
+               dummylines = 11;
+               break;
+       case MODE_SXGA: com7 = COM7_FMT_SXGA;
+               dummylines = 0;
+               break;
+       default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode);
+               return -EFAULT;
+       }
+       switch (dev->vsettings.palette) {
+       case V4L2_PIX_FMT_UYVY:
+               com7 |= COM7_YUV;
+               rv = ov_fmt_uyvy;
+               break;
+       case V4L2_PIX_FMT_RGB565:
+               com7 |= COM7_RGB;
+               rv = ov_fmt_rgbp;
+               break;
+       case V4L2_PIX_FMT_RGB565X:
+               com7 |= COM7_RGB;
+               rv = ov_fmt_rgbr;
+               break;
+       case V4L2_PIX_FMT_SBGGR8:
+               com7 |= COM7_PBAYER;
+               rv = ov_fmt_bayer;
+               break;
+       default: STK_ERROR("Unsupported colorspace\n");
+               return -EFAULT;
+       }
+       /*FIXME sometimes the sensor go to a bad state
+       stk_sensor_write_regvals(dev, ov_initvals); */
+       stk_sensor_outb(dev, REG_COM7, com7);
+       msleep(50);
+       stk_sensor_write_regvals(dev, rv);
+       flip = (dev->vsettings.vflip?MVFP_FLIP:0)
+               | (dev->vsettings.hflip?MVFP_MIRROR:0);
+       stk_sensor_outb(dev, REG_MVFP, flip);
+       if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8
+                       && !dev->vsettings.vflip)
+               stk_sensor_outb(dev, REG_TSLB, 0x08);
+       stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8);
+       stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff);
+       msleep(50);
+       switch (dev->vsettings.mode) {
+       case MODE_VGA:
+               if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
+                       STK_ERROR("stk_sensor_set_hw failed (VGA)\n");
+               break;
+       case MODE_SXGA:
+       case MODE_CIF:
+       case MODE_QVGA:
+       case MODE_QCIF:
+               /*FIXME These settings seem ignored by the sensor
+               if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
+                       STK_ERROR("stk_sensor_set_hw failed (SXGA)\n");
+               */
+               break;
+       }
+       msleep(10);
+       return 0;
+}
+
+int stk_sensor_set_brightness(struct stk_camera *dev, int br)
+{
+       if (br < 0 || br > 0xff)
+               return -EINVAL;
+       stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6));
+       stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6));
+       return 0;
+}
+
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
new file mode 100644 (file)
index 0000000..d37e5e2
--- /dev/null
@@ -0,0 +1,1465 @@
+/*
+ * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
+ *
+ * Copyright (C) 2006 Nicolas VIVIEN
+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
+ *
+ * Some parts are inspired from cafe_ccic.c
+ * Copyright 2006-2007 Jonathan Corbet
+ *
+ * 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
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "stk-webcam.h"
+
+
+static int hflip = 1;
+module_param(hflip, bool, 0444);
+MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
+
+static int vflip = 1;
+module_param(vflip, bool, 0444);
+MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");
+MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
+
+
+
+/* Some cameras have audio interfaces, we aren't interested in those */
+static struct usb_device_id stkwebcam_table[] = {
+       { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, stkwebcam_table);
+
+void stk_camera_cleanup(struct kref *kref)
+{
+       struct stk_camera *dev = to_stk_camera(kref);
+
+       STK_INFO("Syntek USB2.0 Camera release resources"
+               " video device /dev/video%d\n", dev->vdev.minor);
+       video_unregister_device(&dev->vdev);
+       dev->vdev.priv = NULL;
+
+       if (dev->sio_bufs != NULL || dev->isobufs != NULL)
+               STK_ERROR("We are leaking memory\n");
+       usb_put_intf(dev->interface);
+       kfree(dev);
+}
+
+
+/*
+ * Basic stuff
+ */
+int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
+{
+       struct usb_device *udev = dev->udev;
+       int ret;
+
+       ret =  usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       0x01,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       500);
+       if (ret < 0)
+               return ret;
+       else
+               return 0;
+}
+
+int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value)
+{
+       struct usb_device *udev = dev->udev;
+       int ret;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                       0x00,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0x00,
+                       index,
+                       (u8 *) value,
+                       sizeof(u8),
+                       500);
+       if (ret < 0)
+               return ret;
+       else
+               return 0;
+}
+
+static int stk_start_stream(struct stk_camera *dev)
+{
+       int value;
+       int i, ret;
+       int value_116, value_117;
+
+       if (!is_present(dev))
+               return -ENODEV;
+       if (!is_memallocd(dev) || !is_initialised(dev)) {
+               STK_ERROR("FIXME: Buffers are not allocated\n");
+               return -EFAULT;
+       }
+       ret = usb_set_interface(dev->udev, 0, 5);
+
+       if (ret < 0)
+               STK_ERROR("usb_set_interface failed !\n");
+       if (stk_sensor_wakeup(dev))
+               STK_ERROR("error awaking the sensor\n");
+
+       stk_camera_read_reg(dev, 0x0116, &value_116);
+       stk_camera_read_reg(dev, 0x0117, &value_117);
+
+       stk_camera_write_reg(dev, 0x0116, 0x0000);
+       stk_camera_write_reg(dev, 0x0117, 0x0000);
+
+       stk_camera_read_reg(dev, 0x0100, &value);
+       stk_camera_write_reg(dev, 0x0100, value | 0x80);
+
+       stk_camera_write_reg(dev, 0x0116, value_116);
+       stk_camera_write_reg(dev, 0x0117, value_117);
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               if (dev->isobufs[i].urb) {
+                       ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
+                       atomic_inc(&dev->urbs_used);
+                       if (ret)
+                               return ret;
+               }
+       }
+       set_streaming(dev);
+       return 0;
+}
+
+static int stk_stop_stream(struct stk_camera *dev)
+{
+       int value;
+       int i;
+       if (is_present(dev)) {
+               stk_camera_read_reg(dev, 0x0100, &value);
+               stk_camera_write_reg(dev, 0x0100, value & ~0x80);
+               if (dev->isobufs != NULL) {
+                       for (i = 0; i < MAX_ISO_BUFS; i++) {
+                               if (dev->isobufs[i].urb)
+                                       usb_kill_urb(dev->isobufs[i].urb);
+                       }
+               }
+               unset_streaming(dev);
+
+               if (usb_set_interface(dev->udev, 0, 0))
+                       STK_ERROR("usb_set_interface failed !\n");
+               if (stk_sensor_sleep(dev))
+                       STK_ERROR("error suspending the sensor\n");
+       }
+       return 0;
+}
+
+/*
+ * This seems to be the shortest init sequence we
+ * must do in order to find the sensor
+ * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
+ * is also reset. Maybe powers down it?
+ * Rest of values don't make a difference
+ */
+
+static struct regval stk1125_initvals[] = {
+       /*TODO: What means this sequence? */
+       {0x0000, 0x24},
+       {0x0100, 0x21},
+       {0x0002, 0x68},
+       {0x0003, 0x80},
+       {0x0005, 0x00},
+       {0x0007, 0x03},
+       {0x000d, 0x00},
+       {0x000f, 0x02},
+       {0x0300, 0x12},
+       {0x0350, 0x41},
+       {0x0351, 0x00},
+       {0x0352, 0x00},
+       {0x0353, 0x00},
+       {0x0018, 0x10},
+       {0x0019, 0x00},
+       {0x001b, 0x0e},
+       {0x001c, 0x46},
+       {0x0300, 0x80},
+       {0x001a, 0x04},
+       {0x0110, 0x00},
+       {0x0111, 0x00},
+       {0x0112, 0x00},
+       {0x0113, 0x00},
+
+       {0xffff, 0xff},
+};
+
+
+static int stk_initialise(struct stk_camera *dev)
+{
+       struct regval *rv;
+       int ret;
+       if (!is_present(dev))
+               return -ENODEV;
+       if (is_initialised(dev))
+               return 0;
+       rv = stk1125_initvals;
+       while (rv->reg != 0xffff) {
+               ret = stk_camera_write_reg(dev, rv->reg, rv->val);
+               if (ret)
+                       return ret;
+               rv++;
+       }
+       if (stk_sensor_init(dev) == 0) {
+               set_initialised(dev);
+               return 0;
+       } else
+               return -1;
+}
+
+/* sysfs functions */
+/*FIXME cleanup this */
+
+static ssize_t show_brightness(struct device *class,
+                       struct device_attribute *attr, char *buf)
+{
+       struct video_device *vdev = to_video_device(class);
+       struct stk_camera *dev = vdev_to_camera(vdev);
+
+       return sprintf(buf, "%X\n", dev->vsettings.brightness);
+}
+
+static ssize_t store_brightness(struct device *class,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       char *endp;
+       unsigned long value;
+       int ret;
+
+       struct video_device *vdev = to_video_device(class);
+       struct stk_camera *dev = vdev_to_camera(vdev);
+
+       value = simple_strtoul(buf, &endp, 16);
+
+       dev->vsettings.brightness = (int) value;
+
+       ret = stk_sensor_set_brightness(dev, value >> 8);
+       if (ret)
+               return ret;
+       else
+               return count;
+}
+
+static ssize_t show_hflip(struct device *class,
+               struct device_attribute *attr, char *buf)
+{
+       struct video_device *vdev = to_video_device(class);
+       struct stk_camera *dev = vdev_to_camera(vdev);
+
+       return sprintf(buf, "%d\n", dev->vsettings.hflip);
+}
+
+static ssize_t store_hflip(struct device *class,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct video_device *vdev = to_video_device(class);
+       struct stk_camera *dev = vdev_to_camera(vdev);
+
+       if (strncmp(buf, "1", 1) == 0)
+               dev->vsettings.hflip = 1;
+       else if (strncmp(buf, "0", 1) == 0)
+               dev->vsettings.hflip = 0;
+       else
+               return -EINVAL;
+
+       return strlen(buf);
+}
+
+static ssize_t show_vflip(struct device *class,
+               struct device_attribute *attr, char *buf)
+{
+       struct video_device *vdev = to_video_device(class);
+       struct stk_camera *dev = vdev_to_camera(vdev);
+
+       return sprintf(buf, "%d\n", dev->vsettings.vflip);
+}
+
+static ssize_t store_vflip(struct device *class,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct video_device *vdev = to_video_device(class);
+       struct stk_camera *dev = vdev_to_camera(vdev);
+
+       if (strncmp(buf, "1", 1) == 0)
+               dev->vsettings.vflip = 1;
+       else if (strncmp(buf, "0", 1) == 0)
+               dev->vsettings.vflip = 0;
+       else
+               return -EINVAL;
+
+       return strlen(buf);
+}
+
+static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,
+                       show_brightness, store_brightness);
+static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);
+static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);
+
+static int stk_create_sysfs_files(struct video_device *vdev)
+{
+       int ret;
+
+       ret = video_device_create_file(vdev, &dev_attr_brightness);
+       ret += video_device_create_file(vdev, &dev_attr_hflip);
+       ret += video_device_create_file(vdev, &dev_attr_vflip);
+       return ret;
+}
+
+static void stk_remove_sysfs_files(struct video_device *vdev)
+{
+       video_device_remove_file(vdev, &dev_attr_brightness);
+       video_device_remove_file(vdev, &dev_attr_hflip);
+       video_device_remove_file(vdev, &dev_attr_vflip);
+}
+
+
+/* *********************************************** */
+/*
+ * This function is called as an URB transfert is complete (Isochronous pipe).
+ * So, the traitement is done in interrupt time, so it has be fast, not crash,
+ * and not stall. Neat.
+ */
+static void stk_isoc_handler(struct urb *urb)
+{
+       int i;
+       int ret;
+       int framelen;
+       unsigned long flags;
+
+       unsigned char *fill = NULL;
+       unsigned char *iso_buf = NULL;
+
+       struct stk_camera *dev;
+       struct stk_sio_buffer *fb;
+
+       dev = (struct stk_camera *) urb->context;
+
+       if (dev == NULL) {
+               STK_ERROR("isoc_handler called with NULL device !\n");
+               return;
+       }
+
+       if (urb->status == -ENOENT || urb->status == -ECONNRESET
+               || urb->status == -ESHUTDOWN) {
+               atomic_dec(&dev->urbs_used);
+               return;
+       }
+
+       spin_lock_irqsave(&dev->spinlock, flags);
+
+       if (urb->status != -EINPROGRESS && urb->status != 0) {
+               STK_ERROR("isoc_handler: urb->status == %d\n", urb->status);
+               goto resubmit;
+       }
+
+       if (list_empty(&dev->sio_avail)) {
+               /*FIXME Stop streaming after a while */
+               (void) (printk_ratelimit() &&
+               STK_ERROR("isoc_handler without available buffer!\n"));
+               goto resubmit;
+       }
+       fb = list_first_entry(&dev->sio_avail,
+                       struct stk_sio_buffer, list);
+       fill = fb->buffer + fb->v4lbuf.bytesused;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               if (urb->iso_frame_desc[i].status != 0) {
+                       if (urb->iso_frame_desc[i].status != -EXDEV)
+                               STK_ERROR("Frame %d has error %d\n", i,
+                                       urb->iso_frame_desc[i].status);
+                       continue;
+               }
+               framelen = urb->iso_frame_desc[i].actual_length;
+               iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               if (framelen <= 4)
+                       continue; /* no data */
+
+               /*
+                * we found something informational from there
+                * the isoc frames have to type of headers
+                * type1: 00 xx 00 00 or 20 xx 00 00
+                * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00
+                * xx is a sequencer which has never been seen over 0x3f
+                * imho data written down looks like bayer, i see similarities
+                * after every 640 bytes
+                */
+               if (*iso_buf & 0x80) {
+                       framelen -= 8;
+                       iso_buf += 8;
+                       /* This marks a new frame */
+                       if (fb->v4lbuf.bytesused != 0
+                               && fb->v4lbuf.bytesused != dev->frame_size) {
+                               (void) (printk_ratelimit() &&
+                               STK_ERROR("frame %d, "
+                                       "bytesused=%d, skipping\n",
+                                       i, fb->v4lbuf.bytesused));
+                               fb->v4lbuf.bytesused = 0;
+                               fill = fb->buffer;
+                       } else if (fb->v4lbuf.bytesused == dev->frame_size) {
+                               list_move_tail(dev->sio_avail.next,
+                                       &dev->sio_full);
+                               wake_up(&dev->wait_frame);
+                               if (list_empty(&dev->sio_avail)) {
+                                       (void) (printk_ratelimit() &&
+                                       STK_ERROR("No buffer available\n"));
+                                       goto resubmit;
+                               }
+                               fb = list_first_entry(&dev->sio_avail,
+                                       struct stk_sio_buffer, list);
+                               fb->v4lbuf.bytesused = 0;
+                               fill = fb->buffer;
+                       }
+               } else {
+                       framelen -= 4;
+                       iso_buf += 4;
+               }
+
+               /* Our buffer is full !!! */
+               if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
+                       (void) (printk_ratelimit() &&
+                       STK_ERROR("Frame buffer overflow, lost sync\n"));
+                       /*FIXME Do something here? */
+                       continue;
+               }
+               spin_unlock_irqrestore(&dev->spinlock, flags);
+               memcpy(fill, iso_buf, framelen);
+               spin_lock_irqsave(&dev->spinlock, flags);
+               fill += framelen;
+
+               /* New size of our buffer */
+               fb->v4lbuf.bytesused += framelen;
+       }
+
+resubmit:
+       spin_unlock_irqrestore(&dev->spinlock, flags);
+       urb->dev = dev->udev;
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret != 0) {
+               STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n",
+                       ret);
+       }
+}
+
+/* -------------------------------------------- */
+
+static int stk_prepare_iso(struct stk_camera *dev)
+{
+       void *kbuf;
+       int i, j;
+       struct urb *urb;
+       struct usb_device *udev;
+
+       if (dev == NULL)
+               return -ENXIO;
+       udev = dev->udev;
+
+       if (dev->isobufs)
+               STK_ERROR("isobufs already allocated. Bad\n");
+       else
+               dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),
+                                       GFP_KERNEL);
+       if (dev->isobufs == NULL) {
+               STK_ERROR("Unable to allocate iso buffers\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               if (dev->isobufs[i].data == NULL) {
+                       kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+                       if (kbuf == NULL) {
+                               STK_ERROR("Failed to allocate iso buffer %d\n",
+                                       i);
+                               goto isobufs_out;
+                       }
+                       dev->isobufs[i].data = kbuf;
+               } else
+                       STK_ERROR("isobuf data already allocated\n");
+               if (dev->isobufs[i].urb == NULL) {
+                       urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
+                       if (urb == NULL) {
+                               STK_ERROR("Failed to allocate URB %d\n", i);
+                               goto isobufs_out;
+                       }
+                       dev->isobufs[i].urb = urb;
+               } else {
+                       STK_ERROR("Killing URB\n");
+                       usb_kill_urb(dev->isobufs[i].urb);
+                       urb = dev->isobufs[i].urb;
+               }
+               urb->interval = 1;
+               urb->dev = udev;
+               urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = dev->isobufs[i].data;
+               urb->transfer_buffer_length = ISO_BUFFER_SIZE;
+               urb->complete = stk_isoc_handler;
+               urb->context = dev;
+               urb->start_frame = 0;
+               urb->number_of_packets = ISO_FRAMES_PER_DESC;
+
+               for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
+                       urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
+                       urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+               }
+       }
+       set_memallocd(dev);
+       return 0;
+
+isobufs_out:
+       for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++)
+               kfree(dev->isobufs[i].data);
+       for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++)
+               usb_free_urb(dev->isobufs[i].urb);
+       kfree(dev->isobufs);
+       dev->isobufs = NULL;
+       return -ENOMEM;
+}
+
+static void stk_clean_iso(struct stk_camera *dev)
+{
+       int i;
+
+       if (dev == NULL || dev->isobufs == NULL)
+               return;
+
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               struct urb *urb;
+
+               urb = dev->isobufs[i].urb;
+               if (urb) {
+                       if (atomic_read(&dev->urbs_used))
+                               usb_kill_urb(urb);
+                       usb_free_urb(urb);
+               }
+               kfree(dev->isobufs[i].data);
+       }
+       kfree(dev->isobufs);
+       dev->isobufs = NULL;
+       unset_memallocd(dev);
+}
+
+static int stk_setup_siobuf(struct stk_camera *dev, int index)
+{
+       struct stk_sio_buffer *buf = dev->sio_bufs + index;
+       INIT_LIST_HEAD(&buf->list);
+       buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size);
+       buf->buffer = vmalloc_user(buf->v4lbuf.length);
+       if (buf->buffer == NULL)
+               return -ENOMEM;
+       buf->mapcount = 0;
+       buf->dev = dev;
+       buf->v4lbuf.index = index;
+       buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       buf->v4lbuf.field = V4L2_FIELD_NONE;
+       buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
+       buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
+       return 0;
+}
+
+static int stk_free_sio_buffers(struct stk_camera *dev)
+{
+       int i;
+       int nbufs;
+       unsigned long flags;
+       if (dev->n_sbufs == 0 || dev->sio_bufs == NULL)
+               return 0;
+       /*
+       * If any buffers are mapped, we cannot free them at all.
+       */
+       for (i = 0; i < dev->n_sbufs; i++) {
+               if (dev->sio_bufs[i].mapcount > 0)
+                       return -EBUSY;
+       }
+       /*
+       * OK, let's do it.
+       */
+       spin_lock_irqsave(&dev->spinlock, flags);
+       INIT_LIST_HEAD(&dev->sio_avail);
+       INIT_LIST_HEAD(&dev->sio_full);
+       nbufs = dev->n_sbufs;
+       dev->n_sbufs = 0;
+       spin_unlock_irqrestore(&dev->spinlock, flags);
+       for (i = 0; i < nbufs; i++) {
+               if (dev->sio_bufs[i].buffer != NULL)
+                       vfree(dev->sio_bufs[i].buffer);
+       }
+       kfree(dev->sio_bufs);
+       dev->sio_bufs = NULL;
+       return 0;
+}
+
+static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
+{
+       int i;
+       if (dev->sio_bufs != NULL)
+               STK_ERROR("sio_bufs already allocated\n");
+       else {
+               dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer),
+                               GFP_KERNEL);
+               if (dev->sio_bufs == NULL)
+                       return -ENOMEM;
+               for (i = 0; i < n_sbufs; i++) {
+                       if (stk_setup_siobuf(dev, i))
+                               return (dev->n_sbufs > 1)? 0 : -ENOMEM;
+                       dev->n_sbufs = i+1;
+               }
+       }
+       return 0;
+}
+
+static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs)
+{
+       int err;
+       err = stk_prepare_iso(dev);
+       if (err) {
+               stk_clean_iso(dev);
+               return err;
+       }
+       err = stk_prepare_sio_buffers(dev, n_sbufs);
+       if (err) {
+               stk_free_sio_buffers(dev);
+               return err;
+       }
+       return 0;
+}
+
+static void stk_free_buffers(struct stk_camera *dev)
+{
+       stk_clean_iso(dev);
+       stk_free_sio_buffers(dev);
+}
+/* -------------------------------------------- */
+
+/* v4l file operations */
+
+static int v4l_stk_open(struct inode *inode, struct file *fp)
+{
+       struct stk_camera *dev;
+       struct video_device *vdev;
+
+       vdev = video_devdata(fp);
+       dev = vdev_to_camera(vdev);
+
+       if (dev == NULL || !is_present(dev))
+               return -ENXIO;
+       fp->private_data = vdev;
+       kref_get(&dev->kref);
+
+       return 0;
+}
+
+static int v4l_stk_release(struct inode *inode, struct file *fp)
+{
+       struct stk_camera *dev;
+       struct video_device *vdev;
+
+       vdev = video_devdata(fp);
+       if (vdev == NULL) {
+               STK_ERROR("v4l_release called w/o video devdata\n");
+               return -EFAULT;
+       }
+       dev = vdev_to_camera(vdev);
+       if (dev == NULL) {
+               STK_ERROR("v4l_release called on removed device\n");
+               return -ENODEV;
+       }
+
+       if (dev->owner != fp) {
+               kref_put(&dev->kref, stk_camera_cleanup);
+               return 0;
+       }
+
+       stk_stop_stream(dev);
+
+       stk_free_buffers(dev);
+
+       dev->owner = NULL;
+
+       kref_put(&dev->kref, stk_camera_cleanup);
+
+       return 0;
+}
+
+static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
+               size_t count, loff_t *f_pos)
+{
+       int i;
+       int ret;
+       unsigned long flags;
+       struct stk_camera *dev;
+       struct video_device *vdev;
+       struct stk_sio_buffer *sbuf;
+
+       vdev = video_devdata(fp);
+       if (vdev == NULL)
+               return -EFAULT;
+       dev = vdev_to_camera(vdev);
+
+       if (dev == NULL)
+               return -EIO;
+
+       if (!is_present(dev))
+               return -EIO;
+       if (dev->owner && dev->owner != fp)
+               return -EBUSY;
+       dev->owner = fp;
+       if (!is_streaming(dev)) {
+               if (stk_initialise(dev)
+                       || stk_allocate_buffers(dev, 3)
+                       || stk_start_stream(dev))
+                       return -ENOMEM;
+               spin_lock_irqsave(&dev->spinlock, flags);
+               for (i = 0; i < dev->n_sbufs; i++) {
+                       list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
+                       dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED;
+               }
+               spin_unlock_irqrestore(&dev->spinlock, flags);
+       }
+       if (*f_pos == 0) {
+               if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
+                       return -EWOULDBLOCK;
+               ret = wait_event_interruptible(dev->wait_frame,
+                       !list_empty(&dev->sio_full) || !is_present(dev));
+               if (ret)
+                       return ret;
+               if (!is_present(dev))
+                       return -EIO;
+       }
+       if (count + *f_pos > dev->frame_size)
+               count = dev->frame_size - *f_pos;
+       spin_lock_irqsave(&dev->spinlock, flags);
+       if (list_empty(&dev->sio_full)) {
+               spin_unlock_irqrestore(&dev->spinlock, flags);
+               STK_ERROR("BUG: No siobufs ready\n");
+               return 0;
+       }
+       sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
+       spin_unlock_irqrestore(&dev->spinlock, flags);
+
+       if (copy_to_user(buf, sbuf->buffer + *f_pos, count))
+               return -EFAULT;
+
+       *f_pos += count;
+
+       if (*f_pos >= dev->frame_size) {
+               *f_pos = 0;
+               spin_lock_irqsave(&dev->spinlock, flags);
+               list_move_tail(&sbuf->list, &dev->sio_avail);
+               spin_unlock_irqrestore(&dev->spinlock, flags);
+       }
+       return count;
+}
+
+static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
+{
+       struct stk_camera *dev;
+       struct video_device *vdev;
+
+       vdev = video_devdata(fp);
+
+       if (vdev == NULL)
+               return -EFAULT;
+
+       dev = vdev_to_camera(vdev);
+       if (dev == NULL)
+               return -ENODEV;
+
+       poll_wait(fp, &dev->wait_frame, wait);
+
+       if (!is_present(dev))
+               return POLLERR;
+
+       if (!list_empty(&dev->sio_full))
+               return (POLLIN | POLLRDNORM);
+
+       return 0;
+}
+
+
+static void stk_v4l_vm_open(struct vm_area_struct *vma)
+{
+       struct stk_sio_buffer *sbuf = vma->vm_private_data;
+       sbuf->mapcount++;
+}
+static void stk_v4l_vm_close(struct vm_area_struct *vma)
+{
+       struct stk_sio_buffer *sbuf = vma->vm_private_data;
+       sbuf->mapcount--;
+       if (sbuf->mapcount == 0)
+               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+static struct vm_operations_struct stk_v4l_vm_ops = {
+       .open = stk_v4l_vm_open,
+       .close = stk_v4l_vm_close
+};
+
+static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
+{
+       unsigned int i;
+       int ret;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       struct stk_camera *dev;
+       struct video_device *vdev;
+       struct stk_sio_buffer *sbuf = NULL;
+
+       if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
+               return -EINVAL;
+
+       vdev = video_devdata(fp);
+       dev = vdev_to_camera(vdev);
+
+       for (i = 0; i < dev->n_sbufs; i++) {
+               if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
+                       sbuf = dev->sio_bufs + i;
+                       break;
+               }
+       }
+       if (sbuf == NULL)
+               return -EINVAL;
+       ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
+       if (ret)
+               return ret;
+       vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_private_data = sbuf;
+       vma->vm_ops = &stk_v4l_vm_ops;
+       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
+       stk_v4l_vm_open(vma);
+       return 0;
+}
+
+/* v4l ioctl handlers */
+
+static int stk_vidioc_querycap(struct file *filp,
+               void *priv, struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "stk");
+       strcpy(cap->card, "stk");
+       cap->version = DRIVER_VERSION_NUM;
+
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+               | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int stk_vidioc_enum_input(struct file *filp,
+               void *priv, struct v4l2_input *input)
+{
+       if (input->index != 0)
+               return -EINVAL;
+
+       strcpy(input->name, "Syntek USB Camera");
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+       return 0;
+}
+
+
+static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       else
+               return 0;
+}
+
+/* from vivi.c */
+static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+       return 0;
+}
+
+/* List of all V4Lv2 controls supported by the driver */
+static struct v4l2_queryctrl stk_controls[] = {
+       {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xffff,
+               .step    = 0x0100,
+               .default_value = 0x6000,
+       },
+       /*TODO: get more controls to work */
+};
+
+static int stk_vidioc_queryctrl(struct file *filp,
+               void *priv, struct v4l2_queryctrl *c)
+{
+       int i;
+       int nbr;
+       nbr = ARRAY_SIZE(stk_controls);
+
+       for (i = 0; i < nbr; i++) {
+               if (stk_controls[i].id == c->id) {
+                       memcpy(c, &stk_controls[i],
+                               sizeof(struct v4l2_queryctrl));
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static int stk_vidioc_g_ctrl(struct file *filp,
+               void *priv, struct v4l2_control *c)
+{
+       struct stk_camera *dev = priv;
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               c->value = dev->vsettings.brightness;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int stk_vidioc_s_ctrl(struct file *filp,
+               void *priv, struct v4l2_control *c)
+{
+       struct stk_camera *dev = priv;
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               dev->vsettings.brightness = c->value;
+               return stk_sensor_set_brightness(dev, c->value >> 8);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+static int stk_vidioc_enum_fmt_cap(struct file *filp,
+               void *priv, struct v4l2_fmtdesc *fmtd)
+{
+       fmtd->flags = 0;
+
+       switch (fmtd->index) {
+       case 0:
+               fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
+               strcpy(fmtd->description, "r5g6b5");
+               break;
+       case 1:
+               fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
+               strcpy(fmtd->description, "r5g6b5BE");
+               break;
+       case 2:
+               fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
+               strcpy(fmtd->description, "yuv4:2:2");
+               break;
+       case 3:
+               fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
+               strcpy(fmtd->description, "Raw bayer");
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static struct stk_size {
+       unsigned w;
+       unsigned h;
+       enum stk_mode m;
+} stk_sizes[] = {
+       { .w = 1280, .h = 1024, .m = MODE_SXGA, },
+       { .w = 640,  .h = 480,  .m = MODE_VGA,  },
+       { .w = 352,  .h = 288,  .m = MODE_CIF,  },
+       { .w = 320,  .h = 240,  .m = MODE_QVGA, },
+       { .w = 176,  .h = 144,  .m = MODE_QCIF, },
+};
+
+static int stk_vidioc_g_fmt_cap(struct file *filp,
+               void *priv, struct v4l2_format *f)
+{
+       struct v4l2_pix_format *pix_format = &f->fmt.pix;
+       struct stk_camera *dev = priv;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(stk_sizes)
+                       && stk_sizes[i].m != dev->vsettings.mode;
+               i++);
+       if (i == ARRAY_SIZE(stk_sizes)) {
+               STK_ERROR("ERROR: mode invalid\n");
+               return -EINVAL;
+       }
+       pix_format->width = stk_sizes[i].w;
+       pix_format->height = stk_sizes[i].h;
+       pix_format->field = V4L2_FIELD_NONE;
+       pix_format->colorspace = V4L2_COLORSPACE_SRGB;
+       pix_format->priv = 0;
+       pix_format->pixelformat = dev->vsettings.palette;
+       if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
+               pix_format->bytesperline = pix_format->width;
+       else
+               pix_format->bytesperline = 2 * pix_format->width;
+       pix_format->sizeimage = pix_format->bytesperline
+                               * pix_format->height;
+       return 0;
+}
+
+static int stk_vidioc_try_fmt_cap(struct file *filp,
+               void *priv, struct v4l2_format *fmtd)
+{
+       int i;
+       switch (fmtd->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_SBGGR8:
+               break;
+       default:
+               return -EINVAL;
+       }
+       for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) {
+               if (fmtd->fmt.pix.width > stk_sizes[i].w)
+                       break;
+       }
+       if (i == ARRAY_SIZE(stk_sizes)
+               || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w)
+                       < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
+               fmtd->fmt.pix.height = stk_sizes[i-1].h;
+               fmtd->fmt.pix.width = stk_sizes[i-1].w;
+               fmtd->fmt.pix.priv = i - 1;
+       } else {
+               fmtd->fmt.pix.height = stk_sizes[i].h;
+               fmtd->fmt.pix.width = stk_sizes[i].w;
+               fmtd->fmt.pix.priv = i;
+       }
+
+       fmtd->fmt.pix.field = V4L2_FIELD_NONE;
+       fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+       if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
+               fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width;
+       else
+               fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
+       fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
+               * fmtd->fmt.pix.height;
+       return 0;
+}
+
+static int stk_vidioc_s_fmt_cap(struct file *filp,
+               void *priv, struct v4l2_format *fmtd)
+{
+       int ret;
+       struct stk_camera *dev = priv;
+
+       if (dev == NULL)
+               return -ENODEV;
+       if (!is_present(dev))
+               return -ENODEV;
+       if (is_streaming(dev))
+               return -EBUSY;
+       if (dev->owner && dev->owner != filp)
+               return -EBUSY;
+       dev->owner = filp;
+       ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
+       if (ret)
+               return ret;
+
+       dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
+       stk_free_buffers(dev);
+       dev->frame_size = fmtd->fmt.pix.sizeimage;
+       dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m;
+
+       stk_initialise(dev);
+       /* This registers controls some timings, not sure of what. */
+       stk_camera_write_reg(dev, 0x001b, 0x0e);
+       if (dev->vsettings.mode == MODE_SXGA)
+               stk_camera_write_reg(dev, 0x001c, 0x0e);
+       else
+               stk_camera_write_reg(dev, 0x001c, 0x46);
+       /*
+        * Registers 0x0115 0x0114 are the size of each line (bytes),
+        * regs 0x0117 0x0116 are the heigth of the image.
+        */
+       stk_camera_write_reg(dev, 0x0115,
+               (fmtd->fmt.pix.bytesperline >> 8) & 0xff);
+       stk_camera_write_reg(dev, 0x0114,
+               fmtd->fmt.pix.bytesperline & 0xff);
+       stk_camera_write_reg(dev, 0x0117,
+               (fmtd->fmt.pix.height >> 8) & 0xff);
+       stk_camera_write_reg(dev, 0x0116,
+               fmtd->fmt.pix.height & 0xff);
+       return stk_sensor_configure(dev);
+}
+
+static int stk_vidioc_reqbufs(struct file *filp,
+               void *priv, struct v4l2_requestbuffers *rb)
+{
+       struct stk_camera *dev = priv;
+
+       if (dev == NULL)
+               return -ENODEV;
+       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (rb->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+       if (is_streaming(dev)
+               || (dev->owner && dev->owner != filp))
+               return -EBUSY;
+       dev->owner = filp;
+
+       /*FIXME If they ask for zero, we must stop streaming and free */
+       if (rb->count < 3)
+               rb->count = 3;
+       /* Arbitrary limit */
+       else if (rb->count > 5)
+               rb->count = 5;
+
+       stk_allocate_buffers(dev, rb->count);
+       rb->count = dev->n_sbufs;
+       return 0;
+}
+
+static int stk_vidioc_querybuf(struct file *filp,
+               void *priv, struct v4l2_buffer *buf)
+{
+       int index;
+       struct stk_camera *dev = priv;
+       struct stk_sio_buffer *sbuf;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       index = buf->index;
+
+       if (index < 0 || index >= dev->n_sbufs)
+               return -EINVAL;
+       sbuf = dev->sio_bufs + buf->index;
+       *buf = sbuf->v4lbuf;
+       return 0;
+}
+
+static int stk_vidioc_qbuf(struct file *filp,
+               void *priv, struct v4l2_buffer *buf)
+{
+       struct stk_camera *dev = priv;
+       struct stk_sio_buffer *sbuf;
+       unsigned long flags;
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (buf->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (buf->index < 0 || buf->index >= dev->n_sbufs)
+               return -EINVAL;
+       sbuf = dev->sio_bufs + buf->index;
+       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
+               return 0;
+       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
+       sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
+       spin_lock_irqsave(&dev->spinlock, flags);
+       list_add_tail(&sbuf->list, &dev->sio_avail);
+       *buf = sbuf->v4lbuf;
+       spin_unlock_irqrestore(&dev->spinlock, flags);
+       return 0;
+}
+
+static int stk_vidioc_dqbuf(struct file *filp,
+               void *priv, struct v4l2_buffer *buf)
+{
+       struct stk_camera *dev = priv;
+       struct stk_sio_buffer *sbuf;
+       unsigned long flags;
+       int ret;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+               || !is_streaming(dev))
+               return -EINVAL;
+
+       if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
+               return -EWOULDBLOCK;
+       ret = wait_event_interruptible(dev->wait_frame,
+               !list_empty(&dev->sio_full) || !is_present(dev));
+       if (ret)
+               return ret;
+       if (!is_present(dev))
+               return -EIO;
+
+       spin_lock_irqsave(&dev->spinlock, flags);
+       sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
+       list_del_init(&sbuf->list);
+       spin_unlock_irqrestore(&dev->spinlock, flags);
+       sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+       sbuf->v4lbuf.sequence = ++dev->sequence;
+       do_gettimeofday(&sbuf->v4lbuf.timestamp);
+
+       *buf = sbuf->v4lbuf;
+       return 0;
+}
+
+static int stk_vidioc_streamon(struct file *filp,
+               void *priv, enum v4l2_buf_type type)
+{
+       struct stk_camera *dev = priv;
+       if (is_streaming(dev))
+               return 0;
+       if (dev->sio_bufs == NULL)
+               return -EINVAL;
+       dev->sequence = 0;
+       return stk_start_stream(dev);
+}
+
+static int stk_vidioc_streamoff(struct file *filp,
+               void *priv, enum v4l2_buf_type type)
+{
+       struct stk_camera *dev = priv;
+       unsigned long flags;
+       int i;
+       stk_stop_stream(dev);
+       spin_lock_irqsave(&dev->spinlock, flags);
+       INIT_LIST_HEAD(&dev->sio_avail);
+       INIT_LIST_HEAD(&dev->sio_full);
+       for (i = 0; i < dev->n_sbufs; i++) {
+               INIT_LIST_HEAD(&dev->sio_bufs[i].list);
+               dev->sio_bufs[i].v4lbuf.flags = 0;
+       }
+       spin_unlock_irqrestore(&dev->spinlock, flags);
+       return 0;
+}
+
+
+static int stk_vidioc_g_parm(struct file *filp,
+               void *priv, struct v4l2_streamparm *sp)
+{
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp->parm.capture.capability = 0;
+       sp->parm.capture.capturemode = 0;
+       /*FIXME This is not correct */
+       sp->parm.capture.timeperframe.numerator = 1;
+       sp->parm.capture.timeperframe.denominator = 30;
+       sp->parm.capture.readbuffers = 2;
+       sp->parm.capture.extendedmode = 0;
+       return 0;
+}
+
+static struct file_operations v4l_stk_fops = {
+       .owner = THIS_MODULE,
+       .open = v4l_stk_open,
+       .release = v4l_stk_release,
+       .read = v4l_stk_read,
+       .poll = v4l_stk_poll,
+       .mmap = v4l_stk_mmap,
+       .ioctl = video_ioctl2,
+       .llseek = no_llseek
+};
+
+static void stk_v4l_dev_release(struct video_device *vd)
+{
+}
+
+static struct video_device stk_v4l_data = {
+       .name = "stkwebcam",
+       .type = VFL_TYPE_GRABBER,
+       .type2 = VID_TYPE_CAPTURE,
+       .minor = -1,
+       .tvnorms = V4L2_STD_UNKNOWN,
+       .current_norm = V4L2_STD_UNKNOWN,
+       .fops = &v4l_stk_fops,
+       .release = stk_v4l_dev_release,
+
+       .vidioc_querycap = stk_vidioc_querycap,
+       .vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap,
+       .vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap,
+       .vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap,
+       .vidioc_enum_input = stk_vidioc_enum_input,
+       .vidioc_s_input = stk_vidioc_s_input,
+       .vidioc_g_input = stk_vidioc_g_input,
+       .vidioc_s_std = stk_vidioc_s_std,
+       .vidioc_reqbufs = stk_vidioc_reqbufs,
+       .vidioc_querybuf = stk_vidioc_querybuf,
+       .vidioc_qbuf = stk_vidioc_qbuf,
+       .vidioc_dqbuf = stk_vidioc_dqbuf,
+       .vidioc_streamon = stk_vidioc_streamon,
+       .vidioc_streamoff = stk_vidioc_streamoff,
+       .vidioc_queryctrl = stk_vidioc_queryctrl,
+       .vidioc_g_ctrl = stk_vidioc_g_ctrl,
+       .vidioc_s_ctrl = stk_vidioc_s_ctrl,
+       .vidioc_g_parm = stk_vidioc_g_parm,
+};
+
+
+static int stk_register_video_device(struct stk_camera *dev)
+{
+       int err;
+
+       dev->vdev = stk_v4l_data;
+       dev->vdev.debug = debug;
+       dev->vdev.dev = &dev->interface->dev;
+       dev->vdev.priv = dev;
+       err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+       if (err)
+               STK_ERROR("v4l registration failed\n");
+       else
+               STK_INFO("Syntek USB2.0 Camera is now controlling video device"
+                       " /dev/video%d\n", dev->vdev.minor);
+       return err;
+}
+
+
+/* USB Stuff */
+
+static int stk_camera_probe(struct usb_interface *interface,
+               const struct usb_device_id *id)
+{
+       int i;
+       int err;
+
+       struct stk_camera *dev = NULL;
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+
+       dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
+       if (dev == NULL) {
+               STK_ERROR("Out of memory !\n");
+               return -ENOMEM;
+       }
+
+       kref_init(&dev->kref);
+       spin_lock_init(&dev->spinlock);
+       init_waitqueue_head(&dev->wait_frame);
+
+       dev->udev = udev;
+       dev->interface = interface;
+       usb_get_intf(interface);
+
+       dev->vsettings.vflip = vflip;
+       dev->vsettings.hflip = hflip;
+       dev->n_sbufs = 0;
+       set_present(dev);
+
+       /* Set up the endpoint information
+        * use only the first isoc-in endpoint
+        * for the current alternate setting */
+       iface_desc = interface->cur_altsetting;
+
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               if (!dev->isoc_ep
+                       && ((endpoint->bEndpointAddress
+                               & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+                       && ((endpoint->bmAttributes
+                               & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) {
+                       /* we found an isoc in endpoint */
+                       dev->isoc_ep = (endpoint->bEndpointAddress & 0xF);
+                       break;
+               }
+       }
+       if (!dev->isoc_ep) {
+               STK_ERROR("Could not find isoc-in endpoint");
+               kref_put(&dev->kref, stk_camera_cleanup);
+               return -ENODEV;
+       }
+       dev->vsettings.brightness = 0x7fff;
+       dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
+       dev->vsettings.mode = MODE_VGA;
+       dev->frame_size = 640*480*2;
+
+       INIT_LIST_HEAD(&dev->sio_avail);
+       INIT_LIST_HEAD(&dev->sio_full);
+
+       usb_set_intfdata(interface, dev);
+
+       err = stk_register_video_device(dev);
+       if (err) {
+               kref_put(&dev->kref, stk_camera_cleanup);
+               return err;
+       }
+
+       stk_create_sysfs_files(&dev->vdev);
+
+       return 0;
+}
+
+static void stk_camera_disconnect(struct usb_interface *interface)
+{
+       struct stk_camera *dev = usb_get_intfdata(interface);
+
+       usb_set_intfdata(interface, NULL);
+       unset_present(dev);
+
+       wake_up_interruptible(&dev->wait_frame);
+       stk_remove_sysfs_files(&dev->vdev);
+
+       kref_put(&dev->kref, stk_camera_cleanup);
+}
+
+static struct usb_driver stk_camera_driver = {
+       .name = "stkwebcam",
+       .probe = stk_camera_probe,
+       .disconnect = stk_camera_disconnect,
+       .id_table = stkwebcam_table,
+};
+
+
+static int __init stk_camera_init(void)
+{
+       int result;
+
+       result = usb_register(&stk_camera_driver);
+       if (result)
+               STK_ERROR("usb_register failed ! Error number %d\n", result);
+
+
+       return result;
+}
+
+static void __exit stk_camera_exit(void)
+{
+       usb_deregister(&stk_camera_driver);
+}
+
+module_init(stk_camera_init);
+module_exit(stk_camera_exit);
+
+
diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
new file mode 100644 (file)
index 0000000..7e989d1
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * stk-webcam.h : Driver for Syntek 1125 USB webcam controller
+ *
+ * Copyright (C) 2006 Nicolas VIVIEN
+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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 STKWEBCAM_H
+#define STKWEBCAM_H
+
+#include <linux/usb.h>
+#include <media/v4l2-common.h>
+
+#define DRIVER_VERSION         "v0.0.1"
+#define DRIVER_VERSION_NUM     0x000001
+
+#define MAX_ISO_BUFS           3
+#define ISO_FRAMES_PER_DESC    16
+#define ISO_MAX_FRAME_SIZE     3 * 1024
+#define ISO_BUFFER_SIZE                (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
+
+
+#define PREFIX                         "stkwebcam: "
+#define STK_INFO(str, args...)         printk(KERN_INFO PREFIX str, ##args)
+#define STK_ERROR(str, args...)                printk(KERN_ERR PREFIX str, ##args)
+#define STK_WARNING(str, args...)      printk(KERN_WARNING PREFIX str, ##args)
+
+struct stk_iso_buf {
+       void *data;
+       int length;
+       int read;
+       struct urb *urb;
+};
+
+/* Streaming IO buffers */
+struct stk_sio_buffer {
+       struct v4l2_buffer v4lbuf;
+       char *buffer;
+       int mapcount;
+       struct stk_camera *dev;
+       struct list_head list;
+};
+
+enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
+
+struct stk_video {
+       enum stk_mode mode;
+       int brightness;
+       __u32 palette;
+       int hflip;
+       int vflip;
+};
+
+enum stk_status {
+       S_PRESENT = 1,
+       S_INITIALISED = 2,
+       S_MEMALLOCD = 4,
+       S_STREAMING = 8,
+};
+#define is_present(dev)                ((dev)->status & S_PRESENT)
+#define is_initialised(dev)    ((dev)->status & S_INITIALISED)
+#define is_streaming(dev)      ((dev)->status & S_STREAMING)
+#define is_memallocd(dev)      ((dev)->status & S_MEMALLOCD)
+#define set_present(dev)       ((dev)->status = S_PRESENT)
+#define unset_present(dev)     ((dev)->status &= \
+                                       ~(S_PRESENT|S_INITIALISED|S_STREAMING))
+#define set_initialised(dev)   ((dev)->status |= S_INITIALISED)
+#define set_memallocd(dev)     ((dev)->status |= S_MEMALLOCD)
+#define unset_memallocd(dev)   ((dev)->status &= ~S_MEMALLOCD)
+#define set_streaming(dev)     ((dev)->status |= S_STREAMING)
+#define unset_streaming(dev)   ((dev)->status &= ~S_STREAMING)
+
+struct regval {
+       unsigned reg;
+       unsigned val;
+};
+
+struct stk_camera {
+       struct video_device vdev;
+       struct usb_device *udev;
+       struct usb_interface *interface;
+       int webcam_model;
+       struct file *owner;
+
+       u8 isoc_ep;
+
+       struct kref kref;
+       /* Not sure if this is right */
+       atomic_t urbs_used;
+
+       struct stk_video vsettings;
+
+       enum stk_status status;
+
+       spinlock_t spinlock;
+       wait_queue_head_t wait_frame;
+
+       struct stk_iso_buf *isobufs;
+
+       int frame_size;
+       /* Streaming buffers */
+       unsigned int n_sbufs;
+       struct stk_sio_buffer *sio_bufs;
+       struct list_head sio_avail;
+       struct list_head sio_full;
+       unsigned sequence;
+};
+
+#define to_stk_camera(d) container_of(d, struct stk_camera, kref)
+#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
+
+void stk_camera_delete(struct kref *);
+int stk_camera_write_reg(struct stk_camera *, u16, u8);
+int stk_camera_read_reg(struct stk_camera *, u16, int *);
+
+int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val);
+int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val);
+int stk_sensor_init(struct stk_camera *);
+int stk_sensor_configure(struct stk_camera *);
+int stk_sensor_sleep(struct stk_camera *dev);
+int stk_sensor_wakeup(struct stk_camera *dev);
+int stk_sensor_set_brightness(struct stk_camera *dev, int br);
+
+#endif
index 43225802a5511d6b7934561223cd796196d435d8..b4d10f7a4e57e3644d5d2bcfd7773f72807dcbb5 100644 (file)
@@ -8,6 +8,7 @@
  * Muting and tone control by Jonathan Isom <jisom@ematic.com>
  *
  * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
  * This code is placed under the terms of the GNU General Public License
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  * Which was based on tda8425.c by Greg Alexander (c) 1998
@@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client)
        t->volume =  0x3b ;                              /* -27dB Volume            */
        if (loudness)                    /* Turn loudness on?     */
                t->volume |= TDA7432_LD_ON;
-       t->muted    = VIDEO_AUDIO_MUTE;
+       t->muted    = 1;
        t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
        t->bass         = TDA7432_BASS_0DB;      /* 0dB Bass              */
        t->lf     = TDA7432_ATTEN_0DB;   /* 0dB attenuation       */
@@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client)
        return 0;
 }
 
-static int tda7432_command(struct i2c_client *client,
-                          unsigned int cmd, void *arg)
+static int tda7432_get_ctrl(struct i2c_client *client,
+                           struct v4l2_control *ctrl)
 {
        struct tda7432 *t = i2c_get_clientdata(client);
-       v4l_dbg(2, debug,client,"In tda7432_command\n");
-       if (debug>1)
-               v4l_i2c_print_ioctl(client,cmd);
 
-       switch (cmd) {
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-
-       /* Query card - scale from TDA7432 settings to V4L settings */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               va->flags |= VIDEO_AUDIO_VOLUME |
-                       VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE |
-                       VIDEO_AUDIO_MUTABLE;
-               if (t->muted)
-                       va->flags |= VIDEO_AUDIO_MUTE;
-               va->mode |= VIDEO_SOUND_STEREO;
-               /* Master volume control
-                * V4L volume is min 0, max 65535
-                * TDA7432 Volume:
-                * Min (-79dB) is 0x6f
-                * Max (+20dB) is 0x07 (630)
-                * Max (0dB) is 0x20 (829)
-                * (Mask out bit 7 of vol - it's for the loudness setting)
-                */
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value=t->muted;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
                if (!maxvol){  /* max +20db */
-                       va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+                       ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
                } else {       /* max 0db   */
-                       va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
+                       ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
                }
-
-               /* Balance depends on L,R attenuation
-                * V4L balance is 0 to 65535, middle is 32768
-                * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f
-                * to scale up to V4L numbers, mult by 1057
-                * attenuation exists for lf, lr, rf, rr
-                * we use only lf and rf (front channels)
-                */
-
+               return 0;
+       case V4L2_CID_AUDIO_BALANCE:
+       {
                if ( (t->lf) < (t->rf) )
                        /* right is attenuated, balance shifted left */
-                       va->balance = (32768 - 1057*(t->rf));
+                       ctrl->value = (32768 - 1057*(t->rf));
                else
                        /* left is attenuated, balance shifted right */
-                       va->balance = (32768 + 1057*(t->lf));
-
+                       ctrl->value = (32768 + 1057*(t->lf));
+               return 0;
+       }
+       case V4L2_CID_AUDIO_BASS:
+       {
                /* Bass/treble 4 bits each */
-               va->bass=t->bass;
-               if(va->bass >= 0x8)
-                       va->bass = ~(va->bass - 0x8) & 0xf;
-               va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
-               va->treble=t->treble;
-               if(va->treble >= 0x8)
-                       va->treble = ~(va->treble - 0x8) & 0xf;
-               va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
-
-               break; /* VIDIOCGAUDIO case */
+               int bass=t->bass;
+               if(bass >= 0x8)
+                       bass = ~(bass - 0x8) & 0xf;
+               ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
+               return 0;
        }
-
-       /* Set card - scale from V4L settings to TDA7432 settings */
-       case VIDIOCSAUDIO:
+       case V4L2_CID_AUDIO_TREBLE:
        {
-               struct video_audio *va = arg;
+               int treble=t->treble;
+               if(treble >= 0x8)
+                       treble = ~(treble - 0x8) & 0xf;
+               ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
+               return 0;
+       }
+       }
+       return -EINVAL;
+}
 
-               if(va->flags & VIDEO_AUDIO_VOLUME){
-                       if(!maxvol){ /* max +20db */
-                               t->volume = 0x6f - ((va->volume)/630);
-                       } else {    /* max 0db   */
-                               t->volume = 0x6f - ((va->volume)/829);
-                       }
+static int tda7432_set_ctrl(struct i2c_client *client,
+                           struct v4l2_control *ctrl)
+{
+       struct tda7432 *t = i2c_get_clientdata(client);
 
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               t->muted=ctrl->value;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               if(!maxvol){ /* max +20db */
+                       t->volume = 0x6f - ((ctrl->value)/630);
+               } else {    /* max 0db   */
+                       t->volume = 0x6f - ((ctrl->value)/829);
+               }
                if (loudness)           /* Turn on the loudness bit */
                        t->volume |= TDA7432_LD_ON;
 
-                       tda7432_write(client,TDA7432_VL, t->volume);
-               }
-
-               if(va->flags & VIDEO_AUDIO_BASS)
-               {
-                       t->bass = va->bass >> 12;
-                       if(t->bass>= 0x8)
-                                       t->bass = (~t->bass & 0xf) + 0x8 ;
-               }
-               if(va->flags & VIDEO_AUDIO_TREBLE)
-               {
-                       t->treble= va->treble >> 12;
-                       if(t->treble>= 0x8)
-                                       t->treble = (~t->treble & 0xf) + 0x8 ;
-               }
-               if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
-                       tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
-
-               if(va->flags & VIDEO_AUDIO_BALANCE)     {
-               if (va->balance < 32768)
-               {
+               tda7432_write(client,TDA7432_VL, t->volume);
+               return 0;
+       case V4L2_CID_AUDIO_BALANCE:
+               if (ctrl->value < 32768) {
                        /* shifted to left, attenuate right */
-                       t->rr = (32768 - va->balance)/1057;
+                       t->rr = (32768 - ctrl->value)/1057;
                        t->rf = t->rr;
                        t->lr = TDA7432_ATTEN_0DB;
                        t->lf = TDA7432_ATTEN_0DB;
-               }
-               else if(va->balance > 32769)
-               {
+               } else if(ctrl->value > 32769) {
                        /* shifted to right, attenuate left */
-                       t->lf = (va->balance - 32768)/1057;
+                       t->lf = (ctrl->value - 32768)/1057;
                        t->lr = t->lf;
                        t->rr = TDA7432_ATTEN_0DB;
                        t->rf = TDA7432_ATTEN_0DB;
-               }
-               else
-               {
+               } else {
                        /* centered */
                        t->rr = TDA7432_ATTEN_0DB;
                        t->rf = TDA7432_ATTEN_0DB;
                        t->lf = TDA7432_ATTEN_0DB;
                        t->lr = TDA7432_ATTEN_0DB;
                }
-               }
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               t->bass = ctrl->value >> 12;
+               if(t->bass>= 0x8)
+                               t->bass = (~t->bass & 0xf) + 0x8 ;
+
+               tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+               return 0;
+       case V4L2_CID_AUDIO_TREBLE:
+               t->treble= ctrl->value >> 12;
+               if(t->treble>= 0x8)
+                               t->treble = (~t->treble & 0xf) + 0x8 ;
+
+               tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+               return 0;
+       default:
+               return -EINVAL;
+       }
 
-               t->muted=(va->flags & VIDEO_AUDIO_MUTE);
-               if (t->muted)
-               {
-                       /* Mute & update balance*/
-                       tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
-                       tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
-                       tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
-                       tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
-               } else {
-                       tda7432_write(client,TDA7432_LF, t->lf);
-                       tda7432_write(client,TDA7432_LR, t->lr);
-                       tda7432_write(client,TDA7432_RF, t->rf);
-                       tda7432_write(client,TDA7432_RR, t->rr);
-               }
+       /* Used for both mute and balance changes */
+       if (t->muted)
+       {
+               /* Mute & update balance*/
+               tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
+               tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
+               tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
+               tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+       } else {
+               tda7432_write(client,TDA7432_LF, t->lf);
+               tda7432_write(client,TDA7432_LR, t->lr);
+               tda7432_write(client,TDA7432_RF, t->rf);
+               tda7432_write(client,TDA7432_RR, t->rr);
+       }
+       return 0;
+}
 
-               break;
+static int tda7432_command(struct i2c_client *client,
+                          unsigned int cmd, void *arg)
+{
+       v4l_dbg(2, debug,client,"In tda7432_command\n");
+       if (debug>1)
+               v4l_i2c_print_ioctl(client,cmd);
+
+       switch (cmd) {
+       /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *qc = arg;
+
+               switch (qc->id) {
+                       case V4L2_CID_AUDIO_MUTE:
+                       case V4L2_CID_AUDIO_VOLUME:
+                       case V4L2_CID_AUDIO_BALANCE:
+                       case V4L2_CID_AUDIO_BASS:
+                       case V4L2_CID_AUDIO_TREBLE:
+                       default:
+                               return -EINVAL;
+               }
+               return v4l2_ctrl_query_fill_std(qc);
+       }
+       case VIDIOC_S_CTRL:
+               return tda7432_set_ctrl(client, arg);
 
-       } /* end of VIDEOCSAUDIO case */
+       case VIDIOC_G_CTRL:
+               return tda7432_get_ctrl(client, arg);
 
        } /* end of (cmd) switch */
 
index 0e5cf459d3ed615c70474d8064bc111000c92f0f..55bc89a6f0694c7f3d8e35e6804f4fb8d01eda5f 100644 (file)
 #include <linux/videodev.h>
 #include "tuner-i2c.h"
 #include "tda8290.h"
+#include "tda827x.h"
+#include "tda18271.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tda8290 "
+#define PREFIX "tda8290"
 
 /* ---------------------------------------------------------------------- */
 
@@ -38,345 +40,71 @@ struct tda8290_priv {
        struct tuner_i2c_props i2c_props;
 
        unsigned char tda8290_easy_mode;
-       unsigned char tda827x_lpsel;
-       unsigned char tda827x_addr;
-       unsigned char tda827x_ver;
-       unsigned int sgIF;
-
-       u32 frequency;
-
-       unsigned int *lna_cfg;
-       int (*tuner_callback) (void *dev, int command,int arg);
-};
-
-/* ---------------------------------------------------------------------- */
-
-struct tda827x_data {
-       u32 lomax;
-       u8  spd;
-       u8  bs;
-       u8  bp;
-       u8  cp;
-       u8  gc3;
-       u8 div1p5;
-};
-
-     /* Note lomax entry is lo / 62500 */
-
-static struct tda827x_data tda827x_analog[] = {
-       { .lomax =   992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  62 MHz */
-       { .lomax =  1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  66 MHz */
-       { .lomax =  1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  76 MHz */
-       { .lomax =  1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  84 MHz */
-       { .lomax =  1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  93 MHz */
-       { .lomax =  1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  98 MHz */
-       { .lomax =  1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
-       { .lomax =  1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
-       { .lomax =  2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
-       { .lomax =  2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
-       { .lomax =  2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
-       { .lomax =  2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
-       { .lomax =  2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
-       { .lomax =  3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
-       { .lomax =  3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
-       { .lomax =  4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
-       { .lomax =  4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
-       { .lomax =  5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
-       { .lomax =  5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
-       { .lomax =  7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
-       { .lomax =  7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
-       { .lomax =  8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
-       { .lomax =  8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
-       { .lomax =  9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
-       { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
-       { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
-       { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
-       { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
-       { .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
-};
-
-static void tda827x_set_analog_params(struct dvb_frontend *fe,
-                                     struct analog_parameters *params)
-{
-       unsigned char tuner_reg[8];
-       unsigned char reg2[2];
-       u32 N;
-       int i;
-       struct tda8290_priv *priv = fe->tuner_priv;
-       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
-       unsigned int freq = params->frequency;
-
-       if (params->mode == V4L2_TUNER_RADIO)
-               freq = freq / 1000;
-
-       N = freq + priv->sgIF;
-       i = 0;
-       while (tda827x_analog[i].lomax < N) {
-               if(tda827x_analog[i + 1].lomax == 0)
-                       break;
-               i++;
-       }
-
-       N = N << tda827x_analog[i].spd;
-
-       tuner_reg[0] = 0;
-       tuner_reg[1] = (unsigned char)(N>>8);
-       tuner_reg[2] = (unsigned char) N;
-       tuner_reg[3] = 0x40;
-       tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
-       tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
-                      (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
-       tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
-       tuner_reg[7] = 0x8f;
-
-       msg.buf = tuner_reg;
-       msg.len = 8;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       msg.buf= reg2;
-       msg.len = 2;
-       reg2[0] = 0x80;
-       reg2[1] = 0;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       reg2[0] = 0x60;
-       reg2[1] = 0xbf;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       reg2[0] = 0x30;
-       reg2[1] = tuner_reg[4] + 0x80;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       msleep(1);
-       reg2[0] = 0x30;
-       reg2[1] = tuner_reg[4] + 4;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       msleep(1);
-       reg2[0] = 0x30;
-       reg2[1] = tuner_reg[4];
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       msleep(550);
-       reg2[0] = 0x30;
-       reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       reg2[0] = 0x60;
-       reg2[1] = 0x3f;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       reg2[0] = 0x80;
-       reg2[1] = 0x08;   // Vsync en
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-}
 
-static void tda827x_agcf(struct dvb_frontend *fe)
-{
-       struct tda8290_priv *priv = fe->tuner_priv;
-       unsigned char data[] = {0x80, 0x0c};
-       struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
-                             .flags = 0, .len = 2};
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-}
-
-/* ---------------------------------------------------------------------- */
+       unsigned char tda827x_addr;
 
-struct tda827xa_data {
-       u32 lomax;
-       u8  svco;
-       u8  spd;
-       u8  scr;
-       u8  sbs;
-       u8  gc3;
-};
+       unsigned char ver;
+#define TDA8290   1
+#define TDA8295   2
+#define TDA8275   4
+#define TDA8275A  8
+#define TDA18271 16
 
-static struct tda827xa_data tda827xa_analog[] = {
-       { .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
-       { .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
-       { .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
-       { .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
-       { .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
-       { .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
-       { .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
-       { .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
-       { .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
-       { .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
-       { .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
-       { .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
-       { .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
-       { .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
-       { .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
-       { .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
-       { .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
-       { .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
-       { .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
-       { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
-       { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
-       { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
-       { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
-       { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
-       { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
-       { .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
+       struct tda827x_config cfg;
 };
 
-static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
-                             struct analog_parameters *params)
-{
-       struct tda8290_priv *priv = fe->tuner_priv;
-       unsigned char buf[] = {0x22, 0x01};
-       int arg;
-       struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
-
-       if ((priv->lna_cfg == NULL)  || (priv->tuner_callback == NULL))
-           return;
-
-       if (*priv->lna_cfg) {
-               if (high)
-                       tuner_dbg("setting LNA to high gain\n");
-               else
-                       tuner_dbg("setting LNA to low gain\n");
-       }
-       switch (*priv->lna_cfg) {
-       case 0: /* no LNA */
-               break;
-       case 1: /* switch is GPIO 0 of tda8290 */
-       case 2:
-               /* turn Vsync on */
-               if (params->std & V4L2_STD_MN)
-                       arg = 1;
-               else
-                       arg = 0;
-               if (priv->tuner_callback)
-                       priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
-               buf[1] = high ? 0 : 1;
-               if (*priv->lna_cfg == 2)
-                       buf[1] = high ? 1 : 0;
-               i2c_transfer(priv->i2c_props.adap, &msg, 1);
-               break;
-       case 3: /* switch with GPIO of saa713x */
-               if (priv->tuner_callback)
-                       priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
-               break;
-       }
-}
+/*---------------------------------------------------------------------*/
 
-static void tda827xa_set_analog_params(struct dvb_frontend *fe,
-                                      struct analog_parameters *params)
+static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
 {
-       unsigned char tuner_reg[11];
-       u32 N;
-       int i;
-       struct tda8290_priv *priv = fe->tuner_priv;
-       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
-       unsigned int freq = params->frequency;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
 
-       tda827xa_lna_gain(fe, 1, params);
-       msleep(10);
-
-       if (params->mode == V4L2_TUNER_RADIO)
-               freq = freq / 1000;
+       unsigned char  enable[2] = { 0x21, 0xC0 };
+       unsigned char disable[2] = { 0x21, 0x00 };
+       unsigned char *msg;
 
-       N = freq + priv->sgIF;
-       i = 0;
-       while (tda827xa_analog[i].lomax < N) {
-               if(tda827xa_analog[i + 1].lomax == 0)
-                       break;
-               i++;
+       if (close) {
+               msg = enable;
+               tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+               /* let the bridge stabilize */
+               msleep(20);
+       } else {
+               msg = disable;
+               tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
        }
 
-       N = N << tda827xa_analog[i].spd;
-
-       tuner_reg[0] = 0;
-       tuner_reg[1] = (unsigned char)(N>>8);
-       tuner_reg[2] = (unsigned char) N;
-       tuner_reg[3] = 0;
-       tuner_reg[4] = 0x16;
-       tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
-                       tda827xa_analog[i].sbs;
-       tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
-       tuner_reg[7] = 0x1c;
-       tuner_reg[8] = 4;
-       tuner_reg[9] = 0x20;
-       tuner_reg[10] = 0x00;
-       msg.len = 11;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       tuner_reg[0] = 0x90;
-       tuner_reg[1] = 0xff;
-       tuner_reg[2] = 0xe0;
-       tuner_reg[3] = 0;
-       tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
-       msg.len = 5;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       tuner_reg[0] = 0xa0;
-       tuner_reg[1] = 0xc0;
-       msg.len = 2;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       tuner_reg[0] = 0x30;
-       tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       msg.flags = I2C_M_RD;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-       msg.flags = 0;
-       tuner_reg[1] >>= 4;
-       tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
-       if (tuner_reg[1] < 1)
-               tda827xa_lna_gain(fe, 0, params);
-
-       msleep(100);
-       tuner_reg[0] = 0x60;
-       tuner_reg[1] = 0x3c;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       msleep(163);
-       tuner_reg[0] = 0x50;
-       tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       tuner_reg[0] = 0x80;
-       tuner_reg[1] = 0x28;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       tuner_reg[0] = 0xb0;
-       tuner_reg[1] = 0x01;
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-       tuner_reg[0] = 0xc0;
-       tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
-}
-
-static void tda827xa_agcf(struct dvb_frontend *fe)
-{
-       struct tda8290_priv *priv = fe->tuner_priv;
-       unsigned char data[] = {0x80, 0x2c};
-       struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
-                             .flags = 0, .len = 2};
-       i2c_transfer(priv->i2c_props.adap, &msg, 1);
+       return 0;
 }
 
-/*---------------------------------------------------------------------*/
-
-static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
+static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
 
-       unsigned char  enable[2] = { 0x21, 0xC0 };
-       unsigned char disable[2] = { 0x21, 0x00 };
+       unsigned char  enable[2] = { 0x45, 0xc1 };
+       unsigned char disable[2] = { 0x46, 0x00 };
+       unsigned char buf[3] = { 0x45, 0x01, 0x00 };
        unsigned char *msg;
-       if(close) {
+
+       if (close) {
                msg = enable;
                tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
                /* let the bridge stabilize */
                msleep(20);
        } else {
                msg = disable;
+               tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
+               tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
+
+               buf[2] = msg[1];
+               buf[2] &= ~0x04;
+               tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
+               msleep(5);
+
+               msg[1] |= 0x04;
                tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
        }
+
+       return 0;
 }
 
 /*---------------------------------------------------------------------*/
@@ -384,55 +112,43 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
 static void set_audio(struct dvb_frontend *fe,
                      struct analog_parameters *params)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
        char* mode;
 
-       priv->tda827x_lpsel = 0;
        if (params->std & V4L2_STD_MN) {
-               priv->sgIF = 92;
                priv->tda8290_easy_mode = 0x01;
-               priv->tda827x_lpsel = 1;
                mode = "MN";
        } else if (params->std & V4L2_STD_B) {
-               priv->sgIF = 108;
                priv->tda8290_easy_mode = 0x02;
                mode = "B";
        } else if (params->std & V4L2_STD_GH) {
-               priv->sgIF = 124;
                priv->tda8290_easy_mode = 0x04;
                mode = "GH";
        } else if (params->std & V4L2_STD_PAL_I) {
-               priv->sgIF = 124;
                priv->tda8290_easy_mode = 0x08;
                mode = "I";
        } else if (params->std & V4L2_STD_DK) {
-               priv->sgIF = 124;
                priv->tda8290_easy_mode = 0x10;
                mode = "DK";
        } else if (params->std & V4L2_STD_SECAM_L) {
-               priv->sgIF = 124;
                priv->tda8290_easy_mode = 0x20;
                mode = "L";
        } else if (params->std & V4L2_STD_SECAM_LC) {
-               priv->sgIF = 20;
                priv->tda8290_easy_mode = 0x40;
                mode = "LC";
        } else {
-               priv->sgIF = 124;
                priv->tda8290_easy_mode = 0x10;
                mode = "xx";
        }
 
-       if (params->mode == V4L2_TUNER_RADIO)
-               priv->sgIF = 88; /* if frequency is 5.5 MHz */
-
-       tuner_dbg("setting tda8290 to system %s\n", mode);
+       tuner_dbg("setting tda829x to system %s\n", mode);
 }
 
-static int tda8290_set_params(struct dvb_frontend *fe,
-                             struct analog_parameters *params)
+static void tda8290_set_params(struct dvb_frontend *fe,
+                              struct analog_parameters *params)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+
        unsigned char soft_reset[]  = { 0x00, 0x00 };
        unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
        unsigned char expert_mode[] = { 0x01, 0x80 };
@@ -457,8 +173,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
 
        set_audio(fe, params);
 
-       if (priv->lna_cfg)
-               tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
+       if (priv->cfg.config)
+               tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config);
        tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
        tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
        tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
@@ -475,10 +191,10 @@ static int tda8290_set_params(struct dvb_frontend *fe,
        tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
 
        tda8290_i2c_bridge(fe, 1);
-       if (priv->tda827x_ver != 0)
-               tda827xa_set_analog_params(fe, params);
-       else
-               tda827x_set_analog_params(fe, params);
+
+       if (fe->ops.tuner_ops.set_analog_params)
+               fe->ops.tuner_ops.set_analog_params(fe, params);
+
        for (i = 0; i < 3; i++) {
                tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
                tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
@@ -507,10 +223,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
                if ((agc_stat > 115) || !(pll_stat & 0x80)) {
                        tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
                                   agc_stat, pll_stat & 0x80);
-                       if (priv->tda827x_ver != 0)
-                               tda827xa_agcf(fe);
-                       else
-                               tda827x_agcf(fe);
+                       if (priv->cfg.agcf)
+                               priv->cfg.agcf(fe);
                        msleep(100);
                        tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
                        tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
@@ -541,99 +255,242 @@ static int tda8290_set_params(struct dvb_frontend *fe,
 
        tda8290_i2c_bridge(fe, 0);
        tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8295_power(struct dvb_frontend *fe, int enable)
+{
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+       unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
 
-       priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
-               params->frequency * 125 / 2 : params->frequency * 62500;
+       tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
 
-       return 0;
+       if (enable)
+               buf[1] = 0x01;
+       else
+               buf[1] = 0x03;
+
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
+{
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+       unsigned char buf[] = { 0x01, 0x00 };
+
+       tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+
+       if (enable)
+               buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
+       else
+               buf[1] = 0x00; /* reset active bit */
+
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_set_video_std(struct dvb_frontend *fe)
+{
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+       unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
+
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+
+       tda8295_set_easy_mode(fe, 1);
+       msleep(20);
+       tda8295_set_easy_mode(fe, 0);
 }
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_has_signal(struct dvb_frontend *fe)
+static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
-       int ret;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+       unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
 
-       unsigned char i2c_get_afc[1] = { 0x1B };
-       unsigned char afc = 0;
+       tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
 
-       /* for now, report based on afc status */
-       tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
-       tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+       if (enable)
+               buf[1] &= ~0x40;
+       else
+               buf[1] |= 0x40;
 
-       ret = (afc & 0x80) ? 65535 : 0;
+       tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
+{
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+       unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
+       unsigned char set_gpio_val[]   = { 0x46, 0x00 };
+
+       tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
+       tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
 
-       tuner_dbg("AFC status: %d\n", ret);
+       set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
 
-       return ret;
+       if (enable) {
+               set_gpio_cf[1]  |= 0x01; /* config GPIO_0 as Open Drain Out */
+               set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
+       }
+       tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
 }
 
-static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
+static int tda8295_has_signal(struct dvb_frontend *fe)
 {
-       *status = 0;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
 
-       if (tda8290_has_signal(fe))
-               *status = TUNER_STATUS_LOCKED;
+       unsigned char hvpll_stat = 0x26;
+       unsigned char ret;
 
-       return 0;
+       tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
+       return (ret & 0x01) ? 65535 : 0;
 }
 
-static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+/*---------------------------------------------------------------------*/
+
+static void tda8295_set_params(struct dvb_frontend *fe,
+                              struct analog_parameters *params)
 {
-       *strength = tda8290_has_signal(fe);
+       struct tda8290_priv *priv = fe->analog_demod_priv;
 
-       return 0;
+       unsigned char blanking_mode[]     = { 0x1d, 0x00 };
+
+       set_audio(fe, params);
+
+       tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
+
+       tda8295_power(fe, 1);
+       tda8295_agc1_out(fe, 1);
+
+       tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
+       tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
+
+       tda8295_set_video_std(fe);
+
+       blanking_mode[1] = 0x03;
+       tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
+       msleep(20);
+
+       tda8295_i2c_bridge(fe, 1);
+
+       if (fe->ops.tuner_ops.set_analog_params)
+               fe->ops.tuner_ops.set_analog_params(fe, params);
+
+       if (priv->cfg.agcf)
+               priv->cfg.agcf(fe);
+
+       if (tda8295_has_signal(fe))
+               tuner_dbg("tda8295 is locked\n");
+       else
+               tuner_dbg("tda8295 not locked, no signal?\n");
+
+       tda8295_i2c_bridge(fe, 0);
+}
+
+/*---------------------------------------------------------------------*/
+
+static int tda8290_has_signal(struct dvb_frontend *fe)
+{
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+
+       unsigned char i2c_get_afc[1] = { 0x1B };
+       unsigned char afc = 0;
+
+       tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+       tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+       return (afc & 0x80)? 65535:0;
 }
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_standby(struct dvb_frontend *fe)
+static void tda8290_standby(struct dvb_frontend *fe)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+
        unsigned char cb1[] = { 0x30, 0xD0 };
        unsigned char tda8290_standby[] = { 0x00, 0x02 };
        unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
        struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
        tda8290_i2c_bridge(fe, 1);
-       if (priv->tda827x_ver != 0)
+       if (priv->ver & TDA8275A)
                cb1[1] = 0x90;
        i2c_transfer(priv->i2c_props.adap, &msg, 1);
        tda8290_i2c_bridge(fe, 0);
        tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
        tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
-
-       return 0;
 }
 
+static void tda8295_standby(struct dvb_frontend *fe)
+{
+       tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
+
+       tda8295_power(fe, 0);
+}
 
 static void tda8290_init_if(struct dvb_frontend *fe)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
 
        unsigned char set_VS[] = { 0x30, 0x6F };
        unsigned char set_GP00_CF[] = { 0x20, 0x01 };
        unsigned char set_GP01_CF[] = { 0x20, 0x0B };
 
-       if ((priv->lna_cfg) &&
-           ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
+       if ((priv->cfg.config) &&
+           ((*priv->cfg.config == 1) || (*priv->cfg.config == 2)))
                tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
        else
                tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
        tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
 }
 
+static void tda8295_init_if(struct dvb_frontend *fe)
+{
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+
+       static unsigned char set_adc_ctl[]       = { 0x33, 0x14 };
+       static unsigned char set_adc_ctl2[]      = { 0x34, 0x00 };
+       static unsigned char set_pll_reg6[]      = { 0x3e, 0x63 };
+       static unsigned char set_pll_reg0[]      = { 0x38, 0x23 };
+       static unsigned char set_pll_reg7[]      = { 0x3f, 0x01 };
+       static unsigned char set_pll_reg10[]     = { 0x42, 0x61 };
+       static unsigned char set_gpio_reg0[]     = { 0x44, 0x0b };
+
+       tda8295_power(fe, 1);
+
+       tda8295_set_easy_mode(fe, 0);
+       tda8295_set_video_std(fe);
+
+       tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
+       tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
+
+       tda8295_agc1_out(fe, 0);
+       tda8295_agc2_out(fe, 0);
+}
+
 static void tda8290_init_tuner(struct dvb_frontend *fe)
 {
-       struct tda8290_priv *priv = fe->tuner_priv;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
        unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
                                          0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
        unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
                                          0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
        struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
                              .buf=tda8275_init, .len = 14};
-       if (priv->tda827x_ver != 0)
+       if (priv->ver & TDA8275A)
                msg.buf = tda8275a_init;
 
        tda8290_i2c_bridge(fe, 1);
@@ -643,58 +500,42 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_release(struct dvb_frontend *fe)
+static void tda829x_release(struct dvb_frontend *fe)
 {
-       kfree(fe->tuner_priv);
-       fe->tuner_priv = NULL;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
 
-       return 0;
-}
+       /* only try to release the tuner if we've
+        * attached it from within this module */
+       if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
+               if (fe->ops.tuner_ops.release)
+                       fe->ops.tuner_ops.release(fe);
 
-static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-       struct tda8290_priv *priv = fe->tuner_priv;
-       *frequency = priv->frequency;
-       return 0;
+       kfree(fe->analog_demod_priv);
+       fe->analog_demod_priv = NULL;
 }
 
-static struct dvb_tuner_ops tda8290_tuner_ops = {
-       .sleep             = tda8290_standby,
-       .set_analog_params = tda8290_set_params,
-       .release           = tda8290_release,
-       .get_frequency     = tda8290_get_frequency,
-       .get_status        = tda8290_get_status,
-       .get_rf_strength   = tda8290_get_rf_strength,
+static struct tda18271_config tda829x_tda18271_config = {
+       .gate    = TDA18271_GATE_ANALOG,
 };
 
-struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
-                                   struct i2c_adapter* i2c_adap,
-                                   u8 i2c_addr,
-                                   struct tda8290_config *cfg)
+static int tda829x_find_tuner(struct dvb_frontend *fe)
 {
-       struct tda8290_priv *priv = NULL;
-       u8 data;
+       struct tda8290_priv *priv = fe->analog_demod_priv;
+       struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
        int i, ret, tuners_found;
        u32 tuner_addrs;
-       struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+       u8 data;
+       struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
 
-       priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return NULL;
-       fe->tuner_priv = priv;
+       if (NULL == analog_ops->i2c_gate_ctrl)
+               return -EINVAL;
 
-       priv->i2c_props.addr = i2c_addr;
-       priv->i2c_props.adap = i2c_adap;
-       if (cfg) {
-               priv->lna_cfg        = cfg->lna_cfg;
-               priv->tuner_callback = cfg->tuner_callback;
-       }
+       analog_ops->i2c_gate_ctrl(fe, 1);
 
-       tda8290_i2c_bridge(fe, 1);
        /* probe for tuner chip */
        tuners_found = 0;
        tuner_addrs = 0;
-       for (i=0x60; i<= 0x63; i++) {
+       for (i = 0x60; i <= 0x63; i++) {
                msg.addr = i;
                ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
                if (ret == 1) {
@@ -706,20 +547,23 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
           behind the bridge and we choose the highest address that doesn't
           give a response now
         */
-       tda8290_i2c_bridge(fe, 0);
-       if(tuners_found > 1)
+
+       analog_ops->i2c_gate_ctrl(fe, 0);
+
+       if (tuners_found > 1)
                for (i = 0; i < tuners_found; i++) {
                        msg.addr = tuner_addrs  & 0xff;
                        ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-                       if(ret == 1)
+                       if (ret == 1)
                                tuner_addrs = tuner_addrs >> 8;
                        else
                                break;
                }
+
        if (tuner_addrs == 0) {
-               tuner_addrs = 0x61;
-               tuner_info("could not clearly identify tuner address, defaulting to %x\n",
-                            tuner_addrs);
+               tuner_addrs = 0x60;
+               tuner_info("could not clearly identify tuner address, "
+                          "defaulting to %x\n", tuner_addrs);
        } else {
                tuner_addrs = tuner_addrs & 0xff;
                tuner_info("setting tuner address to %x\n", tuner_addrs);
@@ -727,42 +571,181 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
        priv->tda827x_addr = tuner_addrs;
        msg.addr = tuner_addrs;
 
-       tda8290_i2c_bridge(fe, 1);
+       analog_ops->i2c_gate_ctrl(fe, 1);
        ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-       if( ret != 1)
-               tuner_warn("TDA827x access failed!\n");
-
-       memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
-              sizeof(struct dvb_tuner_ops));
-
-       if ((data & 0x3c) == 0) {
-               strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
-                       sizeof(fe->ops.tuner_ops.info.name));
-               fe->ops.tuner_ops.info.frequency_min  =  55000000;
-               fe->ops.tuner_ops.info.frequency_max  = 860000000;
-               fe->ops.tuner_ops.info.frequency_step =    250000;
-               priv->tda827x_ver = 0;
+
+       if (ret != 1) {
+               tuner_warn("tuner access failed!\n");
+               return -EREMOTEIO;
+       }
+
+       if ((data == 0x83) || (data == 0x84)) {
+               priv->ver |= TDA18271;
+               tda18271_attach(fe, priv->tda827x_addr,
+                               priv->i2c_props.adap,
+                               &tda829x_tda18271_config);
        } else {
-               strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
-                       sizeof(fe->ops.tuner_ops.info.name));
-               fe->ops.tuner_ops.info.frequency_min  =  44000000;
-               fe->ops.tuner_ops.info.frequency_max  = 906000000;
-               fe->ops.tuner_ops.info.frequency_step =     62500;
-               priv->tda827x_ver = 2;
+               if ((data & 0x3c) == 0)
+                       priv->ver |= TDA8275;
+               else
+                       priv->ver |= TDA8275A;
+
+               tda827x_attach(fe, priv->tda827x_addr,
+                              priv->i2c_props.adap, &priv->cfg);
+       }
+       if (fe->ops.tuner_ops.init)
+               fe->ops.tuner_ops.init(fe);
+
+       if (fe->ops.tuner_ops.sleep)
+               fe->ops.tuner_ops.sleep(fe);
+
+       analog_ops->i2c_gate_ctrl(fe, 0);
+
+       return 0;
+}
+
+static int tda8290_probe(struct tuner_i2c_props *i2c_props)
+{
+#define TDA8290_ID 0x89
+       unsigned char tda8290_id[] = { 0x1f, 0x00 };
+
+       /* detect tda8290 */
+       tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
+       tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
+
+       if (tda8290_id[1] == TDA8290_ID) {
+               if (debug)
+                       printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
+                              __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+                              i2c_props->addr);
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static int tda8295_probe(struct tuner_i2c_props *i2c_props)
+{
+#define TDA8295_ID 0x8a
+       unsigned char tda8295_id[] = { 0x2f, 0x00 };
+
+       /* detect tda8295 */
+       tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
+       tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
+
+       if (tda8295_id[1] == TDA8295_ID) {
+               if (debug)
+                       printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
+                              __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+                              i2c_props->addr);
+               return 0;
        }
 
-       priv->tda827x_lpsel = 0;
+       return -ENODEV;
+}
+
+static struct analog_demod_ops tda8290_ops = {
+       .set_params     = tda8290_set_params,
+       .has_signal     = tda8290_has_signal,
+       .standby        = tda8290_standby,
+       .release        = tda829x_release,
+       .i2c_gate_ctrl  = tda8290_i2c_bridge,
+};
+
+static struct analog_demod_ops tda8295_ops = {
+       .set_params     = tda8295_set_params,
+       .has_signal     = tda8295_has_signal,
+       .standby        = tda8295_standby,
+       .release        = tda829x_release,
+       .i2c_gate_ctrl  = tda8295_i2c_bridge,
+};
+
+struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+                                   struct i2c_adapter *i2c_adap, u8 i2c_addr,
+                                   struct tda829x_config *cfg)
+{
+       struct tda8290_priv *priv = NULL;
+       char *name;
+
+       priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+       fe->analog_demod_priv = priv;
+
+       priv->i2c_props.addr     = i2c_addr;
+       priv->i2c_props.adap     = i2c_adap;
+       if (cfg) {
+               priv->cfg.config         = cfg->lna_cfg;
+               priv->cfg.tuner_callback = cfg->tuner_callback;
+       }
+
+       if (tda8290_probe(&priv->i2c_props) == 0) {
+               priv->ver = TDA8290;
+               memcpy(&fe->ops.analog_ops, &tda8290_ops,
+                      sizeof(struct analog_demod_ops));
+       }
+
+       if (tda8295_probe(&priv->i2c_props) == 0) {
+               priv->ver = TDA8295;
+               memcpy(&fe->ops.analog_ops, &tda8295_ops,
+                      sizeof(struct analog_demod_ops));
+       }
+
+       if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
+           (tda829x_find_tuner(fe) < 0))
+               goto fail;
+
+       switch (priv->ver) {
+       case TDA8290:
+               name = "tda8290";
+               break;
+       case TDA8295:
+               name = "tda8295";
+               break;
+       case TDA8290 | TDA8275:
+               name = "tda8290+75";
+               break;
+       case TDA8295 | TDA8275:
+               name = "tda8295+75";
+               break;
+       case TDA8290 | TDA8275A:
+               name = "tda8290+75a";
+               break;
+       case TDA8295 | TDA8275A:
+               name = "tda8295+75a";
+               break;
+       case TDA8290 | TDA18271:
+               name = "tda8290+18271";
+               break;
+       case TDA8295 | TDA18271:
+               name = "tda8295+18271";
+               break;
+       default:
+               goto fail;
+       }
+       tuner_info("type set to %s\n", name);
+
+       fe->ops.analog_ops.info.name = name;
+
+       if (priv->ver & TDA8290) {
+               tda8290_init_tuner(fe);
+               tda8290_init_if(fe);
+       } else if (priv->ver & TDA8295)
+               tda8295_init_if(fe);
 
-       tda8290_init_tuner(fe);
-       tda8290_init_if(fe);
        return fe;
+
+fail:
+       tda829x_release(fe);
+       return NULL;
 }
+EXPORT_SYMBOL_GPL(tda829x_attach);
 
-int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
        struct tuner_i2c_props i2c_props = {
                .adap = i2c_adap,
-               .addr = i2c_addr
+               .addr = i2c_addr,
        };
 
        unsigned char soft_reset[]   = { 0x00, 0x00 };
@@ -771,7 +754,27 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
        unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
        unsigned char addr_dto_lsb = 0x07;
        unsigned char data;
+#define PROBE_BUFFER_SIZE 8
+       unsigned char buf[PROBE_BUFFER_SIZE];
+       int i;
+
+       /* rule out tda9887, which would return the same byte repeatedly */
+       tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
+       tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
+       for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
+               if (buf[i] != buf[0])
+                       break;
+       }
 
+       /* all bytes are equal, not a tda829x - probably a tda9887 */
+       if (i == PROBE_BUFFER_SIZE)
+               return -ENODEV;
+
+       if ((tda8290_probe(&i2c_props) == 0) ||
+           (tda8295_probe(&i2c_props) == 0))
+               return 0;
+
+       /* fall back to old probing method */
        tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
        tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
        tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
@@ -786,14 +789,12 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
                }
        }
        tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
-       return -1;
+       return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(tda829x_probe);
 
-EXPORT_SYMBOL_GPL(tda8290_probe);
-EXPORT_SYMBOL_GPL(tda8290_attach);
-
-MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
-MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
+MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
 MODULE_LICENSE("GPL");
 
 /*
index 107b24b05aa189b3378a49d5930aff8c56840036..dc8ef310b7b26b1fbccc6e24d321eb70d63caba2 100644 (file)
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
-struct tda8290_config
-{
+struct tda829x_config {
        unsigned int *lna_cfg;
-       int (*tuner_callback) (void *dev, int command,int arg);
+       int (*tuner_callback) (void *dev, int command, int arg);
+
+       unsigned int probe_tuner:1;
+#define TDA829X_PROBE_TUNER 0
+#define TDA829X_DONT_PROBE  1
 };
 
 #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
-extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
 
-extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
-                                          struct i2c_adapteri2c_adap,
+extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+                                          struct i2c_adapter *i2c_adap,
                                           u8 i2c_addr,
-                                          struct tda8290_config *cfg);
+                                          struct tda829x_config *cfg);
 #else
-static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
-       printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-              __FUNCTION__);
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
        return -EINVAL;
 }
 
-static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
-                                                 struct i2c_adapteri2c_adap,
+static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+                                                 struct i2c_adapter *i2c_adap,
                                                  u8 i2c_addr,
-                                                 struct tda8290_config *cfg)
+                                                 struct tda829x_config *cfg)
 {
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+              __FUNCTION__);
        return NULL;
 }
 #endif
index d110441708722b3d711cf82ceb61e5bfd01e94ac..3c0557130a704ec1084899b18288be3b7a36f514 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
  * Eric Sandeen
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
  * This code is placed under the terms of the GNU General Public License
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  * Which was based on tda8425.c by Greg Alexander (c) 1998
@@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client)
        return 0;
 }
 
-static int tda9875_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
+static int tda9875_get_ctrl(struct i2c_client *client,
+                           struct v4l2_control *ctrl)
 {
        struct tda9875 *t = i2c_get_clientdata(client);
 
-       dprintk("In tda9875_command...\n");
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+       {
+               int left = (t->lvol+84)*606;
+               int right = (t->rvol+84)*606;
 
-       switch (cmd) {
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
+               ctrl->value=max(left,right);
+               return 0;
+       }
+       case V4L2_CID_AUDIO_BALANCE:
        {
-               struct video_audio *va = arg;
-               int left,right;
+               int left = (t->lvol+84)*606;
+               int right = (t->rvol+84)*606;
+               int volume = max(left,right);
+               int balance = (32768*min(left,right))/
+                             (volume ? volume : 1);
+               ctrl->value=(left<right)?
+                       (65535-balance) : balance;
+               return 0;
+       }
+       case V4L2_CID_AUDIO_BASS:
+               ctrl->value = (t->bass+12)*2427;    /* min -12 max +15 */
+               return 0;
+       case V4L2_CID_AUDIO_TREBLE:
+               ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
+               return 0;
+       }
+       return -EINVAL;
+}
 
-               dprintk("VIDIOCGAUDIO\n");
+static int tda9875_set_ctrl(struct i2c_client *client,
+                           struct v4l2_control *ctrl)
+{
+       struct tda9875 *t = i2c_get_clientdata(client);
+       int chvol=0, volume, balance, left, right;
 
-               va->flags |= VIDEO_AUDIO_VOLUME |
-                       VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE;
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               left = (t->lvol+84)*606;
+               right = (t->rvol+84)*606;
+
+               volume = max(left,right);
+               balance = (32768*min(left,right))/
+                             (volume ? volume : 1);
+               balance =(left<right)?
+                       (65535-balance) : balance;
+
+               volume = ctrl->value;
 
-               /* min is -84 max is 24 */
+               chvol=1;
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
                left = (t->lvol+84)*606;
                right = (t->rvol+84)*606;
-               va->volume=max(left,right);
-               va->balance=(32768*min(left,right))/
-                       (va->volume ? va->volume : 1);
-               va->balance=(left<right)?
-                       (65535-va->balance) : va->balance;
-               va->bass = (t->bass+12)*2427;    /* min -12 max +15 */
-               va->treble = (t->treble+12)*2730;/* min -12 max +12 */
-               va->mode |= VIDEO_SOUND_MONO;
-
-               break; /* VIDIOCGAUDIO case */
+
+               volume=max(left,right);
+
+               balance = ctrl->value;
+
+               chvol=1;
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               t->bass = ((ctrl->value/2400)-12) & 0xff;
+               if (t->bass > 15)
+                       t->bass = 15;
+               if (t->bass < -12)
+                       t->bass = -12 & 0xff;
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               t->treble = ((ctrl->value/2700)-12) & 0xff;
+               if (t->treble > 12)
+                       t->treble = 12;
+               if (t->treble < -12)
+                       t->treble = -12 & 0xff;
+               break;
+       default:
+               return -EINVAL;
        }
 
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *va = arg;
-               int left,right;
-
-               dprintk("VIDEOCSAUDIO...\n");
-               left = (min(65536 - va->balance,32768) *
-                       va->volume) / 32768;
-               right = (min(va->balance,(__u16)32768) *
-                        va->volume) / 32768;
+       if (chvol) {
+               left = (min(65536 - balance,32768) *
+                       volume) / 32768;
+               right = (min(balance,32768) *
+                               volume) / 32768;
                t->lvol = ((left/606)-84) & 0xff;
                if (t->lvol > 24)
-                t->lvol = 24;
+                       t->lvol = 24;
                if (t->lvol < -84)
-                t->lvol = -84 & 0xff;
+                       t->lvol = -84 & 0xff;
 
                t->rvol = ((right/606)-84) & 0xff;
                if (t->rvol > 24)
-                t->rvol = 24;
+                       t->rvol = 24;
                if (t->rvol < -84)
-                t->rvol = -84 & 0xff;
-
-               t->bass = ((va->bass/2400)-12) & 0xff;
-               if (t->bass > 15)
-                t->bass = 15;
-               if (t->bass < -12)
-                t->bass = -12 & 0xff;
-
-               t->treble = ((va->treble/2700)-12) & 0xff;
-               if (t->treble > 12)
-                t->treble = 12;
-               if (t->treble < -12)
-                t->treble = -12 & 0xff;
+                       t->rvol = -84 & 0xff;
+       }
 
+//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
 
+       tda9875_set(client);
 
-//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
+       return 0;
+}
 
 
-               tda9875_set(client);
+static int tda9875_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       dprintk("In tda9875_command...\n");
 
-               break;
+       switch (cmd) {
+       /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *qc = arg;
+
+               switch (qc->id) {
+                       case V4L2_CID_AUDIO_VOLUME:
+                       case V4L2_CID_AUDIO_BASS:
+                       case V4L2_CID_AUDIO_TREBLE:
+                       default:
+                               return -EINVAL;
+               }
+               return v4l2_ctrl_query_fill_std(qc);
+       }
+       case VIDIOC_S_CTRL:
+               return tda9875_set_ctrl(client, arg);
 
-       } /* end of VIDEOCSAUDIO case */
+       case VIDIOC_G_CTRL:
+               return tda9875_get_ctrl(client, arg);
 
        default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
 
index be5387f11afb3de8d3c71da946b65d9ce5f8cd0c..106c93b8203fea587562240b37b8d0564cbb21a3 100644 (file)
@@ -9,7 +9,8 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
-#include "tuner-driver.h"
+#include "tuner-i2c.h"
+#include "tda9887.h"
 
 
 /* Chips:
    Used as part of several tuners
 */
 
-#define tda9887_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tda9887_dbg(fmt, arg...) do {\
-       if (tuner_debug) \
-               printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tda9887"
 
 struct tda9887_priv {
        struct tuner_i2c_props i2c_props;
 
        unsigned char      data[4];
+       unsigned int       config;
+       unsigned int       mode;
+       unsigned int       audmode;
+       v4l2_std_id        std;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -262,8 +265,10 @@ static struct tvnorm radio_mono = {
 
 /* ---------------------------------------------------------------------- */
 
-static void dump_read_message(struct tuner *t, unsigned char *buf)
+static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
 {
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+
        static char *afc[16] = {
                "- 12.5 kHz",
                "- 37.5 kHz",
@@ -282,16 +287,18 @@ static void dump_read_message(struct tuner *t, unsigned char *buf)
                "+ 37.5 kHz",
                "+ 12.5 kHz",
        };
-       tda9887_info("read: 0x%2x\n", buf[0]);
-       tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
-       tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
-       tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
-       tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
-       tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
+       tuner_info("read: 0x%2x\n", buf[0]);
+       tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+       tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+       tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
+       tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
+       tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
 }
 
-static void dump_write_message(struct tuner *t, unsigned char *buf)
+static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
 {
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+
        static char *sound[4] = {
                "AM/TV",
                "FM/radio",
@@ -330,86 +337,90 @@ static void dump_write_message(struct tuner *t, unsigned char *buf)
                "44 MHz",
        };
 
-       tda9887_info("write: byte B 0x%02x\n",buf[1]);
-       tda9887_info("  B0   video mode      : %s\n",
-              (buf[1] & 0x01) ? "video trap" : "sound trap");
-       tda9887_info("  B1   auto mute fm    : %s\n",
-              (buf[1] & 0x02) ? "yes" : "no");
-       tda9887_info("  B2   carrier mode    : %s\n",
-              (buf[1] & 0x04) ? "QSS" : "Intercarrier");
-       tda9887_info("  B3-4 tv sound/radio  : %s\n",
-              sound[(buf[1] & 0x18) >> 3]);
-       tda9887_info("  B5   force mute audio: %s\n",
-              (buf[1] & 0x20) ? "yes" : "no");
-       tda9887_info("  B6   output port 1   : %s\n",
-              (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
-       tda9887_info("  B7   output port 2   : %s\n",
-              (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
-
-       tda9887_info("write: byte C 0x%02x\n",buf[2]);
-       tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
-       tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
-       tda9887_info("  C7   audio gain      : %s\n",
-              (buf[2] & 0x80) ? "-6" : "0");
-
-       tda9887_info("write: byte E 0x%02x\n",buf[3]);
-       tda9887_info("  E0-1 sound carrier   : %s\n",
-              carrier[(buf[3] & 0x03)]);
-       tda9887_info("  E6   l pll gating   : %s\n",
-              (buf[3] & 0x40) ? "36" : "13");
+       tuner_info("write: byte B 0x%02x\n", buf[1]);
+       tuner_info("  B0   video mode      : %s\n",
+                  (buf[1] & 0x01) ? "video trap" : "sound trap");
+       tuner_info("  B1   auto mute fm    : %s\n",
+                  (buf[1] & 0x02) ? "yes" : "no");
+       tuner_info("  B2   carrier mode    : %s\n",
+                  (buf[1] & 0x04) ? "QSS" : "Intercarrier");
+       tuner_info("  B3-4 tv sound/radio  : %s\n",
+                  sound[(buf[1] & 0x18) >> 3]);
+       tuner_info("  B5   force mute audio: %s\n",
+                  (buf[1] & 0x20) ? "yes" : "no");
+       tuner_info("  B6   output port 1   : %s\n",
+                  (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
+       tuner_info("  B7   output port 2   : %s\n",
+                  (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
+
+       tuner_info("write: byte C 0x%02x\n", buf[2]);
+       tuner_info("  C0-4 top adjustment  : %s dB\n",
+                  adjust[buf[2] & 0x1f]);
+       tuner_info("  C5-6 de-emphasis     : %s\n",
+                  deemph[(buf[2] & 0x60) >> 5]);
+       tuner_info("  C7   audio gain      : %s\n",
+                  (buf[2] & 0x80) ? "-6" : "0");
+
+       tuner_info("write: byte E 0x%02x\n", buf[3]);
+       tuner_info("  E0-1 sound carrier   : %s\n",
+                  carrier[(buf[3] & 0x03)]);
+       tuner_info("  E6   l pll gating   : %s\n",
+                  (buf[3] & 0x40) ? "36" : "13");
 
        if (buf[1] & 0x08) {
                /* radio */
-               tda9887_info("  E2-4 video if        : %s\n",
-                      rif[(buf[3] & 0x0c) >> 2]);
-               tda9887_info("  E7   vif agc output  : %s\n",
-                      (buf[3] & 0x80)
-                      ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
-                      : "fm radio carrier afc");
+               tuner_info("  E2-4 video if        : %s\n",
+                          rif[(buf[3] & 0x0c) >> 2]);
+               tuner_info("  E7   vif agc output  : %s\n",
+                          (buf[3] & 0x80)
+                          ? ((buf[3] & 0x10) ? "fm-agc radio" :
+                                               "sif-agc radio")
+                          : "fm radio carrier afc");
        } else {
                /* video */
-               tda9887_info("  E2-4 video if        : %s\n",
-                      vif[(buf[3] & 0x1c) >> 2]);
-               tda9887_info("  E5   tuner gain      : %s\n",
-                      (buf[3] & 0x80)
-                      ? ((buf[3] & 0x20) ? "external" : "normal")
-                      : ((buf[3] & 0x20) ? "minimum"  : "normal"));
-               tda9887_info("  E7   vif agc output  : %s\n",
-                      (buf[3] & 0x80)
-                      ? ((buf[3] & 0x20)
-                         ? "pin3 port, pin22 vif agc out"
-                         : "pin22 port, pin3 vif acg ext in")
-                      : "pin3+pin22 port");
+               tuner_info("  E2-4 video if        : %s\n",
+                          vif[(buf[3] & 0x1c) >> 2]);
+               tuner_info("  E5   tuner gain      : %s\n",
+                          (buf[3] & 0x80)
+                          ? ((buf[3] & 0x20) ? "external" : "normal")
+                          : ((buf[3] & 0x20) ? "minimum"  : "normal"));
+               tuner_info("  E7   vif agc output  : %s\n",
+                          (buf[3] & 0x80) ? ((buf[3] & 0x20)
+                               ? "pin3 port, pin22 vif agc out"
+                               : "pin22 port, pin3 vif acg ext in")
+                               : "pin3+pin22 port");
        }
-       tda9887_info("--\n");
+       tuner_info("--\n");
 }
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_tvnorm(struct tuner *t, char *buf)
+static int tda9887_set_tvnorm(struct dvb_frontend *fe)
 {
+       struct tda9887_priv *priv = fe->analog_demod_priv;
        struct tvnorm *norm = NULL;
+       char *buf = priv->data;
        int i;
 
-       if (t->mode == V4L2_TUNER_RADIO) {
-               if (t->audmode == V4L2_TUNER_MODE_MONO)
+       if (priv->mode == V4L2_TUNER_RADIO) {
+               if (priv->audmode == V4L2_TUNER_MODE_MONO)
                        norm = &radio_mono;
                else
                        norm = &radio_stereo;
        } else {
                for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
-                       if (tvnorms[i].std & t->std) {
+                       if (tvnorms[i].std & priv->std) {
                                norm = tvnorms+i;
                                break;
                        }
                }
        }
        if (NULL == norm) {
-               tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
+               tuner_dbg("Unsupported tvnorm entry - audio muted\n");
                return -1;
        }
 
-       tda9887_dbg("configure for: %s\n",norm->name);
+       tuner_dbg("configure for: %s\n", norm->name);
        buf[1] = norm->b;
        buf[2] = norm->c;
        buf[3] = norm->e;
@@ -426,8 +437,11 @@ module_param(port2, int, 0644);
 module_param(qss, int, 0644);
 module_param(adjust, int, 0644);
 
-static int tda9887_set_insmod(struct tuner *t, char *buf)
+static int tda9887_set_insmod(struct dvb_frontend *fe)
 {
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+       char *buf = priv->data;
+
        if (UNSET != port1) {
                if (port1)
                        buf[1] |= cOutputPort1Inactive;
@@ -455,27 +469,30 @@ static int tda9887_set_insmod(struct tuner *t, char *buf)
        return 0;
 }
 
-static int tda9887_set_config(struct tuner *t, char *buf)
+static int tda9887_do_config(struct dvb_frontend *fe)
 {
-       if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+       char *buf = priv->data;
+
+       if (priv->config & TDA9887_PORT1_ACTIVE)
                buf[1] &= ~cOutputPort1Inactive;
-       if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
+       if (priv->config & TDA9887_PORT1_INACTIVE)
                buf[1] |= cOutputPort1Inactive;
-       if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
+       if (priv->config & TDA9887_PORT2_ACTIVE)
                buf[1] &= ~cOutputPort2Inactive;
-       if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
+       if (priv->config & TDA9887_PORT2_INACTIVE)
                buf[1] |= cOutputPort2Inactive;
 
-       if (t->tda9887_config & TDA9887_QSS)
+       if (priv->config & TDA9887_QSS)
                buf[1] |= cQSS;
-       if (t->tda9887_config & TDA9887_INTERCARRIER)
+       if (priv->config & TDA9887_INTERCARRIER)
                buf[1] &= ~cQSS;
 
-       if (t->tda9887_config & TDA9887_AUTOMUTE)
+       if (priv->config & TDA9887_AUTOMUTE)
                buf[1] |= cAutoMuteFmActive;
-       if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
+       if (priv->config & TDA9887_DEEMPHASIS_MASK) {
                buf[2] &= ~0x60;
-               switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
+               switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
                case TDA9887_DEEMPHASIS_NONE:
                        buf[2] |= cDeemphasisOFF;
                        break;
@@ -487,21 +504,22 @@ static int tda9887_set_config(struct tuner *t, char *buf)
                        break;
                }
        }
-       if (t->tda9887_config & TDA9887_TOP_SET) {
+       if (priv->config & TDA9887_TOP_SET) {
                buf[2] &= ~cTopMask;
-               buf[2] |= (t->tda9887_config >> 8) & cTopMask;
+               buf[2] |= (priv->config >> 8) & cTopMask;
        }
-       if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+       if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
+           (priv->std & V4L2_STD_NTSC))
                buf[1] &= ~cQSS;
-       if (t->tda9887_config & TDA9887_GATING_18)
+       if (priv->config & TDA9887_GATING_18)
                buf[3] &= ~cGating_36;
 
-       if (t->mode == V4L2_TUNER_RADIO) {
-               if (t->tda9887_config & TDA9887_RIF_41_3) {
+       if (priv->mode == V4L2_TUNER_RADIO) {
+               if (priv->config & TDA9887_RIF_41_3) {
                        buf[3] &= ~cVideoIFMask;
                        buf[3] |= cRadioIF_41_30;
                }
-               if (t->tda9887_config & TDA9887_GAIN_NORMAL)
+               if (priv->config & TDA9887_GAIN_NORMAL)
                        buf[3] &= ~cTunerGainLow;
        }
 
@@ -510,26 +528,26 @@ static int tda9887_set_config(struct tuner *t, char *buf)
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_status(struct tuner *t)
+static int tda9887_status(struct dvb_frontend *fe)
 {
-       struct tda9887_priv *priv = t->priv;
+       struct tda9887_priv *priv = fe->analog_demod_priv;
        unsigned char buf[1];
        int rc;
 
        memset(buf,0,sizeof(buf));
        if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
-               tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
-       dump_read_message(t, buf);
+               tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
+       dump_read_message(fe, buf);
        return 0;
 }
 
-static void tda9887_configure(struct tuner *t)
+static void tda9887_configure(struct dvb_frontend *fe)
 {
-       struct tda9887_priv *priv = t->priv;
+       struct tda9887_priv *priv = fe->analog_demod_priv;
        int rc;
 
        memset(priv->data,0,sizeof(priv->data));
-       tda9887_set_tvnorm(t,priv->data);
+       tda9887_set_tvnorm(fe);
 
        /* A note on the port settings:
           These settings tend to depend on the specifics of the board.
@@ -547,38 +565,38 @@ static void tda9887_configure(struct tuner *t)
        priv->data[1] |= cOutputPort1Inactive;
        priv->data[1] |= cOutputPort2Inactive;
 
-       tda9887_set_config(t,priv->data);
-       tda9887_set_insmod(t,priv->data);
+       tda9887_do_config(fe);
+       tda9887_set_insmod(fe);
 
-       if (t->mode == T_STANDBY) {
+       if (priv->mode == T_STANDBY)
                priv->data[1] |= cForcedMuteAudioON;
-       }
 
-       tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-               priv->data[1],priv->data[2],priv->data[3]);
-       if (tuner_debug > 1)
-               dump_write_message(t, priv->data);
+       tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+                 priv->data[1], priv->data[2], priv->data[3]);
+       if (debug > 1)
+               dump_write_message(fe, priv->data);
 
        if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
-               tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
+               tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
 
-       if (tuner_debug > 2) {
+       if (debug > 2) {
                msleep_interruptible(1000);
-               tda9887_status(t);
+               tda9887_status(fe);
        }
 }
 
 /* ---------------------------------------------------------------------- */
 
-static void tda9887_tuner_status(struct tuner *t)
+static void tda9887_tuner_status(struct dvb_frontend *fe)
 {
-       struct tda9887_priv *priv = t->priv;
-       tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+       tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
+                  priv->data[1], priv->data[2], priv->data[3]);
 }
 
-static int tda9887_get_afc(struct tuner *t)
+static int tda9887_get_afc(struct dvb_frontend *fe)
 {
-       struct tda9887_priv *priv = t->priv;
+       struct tda9887_priv *priv = fe->analog_demod_priv;
        static int AFC_BITS_2_kHz[] = {
                -12500,  -37500,  -62500,  -97500,
                -112500, -137500, -162500, -187500,
@@ -594,52 +612,79 @@ static int tda9887_get_afc(struct tuner *t)
        return afc;
 }
 
-static void tda9887_standby(struct tuner *t)
+static void tda9887_standby(struct dvb_frontend *fe)
+{
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+
+       priv->mode = T_STANDBY;
+
+       tda9887_configure(fe);
+}
+
+static void tda9887_set_params(struct dvb_frontend *fe,
+                              struct analog_parameters *params)
 {
-       tda9887_configure(t);
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+
+       priv->mode    = params->mode;
+       priv->audmode = params->audmode;
+       priv->std     = params->std;
+       tda9887_configure(fe);
 }
 
-static void tda9887_set_freq(struct tuner *t, unsigned int freq)
+static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
 {
-       tda9887_configure(t);
+       struct tda9887_priv *priv = fe->analog_demod_priv;
+
+       priv->config = *(unsigned int *)priv_cfg;
+       tda9887_configure(fe);
+
+       return 0;
 }
 
-static void tda9887_release(struct tuner *t)
+static void tda9887_release(struct dvb_frontend *fe)
 {
-       kfree(t->priv);
-       t->priv = NULL;
+       kfree(fe->analog_demod_priv);
+       fe->analog_demod_priv = NULL;
 }
 
-static struct tuner_operations tda9887_tuner_ops = {
-       .set_tv_freq    = tda9887_set_freq,
-       .set_radio_freq = tda9887_set_freq,
+static struct analog_demod_ops tda9887_ops = {
+       .info           = {
+               .name   = "tda9887",
+       },
+       .set_params     = tda9887_set_params,
        .standby        = tda9887_standby,
        .tuner_status   = tda9887_tuner_status,
        .get_afc        = tda9887_get_afc,
        .release        = tda9887_release,
+       .set_config     = tda9887_set_config,
 };
 
-int tda9887_tuner_init(struct tuner *t)
+struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+                                   struct i2c_adapter *i2c_adap,
+                                   u8 i2c_addr)
 {
        struct tda9887_priv *priv = NULL;
 
        priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
        if (priv == NULL)
-               return -ENOMEM;
-       t->priv = priv;
-
-       priv->i2c_props.addr = t->i2c.addr;
-       priv->i2c_props.adap = t->i2c.adapter;
+               return NULL;
+       fe->analog_demod_priv = priv;
 
-       strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
+       priv->i2c_props.addr = i2c_addr;
+       priv->i2c_props.adap = i2c_adap;
+       priv->mode = T_STANDBY;
 
-       tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
-                                               t->i2c.driver->driver.name);
+       tuner_info("tda988[5/6/7] found\n");
 
-       memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
+       memcpy(&fe->ops.analog_ops, &tda9887_ops,
+              sizeof(struct analog_demod_ops));
 
-       return 0;
+       return fe;
 }
+EXPORT_SYMBOL_GPL(tda9887_attach);
+
+MODULE_LICENSE("GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h
new file mode 100644 (file)
index 0000000..8f873a8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA9887_H__
+#define __TDA9887_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* ------------------------------------------------------------------------ */
+#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+                                          struct i2c_adapter *i2c_adap,
+                                          u8 i2c_addr);
+#else
+static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+                                                 struct i2c_adapter *i2c_adap,
+                                                 u8 i2c_addr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       return NULL;
+}
+#endif
+
+#endif /* __TDA9887_H__ */
index 2150222a3860537aacb11ceebd2e6dc074f73a1f..5326eeceaacdabb0bdce32825182924fd8d65f35 100644 (file)
@@ -18,7 +18,7 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tea5761 "
+#define PREFIX "tea5761"
 
 struct tea5761_priv {
        struct tuner_i2c_props i2c_props;
index 71df419df7bc85b7c867fc27f593a72b1ee5bae2..e1b48d87e7b74fba277b9796e074bf13b514bd86 100644 (file)
@@ -20,12 +20,14 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tea5767 "
+#define PREFIX "tea5767"
 
-struct tea5767_priv {
-       struct tuner_i2c_props i2c_props;
+/*****************************************************************************/
 
-       u32 frequency;
+struct tea5767_priv {
+       struct tuner_i2c_props  i2c_props;
+       u32                     frequency;
+       struct tea5767_ctrl     ctrl;
 };
 
 /*****************************************************************************/
@@ -127,17 +129,10 @@ struct tea5767_priv {
 /* Reserved for future extensions */
 #define TEA5767_RESERVED_MASK  0xff
 
-enum tea5767_xtal_freq {
-       TEA5767_LOW_LO_32768    = 0,
-       TEA5767_HIGH_LO_32768   = 1,
-       TEA5767_LOW_LO_13MHz    = 2,
-       TEA5767_HIGH_LO_13MHz   = 3,
-};
-
-
 /*****************************************************************************/
 
-static void tea5767_status_dump(unsigned char *buffer)
+static void tea5767_status_dump(struct tea5767_priv *priv,
+                               unsigned char *buffer)
 {
        unsigned int div, frq;
 
@@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer)
 
        div = ((buffer[0] & 0x3f) << 8) | buffer[1];
 
-       switch (TEA5767_HIGH_LO_32768) {
+       switch (priv->ctrl.xtal_freq) {
        case TEA5767_HIGH_LO_13MHz:
                frq = (div * 50000 - 700000 - 225000) / 4;      /* Freq in KHz */
                break;
@@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe,
 
        tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
 
-       /* Rounds freq to next decimal value - for 62.5 KHz step */
-       /* frq = 20*(frq/16)+radio_frq[frq%16]; */
+       buffer[2] = 0;
 
-       buffer[2] = TEA5767_PORT1_HIGH;
-       buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
-                   TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
-       buffer[4] = 0;
+       if (priv->ctrl.port1)
+               buffer[2] |= TEA5767_PORT1_HIGH;
 
        if (params->audmode == V4L2_TUNER_MODE_MONO) {
                tuner_dbg("TEA5767 set to mono\n");
@@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe,
                tuner_dbg("TEA5767 set to stereo\n");
        }
 
-       /* Should be replaced */
-       switch (TEA5767_HIGH_LO_32768) {
+
+       buffer[3] = 0;
+
+       if (priv->ctrl.port2)
+               buffer[3] |= TEA5767_PORT2_HIGH;
+
+       if (priv->ctrl.high_cut)
+               buffer[3] |= TEA5767_HIGH_CUT_CTRL;
+
+       if (priv->ctrl.st_noise)
+               buffer[3] |= TEA5767_ST_NOISE_CTL;
+
+       if (priv->ctrl.soft_mute)
+               buffer[3] |= TEA5767_SOFT_MUTE;
+
+       if (priv->ctrl.japan_band)
+               buffer[3] |= TEA5767_JAPAN_BAND;
+
+       buffer[4] = 0;
+
+       if (priv->ctrl.deemph_75)
+               buffer[4] |= TEA5767_DEEMPH_75;
+
+       if (priv->ctrl.pllref)
+               buffer[4] |= TEA5767_PLLREF_ENABLE;
+
+
+       /* Rounds freq to next decimal value - for 62.5 KHz step */
+       /* frq = 20*(frq/16)+radio_frq[frq%16]; */
+
+       switch (priv->ctrl.xtal_freq) {
        case TEA5767_HIGH_LO_13MHz:
                tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
                buffer[2] |= TEA5767_HIGH_LO_INJECT;
-               buffer[4] |= TEA5767_PLLREF_ENABLE;
                div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
                break;
        case TEA5767_LOW_LO_13MHz:
                tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
 
-               buffer[4] |= TEA5767_PLLREF_ENABLE;
                div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
                break;
        case TEA5767_LOW_LO_32768:
@@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe,
                if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
                        tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
                else
-                       tea5767_status_dump(buffer);
+                       tea5767_status_dump(priv, buffer);
        }
 
        priv->frequency = frq * 125 / 2;
@@ -382,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
                return EINVAL;
        }
 
-       printk(KERN_WARNING "TEA5767 detected.\n");
        return 0;
 }
 
@@ -398,6 +416,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct tea5767_priv *priv = fe->tuner_priv;
        *frequency = priv->frequency;
+
+       return 0;
+}
+
+static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
+{
+       struct tea5767_priv *priv = fe->tuner_priv;
+
+       memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
+
        return 0;
 }
 
@@ -407,6 +435,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = {
        },
 
        .set_analog_params = set_radio_freq,
+       .set_config        = tea5767_set_config,
        .sleep             = tea5767_standby,
        .release           = tea5767_release,
        .get_frequency     = tea5767_get_frequency,
@@ -425,8 +454,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
                return NULL;
        fe->tuner_priv = priv;
 
-       priv->i2c_props.addr = i2c_addr;
-       priv->i2c_props.adap = i2c_adap;
+       priv->i2c_props.addr  = i2c_addr;
+       priv->i2c_props.adap  = i2c_adap;
+       priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
+       priv->ctrl.port1      = 1;
+       priv->ctrl.port2      = 1;
+       priv->ctrl.high_cut   = 1;
+       priv->ctrl.st_noise   = 1;
+       priv->ctrl.japan_band = 1;
 
        memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
               sizeof(struct dvb_tuner_ops));
@@ -436,7 +471,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
        return fe;
 }
 
-
 EXPORT_SYMBOL_GPL(tea5767_attach);
 EXPORT_SYMBOL_GPL(tea5767_autodetection);
 
index 5d78281adcc2acb5af002f844e1abdb9aecc73bb..a44451f6114544ea689afa716cae716d559f47bf 100644 (file)
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
+enum tea5767_xtal {
+       TEA5767_LOW_LO_32768    = 0,
+       TEA5767_HIGH_LO_32768   = 1,
+       TEA5767_LOW_LO_13MHz    = 2,
+       TEA5767_HIGH_LO_13MHz   = 3,
+};
+
+struct tea5767_ctrl {
+       unsigned int            port1:1;
+       unsigned int            port2:1;
+       unsigned int            high_cut:1;
+       unsigned int            st_noise:1;
+       unsigned int            soft_mute:1;
+       unsigned int            japan_band:1;
+       unsigned int            deemph_75:1;
+       unsigned int            pllref:1;
+       enum tea5767_xtal       xtal_freq;
+};
+
 #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
 extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
 
index 76b2e96429d90f22bb2d0ad6ad188a01a21023aa..dc7b9c220b90f5f7ab3e25b18dd00c571daa912f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
 MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
@@ -56,37 +57,35 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
                return -1;
        }
 
-       for (i = 0; i < 3; i++) {
-               if (i2c_smbus_write_byte_data(client, (reg << 1) |
-                                       (val >> 8), val & 0xff) == 0) {
+       for (i = 0; i < 3; i++)
+               if (i2c_smbus_write_byte_data(client,
+                               (reg << 1) | (val >> 8), val & 0xff) == 0)
                        return 0;
-               }
-       }
        v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
 
-static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
-                         void *arg)
+static int tlv320aic23b_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
 {
        struct tlv320aic23b_state *state = i2c_get_clientdata(client);
        struct v4l2_control *ctrl = arg;
-       u32freq = arg;
+       u32 *freq = arg;
 
        switch (cmd) {
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
                switch (*freq) {
-                       case 32000: /* set sample rate to 32 kHz */
-                               tlv320aic23b_write(client, 8, 0x018);
-                               break;
-                       case 44100: /* set sample rate to 44.1 kHz */
-                               tlv320aic23b_write(client, 8, 0x022);
-                               break;
-                       case 48000: /* set sample rate to 48 kHz */
-                               tlv320aic23b_write(client, 8, 0x000);
-                               break;
-                       default:
-                               return -EINVAL;
+               case 32000: /* set sample rate to 32 kHz */
+                       tlv320aic23b_write(client, 8, 0x018);
+                       break;
+               case 44100: /* set sample rate to 44.1 kHz */
+                       tlv320aic23b_write(client, 8, 0x022);
+                       break;
+               case 48000: /* set sample rate to 48 kHz */
+                       tlv320aic23b_write(client, 8, 0x000);
+                       break;
+               default:
+                       return -EINVAL;
                }
                break;
 
@@ -126,92 +125,53 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+static int tlv320aic23b_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct tlv320aic23b_state *state;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
-       snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
-       if (state == NULL) {
-               kfree(client);
+       if (state == NULL)
                return -ENOMEM;
-       }
        state->muted = 0;
        i2c_set_clientdata(client, state);
 
-       /* initialize tlv320aic23b */
-       tlv320aic23b_write(client, 15, 0x000);  /* RESET */
-       tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
-       tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
-       tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
-       tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
-       tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
-
-       i2c_attach_client(client);
-
+       /* Initialize tlv320aic23b */
+
+       /* RESET */
+       tlv320aic23b_write(client, 15, 0x000);
+       /* turn off DAC & mic input */
+       tlv320aic23b_write(client, 6, 0x00A);
+       /* left-justified, 24-bit, master mode */
+       tlv320aic23b_write(client, 7, 0x049);
+       /* set gain on both channels to +3.0 dB */
+       tlv320aic23b_write(client, 0, 0x119);
+       /* set sample rate to 48 kHz */
+       tlv320aic23b_write(client, 8, 0x000);
+       /* activate digital interface */
+       tlv320aic23b_write(client, 9, 0x001);
        return 0;
 }
 
-static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+static int tlv320aic23b_remove(struct i2c_client *client)
 {
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
-       return 0;
-}
-
-static int tlv320aic23b_detach(struct i2c_client *client)
-{
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "tlv320aic23b",
-       },
-       .id             = I2C_DRIVERID_TLV320AIC23B,
-       .attach_adapter = tlv320aic23b_probe,
-       .detach_client  = tlv320aic23b_detach,
-       .command        = tlv320aic23b_command,
-};
-
 
-static int __init tlv320aic23b_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit tlv320aic23b_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(tlv320aic23b_init_module);
-module_exit(tlv320aic23b_cleanup_module);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tlv320aic23b",
+       .driverid = I2C_DRIVERID_TLV320AIC23B,
+       .command = tlv320aic23b_command,
+       .probe = tlv320aic23b_probe,
+       .remove = tlv320aic23b_remove,
+};
index 9e99f3636d3dc36a407f46007486b8fe7af252b2..ba538f6fbcc387a7779ae77e0d64b93f043db4c5 100644 (file)
 #include <media/tuner.h>
 #include <media/tuner-types.h>
 #include <media/v4l2-common.h>
-#include "tuner-driver.h"
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "mt20xx.h"
 #include "tda8290.h"
 #include "tea5761.h"
 #include "tea5767.h"
+#include "tuner-xc2028.h"
 #include "tuner-simple.h"
+#include "tda9887.h"
+#include "xc5000.h"
 
 #define UNSET (-1U)
 
+#define PREFIX t->i2c->driver->driver.name
+
+struct tuner {
+       /* device */
+       struct dvb_frontend fe;
+       struct i2c_client   *i2c;
+       struct list_head    list;
+       unsigned int        using_v4l2:1;
+
+       /* keep track of the current settings */
+       v4l2_std_id         std;
+       unsigned int        tv_freq;
+       unsigned int        radio_freq;
+       unsigned int        audmode;
+
+       unsigned int        mode;
+       unsigned int        mode_mask; /* Combination of allowable modes */
+
+       unsigned int        type; /* chip type id */
+       unsigned int        config;
+       int (*tuner_callback) (void *dev, int command, int arg);
+};
+
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
 #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
@@ -47,7 +73,34 @@ static unsigned int no_autodetect = 0;
 static unsigned int show_i2c = 0;
 
 /* insmod options used at runtime => read/write */
-int tuner_debug = 0;
+static int tuner_debug;
+
+#define tuner_warn(fmt, arg...) do {                   \
+       printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
+              i2c_adapter_id(t->i2c->adapter),         \
+              t->i2c->addr, ##arg);                    \
+        } while (0)
+
+#define tuner_info(fmt, arg...) do {                   \
+       printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,    \
+              i2c_adapter_id(t->i2c->adapter),         \
+              t->i2c->addr, ##arg);                    \
+        } while (0)
+
+#define tuner_err(fmt, arg...) do {                    \
+       printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,     \
+              i2c_adapter_id(t->i2c->adapter),         \
+              t->i2c->addr, ##arg);                    \
+        } while (0)
+
+#define tuner_dbg(fmt, arg...) do {                            \
+       if (tuner_debug)                                        \
+               printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,   \
+                      i2c_adapter_id(t->i2c->adapter),         \
+                      t->i2c->addr, ##arg);                    \
+        } while (0)
+
+/* ------------------------------------------------------------------------ */
 
 static unsigned int tv_range[2] = { 44, 958 };
 static unsigned int radio_range[2] = { 65, 108 };
@@ -71,66 +124,96 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
 MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
 MODULE_LICENSE("GPL");
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* ---------------------------------------------------------------------- */
 
-static void fe_set_freq(struct tuner *t, unsigned int freq)
+static void fe_set_params(struct dvb_frontend *fe,
+                         struct analog_parameters *params)
 {
-       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-
-       struct analog_parameters params = {
-               .frequency = freq,
-               .mode      = t->mode,
-               .audmode   = t->audmode,
-               .std       = t->std
-       };
+       struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+       struct tuner *t = fe->analog_demod_priv;
 
        if (NULL == fe_tuner_ops->set_analog_params) {
                tuner_warn("Tuner frontend module has no way to set freq\n");
                return;
        }
-       fe_tuner_ops->set_analog_params(&t->fe, &params);
+       fe_tuner_ops->set_analog_params(fe, params);
 }
 
-static void fe_release(struct tuner *t)
+static void fe_release(struct dvb_frontend *fe)
 {
-       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-
-       if (fe_tuner_ops->release)
-               fe_tuner_ops->release(&t->fe);
+       if (fe->ops.tuner_ops.release)
+               fe->ops.tuner_ops.release(fe);
+
+       /* DO NOT kfree(fe->analog_demod_priv)
+        *
+        * If we are in this function, analog_demod_priv contains a pointer
+        * to struct tuner *t.  This will be kfree'd in tuner_detach().
+        *
+        * Otherwise, fe->ops.analog_demod_ops->release will
+        * handle the cleanup for analog demodulator modules.
+        */
+       fe->analog_demod_priv = NULL;
 }
 
-static void fe_standby(struct tuner *t)
+static void fe_standby(struct dvb_frontend *fe)
 {
-       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+       struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
 
        if (fe_tuner_ops->sleep)
-               fe_tuner_ops->sleep(&t->fe);
+               fe_tuner_ops->sleep(fe);
 }
 
-static int fe_has_signal(struct tuner *t)
+static int fe_has_signal(struct dvb_frontend *fe)
 {
-       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
        u16 strength = 0;
 
-       if (fe_tuner_ops->get_rf_strength)
-               fe_tuner_ops->get_rf_strength(&t->fe, &strength);
+       if (fe->ops.tuner_ops.get_rf_strength)
+               fe->ops.tuner_ops.get_rf_strength(fe, &strength);
 
        return strength;
 }
 
+static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+       struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+       struct tuner *t = fe->analog_demod_priv;
+
+       if (fe_tuner_ops->set_config)
+               return fe_tuner_ops->set_config(fe, priv_cfg);
+
+       tuner_warn("Tuner frontend module has no way to set config\n");
+
+       return 0;
+}
+
+static void tuner_status(struct dvb_frontend *fe);
+
+static struct analog_demod_ops tuner_core_ops = {
+       .set_params     = fe_set_params,
+       .standby        = fe_standby,
+       .release        = fe_release,
+       .has_signal     = fe_has_signal,
+       .set_config     = fe_set_config,
+       .tuner_status   = tuner_status
+};
+
 /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       struct analog_parameters params = {
+               .mode      = t->mode,
+               .audmode   = t->audmode,
+               .std       = t->std
+       };
 
        if (t->type == UNSET) {
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if (NULL == t->ops.set_tv_freq) {
+       if (NULL == analog_ops->set_params) {
                tuner_warn ("Tuner has no way to set tv freq\n");
                return;
        }
@@ -145,18 +228,27 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                else
                        freq = tv_range[1] * 16;
        }
-       t->ops.set_tv_freq(t, freq);
+       params.frequency = freq;
+
+       analog_ops->set_params(&t->fe, &params);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       struct analog_parameters params = {
+               .mode      = t->mode,
+               .audmode   = t->audmode,
+               .std       = t->std
+       };
 
        if (t->type == UNSET) {
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if (NULL == t->ops.set_radio_freq) {
+       if (NULL == analog_ops->set_params) {
                tuner_warn ("tuner has no way to set radio frequency\n");
                return;
        }
@@ -171,8 +263,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                else
                        freq = radio_range[1] * 16000;
        }
+       params.frequency = freq;
 
-       t->ops.set_radio_freq(t, freq);
+       analog_ops->set_params(&t->fe, &params);
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -193,54 +286,65 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
                set_tv_freq(c, freq);
                t->tv_freq = freq;
                break;
+       default:
+               tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
        }
 }
 
 static void tuner_i2c_address_check(struct tuner *t)
 {
        if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
-           ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
+           ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
+               return;
+
+       /* We already know that the XC5000 can only be located at
+        * i2c address 0x61, 0x62, 0x63 or 0x64 */
+       if ((t->type == TUNER_XC5000) &&
+           ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
                return;
 
        tuner_warn("====================== WARNING! ======================\n");
        tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
        tuner_warn("will soon be dropped. This message indicates that your\n");
        tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
-                  t->i2c.name, t->i2c.addr);
+                  t->i2c->name, t->i2c->addr);
        tuner_warn("To ensure continued support for your device, please\n");
        tuner_warn("send a copy of this message, along with full dmesg\n");
        tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
        tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
        tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
-                  t->i2c.adapter->name, t->i2c.addr, t->type,
+                  t->i2c->adapter->name, t->i2c->addr, t->type,
                   tuners[t->type].name);
        tuner_warn("====================== WARNING! ======================\n");
 }
 
-static void attach_tda8290(struct tuner *t)
-{
-       struct tda8290_config cfg = {
-               .lna_cfg        = &t->config,
-               .tuner_callback = t->tuner_callback
-       };
-       tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
-}
-
 static void attach_simple_tuner(struct tuner *t)
 {
        struct simple_tuner_config cfg = {
                .type = t->type,
                .tun  = &tuners[t->type]
        };
-       simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+       simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
 }
 
+static void attach_tda829x(struct tuner *t)
+{
+       struct tda829x_config cfg = {
+               .lna_cfg        = &t->config,
+               .tuner_callback = t->tuner_callback,
+       };
+       tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
+}
+
+static struct xc5000_config xc5000_cfg;
+
 static void set_type(struct i2c_client *c, unsigned int type,
                     unsigned int new_mode_mask, unsigned int new_config,
                     int (*tuner_callback) (void *dev, int command,int arg))
 {
        struct tuner *t = i2c_get_clientdata(c);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        unsigned char buffer[4];
 
        if (type == UNSET || type == TUNER_ABSENT) {
@@ -260,32 +364,27 @@ static void set_type(struct i2c_client *c, unsigned int type,
                t->tuner_callback = tuner_callback;
        }
 
-       /* This code detects calls by card attach_inform */
-       if (NULL == t->i2c.dev.driver) {
+       if (t->mode == T_UNINITIALIZED) {
                tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
 
                return;
        }
 
        /* discard private data, in case set_type() was previously called */
-       if (t->ops.release)
-               t->ops.release(t);
-       else {
-               kfree(t->priv);
-               t->priv = NULL;
-       }
+       if (analog_ops->release)
+               analog_ops->release(&t->fe);
 
        switch (t->type) {
        case TUNER_MT2032:
-               microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
+               microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
                break;
        case TUNER_PHILIPS_TDA8290:
        {
-               attach_tda8290(t);
+               attach_tda829x(t);
                break;
        }
        case TUNER_TEA5767:
-               if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
+               if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
                        t->type = TUNER_ABSENT;
                        t->mode_mask = T_UNINITIALIZED;
                        return;
@@ -293,7 +392,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
                t->mode_mask = T_RADIO;
                break;
        case TUNER_TEA5761:
-               if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
+               if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
                        t->type = TUNER_ABSENT;
                        t->mode_mask = T_UNINITIALIZED;
                        return;
@@ -320,25 +419,60 @@ static void set_type(struct i2c_client *c, unsigned int type,
                i2c_master_send(c,buffer,4);
                attach_simple_tuner(t);
                break;
+       case TUNER_XC2028:
+       {
+               struct xc2028_config cfg = {
+                       .i2c_adap  = t->i2c->adapter,
+                       .i2c_addr  = t->i2c->addr,
+                       .video_dev = c->adapter->algo_data,
+                       .callback  = t->tuner_callback,
+               };
+               if (!xc2028_attach(&t->fe, &cfg)) {
+                       t->type = TUNER_ABSENT;
+                       t->mode_mask = T_UNINITIALIZED;
+                       return;
+               }
+               break;
+       }
        case TUNER_TDA9887:
-               tda9887_tuner_init(t);
+               tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+               break;
+       case TUNER_XC5000:
+               xc5000_cfg.i2c_address    = t->i2c->addr;
+               xc5000_cfg.if_khz         = 5380;
+               xc5000_cfg.priv           = c->adapter->algo_data;
+               xc5000_cfg.tuner_callback = t->tuner_callback;
+               if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
+                       t->type = TUNER_ABSENT;
+                       t->mode_mask = T_UNINITIALIZED;
+                       return;
+               }
+               {
+               struct dvb_tuner_ops *xc_tuner_ops;
+               xc_tuner_ops = &t->fe.ops.tuner_ops;
+               if(xc_tuner_ops->init != NULL)
+                       xc_tuner_ops->init(&t->fe);
+               }
                break;
        default:
                attach_simple_tuner(t);
                break;
        }
 
-       if (fe_tuner_ops->set_analog_params) {
-               strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
+       if ((NULL == analog_ops->set_params) &&
+           (fe_tuner_ops->set_analog_params)) {
+               strlcpy(t->i2c->name, fe_tuner_ops->info.name,
+                       sizeof(t->i2c->name));
 
-               t->ops.set_tv_freq    = fe_set_freq;
-               t->ops.set_radio_freq = fe_set_freq;
-               t->ops.standby        = fe_standby;
-               t->ops.release        = fe_release;
-               t->ops.has_signal     = fe_has_signal;
+               t->fe.analog_demod_priv = t;
+               memcpy(analog_ops, &tuner_core_ops,
+                      sizeof(struct analog_demod_ops));
+       } else {
+               strlcpy(t->i2c->name, analog_ops->info.name,
+                       sizeof(t->i2c->name));
        }
 
-       tuner_info("type set to %s\n", t->i2c.name);
+       tuner_dbg("type set to %s\n", t->i2c->name);
 
        if (t->mode_mask == T_UNINITIALIZED)
                t->mode_mask = new_mode_mask;
@@ -508,10 +642,12 @@ static int tuner_fixup_std(struct tuner *t)
        return 0;
 }
 
-static void tuner_status(struct tuner *t)
+static void tuner_status(struct dvb_frontend *fe)
 {
+       struct tuner *t = fe->analog_demod_priv;
        unsigned long freq, freq_fraction;
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        const char *p;
 
        switch (t->mode) {
@@ -541,172 +677,16 @@ static void tuner_status(struct tuner *t)
                if (tuner_status & TUNER_STATUS_STEREO)
                        tuner_info("Stereo:          yes\n");
        }
-       if (t->ops.has_signal) {
-               tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
-       }
-       if (t->ops.is_stereo) {
-               tuner_info("Stereo:          %s\n", t->ops.is_stereo(t) ? "yes" : "no");
-       }
+       if (analog_ops->has_signal)
+               tuner_info("Signal strength: %d\n",
+                          analog_ops->has_signal(fe));
+       if (analog_ops->is_stereo)
+               tuner_info("Stereo:          %s\n",
+                          analog_ops->is_stereo(fe) ? "yes" : "no");
 }
 
 /* ---------------------------------------------------------------------- */
 
-/* static vars: used only in tuner_attach and tuner_probe */
-static unsigned default_mode_mask;
-
-/* During client attach, set_type is called by adapter's attach_inform callback.
-   set_type must then be completed by tuner_attach.
- */
-static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       struct tuner *t;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
-       if (NULL == t)
-               return -ENOMEM;
-       memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
-       i2c_set_clientdata(&t->i2c, t);
-       t->type = UNSET;
-       t->audmode = V4L2_TUNER_MODE_STEREO;
-       t->mode_mask = T_UNINITIALIZED;
-       t->ops.tuner_status = tuner_status;
-
-       if (show_i2c) {
-               unsigned char buffer[16];
-               int i,rc;
-
-               memset(buffer, 0, sizeof(buffer));
-               rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
-               tuner_info("I2C RECV = ");
-               for (i=0;i<rc;i++)
-                       printk("%02x ",buffer[i]);
-               printk("\n");
-       }
-       /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
-       if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
-               return -ENODEV;
-
-       /* autodetection code based on the i2c addr */
-       if (!no_autodetect) {
-               switch (addr) {
-               case 0x10:
-                       if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
-                               t->type = TUNER_TEA5761;
-                               t->mode_mask = T_RADIO;
-                               t->mode = T_STANDBY;
-                               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-                               default_mode_mask &= ~T_RADIO;
-
-                               goto register_client;
-                       }
-                       break;
-               case 0x42:
-               case 0x43:
-               case 0x4a:
-               case 0x4b:
-                       /* If chip is not tda8290, don't register.
-                          since it can be tda9887*/
-                       if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
-                               tuner_dbg("chip at addr %x is a tda8290\n", addr);
-                       } else {
-                               /* Default is being tda9887 */
-                               t->type = TUNER_TDA9887;
-                               t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-                               t->mode = T_STANDBY;
-                               goto register_client;
-                       }
-                       break;
-               case 0x60:
-                       if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
-                               t->type = TUNER_TEA5767;
-                               t->mode_mask = T_RADIO;
-                               t->mode = T_STANDBY;
-                               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-                               default_mode_mask &= ~T_RADIO;
-
-                               goto register_client;
-                       }
-                       break;
-               }
-       }
-
-       /* Initializes only the first adapter found */
-       if (default_mode_mask != T_UNINITIALIZED) {
-               tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
-               t->mode_mask = default_mode_mask;
-               t->tv_freq = 400 * 16; /* Sets freq to VHF High */
-               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-               default_mode_mask = T_UNINITIALIZED;
-       }
-
-       /* Should be just before return */
-register_client:
-       tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-       i2c_attach_client (&t->i2c);
-       set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
-       return 0;
-}
-
-static int tuner_probe(struct i2c_adapter *adap)
-{
-       if (0 != addr) {
-               normal_i2c[0] = addr;
-               normal_i2c[1] = I2C_CLIENT_END;
-       }
-
-       /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
-        * FusionHDTV5 RT Gold has an ir receiver at 0x6b
-        * and an RTC at 0x6f which can get corrupted if probed.
-        */
-       if ((adap->id == I2C_HW_B_CX2388x) ||
-           (adap->id == I2C_HW_B_CX23885)) {
-               unsigned int i = 0;
-
-               while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
-                       i += 2;
-               if (i + 4 < I2C_CLIENT_MAX_OPTS) {
-                       ignore[i+0] = adap->nr;
-                       ignore[i+1] = 0x6b;
-                       ignore[i+2] = adap->nr;
-                       ignore[i+3] = 0x6f;
-                       ignore[i+4] = I2C_CLIENT_END;
-               } else
-                       printk(KERN_WARNING "tuner: "
-                              "too many options specified "
-                              "in i2c probe ignore list!\n");
-       }
-
-       default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, tuner_attach);
-       return 0;
-}
-
-static int tuner_detach(struct i2c_client *client)
-{
-       struct tuner *t = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(&t->i2c);
-       if (err) {
-               tuner_warn
-                   ("Client deregistration failed, client not detached.\n");
-               return err;
-       }
-
-       if (t->ops.release)
-               t->ops.release(t);
-       else {
-               kfree(t->priv);
-       }
-       kfree(t);
-       return 0;
-}
-
 /*
  * Switch tuner to other mode. If tuner support both tv and radio,
  * set another frequency to some value (This is needed for some pal
@@ -716,6 +696,8 @@ static int tuner_detach(struct i2c_client *client)
 
 static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
 {
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
        if (mode == t->mode)
                return 0;
 
@@ -723,8 +705,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
 
        if (check_mode(t, cmd) == EINVAL) {
                t->mode = T_STANDBY;
-               if (t->ops.standby)
-                       t->ops.standby(t);
+               if (analog_ops->standby)
+                       analog_ops->standby(&t->fe);
                return EINVAL;
        }
        return 0;
@@ -747,9 +729,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct tuner *t = i2c_get_clientdata(client);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        if (tuner_debug>1)
-               v4l_i2c_print_ioctl(&(t->i2c),cmd);
+               v4l_i2c_print_ioctl(client,cmd);
 
        switch (cmd) {
        /* --- configuration --- */
@@ -773,8 +756,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
                        return 0;
                t->mode = T_STANDBY;
-               if (t->ops.standby)
-                       t->ops.standby(t);
+               if (analog_ops->standby)
+                       analog_ops->standby(&t->fe);
                break;
 #ifdef CONFIG_VIDEO_V4L1
        case VIDIOCSAUDIO:
@@ -842,8 +825,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                        else
                                                vt->flags &= ~VIDEO_TUNER_STEREO_ON;
                                } else {
-                                       if (t->ops.is_stereo) {
-                                               if (t->ops.is_stereo(t))
+                                       if (analog_ops->is_stereo) {
+                                               if (analog_ops->is_stereo(&t->fe))
                                                        vt->flags |=
                                                                VIDEO_TUNER_STEREO_ON;
                                                else
@@ -851,8 +834,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                                                ~VIDEO_TUNER_STEREO_ON;
                                        }
                                }
-                               if (t->ops.has_signal)
-                                       vt->signal = t->ops.has_signal(t);
+                               if (analog_ops->has_signal)
+                                       vt->signal =
+                                               analog_ops->has_signal(&t->fe);
 
                                vt->flags |= VIDEO_TUNER_LOW;   /* Allow freqs at 62.5 Hz */
 
@@ -882,21 +866,28 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                        fe_tuner_ops->get_status(&t->fe, &tuner_status);
                                        va->mode = (tuner_status & TUNER_STATUS_STEREO)
                                            ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-                               } else if (t->ops.is_stereo)
-                                       va->mode = t->ops.is_stereo(t)
+                               } else if (analog_ops->is_stereo)
+                                       va->mode = analog_ops->is_stereo(&t->fe)
                                            ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
                        }
                        return 0;
                }
 #endif
-       case TDA9887_SET_CONFIG:
-               if (t->type == TUNER_TDA9887) {
-                       int *i = arg;
+       case TUNER_SET_CONFIG:
+       {
+               struct v4l2_priv_tun_config *cfg = arg;
 
-                       t->tda9887_config = *i;
-                       set_freq(client, t->tv_freq);
+               if (t->type != cfg->tuner)
+                       break;
+
+               if (analog_ops->set_config) {
+                       analog_ops->set_config(&t->fe, cfg->priv);
+                       break;
                }
+
+               tuner_dbg("Tuner frontend module has no way to set config\n");
                break;
+       }
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
           kernel pointer here... */
@@ -958,8 +949,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        switch_v4l2();
 
                        tuner->type = t->mode;
-                       if (t->ops.get_afc)
-                               tuner->afc=t->ops.get_afc(t);
+                       if (analog_ops->get_afc)
+                               tuner->afc = analog_ops->get_afc(&t->fe);
                        if (t->mode == V4L2_TUNER_ANALOG_TV)
                                tuner->capability |= V4L2_TUNER_CAP_NORM;
                        if (t->mode != V4L2_TUNER_RADIO) {
@@ -975,16 +966,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                u32 tuner_status;
 
                                fe_tuner_ops->get_status(&t->fe, &tuner_status);
-                               tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
-                                       V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+                               tuner->rxsubchans =
+                                       (tuner_status & TUNER_STATUS_STEREO) ?
+                                       V4L2_TUNER_SUB_STEREO :
+                                       V4L2_TUNER_SUB_MONO;
                        } else {
-                               if (t->ops.is_stereo) {
-                                       tuner->rxsubchans = t->ops.is_stereo(t) ?
-                                               V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+                               if (analog_ops->is_stereo) {
+                                       tuner->rxsubchans =
+                                               analog_ops->is_stereo(&t->fe) ?
+                                               V4L2_TUNER_SUB_STEREO :
+                                               V4L2_TUNER_SUB_MONO;
                                }
                        }
-                       if (t->ops.has_signal)
-                               tuner->signal = t->ops.has_signal(t);
+                       if (analog_ops->has_signal)
+                               tuner->signal = analog_ops->has_signal(&t->fe);
                        tuner->capability |=
                            V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
                        tuner->audmode = t->audmode;
@@ -1009,8 +1004,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        case VIDIOC_LOG_STATUS:
-               if (t->ops.tuner_status)
-                       t->ops.tuner_status(t);
+               if (analog_ops->tuner_status)
+                       analog_ops->tuner_status(&t->fe);
                break;
        }
 
@@ -1019,18 +1014,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static int tuner_suspend(struct i2c_client *c, pm_message_t state)
 {
-       struct tuner *t = i2c_get_clientdata (c);
+       struct tuner *t = i2c_get_clientdata(c);
 
-       tuner_dbg ("suspend\n");
+       tuner_dbg("suspend\n");
        /* FIXME: power down ??? */
        return 0;
 }
 
 static int tuner_resume(struct i2c_client *c)
 {
-       struct tuner *t = i2c_get_clientdata (c);
+       struct tuner *t = i2c_get_clientdata(c);
 
-       tuner_dbg ("resume\n");
+       tuner_dbg("resume\n");
        if (V4L2_TUNER_RADIO == t->mode) {
                if (t->radio_freq)
                        set_freq(c, t->radio_freq);
@@ -1041,36 +1036,227 @@ static int tuner_resume(struct i2c_client *c)
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
 
-static struct i2c_driver driver = {
-       .id = I2C_DRIVERID_TUNER,
-       .attach_adapter = tuner_probe,
-       .detach_client = tuner_detach,
-       .command = tuner_command,
-       .suspend = tuner_suspend,
-       .resume  = tuner_resume,
-       .driver = {
-               .name    = "tuner",
-       },
-};
-static struct i2c_client client_template = {
-       .name = "(tuner unset)",
-       .driver = &driver,
-};
+LIST_HEAD(tuner_list);
 
-static int __init tuner_init_module(void)
+/* Search for existing radio and/or TV tuners on the given I2C adapter.
+   Note that when this function is called from tuner_probe you can be
+   certain no other devices will be added/deleted at the same time, I2C
+   core protects against that. */
+static void tuner_lookup(struct i2c_adapter *adap,
+               struct tuner **radio, struct tuner **tv)
 {
-       return i2c_add_driver(&driver);
+       struct tuner *pos;
+
+       *radio = NULL;
+       *tv = NULL;
+
+       list_for_each_entry(pos, &tuner_list, list) {
+               int mode_mask;
+
+               if (pos->i2c->adapter != adap ||
+                   pos->i2c->driver->id != I2C_DRIVERID_TUNER)
+                       continue;
+
+               mode_mask = pos->mode_mask & ~T_STANDBY;
+               if (*radio == NULL && mode_mask == T_RADIO)
+                       *radio = pos;
+               /* Note: currently TDA9887 is the only demod-only
+                  device. If other devices appear then we need to
+                  make this test more general. */
+               else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
+                        (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
+                       *tv = pos;
+       }
 }
 
-static void __exit tuner_cleanup_module(void)
+/* During client attach, set_type is called by adapter's attach_inform callback.
+   set_type must then be completed by tuner_probe.
+ */
+static int tuner_probe(struct i2c_client *client)
 {
-       i2c_del_driver(&driver);
+       struct tuner *t;
+       struct tuner *radio;
+       struct tuner *tv;
+
+       t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
+       if (NULL == t)
+               return -ENOMEM;
+       t->i2c = client;
+       strlcpy(client->name, "(tuner unset)", sizeof(client->name));
+       i2c_set_clientdata(client, t);
+       t->type = UNSET;
+       t->audmode = V4L2_TUNER_MODE_STEREO;
+       t->mode_mask = T_UNINITIALIZED;
+
+       if (show_i2c) {
+               unsigned char buffer[16];
+               int i, rc;
+
+               memset(buffer, 0, sizeof(buffer));
+               rc = i2c_master_recv(client, buffer, sizeof(buffer));
+               tuner_info("I2C RECV = ");
+               for (i = 0; i < rc; i++)
+                       printk(KERN_CONT "%02x ", buffer[i]);
+               printk("\n");
+       }
+       /* HACK: This test was added to avoid tuner to probe tda9840 and
+          tea6415c on the MXB card */
+       if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
+               kfree(t);
+               return -ENODEV;
+       }
+
+       /* autodetection code based on the i2c addr */
+       if (!no_autodetect) {
+               switch (client->addr) {
+               case 0x10:
+                       if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
+                                       != EINVAL) {
+                               t->type = TUNER_TEA5761;
+                               t->mode_mask = T_RADIO;
+                               t->mode = T_STANDBY;
+                               /* Sets freq to FM range */
+                               t->radio_freq = 87.5 * 16000;
+                               tuner_lookup(t->i2c->adapter, &radio, &tv);
+                               if (tv)
+                                       tv->mode_mask &= ~T_RADIO;
+
+                               goto register_client;
+                       }
+                       break;
+               case 0x42:
+               case 0x43:
+               case 0x4a:
+               case 0x4b:
+                       /* If chip is not tda8290, don't register.
+                          since it can be tda9887*/
+                       if (tda829x_probe(t->i2c->adapter,
+                                         t->i2c->addr) == 0) {
+                               tuner_dbg("tda829x detected\n");
+                       } else {
+                               /* Default is being tda9887 */
+                               t->type = TUNER_TDA9887;
+                               t->mode_mask = T_RADIO | T_ANALOG_TV |
+                                              T_DIGITAL_TV;
+                               t->mode = T_STANDBY;
+                               goto register_client;
+                       }
+                       break;
+               case 0x60:
+                       if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
+                                       != EINVAL) {
+                               t->type = TUNER_TEA5767;
+                               t->mode_mask = T_RADIO;
+                               t->mode = T_STANDBY;
+                               /* Sets freq to FM range */
+                               t->radio_freq = 87.5 * 16000;
+                               tuner_lookup(t->i2c->adapter, &radio, &tv);
+                               if (tv)
+                                       tv->mode_mask &= ~T_RADIO;
+
+                               goto register_client;
+                       }
+                       break;
+               }
+       }
+
+       /* Initializes only the first TV tuner on this adapter. Why only the
+          first? Because there are some devices (notably the ones with TI
+          tuners) that have more than one i2c address for the *same* device.
+          Experience shows that, except for just one case, the first
+          address is the right one. The exception is a Russian tuner
+          (ACORP_Y878F). So, the desired behavior is just to enable the
+          first found TV tuner. */
+       tuner_lookup(t->i2c->adapter, &radio, &tv);
+       if (tv == NULL) {
+               t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+               if (radio == NULL)
+                       t->mode_mask |= T_RADIO;
+               tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
+               t->tv_freq = 400 * 16; /* Sets freq to VHF High */
+               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+       }
+
+       /* Should be just before return */
+register_client:
+       tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
+                      client->adapter->name);
+
+       /* Sets a default mode */
+       if (t->mode_mask & T_ANALOG_TV) {
+               t->mode = V4L2_TUNER_ANALOG_TV;
+       } else  if (t->mode_mask & T_RADIO) {
+               t->mode = V4L2_TUNER_RADIO;
+       } else {
+               t->mode = V4L2_TUNER_DIGITAL_TV;
+       }
+       set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
+       list_add_tail(&t->list, &tuner_list);
+       return 0;
+}
+
+static int tuner_legacy_probe(struct i2c_adapter *adap)
+{
+       if (0 != addr) {
+               normal_i2c[0] = addr;
+               normal_i2c[1] = I2C_CLIENT_END;
+       }
+
+       if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
+               return 0;
+
+       /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
+        * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+        * and an RTC at 0x6f which can get corrupted if probed.
+        */
+       if ((adap->id == I2C_HW_B_CX2388x) ||
+           (adap->id == I2C_HW_B_CX23885)) {
+               unsigned int i = 0;
+
+               while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
+                       i += 2;
+               if (i + 4 < I2C_CLIENT_MAX_OPTS) {
+                       ignore[i+0] = adap->nr;
+                       ignore[i+1] = 0x6b;
+                       ignore[i+2] = adap->nr;
+                       ignore[i+3] = 0x6f;
+                       ignore[i+4] = I2C_CLIENT_END;
+               } else
+                       printk(KERN_WARNING "tuner: "
+                              "too many options specified "
+                              "in i2c probe ignore list!\n");
+       }
+       return 1;
 }
 
-module_init(tuner_init_module);
-module_exit(tuner_cleanup_module);
+static int tuner_remove(struct i2c_client *client)
+{
+       struct tuner *t = i2c_get_clientdata(client);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       if (analog_ops->release)
+               analog_ops->release(&t->fe);
+
+       list_del(&t->list);
+       kfree(t);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tuner",
+       .driverid = I2C_DRIVERID_TUNER,
+       .command = tuner_command,
+       .probe = tuner_probe,
+       .remove = tuner_remove,
+       .suspend = tuner_suspend,
+       .resume = tuner_resume,
+       .legacy_probe = tuner_legacy_probe,
+};
+
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
deleted file mode 100644 (file)
index 28a10da..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-    tuner-driver.h - interface for different tuners
-
-    Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
-    minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TUNER_DRIVER_H__
-#define __TUNER_DRIVER_H__
-
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include "tuner-i2c.h"
-#include "dvb_frontend.h"
-
-extern unsigned const int tuner_count;
-
-struct tuner;
-
-struct tuner_operations {
-       void (*set_tv_freq)(struct tuner *t, unsigned int freq);
-       void (*set_radio_freq)(struct tuner *t, unsigned int freq);
-       int  (*has_signal)(struct tuner *t);
-       int  (*is_stereo)(struct tuner *t);
-       int  (*get_afc)(struct tuner *t);
-       void (*tuner_status)(struct tuner *t);
-       void (*standby)(struct tuner *t);
-       void (*release)(struct tuner *t);
-};
-
-struct tuner {
-       /* device */
-       struct i2c_client i2c;
-
-       unsigned int type;      /* chip type */
-
-       unsigned int mode;
-       unsigned int mode_mask; /* Combination of allowable modes */
-
-       unsigned int tv_freq;   /* keep track of the current settings */
-       unsigned int radio_freq;
-       unsigned int audmode;
-       v4l2_std_id  std;
-
-       int          using_v4l2;
-       void *priv;
-
-       struct dvb_frontend fe;
-
-       /* used by tda9887 */
-       unsigned int       tda9887_config;
-
-       unsigned int config;
-       int (*tuner_callback) (void *dev, int command,int arg);
-
-       struct tuner_operations ops;
-};
-
-/* ------------------------------------------------------------------------ */
-
-extern int tda9887_tuner_init(struct tuner *t);
-
-/* ------------------------------------------------------------------------ */
-
-#define tuner_warn(fmt, arg...) do {\
-       printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
-       extern int tuner_debug; \
-       if (tuner_debug) \
-               printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-
-#endif /* __TUNER_DRIVER_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 159019ec337391365d69c4fc4bc3a8578aee24e4..de52e8ffd347df1dcd2060c2e6c406b0a58933c2 100644 (file)
@@ -46,25 +46,42 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf,
        return (ret == 1) ? len : ret;
 }
 
-#ifndef __TUNER_DRIVER_H__
-#define tuner_warn(fmt, arg...) do {\
-       printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
-                       i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
-       printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
-                       i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
-       if ((debug)) \
-               printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
-                       i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
-#endif /* __TUNER_DRIVER_H__ */
+static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
+                                          char *obuf, int olen,
+                                          char *ibuf, int ilen)
+{
+       struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
+                                   .buf = obuf, .len = olen },
+                                 { .addr = props->addr, .flags = I2C_M_RD,
+                                   .buf = ibuf, .len = ilen } };
+       int ret = i2c_transfer(props->adap, msg, 2);
 
-#endif /* __TUNER_I2C_H__ */
+       return (ret == 2) ? ilen : ret;
+}
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#define tuner_warn(fmt, arg...) do {                                   \
+       printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX,                 \
+                       i2c_adapter_id(priv->i2c_props.adap),           \
+                       priv->i2c_props.addr, ##arg);                   \
+        } while (0)
+
+#define tuner_info(fmt, arg...) do {                                   \
+       printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,                    \
+                       i2c_adapter_id(priv->i2c_props.adap),           \
+                       priv->i2c_props.addr , ##arg);                  \
+       } while (0)
+
+#define tuner_err(fmt, arg...) do {                                    \
+       printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,                     \
+                       i2c_adapter_id(priv->i2c_props.adap),           \
+                       priv->i2c_props.addr , ##arg);                  \
+       } while (0)
+
+#define tuner_dbg(fmt, arg...) do {                                    \
+       if ((debug))                                                    \
+               printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,           \
+                       i2c_adapter_id(priv->i2c_props.adap),           \
+                       priv->i2c_props.addr , ##arg);                  \
+       } while (0)
+
+#endif /* __TUNER_I2C_H__ */
index 7b93d3b1f4c6aa540ced10abdfdaa2fd4198cae1..c1db576696c6d34288e2b4cc6a596c4e730f9dc9 100644 (file)
@@ -17,7 +17,7 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tuner-simple "
+#define PREFIX "tuner-simple"
 
 static int offset = 0;
 module_param(offset, int, 0664);
@@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
        }
        priv->last_div = div;
        if (t_params->has_tda9887) {
+               struct v4l2_priv_tun_config tda9887_cfg;
                int config = 0;
                int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
                        !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
 
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv  = &config;
+
                if (params->std == V4L2_STD_SECAM_LC) {
                        if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
                                config |= TDA9887_PORT1_ACTIVE;
@@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
                }
                if (t_params->default_pll_gating_18)
                        config |= TDA9887_GATING_18;
-               i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
+               i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
+                                   &tda9887_cfg);
        }
        tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
                  buffer[0],buffer[1],buffer[2],buffer[3]);
@@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
 
        if (t_params->has_tda9887) {
                int config = 0;
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv = &config;
+
                if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
                        config |= TDA9887_PORT1_ACTIVE;
                if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
@@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
                        config |= TDA9887_GAIN_NORMAL;
                if (t_params->radio_if == 2)
                        config |= TDA9887_RIF_41_3;
-               i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
+               i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
+                                       &tda9887_cfg);
        }
        if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
                tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
index c6a7934bd5a678f9287c6963344f9e3d1e7c216e..883047f9c28c32f66eb7c98a5b080dcf92bc6e06 100644 (file)
@@ -1366,7 +1366,7 @@ struct tunertype tuners[] = {
                .count  = ARRAY_SIZE(tuner_philips_fq1286_params),
        },
        [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
-               .name   = "tda8290+75",
+               .name   = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
                /* see tda8290.c for details */ },
        [TUNER_TCL_2002MB] = { /* TCL PAL */
                .name   = "TCL 2002MB",
@@ -1452,9 +1452,9 @@ struct tunertype tuners[] = {
                .params = tuner_samsung_tcpn_2121p30a_params,
                .count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
        },
-       [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */
-               .name   = "Xceive xc3028",
-               /* see xc3028.c for details */
+       [TUNER_XC2028] = { /* Xceive 2028 */
+               .name   = "Xceive xc2028/xc3028 tuner",
+               /* see tuner-xc2028.c for details */
        },
        [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
                .name   = "Thomson FE6600",
@@ -1475,6 +1475,10 @@ struct tunertype tuners[] = {
                .name   = "Philips TEA5761 FM Radio",
                /* see tea5767.c for details */
        },
+       [TUNER_XC5000] = { /* Xceive 5000 */
+               .name   = "Xceive 5000 tuner",
+               /* see xc5000.c for details */
+       },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h
new file mode 100644 (file)
index 0000000..d0057fb
--- /dev/null
@@ -0,0 +1,128 @@
+/* tuner-xc2028_types
+ *
+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+/* xc3028 firmware types */
+
+/* BASE firmware should be loaded before any other firmware */
+#define BASE           (1<<0)
+#define BASE_TYPES     (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
+
+/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
+#define F8MHZ          (1<<1)
+
+/* Multichannel Television Sound (MTS)
+   Those firmwares are capable of using xc2038 DSP to decode audio and
+   produce a baseband audio output on some pins of the chip.
+   There are MTS firmwares for the most used video standards. It should be
+   required to use MTS firmwares, depending on the way audio is routed into
+   the bridge chip
+ */
+#define MTS            (1<<2)
+
+/* FIXME: I have no idea what's the difference between
+   D2620 and D2633 firmwares
+ */
+#define D2620          (1<<3)
+#define D2633          (1<<4)
+
+/* DTV firmwares for 6, 7 and 8 MHz
+   DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
+   DTV8 - 8MHz - DVB-C/DVB-T
+ */
+#define DTV6           (1 << 5)
+#define QAM            (1 << 6)
+#define DTV7           (1<<7)
+#define DTV78          (1<<8)
+#define DTV8           (1<<9)
+
+#define DTV_TYPES      (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
+
+/* There's a FM | BASE firmware + FM specific firmware (std=0) */
+#define        FM              (1<<10)
+
+#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
+
+/* Applies only for FM firmware
+   Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
+ */
+#define INPUT1         (1<<11)
+
+
+/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
+       and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+       There are variants both with and without NOGD
+ */
+#define LCD            (1<<12)
+
+/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
+       and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+ */
+#define NOGD           (1<<13)
+
+/* Old firmwares were broken into init0 and init1 */
+#define INIT1          (1<<14)
+
+/* SCODE firmware selects particular behaviours */
+#define MONO           (1 << 15)
+#define ATSC           (1 << 16)
+#define IF             (1 << 17)
+#define LG60           (1 << 18)
+#define ATI638         (1 << 19)
+#define OREN538        (1 << 20)
+#define OREN36         (1 << 21)
+#define TOYOTA388      (1 << 22)
+#define TOYOTA794      (1 << 23)
+#define DIBCOM52       (1 << 24)
+#define ZARLINK456     (1 << 25)
+#define CHINA          (1 << 26)
+#define F6MHZ          (1 << 27)
+#define INPUT2         (1 << 28)
+#define SCODE          (1 << 29)
+
+/* This flag identifies that the scode table has a new format */
+#define HAS_IF         (1 << 30)
+
+#define SCODE_TYPES    (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
+                        LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794|     \
+                        DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
+
+/* Newer types to be moved to videodev2.h */
+
+#define V4L2_STD_SECAM_K3      (0x04000000)
+
+/* Audio types */
+
+#define V4L2_STD_A2_A          (1LL<<32)
+#define V4L2_STD_A2_B          (1LL<<33)
+#define V4L2_STD_NICAM_A       (1LL<<34)
+#define V4L2_STD_NICAM_B       (1LL<<35)
+#define V4L2_STD_AM            (1LL<<36)
+#define V4L2_STD_BTSC          (1LL<<37)
+#define V4L2_STD_EIAJ          (1LL<<38)
+
+#define V4L2_STD_A2            (V4L2_STD_A2_A    | V4L2_STD_A2_B)
+#define V4L2_STD_NICAM         (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
+
+/* To preserve backward compatibilty,
+   (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
+ */
+
+#define V4L2_STD_AUDIO         (V4L2_STD_A2    | \
+                                V4L2_STD_NICAM | \
+                                V4L2_STD_AM    | \
+                                V4L2_STD_BTSC  | \
+                                V4L2_STD_EIAJ)
+
+/* Used standards with audio restrictions */
+
+#define V4L2_STD_PAL_BG_A2_A   (V4L2_STD_PAL_BG | V4L2_STD_A2_A)
+#define V4L2_STD_PAL_BG_A2_B   (V4L2_STD_PAL_BG | V4L2_STD_A2_B)
+#define V4L2_STD_PAL_BG_NICAM_A        (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
+#define V4L2_STD_PAL_BG_NICAM_B        (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
+#define V4L2_STD_PAL_DK_A2     (V4L2_STD_PAL_DK | V4L2_STD_A2)
+#define V4L2_STD_PAL_DK_NICAM  (V4L2_STD_PAL_DK | V4L2_STD_NICAM)
+#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM)
+#define V4L2_STD_SECAM_L_AM    (V4L2_STD_SECAM_L | V4L2_STD_AM)
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
new file mode 100644 (file)
index 0000000..f191f6a
--- /dev/null
@@ -0,0 +1,1213 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ *
+ * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
+ *       - frontend interface
+ *
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <asm/div64.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include <linux/mutex.h>
+#include "tuner-i2c.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+#define PREFIX "xc2028"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static char audio_std[8];
+module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
+MODULE_PARM_DESC(audio_std,
+       "Audio standard. XC3028 audio decoder explicitly "
+       "needs to know what audio\n"
+       "standard is needed for some video standards with audio A2 or NICAM.\n"
+       "The valid values are:\n"
+       "A2\n"
+       "A2/A\n"
+       "A2/B\n"
+       "NICAM\n"
+       "NICAM/A\n"
+       "NICAM/B\n");
+
+static LIST_HEAD(xc2028_list);
+static DEFINE_MUTEX(xc2028_list_mutex);
+
+/* struct for storing firmware table */
+struct firmware_description {
+       unsigned int  type;
+       v4l2_std_id   id;
+       __u16         int_freq;
+       unsigned char *ptr;
+       unsigned int  size;
+};
+
+struct firmware_properties {
+       unsigned int    type;
+       v4l2_std_id     id;
+       v4l2_std_id     std_req;
+       __u16           int_freq;
+       unsigned int    scode_table;
+       int             scode_nr;
+};
+
+struct xc2028_data {
+       struct list_head        xc2028_list;
+       struct tuner_i2c_props  i2c_props;
+       int                     (*tuner_callback) (void *dev,
+                                                  int command, int arg);
+       void                    *video_dev;
+       int                     count;
+       __u32                   frequency;
+
+       struct firmware_description *firm;
+       int                     firm_size;
+       __u16                   firm_version;
+
+       __u16                   hwmodel;
+       __u16                   hwvers;
+
+       struct xc2028_ctrl      ctrl;
+
+       struct firmware_properties cur_fw;
+
+       struct mutex lock;
+};
+
+#define i2c_send(priv, buf, size) ({                                   \
+       int _rc;                                                        \
+       _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);         \
+       if (size != _rc)                                                \
+               tuner_info("i2c output error: rc = %d (should be %d)\n",\
+                          _rc, (int)size);                             \
+       _rc;                                                            \
+})
+
+#define i2c_rcv(priv, buf, size) ({                                    \
+       int _rc;                                                        \
+       _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);         \
+       if (size != _rc)                                                \
+               tuner_err("i2c input error: rc = %d (should be %d)\n",  \
+                          _rc, (int)size);                             \
+       _rc;                                                            \
+})
+
+#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({               \
+       int _rc;                                                        \
+       _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,   \
+                                      ibuf, isize);                    \
+       if (isize != _rc)                                               \
+               tuner_err("i2c input error: rc = %d (should be %d)\n",  \
+                          _rc, (int)isize);                            \
+       _rc;                                                            \
+})
+
+#define send_seq(priv, data...)        ({                                      \
+       static u8 _val[] = data;                                        \
+       int _rc;                                                        \
+       if (sizeof(_val) !=                                             \
+                       (_rc = tuner_i2c_xfer_send(&priv->i2c_props,    \
+                                               _val, sizeof(_val)))) { \
+               tuner_err("Error on line %d: %d\n", __LINE__, _rc);     \
+       } else                                                          \
+               msleep(10);                                             \
+       _rc;                                                            \
+})
+
+static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+{
+       unsigned char buf[2];
+       unsigned char ibuf[2];
+
+       tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
+
+       buf[0] = reg >> 8;
+       buf[1] = (unsigned char) reg;
+
+       if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
+               return -EIO;
+
+       *val = (ibuf[1]) | (ibuf[0] << 8);
+       return 0;
+}
+
+#define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
+void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+        if (type & BASE)
+               printk("BASE ");
+        if (type & INIT1)
+               printk("INIT1 ");
+        if (type & F8MHZ)
+               printk("F8MHZ ");
+        if (type & MTS)
+               printk("MTS ");
+        if (type & D2620)
+               printk("D2620 ");
+        if (type & D2633)
+               printk("D2633 ");
+        if (type & DTV6)
+               printk("DTV6 ");
+        if (type & QAM)
+               printk("QAM ");
+        if (type & DTV7)
+               printk("DTV7 ");
+        if (type & DTV78)
+               printk("DTV78 ");
+        if (type & DTV8)
+               printk("DTV8 ");
+        if (type & FM)
+               printk("FM ");
+        if (type & INPUT1)
+               printk("INPUT1 ");
+        if (type & LCD)
+               printk("LCD ");
+        if (type & NOGD)
+               printk("NOGD ");
+        if (type & MONO)
+               printk("MONO ");
+        if (type & ATSC)
+               printk("ATSC ");
+        if (type & IF)
+               printk("IF ");
+        if (type & LG60)
+               printk("LG60 ");
+        if (type & ATI638)
+               printk("ATI638 ");
+        if (type & OREN538)
+               printk("OREN538 ");
+        if (type & OREN36)
+               printk("OREN36 ");
+        if (type & TOYOTA388)
+               printk("TOYOTA388 ");
+        if (type & TOYOTA794)
+               printk("TOYOTA794 ");
+        if (type & DIBCOM52)
+               printk("DIBCOM52 ");
+        if (type & ZARLINK456)
+               printk("ZARLINK456 ");
+        if (type & CHINA)
+               printk("CHINA ");
+        if (type & F6MHZ)
+               printk("F6MHZ ");
+        if (type & INPUT2)
+               printk("INPUT2 ");
+        if (type & SCODE)
+               printk("SCODE ");
+        if (type & HAS_IF)
+               printk("HAS_IF_%d ", int_freq);
+}
+
+static  v4l2_std_id parse_audio_std_option(void)
+{
+       if (strcasecmp(audio_std, "A2") == 0)
+               return V4L2_STD_A2;
+       if (strcasecmp(audio_std, "A2/A") == 0)
+               return V4L2_STD_A2_A;
+       if (strcasecmp(audio_std, "A2/B") == 0)
+               return V4L2_STD_A2_B;
+       if (strcasecmp(audio_std, "NICAM") == 0)
+               return V4L2_STD_NICAM;
+       if (strcasecmp(audio_std, "NICAM/A") == 0)
+               return V4L2_STD_NICAM_A;
+       if (strcasecmp(audio_std, "NICAM/B") == 0)
+               return V4L2_STD_NICAM_B;
+
+       return 0;
+}
+
+static void free_firmware(struct xc2028_data *priv)
+{
+       int i;
+
+       if (!priv->firm)
+               return;
+
+       for (i = 0; i < priv->firm_size; i++)
+               kfree(priv->firm[i].ptr);
+
+       kfree(priv->firm);
+
+       priv->firm = NULL;
+       priv->firm_size = 0;
+
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+}
+
+static int load_all_firmwares(struct dvb_frontend *fe)
+{
+       struct xc2028_data    *priv = fe->tuner_priv;
+       const struct firmware *fw   = NULL;
+       unsigned char         *p, *endp;
+       int                   rc = 0;
+       int                   n, n_array;
+       char                  name[33];
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
+       rc = request_firmware(&fw, priv->ctrl.fname,
+                             &priv->i2c_props.adap->dev);
+       if (rc < 0) {
+               if (rc == -ENOENT)
+                       tuner_err("Error: firmware %s not found.\n",
+                                  priv->ctrl.fname);
+               else
+                       tuner_err("Error %d while requesting firmware %s \n",
+                                  rc, priv->ctrl.fname);
+
+               return rc;
+       }
+       p = fw->data;
+       endp = p + fw->size;
+
+       if (fw->size < sizeof(name) - 1 + 2 + 2) {
+               tuner_err("Error: firmware file %s has invalid size!\n",
+                         priv->ctrl.fname);
+               goto corrupt;
+       }
+
+       memcpy(name, p, sizeof(name) - 1);
+       name[sizeof(name) - 1] = 0;
+       p += sizeof(name) - 1;
+
+       priv->firm_version = le16_to_cpu(*(__u16 *) p);
+       p += 2;
+
+       n_array = le16_to_cpu(*(__u16 *) p);
+       p += 2;
+
+       tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+                  n_array, priv->ctrl.fname, name,
+                  priv->firm_version >> 8, priv->firm_version & 0xff);
+
+       priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+       if (priv->firm == NULL) {
+               tuner_err("Not enough memory to load firmware file.\n");
+               rc = -ENOMEM;
+               goto err;
+       }
+       priv->firm_size = n_array;
+
+       n = -1;
+       while (p < endp) {
+               __u32 type, size;
+               v4l2_std_id id;
+               __u16 int_freq = 0;
+
+               n++;
+               if (n >= n_array) {
+                       tuner_err("More firmware images in file than "
+                                 "were expected!\n");
+                       goto corrupt;
+               }
+
+               /* Checks if there's enough bytes to read */
+               if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
+                       tuner_err("Firmware header is incomplete!\n");
+                       goto corrupt;
+               }
+
+               type = le32_to_cpu(*(__u32 *) p);
+               p += sizeof(type);
+
+               id = le64_to_cpu(*(v4l2_std_id *) p);
+               p += sizeof(id);
+
+               if (type & HAS_IF) {
+                       int_freq = le16_to_cpu(*(__u16 *) p);
+                       p += sizeof(int_freq);
+               }
+
+               size = le32_to_cpu(*(__u32 *) p);
+               p += sizeof(size);
+
+               if ((!size) || (size + p > endp)) {
+                       tuner_err("Firmware type ");
+                       dump_firm_type(type);
+                       printk("(%x), id %llx is corrupted "
+                              "(size=%d, expected %d)\n",
+                              type, (unsigned long long)id,
+                              (unsigned)(endp - p), size);
+                       goto corrupt;
+               }
+
+               priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+               if (priv->firm[n].ptr == NULL) {
+                       tuner_err("Not enough memory to load firmware file.\n");
+                       rc = -ENOMEM;
+                       goto err;
+               }
+               tuner_dbg("Reading firmware type ");
+               if (debug) {
+                       dump_firm_type_and_int_freq(type, int_freq);
+                       printk("(%x), id %llx, size=%d.\n",
+                              type, (unsigned long long)id, size);
+               }
+
+               memcpy(priv->firm[n].ptr, p, size);
+               priv->firm[n].type = type;
+               priv->firm[n].id   = id;
+               priv->firm[n].size = size;
+               priv->firm[n].int_freq = int_freq;
+
+               p += size;
+       }
+
+       if (n + 1 != priv->firm_size) {
+               tuner_err("Firmware file is incomplete!\n");
+               goto corrupt;
+       }
+
+       goto done;
+
+corrupt:
+       rc = -EINVAL;
+       tuner_err("Error: firmware file is corrupted!\n");
+
+err:
+       tuner_info("Releasing partially loaded firmware file.\n");
+       free_firmware(priv);
+
+done:
+       release_firmware(fw);
+       if (rc == 0)
+               tuner_dbg("Firmware files loaded.\n");
+
+       return rc;
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int                 i, best_i = -1, best_nr_matches = 0;
+       unsigned int        ign_firm_type_mask = 0;
+
+       tuner_dbg("%s called, want type=", __FUNCTION__);
+       if (debug) {
+               dump_firm_type(type);
+               printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+       }
+
+       if (!priv->firm) {
+               tuner_err("Error! firmware not loaded\n");
+               return -EINVAL;
+       }
+
+       if (((type & ~SCODE) == 0) && (*id == 0))
+               *id = V4L2_STD_PAL;
+
+       if (type & BASE)
+               type &= BASE_TYPES;
+       else if (type & SCODE) {
+               type &= SCODE_TYPES;
+               ign_firm_type_mask = HAS_IF;
+       } else if (type & DTV_TYPES)
+               type &= DTV_TYPES;
+       else if (type & STD_SPECIFIC_TYPES)
+               type &= STD_SPECIFIC_TYPES;
+
+       /* Seek for exact match */
+       for (i = 0; i < priv->firm_size; i++) {
+               if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
+                   (*id == priv->firm[i].id))
+                       goto found;
+       }
+
+       /* Seek for generic video standard match */
+       for (i = 0; i < priv->firm_size; i++) {
+               v4l2_std_id match_mask;
+               int nr_matches;
+
+               if (type != (priv->firm[i].type & ~ign_firm_type_mask))
+                       continue;
+
+               match_mask = *id & priv->firm[i].id;
+               if (!match_mask)
+                       continue;
+
+               if ((*id & match_mask) == *id)
+                       goto found; /* Supports all the requested standards */
+
+               nr_matches = hweight64(match_mask);
+               if (nr_matches > best_nr_matches) {
+                       best_nr_matches = nr_matches;
+                       best_i = i;
+               }
+       }
+
+       if (best_nr_matches > 0) {
+               tuner_dbg("Selecting best matching firmware (%d bits) for "
+                         "type=", best_nr_matches);
+               dump_firm_type(type);
+               printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
+               i = best_i;
+               goto found;
+       }
+
+       /*FIXME: Would make sense to seek for type "hint" match ? */
+
+       i = -ENOENT;
+       goto ret;
+
+found:
+       *id = priv->firm[i].id;
+
+ret:
+       tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
+       if (debug) {
+               dump_firm_type(type);
+               printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+       }
+       return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int                pos, rc;
+       unsigned char      *p, *endp, buf[priv->ctrl.max_len];
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       pos = seek_firmware(fe, type, id);
+       if (pos < 0)
+               return pos;
+
+       tuner_info("Loading firmware for type=");
+       dump_firm_type(priv->firm[pos].type);
+       printk("(%x), id %016llx.\n", priv->firm[pos].type,
+              (unsigned long long)*id);
+
+       p = priv->firm[pos].ptr;
+       endp = p + priv->firm[pos].size;
+
+       while (p < endp) {
+               __u16 size;
+
+               /* Checks if there's enough bytes to read */
+               if (p + sizeof(size) > endp) {
+                       tuner_err("Firmware chunk size is wrong\n");
+                       return -EINVAL;
+               }
+
+               size = le16_to_cpu(*(__u16 *) p);
+               p += sizeof(size);
+
+               if (size == 0xffff)
+                       return 0;
+
+               if (!size) {
+                       /* Special callback command received */
+                       rc = priv->tuner_callback(priv->video_dev,
+                                                 XC2028_TUNER_RESET, 0);
+                       if (rc < 0) {
+                               tuner_err("Error at RESET code %d\n",
+                                          (*p) & 0x7f);
+                               return -EINVAL;
+                       }
+                       continue;
+               }
+               if (size >= 0xff00) {
+                       switch (size) {
+                       case 0xff00:
+                               rc = priv->tuner_callback(priv->video_dev,
+                                                       XC2028_RESET_CLK, 0);
+                               if (rc < 0) {
+                                       tuner_err("Error at RESET code %d\n",
+                                                 (*p) & 0x7f);
+                                       return -EINVAL;
+                               }
+                               break;
+                       default:
+                               tuner_info("Invalid RESET code %d\n",
+                                          size & 0x7f);
+                               return -EINVAL;
+
+                       }
+                       continue;
+               }
+
+               /* Checks for a sleep command */
+               if (size & 0x8000) {
+                       msleep(size & 0x7fff);
+                       continue;
+               }
+
+               if ((size + p > endp)) {
+                       tuner_err("missing bytes: need %d, have %d\n",
+                                  size, (int)(endp - p));
+                       return -EINVAL;
+               }
+
+               buf[0] = *p;
+               p++;
+               size--;
+
+               /* Sends message chunks */
+               while (size > 0) {
+                       int len = (size < priv->ctrl.max_len - 1) ?
+                                  size : priv->ctrl.max_len - 1;
+
+                       memcpy(buf + 1, p, len);
+
+                       rc = i2c_send(priv, buf, len + 1);
+                       if (rc < 0) {
+                               tuner_err("%d returned from send\n", rc);
+                               return -EINVAL;
+                       }
+
+                       p += len;
+                       size -= len;
+               }
+       }
+       return 0;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id, __u16 int_freq, int scode)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int                pos, rc;
+       unsigned char      *p;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       if (!int_freq) {
+               pos = seek_firmware(fe, type, id);
+               if (pos < 0)
+                       return pos;
+       } else {
+               for (pos = 0; pos < priv->firm_size; pos++) {
+                       if ((priv->firm[pos].int_freq == int_freq) &&
+                           (priv->firm[pos].type & HAS_IF))
+                               break;
+               }
+               if (pos == priv->firm_size)
+                       return -ENOENT;
+       }
+
+       p = priv->firm[pos].ptr;
+
+       if (priv->firm[pos].type & HAS_IF) {
+               if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+                       return -EINVAL;
+               p += 12 * scode;
+       } else {
+               /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
+                * has a 2-byte size header in the firmware format. */
+               if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
+                   le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+                       return -EINVAL;
+               p += 14 * scode + 2;
+       }
+
+       tuner_info("Loading SCODE for type=");
+       dump_firm_type_and_int_freq(priv->firm[pos].type,
+                                   priv->firm[pos].int_freq);
+       printk("(%x), id %016llx.\n", priv->firm[pos].type,
+              (unsigned long long)*id);
+
+       if (priv->firm_version < 0x0202)
+               rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
+       else
+               rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
+       if (rc < 0)
+               return -EIO;
+
+       rc = i2c_send(priv, p, 12);
+       if (rc < 0)
+               return -EIO;
+
+       rc = send_seq(priv, {0x00, 0x8c});
+       if (rc < 0)
+               return -EIO;
+
+       return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+                         v4l2_std_id std, __u16 int_freq)
+{
+       struct xc2028_data         *priv = fe->tuner_priv;
+       struct firmware_properties new_fw;
+       int                        rc = 0, is_retry = 0;
+       u16                        version, hwmodel;
+       v4l2_std_id                std0;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       if (!priv->firm) {
+               if (!priv->ctrl.fname) {
+                       tuner_info("xc2028/3028 firmware name not set!\n");
+                       return -EINVAL;
+               }
+
+               rc = load_all_firmwares(fe);
+               if (rc < 0)
+                       return rc;
+       }
+
+       if (priv->ctrl.mts && !(type & FM))
+               type |= MTS;
+
+retry:
+       new_fw.type = type;
+       new_fw.id = std;
+       new_fw.std_req = std;
+       new_fw.scode_table = SCODE | priv->ctrl.scode_table;
+       new_fw.scode_nr = 0;
+       new_fw.int_freq = int_freq;
+
+       tuner_dbg("checking firmware, user requested type=");
+       if (debug) {
+               dump_firm_type(new_fw.type);
+               printk("(%x), id %016llx, ", new_fw.type,
+                      (unsigned long long)new_fw.std_req);
+               if (!int_freq) {
+                       printk("scode_tbl ");
+                       dump_firm_type(priv->ctrl.scode_table);
+                       printk("(%x), ", priv->ctrl.scode_table);
+               } else
+                       printk("int_freq %d, ", new_fw.int_freq);
+               printk("scode_nr %d\n", new_fw.scode_nr);
+       }
+
+       /* No need to reload base firmware if it matches */
+       if (((BASE | new_fw.type) & BASE_TYPES) ==
+           (priv->cur_fw.type & BASE_TYPES)) {
+               tuner_dbg("BASE firmware not changed.\n");
+               goto skip_base;
+       }
+
+       /* Updating BASE - forget about all currently loaded firmware */
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+       /* Reset is needed before loading firmware */
+       rc = priv->tuner_callback(priv->video_dev,
+                                 XC2028_TUNER_RESET, 0);
+       if (rc < 0)
+               goto fail;
+
+       /* BASE firmwares are all std0 */
+       std0 = 0;
+       rc = load_firmware(fe, BASE | new_fw.type, &std0);
+       if (rc < 0) {
+               tuner_err("Error %d while loading base firmware\n",
+                         rc);
+               goto fail;
+       }
+
+       /* Load INIT1, if needed */
+       tuner_dbg("Load init1 firmware, if exists\n");
+
+       rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
+       if (rc == -ENOENT)
+               rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
+                                  &std0);
+       if (rc < 0 && rc != -ENOENT) {
+               tuner_err("Error %d while loading init1 firmware\n",
+                         rc);
+               goto fail;
+       }
+
+skip_base:
+       /*
+        * No need to reload standard specific firmware if base firmware
+        * was not reloaded and requested video standards have not changed.
+        */
+       if (priv->cur_fw.type == (BASE | new_fw.type) &&
+           priv->cur_fw.std_req == std) {
+               tuner_dbg("Std-specific firmware already loaded.\n");
+               goto skip_std_specific;
+       }
+
+       /* Reloading std-specific firmware forces a SCODE update */
+       priv->cur_fw.scode_table = 0;
+
+       rc = load_firmware(fe, new_fw.type, &new_fw.id);
+       if (rc == -ENOENT)
+               rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
+
+       if (rc < 0)
+               goto fail;
+
+skip_std_specific:
+       if (priv->cur_fw.scode_table == new_fw.scode_table &&
+           priv->cur_fw.scode_nr == new_fw.scode_nr) {
+               tuner_dbg("SCODE firmware already loaded.\n");
+               goto check_device;
+       }
+
+       /* Load SCODE firmware, if exists */
+       tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
+
+       rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+                       new_fw.int_freq, new_fw.scode_nr);
+
+check_device:
+       if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
+           xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
+               tuner_err("Unable to read tuner registers.\n");
+               goto fail;
+       }
+
+       tuner_info("Device is Xceive %d version %d.%d, "
+                  "firmware version %d.%d\n",
+                  hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+                  (version & 0xf0) >> 4, version & 0xf);
+
+       /* Check firmware version against what we downloaded. */
+       if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
+               tuner_err("Incorrect readback of firmware version.\n");
+               goto fail;
+       }
+
+       /* Check that the tuner hardware model remains consistent over time. */
+       if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
+               priv->hwmodel = hwmodel;
+               priv->hwvers  = version & 0xff00;
+       } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+                  priv->hwvers != (version & 0xff00)) {
+               tuner_err("Read invalid device hardware information - tuner "
+                         "hung?\n");
+               goto fail;
+       }
+
+       memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+       /*
+        * By setting BASE in cur_fw.type only after successfully loading all
+        * firmwares, we can:
+        * 1. Identify that BASE firmware with type=0 has been loaded;
+        * 2. Tell whether BASE firmware was just changed the next time through.
+        */
+       priv->cur_fw.type |= BASE;
+
+       return 0;
+
+fail:
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+       if (!is_retry) {
+               msleep(50);
+               is_retry = 1;
+               tuner_dbg("Retrying firmware load\n");
+               goto retry;
+       }
+
+       if (rc == -ENOENT)
+               rc = -EINVAL;
+       return rc;
+}
+
+static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       u16                 frq_lock, signal = 0;
+       int                 rc;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       mutex_lock(&priv->lock);
+
+       /* Sync Lock Indicator */
+       rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
+       if (rc < 0 || frq_lock == 0)
+               goto ret;
+
+       /* Frequency is locked. Return signal quality */
+
+       /* Get SNR of the video signal */
+       rc = xc2028_get_reg(priv, 0x0040, &signal);
+       if (rc < 0)
+               signal = -frq_lock;
+
+ret:
+       mutex_unlock(&priv->lock);
+
+       *strength = signal;
+
+       return rc;
+}
+
+#define DIV 15625
+
+static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
+                           enum tuner_mode new_mode,
+                           unsigned int type,
+                           v4l2_std_id std,
+                           u16 int_freq)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int                rc = -EINVAL;
+       unsigned char      buf[4];
+       u32                div, offset = 0;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       mutex_lock(&priv->lock);
+
+       tuner_dbg("should set frequency %d kHz\n", freq / 1000);
+
+       if (check_firmware(fe, type, std, int_freq) < 0)
+               goto ret;
+
+       /* On some cases xc2028 can disable video output, if
+        * very weak signals are received. By sending a soft
+        * reset, this is re-enabled. So, it is better to always
+        * send a soft reset before changing channels, to be sure
+        * that xc2028 will be in a safe state.
+        * Maybe this might also be needed for DTV.
+        */
+       if (new_mode == T_ANALOG_TV) {
+               rc = send_seq(priv, {0x00, 0x00});
+       } else if (priv->cur_fw.type & ATSC) {
+               offset = 1750000;
+       } else {
+               offset = 2750000;
+               /*
+                * We must adjust the offset by 500kHz in two cases in order
+                * to correctly center the IF output:
+                * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
+                *    selected and a 7MHz channel is tuned;
+                * 2) When tuning a VHF channel with DTV78 firmware.
+                */
+               if (((priv->cur_fw.type & DTV7) &&
+                    (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
+                   ((priv->cur_fw.type & DTV78) && freq < 470000000))
+                       offset -= 500000;
+       }
+
+       div = (freq - offset + DIV / 2) / DIV;
+
+       /* CMD= Set frequency */
+       if (priv->firm_version < 0x0202)
+               rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
+       else
+               rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
+       if (rc < 0)
+               goto ret;
+
+       rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+       if (rc < 0)
+               goto ret;
+
+       msleep(10);
+
+       buf[0] = 0xff & (div >> 24);
+       buf[1] = 0xff & (div >> 16);
+       buf[2] = 0xff & (div >> 8);
+       buf[3] = 0xff & (div);
+
+       rc = i2c_send(priv, buf, sizeof(buf));
+       if (rc < 0)
+               goto ret;
+       msleep(100);
+
+       priv->frequency = freq;
+
+       tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
+              buf[0], buf[1], buf[2], buf[3],
+              freq / 1000000, (freq % 1000000) / 1000);
+
+       rc = 0;
+
+ret:
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
+
+static int xc2028_set_analog_freq(struct dvb_frontend *fe,
+                             struct analog_parameters *p)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       unsigned int       type=0;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       if (p->mode == V4L2_TUNER_RADIO) {
+               type |= FM;
+               if (priv->ctrl.input1)
+                       type |= INPUT1;
+               return generic_set_freq(fe, (625l * p->frequency) / 10,
+                               T_ANALOG_TV, type, 0, 0);
+       }
+
+       /* if std is not defined, choose one */
+       if (!p->std)
+               p->std = V4L2_STD_MN;
+
+       /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
+       if (!(p->std & V4L2_STD_MN))
+               type |= F8MHZ;
+
+       /* Add audio hack to std mask */
+       p->std |= parse_audio_std_option();
+
+       return generic_set_freq(fe, 62500l * p->frequency,
+                               T_ANALOG_TV, type, p->std, 0);
+}
+
+static int xc2028_set_params(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *p)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       unsigned int       type=0;
+       fe_bandwidth_t     bw = BANDWIDTH_8_MHZ;
+       u16                demod = 0;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       if (priv->ctrl.d2633)
+               type |= D2633;
+       else
+               type |= D2620;
+
+       switch(fe->ops.info.type) {
+       case FE_OFDM:
+               bw = p->u.ofdm.bandwidth;
+               break;
+       case FE_QAM:
+               tuner_info("WARN: There are some reports that "
+                          "QAM 6 MHz doesn't work.\n"
+                          "If this works for you, please report by "
+                          "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
+               bw = BANDWIDTH_6_MHZ;
+               type |= QAM;
+               break;
+       case FE_ATSC:
+               bw = BANDWIDTH_6_MHZ;
+               /* The only ATSC firmware (at least on v2.7) is D2633,
+                  so overrides ctrl->d2633 */
+               type |= ATSC| D2633;
+               type &= ~D2620;
+               break;
+       /* DVB-S is not supported */
+       default:
+               return -EINVAL;
+       }
+
+       switch (bw) {
+       case BANDWIDTH_8_MHZ:
+               if (p->frequency < 470000000)
+                       priv->ctrl.vhfbw7 = 0;
+               else
+                       priv->ctrl.uhfbw8 = 1;
+               type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
+               type |= F8MHZ;
+               break;
+       case BANDWIDTH_7_MHZ:
+               if (p->frequency < 470000000)
+                       priv->ctrl.vhfbw7 = 1;
+               else
+                       priv->ctrl.uhfbw8 = 0;
+               type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
+               type |= F8MHZ;
+               break;
+       case BANDWIDTH_6_MHZ:
+               type |= DTV6;
+               priv->ctrl.vhfbw7 = 0;
+               priv->ctrl.uhfbw8 = 0;
+               break;
+       default:
+               tuner_err("error: bandwidth not supported.\n");
+       };
+
+       /* All S-code tables need a 200kHz shift */
+       if (priv->ctrl.demod)
+               demod = priv->ctrl.demod + 200;
+
+       return generic_set_freq(fe, p->frequency,
+                               T_DIGITAL_TV, type, 0, demod);
+}
+
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int rc = 0;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       mutex_lock(&priv->lock);
+
+       if (priv->firm_version < 0x0202)
+               rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+       else
+               rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+
+       priv->cur_fw.type = 0;  /* need firmware reload */
+
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
+
+
+static int xc2028_dvb_release(struct dvb_frontend *fe)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       mutex_lock(&xc2028_list_mutex);
+
+       priv->count--;
+
+       if (!priv->count) {
+               list_del(&priv->xc2028_list);
+
+               kfree(priv->ctrl.fname);
+
+               free_firmware(priv);
+               kfree(priv);
+               fe->tuner_priv = NULL;
+       }
+
+       mutex_unlock(&xc2028_list_mutex);
+
+       return 0;
+}
+
+static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       *frequency = priv->frequency;
+
+       return 0;
+}
+
+static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       struct xc2028_ctrl *p    = priv_cfg;
+       int                 rc   = 0;
+
+       tuner_dbg("%s called\n", __FUNCTION__);
+
+       mutex_lock(&priv->lock);
+
+       kfree(priv->ctrl.fname);
+       free_firmware(priv);
+
+       memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
+       priv->ctrl.fname = NULL;
+
+       if (p->fname) {
+               priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
+               if (priv->ctrl.fname == NULL)
+                       rc = -ENOMEM;
+       }
+
+       if (priv->ctrl.max_len < 9)
+               priv->ctrl.max_len = 13;
+
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
+
+static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
+       .info = {
+                .name = "Xceive XC3028",
+                .frequency_min = 42000000,
+                .frequency_max = 864000000,
+                .frequency_step = 50000,
+                },
+
+       .set_config        = xc2028_set_config,
+       .set_analog_params = xc2028_set_analog_freq,
+       .release           = xc2028_dvb_release,
+       .get_frequency     = xc2028_get_frequency,
+       .get_rf_strength   = xc2028_signal,
+       .set_params        = xc2028_set_params,
+       .sleep             = xc2028_sleep,
+
+};
+
+struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+                                  struct xc2028_config *cfg)
+{
+       struct xc2028_data *priv;
+       void               *video_dev;
+
+       if (debug)
+               printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
+
+       if (NULL == cfg || NULL == cfg->video_dev)
+               return NULL;
+
+       if (!fe) {
+               printk(KERN_ERR PREFIX ": No frontend!\n");
+               return NULL;
+       }
+
+       video_dev = cfg->video_dev;
+
+       mutex_lock(&xc2028_list_mutex);
+
+       list_for_each_entry(priv, &xc2028_list, xc2028_list) {
+               if (priv->video_dev == cfg->video_dev) {
+                       video_dev = NULL;
+                       break;
+               }
+       }
+
+       if (video_dev) {
+               priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+               if (priv == NULL) {
+                       mutex_unlock(&xc2028_list_mutex);
+                       return NULL;
+               }
+
+               priv->i2c_props.addr = cfg->i2c_addr;
+               priv->i2c_props.adap = cfg->i2c_adap;
+               priv->video_dev = video_dev;
+               priv->tuner_callback = cfg->callback;
+               priv->ctrl.max_len = 13;
+
+               mutex_init(&priv->lock);
+
+               list_add_tail(&priv->xc2028_list, &xc2028_list);
+       }
+
+       fe->tuner_priv = priv;
+       priv->count++;
+
+       memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
+              sizeof(xc2028_dvb_tuner_ops));
+
+       tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
+
+       if (cfg->ctrl)
+               xc2028_set_config(fe, cfg->ctrl);
+
+       mutex_unlock(&xc2028_list_mutex);
+
+       return fe;
+}
+
+EXPORT_SYMBOL(xc2028_attach);
+
+MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
+MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
new file mode 100644 (file)
index 0000000..3eb8420
--- /dev/null
@@ -0,0 +1,63 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#ifndef __TUNER_XC2028_H__
+#define __TUNER_XC2028_H__
+
+#include "dvb_frontend.h"
+
+#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
+
+/*      Dmoduler               IF (kHz) */
+#define        XC3028_FE_DEFAULT       0
+#define XC3028_FE_LG60         6000
+#define        XC3028_FE_ATI638        6380
+#define        XC3028_FE_OREN538       5380
+#define        XC3028_FE_OREN36        3600
+#define        XC3028_FE_TOYOTA388     3880
+#define        XC3028_FE_TOYOTA794     7940
+#define        XC3028_FE_DIBCOM52      5200
+#define        XC3028_FE_ZARLINK456    4560
+#define        XC3028_FE_CHINA         5200
+
+struct xc2028_ctrl {
+       char                    *fname;
+       int                     max_len;
+       unsigned int            scode_table;
+       unsigned int            mts   :1;
+       unsigned int            d2633 :1;
+       unsigned int            input1:1;
+       unsigned int            vhfbw7:1;
+       unsigned int            uhfbw8:1;
+       unsigned int            demod;
+};
+
+struct xc2028_config {
+       struct i2c_adapter *i2c_adap;
+       u8                 i2c_addr;
+       void               *video_dev;
+       struct xc2028_ctrl *ctrl;
+       int                (*callback) (void *dev, int command, int arg);
+};
+
+/* xc2028 commands for callback */
+#define XC2028_TUNER_RESET     0
+#define XC2028_RESET_CLK       1
+
+#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+                                         struct xc2028_config *cfg);
+#else
+static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+                                                struct xc2028_config *cfg)
+{
+       printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+              __FUNCTION__);
+       return NULL;
+}
+#endif
+
+#endif /* __TUNER_XC2028_H__ */
index a19cdcc17ef7b9ded8ea55010401b6618356da7a..a75560540e798457e32f537f32a46692f0aa930f 100644 (file)
@@ -31,6 +31,7 @@
 #include <media/tvaudio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 #include <media/i2c-addr.h>
 
@@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[];
 
 /* current state of the chip */
 struct CHIPSTATE {
-       struct i2c_client c;
+       struct i2c_client *c;
 
        /* index into CHIPDESC array */
        int type;
@@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = {
        I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-
 /* ---------------------------------------------------------------------- */
 /* i2c I/O functions                                                      */
 
@@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
        unsigned char buffer[2];
 
        if (-1 == subaddr) {
-               v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n",
-                       chip->c.name, val);
+               v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
+                       chip->c->name, val);
                chip->shadow.bytes[1] = val;
                buffer[0] = val;
-               if (1 != i2c_master_send(&chip->c,buffer,1)) {
-                       v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
-                               chip->c.name, val);
+               if (1 != i2c_master_send(chip->c,buffer,1)) {
+                       v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n",
+                               chip->c->name, val);
                        return -1;
                }
        } else {
-               v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n",
-                       chip->c.name, subaddr, val);
+               v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
+                       chip->c->name, subaddr, val);
                chip->shadow.bytes[subaddr+1] = val;
                buffer[0] = subaddr;
                buffer[1] = val;
-               if (2 != i2c_master_send(&chip->c,buffer,2)) {
-                       v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
-                       chip->c.name, subaddr, val);
+               if (2 != i2c_master_send(chip->c,buffer,2)) {
+                       v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n",
+                       chip->c->name, subaddr, val);
                        return -1;
                }
        }
@@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip)
 {
        unsigned char buffer;
 
-       if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
-               v4l_warn(&chip->c, "%s: I/O error (read)\n",
-               chip->c.name);
+       if (1 != i2c_master_recv(chip->c,&buffer,1)) {
+               v4l_warn(chip->c, "%s: I/O error (read)\n",
+               chip->c->name);
                return -1;
        }
-       v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
+       v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer);
        return buffer;
 }
 
@@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
        unsigned char write[1];
        unsigned char read[1];
        struct i2c_msg msgs[2] = {
-               { chip->c.addr, 0,        1, write },
-               { chip->c.addr, I2C_M_RD, 1, read  }
+               { chip->c->addr, 0,        1, write },
+               { chip->c->addr, I2C_M_RD, 1, read  }
        };
        write[0] = subaddr;
 
-       if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
-               v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
+       if (2 != i2c_transfer(chip->c->adapter,msgs,2)) {
+               v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name);
                return -1;
        }
-       v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
-               chip->c.name, subaddr,read[0]);
+       v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n",
+               chip->c->name, subaddr,read[0]);
        return read[0];
 }
 
@@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
                return 0;
 
        /* update our shadow register set; print bytes if (debug > 0) */
-       v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
-               chip->c.name, name,cmd->bytes[0]);
+       v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
+               chip->c->name, name,cmd->bytes[0]);
        for (i = 1; i < cmd->count; i++) {
                if (debug)
                        printk(" 0x%x",cmd->bytes[i]);
@@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
                printk("\n");
 
        /* send data to the chip */
-       if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
-               v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
+       if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) {
+               v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name);
                return -1;
        }
        return 0;
@@ -269,7 +266,7 @@ static int chip_thread(void *data)
        struct CHIPSTATE *chip = data;
        struct CHIPDESC  *desc = chiplist + chip->type;
 
-       v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
+       v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
        set_freezable();
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
@@ -279,7 +276,7 @@ static int chip_thread(void *data)
                try_to_freeze();
                if (kthread_should_stop())
                        break;
-               v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
+               v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
 
                /* don't do anything for radio or if mode != auto */
                if (chip->radio || chip->mode != 0)
@@ -292,7 +289,7 @@ static int chip_thread(void *data)
                mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
        }
 
-       v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
+       v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
        return 0;
 }
 
@@ -304,17 +301,19 @@ static void generic_checkmode(struct CHIPSTATE *chip)
        if (mode == chip->prevmode)
        return;
 
-       v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name);
+       v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name);
        chip->prevmode = mode;
 
-       if (mode & VIDEO_SOUND_STEREO)
-               desc->setmode(chip,VIDEO_SOUND_STEREO);
-       else if (mode & VIDEO_SOUND_LANG1)
-               desc->setmode(chip,VIDEO_SOUND_LANG1);
-       else if (mode & VIDEO_SOUND_LANG2)
-               desc->setmode(chip,VIDEO_SOUND_LANG2);
+       if (mode & V4L2_TUNER_MODE_STEREO)
+               desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
+       if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
+               desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
+       else if (mode & V4L2_TUNER_MODE_LANG1)
+               desc->setmode(chip,V4L2_TUNER_MODE_LANG1);
+       else if (mode & V4L2_TUNER_MODE_LANG2)
+               desc->setmode(chip,V4L2_TUNER_MODE_LANG2);
        else
-               desc->setmode(chip,VIDEO_SOUND_MONO);
+               desc->setmode(chip,V4L2_TUNER_MODE_MONO);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -345,13 +344,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
        int val, mode;
 
        val = chip_read(chip);
-       mode = VIDEO_SOUND_MONO;
+       mode = V4L2_TUNER_MODE_MONO;
        if (val & TDA9840_DS_DUAL)
-               mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+               mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
        if (val & TDA9840_ST_STEREO)
-               mode |= VIDEO_SOUND_STEREO;
+               mode |= V4L2_TUNER_MODE_STEREO;
 
-       v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
+       v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
@@ -362,16 +361,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
        int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
 
        switch (mode) {
-       case VIDEO_SOUND_MONO:
+       case V4L2_TUNER_MODE_MONO:
                t |= TDA9840_MONO;
                break;
-       case VIDEO_SOUND_STEREO:
+       case V4L2_TUNER_MODE_STEREO:
                t |= TDA9840_STEREO;
                break;
-       case VIDEO_SOUND_LANG1:
+       case V4L2_TUNER_MODE_LANG1:
                t |= TDA9840_DUALA;
                break;
-       case VIDEO_SOUND_LANG2:
+       case V4L2_TUNER_MODE_LANG2:
                t |= TDA9840_DUALB;
                break;
        default:
@@ -502,7 +501,7 @@ static int  tda985x_getmode(struct CHIPSTATE *chip)
                chip_read(chip)) >> 4;
        /* Add mono mode regardless of SAP and stereo */
        /* Allows forced mono */
-       return mode | VIDEO_SOUND_MONO;
+       return mode | V4L2_TUNER_MODE_MONO;
 }
 
 static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
@@ -511,13 +510,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
        int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
 
        switch (mode) {
-       case VIDEO_SOUND_MONO:
+       case V4L2_TUNER_MODE_MONO:
                c6 |= TDA985x_MONO;
                break;
-       case VIDEO_SOUND_STEREO:
+       case V4L2_TUNER_MODE_STEREO:
                c6 |= TDA985x_STEREO;
                break;
-       case VIDEO_SOUND_LANG1:
+       case V4L2_TUNER_MODE_LANG1:
                c6 |= TDA985x_SAP;
                break;
        default:
@@ -650,12 +649,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
        int val,mode;
 
        val = chip_read(chip);
-       mode = VIDEO_SOUND_MONO;
+       mode = V4L2_TUNER_MODE_MONO;
        if (val & TDA9873_STEREO)
-               mode |= VIDEO_SOUND_STEREO;
+               mode |= V4L2_TUNER_MODE_STEREO;
        if (val & TDA9873_DUAL)
-               mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
+               mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
@@ -666,24 +665,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        /*      int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
        if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-               v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n");
+               v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n");
                return;
        }
 
-       v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-       v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
+       v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+       v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
 
        switch (mode) {
-       case VIDEO_SOUND_MONO:
+       case V4L2_TUNER_MODE_MONO:
                sw_data |= TDA9873_TR_MONO;
                break;
-       case VIDEO_SOUND_STEREO:
+       case V4L2_TUNER_MODE_STEREO:
                sw_data |= TDA9873_TR_STEREO;
                break;
-       case VIDEO_SOUND_LANG1:
+       case V4L2_TUNER_MODE_LANG1:
                sw_data |= TDA9873_TR_DUALA;
                break;
-       case VIDEO_SOUND_LANG2:
+       case V4L2_TUNER_MODE_LANG2:
                sw_data |= TDA9873_TR_DUALB;
                break;
        default:
@@ -692,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        }
 
        chip_write(chip, TDA9873_SW, sw_data);
-       v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
+       v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
                mode, sw_data);
 }
 
@@ -831,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
                chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
                chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
        }
-       v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
+       v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n",
                tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
        return 1;
 }
@@ -841,7 +840,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
        int dsr,nsr,mode;
        int necr; /* just for debugging */
 
-       mode = VIDEO_SOUND_MONO;
+       mode = V4L2_TUNER_MODE_MONO;
 
        if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
                return mode;
@@ -860,21 +859,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
                 * that sound has (temporarily) switched from NICAM to
                 * mono FM (or AM) on 1st sound carrier due to high NICAM bit
                 * error count. So in fact there is no stereo in this case :-(
-                * But changing the mode to VIDEO_SOUND_MONO would switch
+                * But changing the mode to V4L2_TUNER_MODE_MONO would switch
                 * external 4052 multiplexer in audio_hook().
                 */
                if(nsr & 0x02) /* NSR.S/MB=1 */
-                       mode |= VIDEO_SOUND_STEREO;
+                       mode |= V4L2_TUNER_MODE_STEREO;
                if(nsr & 0x01) /* NSR.D/SB=1 */
-                       mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+                       mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
        } else {
                if(dsr & 0x02) /* DSR.IDSTE=1 */
-                       mode |= VIDEO_SOUND_STEREO;
+                       mode |= V4L2_TUNER_MODE_STEREO;
                if(dsr & 0x04) /* DSR.IDDUA=1 */
-                       mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+                       mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
        }
 
-       v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+       v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
                 dsr, nsr, necr, mode);
        return mode;
 }
@@ -902,14 +901,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                int mdacosr = (tda9874a_mode) ? 0x82:0x80;
 
                switch(mode) {
-               case VIDEO_SOUND_MONO:
-               case VIDEO_SOUND_STEREO:
+               case V4L2_TUNER_MODE_MONO:
+               case V4L2_TUNER_MODE_STEREO:
                        break;
-               case VIDEO_SOUND_LANG1:
+               case V4L2_TUNER_MODE_LANG1:
                        aosr = 0x80; /* auto-select, dual A/A */
                        mdacosr = (tda9874a_mode) ? 0x82:0x80;
                        break;
-               case VIDEO_SOUND_LANG2:
+               case V4L2_TUNER_MODE_LANG2:
                        aosr = 0xa0; /* auto-select, dual B/B */
                        mdacosr = (tda9874a_mode) ? 0x83:0x81;
                        break;
@@ -920,18 +919,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                chip_write(chip, TDA9874A_AOSR, aosr);
                chip_write(chip, TDA9874A_MDACOSR, mdacosr);
 
-               v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+               v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
                        mode, aosr, mdacosr);
 
        } else { /* dic == 0x07 */
                int fmmr,aosr;
 
                switch(mode) {
-               case VIDEO_SOUND_MONO:
+               case V4L2_TUNER_MODE_MONO:
                        fmmr = 0x00; /* mono */
                        aosr = 0x10; /* A/A */
                        break;
-               case VIDEO_SOUND_STEREO:
+               case V4L2_TUNER_MODE_STEREO:
                        if(tda9874a_mode) {
                                fmmr = 0x00;
                                aosr = 0x00; /* handled by NICAM auto-mute */
@@ -940,11 +939,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                                aosr = 0x00;
                        }
                        break;
-               case VIDEO_SOUND_LANG1:
+               case V4L2_TUNER_MODE_LANG1:
                        fmmr = 0x02; /* dual */
                        aosr = 0x10; /* dual A/A */
                        break;
-               case VIDEO_SOUND_LANG2:
+               case V4L2_TUNER_MODE_LANG2:
                        fmmr = 0x02; /* dual */
                        aosr = 0x20; /* dual B/B */
                        break;
@@ -955,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                chip_write(chip, TDA9874A_FMMR, fmmr);
                chip_write(chip, TDA9874A_AOSR, aosr);
 
-               v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+               v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
                        mode, fmmr, aosr);
        }
 }
@@ -969,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
        if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
                return 0;
 
-       v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+       v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
 
        if((dic == 0x11)||(dic == 0x07)) {
-               v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+               v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
                tda9874a_dic = dic;     /* remember device id. */
                return 1;
        }
@@ -1095,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip)
        int inputmap[4] = { /* tuner    */ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
                            /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
 
-       if (chip->c.adapter->id == I2C_HW_B_RIVA) {
+       if (chip->c->adapter->id == I2C_HW_B_RIVA) {
                memcpy (desc->inputmap, inputmap, sizeof (inputmap));
        }
        return 0;
@@ -1105,20 +1104,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 {
        int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
 
-       if (mode & VIDEO_SOUND_LANG1) {
+       if (mode & V4L2_TUNER_MODE_LANG1) {
                s1 |= TDA8425_S1_ML_SOUND_A;
                s1 |= TDA8425_S1_STEREO_PSEUDO;
 
-       } else if (mode & VIDEO_SOUND_LANG2) {
+       } else if (mode & V4L2_TUNER_MODE_LANG2) {
                s1 |= TDA8425_S1_ML_SOUND_B;
                s1 |= TDA8425_S1_STEREO_PSEUDO;
 
        } else {
                s1 |= TDA8425_S1_ML_STEREO;
 
-               if (mode & VIDEO_SOUND_MONO)
+               if (mode & V4L2_TUNER_MODE_MONO)
                        s1 |= TDA8425_S1_STEREO_MONO;
-               if (mode & VIDEO_SOUND_STEREO)
+               if (mode & V4L2_TUNER_MODE_STEREO)
                        s1 |= TDA8425_S1_STEREO_SPATIAL;
        }
        chip_write(chip,TDA8425_S1,s1);
@@ -1177,13 +1176,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
        int val, mode;
 
        val = chip_read(chip);
-       mode = VIDEO_SOUND_MONO;
+       mode = V4L2_TUNER_MODE_MONO;
        if (val & TA8874Z_B1){
-               mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+               mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
        }else if (!(val & TA8874Z_B0)){
-               mode |= VIDEO_SOUND_STEREO;
+               mode |= V4L2_TUNER_MODE_STEREO;
        }
-       /* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+       /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
        return mode;
 }
 
@@ -1196,19 +1195,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 {
        int update = 1;
        audiocmd *t = NULL;
-       v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
+       v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
 
        switch(mode){
-       case VIDEO_SOUND_MONO:
+       case V4L2_TUNER_MODE_MONO:
                t = &ta8874z_mono;
                break;
-       case VIDEO_SOUND_STEREO:
+       case V4L2_TUNER_MODE_STEREO:
                t = &ta8874z_stereo;
                break;
-       case VIDEO_SOUND_LANG1:
+       case V4L2_TUNER_MODE_LANG1:
                t = &ta8874z_main;
                break;
-       case VIDEO_SOUND_LANG2:
+       case V4L2_TUNER_MODE_LANG2:
                t = &ta8874z_sub;
                break;
        default:
@@ -1462,51 +1461,55 @@ static struct CHIPDESC chiplist[] = {
 /* ---------------------------------------------------------------------- */
 /* i2c registration                                                       */
 
-static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
+static int chip_probe(struct i2c_client *client)
 {
        struct CHIPSTATE *chip;
        struct CHIPDESC  *desc;
 
+       if (debug) {
+               printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+               printk(KERN_INFO "tvaudio: known chips: ");
+               for (desc = chiplist; desc->name != NULL; desc++)
+                       printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
+               printk("\n");
+       }
+
        chip = kzalloc(sizeof(*chip),GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
-       memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
-       chip->c.adapter = adap;
-       chip->c.addr = addr;
-       i2c_set_clientdata(&chip->c, chip);
+       chip->c = client;
+       i2c_set_clientdata(client, chip);
 
        /* find description for the chip */
-       v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1);
+       v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);
        for (desc = chiplist; desc->name != NULL; desc++) {
                if (0 == *(desc->insmodopt))
                        continue;
-               if (addr < desc->addr_lo ||
-                   addr > desc->addr_hi)
+               if (client->addr < desc->addr_lo ||
+                   client->addr > desc->addr_hi)
                        continue;
                if (desc->checkit && !desc->checkit(chip))
                        continue;
                break;
        }
        if (desc->name == NULL) {
-               v4l_dbg(1, debug, &chip->c, "no matching chip description found\n");
+               v4l_dbg(1, debug, client, "no matching chip description found\n");
                return -EIO;
        }
-       v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
+       v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
        if (desc->flags) {
-               v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n",
+               v4l_dbg(1, debug, client, "matches:%s%s%s.\n",
                        (desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
                        (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
                        (desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
        }
 
        /* fill required data structures */
-       strcpy(chip->c.name, desc->name);
+       strcpy(client->name, desc->name);
        chip->type = desc-chiplist;
        chip->shadow.count = desc->registers+1;
        chip->prevmode = -1;
        chip->audmode = V4L2_TUNER_MODE_LANG1;
-       /* register */
-       i2c_attach_client(&chip->c);
 
        /* initialization  */
        if (desc->initialize != NULL)
@@ -1533,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
                init_timer(&chip->wt);
                chip->wt.function = chip_thread_wake;
                chip->wt.data     = (unsigned long)chip;
-               chip->thread = kthread_run(chip_thread, chip, chip->c.name);
+               chip->thread = kthread_run(chip_thread, chip, chip->c->name);
                if (IS_ERR(chip->thread)) {
-                       v4l_warn(&chip->c, "%s: failed to create kthread\n",
-                              chip->c.name);
+                       v4l_warn(chip->c, "%s: failed to create kthread\n",
+                              chip->c->name);
                        chip->thread = NULL;
                }
        }
        return 0;
 }
 
-static int chip_probe(struct i2c_adapter *adap)
-{
-       /* don't attach on saa7146 based cards,
-          because dedicated drivers are used */
-       if ((adap->id == I2C_HW_SAA7146))
-               return 0;
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, chip_attach);
-       return 0;
-}
-
-static int chip_detach(struct i2c_client *client)
+static int chip_remove(struct i2c_client *client)
 {
        struct CHIPSTATE *chip = i2c_get_clientdata(client);
 
@@ -1565,12 +1557,52 @@ static int chip_detach(struct i2c_client *client)
                chip->thread = NULL;
        }
 
-       i2c_detach_client(&chip->c);
        kfree(chip);
        return 0;
 }
 
-static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
+static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
+                           struct v4l2_control *ctrl)
+{
+       struct CHIPDESC *desc = chiplist + chip->type;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value=chip->muted;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               if (!desc->flags & CHIP_HAS_VOLUME)
+                       break;
+               ctrl->value = max(chip->left,chip->right);
+               return 0;
+       case V4L2_CID_AUDIO_BALANCE:
+       {
+               int volume;
+               if (!desc->flags & CHIP_HAS_VOLUME)
+                       break;
+               volume = max(chip->left,chip->right);
+               if (volume)
+                       ctrl->value=(32768*min(chip->left,chip->right))/volume;
+               else
+                       ctrl->value=32768;
+               return 0;
+       }
+       case V4L2_CID_AUDIO_BASS:
+               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                       break;
+               ctrl->value = chip->bass;
+               return 0;
+       case V4L2_CID_AUDIO_TREBLE:
+               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                       return -EINVAL;
+               ctrl->value = chip->treble;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
+                           struct v4l2_control *ctrl)
 {
        struct CHIPDESC *desc = chiplist + chip->type;
 
@@ -1584,11 +1616,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
                else
                        chip_write_masked(chip,desc->inputreg,
                                        desc->inputmap[chip->input],desc->inputmask);
-               break;
-       default:
-               return -EINVAL;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+       {
+               int volume,balance;
+
+               if (!desc->flags & CHIP_HAS_VOLUME)
+                       break;
+
+               volume = max(chip->left,chip->right);
+               if (volume)
+                       balance=(32768*min(chip->left,chip->right))/volume;
+               else
+                       balance=32768;
+
+               volume=ctrl->value;
+               chip->left = (min(65536 - balance,32768) * volume) / 32768;
+               chip->right = (min(balance,volume *(__u16)32768)) / 32768;
+
+               chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+               chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+
+               return 0;
        }
-       return 0;
+       case V4L2_CID_AUDIO_BALANCE:
+       {
+               int volume, balance;
+               if (!desc->flags & CHIP_HAS_VOLUME)
+                       break;
+
+               volume = max(chip->left,chip->right);
+               balance = ctrl->value;
+
+               chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+               chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+
+               return 0;
+       }
+       case V4L2_CID_AUDIO_BASS:
+               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                       break;
+               chip->bass = ctrl->value;
+               chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+
+               return 0;
+       case V4L2_CID_AUDIO_TREBLE:
+               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                       return -EINVAL;
+
+               chip->treble = ctrl->value;
+               chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+
+               return 0;
+       }
+       return -EINVAL;
 }
 
 
@@ -1601,7 +1682,7 @@ static int chip_command(struct i2c_client *client,
        struct CHIPSTATE *chip = i2c_get_clientdata(client);
        struct CHIPDESC  *desc = chiplist + chip->type;
 
-       v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
+       v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);
 
        switch (cmd) {
        case AUDC_SET_RADIO:
@@ -1609,67 +1690,36 @@ static int chip_command(struct i2c_client *client,
                chip->watch_stereo = 0;
                /* del_timer(&chip->wt); */
                break;
-
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
        kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               if (desc->flags & CHIP_HAS_VOLUME) {
-                       va->flags  |= VIDEO_AUDIO_VOLUME;
-                       va->volume  = max(chip->left,chip->right);
-                       if (va->volume)
-                               va->balance = (32768*min(chip->left,chip->right))/
-                                       va->volume;
-                       else
-                               va->balance = 32768;
-               }
-               if (desc->flags & CHIP_HAS_BASSTREBLE) {
-                       va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
-                       va->bass   = chip->bass;
-                       va->treble = chip->treble;
-               }
-               if (!chip->radio) {
-                       if (desc->getmode)
-                               va->mode = desc->getmode(chip);
-                       else
-                               va->mode = VIDEO_SOUND_MONO;
-               }
-               break;
-       }
-
-       case VIDIOCSAUDIO:
+       case VIDIOC_QUERYCTRL:
        {
-               struct video_audio *va = arg;
-
-               if (desc->flags & CHIP_HAS_VOLUME) {
-                       chip->left = (min(65536 - va->balance,32768) *
-                               va->volume) / 32768;
-                       chip->right = (min(va->balance,(__u16)32768) *
-                               va->volume) / 32768;
-                       chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-                       chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
-               }
-               if (desc->flags & CHIP_HAS_BASSTREBLE) {
-                       chip->bass = va->bass;
-                       chip->treble = va->treble;
-                       chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
-                       chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
-               }
-               if (desc->setmode && va->mode) {
-                       chip->watch_stereo = 0;
-                       /* del_timer(&chip->wt); */
-                       chip->mode = va->mode;
-                       desc->setmode(chip,va->mode);
+               struct v4l2_queryctrl *qc = arg;
+
+               switch (qc->id) {
+                       case V4L2_CID_AUDIO_MUTE:
+                               break;
+                       case V4L2_CID_AUDIO_VOLUME:
+                       case V4L2_CID_AUDIO_BALANCE:
+                               if (!desc->flags & CHIP_HAS_VOLUME)
+                                       return -EINVAL;
+                               break;
+                       case V4L2_CID_AUDIO_BASS:
+                       case V4L2_CID_AUDIO_TREBLE:
+                               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                                       return -EINVAL;
+                               break;
+                       default:
+                               return -EINVAL;
                }
-               break;
+               return v4l2_ctrl_query_fill_std(qc);
        }
-
        case VIDIOC_S_CTRL:
                return tvaudio_set_ctrl(chip, arg);
 
+       case VIDIOC_G_CTRL:
+               return tvaudio_get_ctrl(chip, arg);
        case VIDIOC_INT_G_AUDIO_ROUTING:
        {
                struct v4l2_routing *rt = arg;
@@ -1678,7 +1728,6 @@ static int chip_command(struct i2c_client *client,
                rt->output = 0;
                break;
        }
-
        case VIDIOC_INT_S_AUDIO_ROUTING:
        {
                struct v4l2_routing *rt = arg;
@@ -1693,7 +1742,6 @@ static int chip_command(struct i2c_client *client,
                                desc->inputmap[chip->input], desc->inputmask);
                break;
        }
-
        case VIDIOC_S_TUNER:
        {
                struct v4l2_tuner *vt = arg;
@@ -1703,17 +1751,13 @@ static int chip_command(struct i2c_client *client,
                        break;
                switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
-                       mode = VIDEO_SOUND_MONO;
-                       break;
                case V4L2_TUNER_MODE_STEREO:
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       mode = VIDEO_SOUND_STEREO;
-                       break;
                case V4L2_TUNER_MODE_LANG1:
-                       mode = VIDEO_SOUND_LANG1;
-                       break;
                case V4L2_TUNER_MODE_LANG2:
-                       mode = VIDEO_SOUND_LANG2;
+                       mode = vt->audmode;
+                       break;
+               case V4L2_TUNER_MODE_LANG1_LANG2:
+                       mode = V4L2_TUNER_MODE_STEREO;
                        break;
                default:
                        return -EINVAL;
@@ -1728,11 +1772,10 @@ static int chip_command(struct i2c_client *client,
                }
                break;
        }
-
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = arg;
-               int mode = VIDEO_SOUND_MONO;
+               int mode = V4L2_TUNER_MODE_MONO;
 
                if (chip->radio)
                        break;
@@ -1744,30 +1787,26 @@ static int chip_command(struct i2c_client *client,
                if (desc->getmode)
                        mode = desc->getmode(chip);
 
-               if (mode & VIDEO_SOUND_MONO)
+               if (mode & V4L2_TUNER_MODE_MONO)
                        vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
-               if (mode & VIDEO_SOUND_STEREO)
+               if (mode & V4L2_TUNER_MODE_STEREO)
                        vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
                /* Note: for SAP it should be mono/lang2 or stereo/lang2.
                   When this module is converted fully to v4l2, then this
                   should change for those chips that can detect SAP. */
-               if (mode & VIDEO_SOUND_LANG1)
+               if (mode & V4L2_TUNER_MODE_LANG1)
                        vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
                                         V4L2_TUNER_SUB_LANG2;
                break;
        }
-
-       case VIDIOCSCHAN:
        case VIDIOC_S_STD:
                chip->radio = 0;
                break;
-
-       case VIDIOCSFREQ:
        case VIDIOC_S_FREQUENCY:
                chip->mode = 0; /* automatic */
                if (desc->checkmode) {
-                       desc->setmode(chip,VIDEO_SOUND_MONO);
-                       if (chip->prevmode != VIDEO_SOUND_MONO)
+                       desc->setmode(chip,V4L2_TUNER_MODE_MONO);
+                       if (chip->prevmode != V4L2_TUNER_MODE_MONO)
                                chip->prevmode = -1; /* reset previous mode */
                        mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
                        /* the thread will call checkmode() later */
@@ -1780,44 +1819,25 @@ static int chip_command(struct i2c_client *client,
        return 0;
 }
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name    = "tvaudio",
-       },
-       .id              = I2C_DRIVERID_TVAUDIO,
-       .attach_adapter  = chip_probe,
-       .detach_client   = chip_detach,
-       .command         = chip_command,
-};
-
-static struct i2c_client client_template =
+static int chip_legacy_probe(struct i2c_adapter *adap)
 {
-       .name       = "(unset)",
-       .driver     = &driver,
-};
-
-static int __init audiochip_init_module(void)
-{
-       struct CHIPDESC  *desc;
-
-       if (debug) {
-               printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
-               printk(KERN_INFO "tvaudio: known chips: ");
-               for (desc = chiplist; desc->name != NULL; desc++)
-                       printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
-               printk("\n");
-       }
-
-       return i2c_add_driver(&driver);
-}
-
-static void __exit audiochip_cleanup_module(void)
-{
-       i2c_del_driver(&driver);
+       /* don't attach on saa7146 based cards,
+          because dedicated drivers are used */
+       if ((adap->id == I2C_HW_SAA7146))
+               return 0;
+       if (adap->class & I2C_CLASS_TV_ANALOG)
+               return 1;
+       return 0;
 }
 
-module_init(audiochip_init_module);
-module_exit(audiochip_cleanup_module);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tvaudio",
+       .driverid = I2C_DRIVERID_TVAUDIO,
+       .command = chip_command,
+       .probe = chip_probe,
+       .remove = chip_remove,
+       .legacy_probe = chip_legacy_probe,
+};
 
 /*
  * Local variables:
index 4b2c4034f5b375be96b3d348f0eb7f4e1b94cfae..0b8fbad3c7212aa3e849fffb9d020f730810d96e 100644 (file)
@@ -46,11 +46,12 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
 MODULE_AUTHOR("John Klar");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
+#define STRM(array, i) \
+       (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown")
 
 #define tveeprom_info(fmt, arg...) \
        v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
@@ -58,7 +59,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
        v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
 #define tveeprom_dbg(fmt, arg...) do { \
        if (debug) \
-               v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
+               v4l_printk(KERN_DEBUG, "tveeprom", \
+                               c->adapter, c->addr, fmt , ## arg); \
        } while (0)
 
 /*
@@ -94,170 +96,172 @@ static struct HAUPPAUGE_TUNER
 hauppauge_tuner[] =
 {
        /* 0-9 */
-       { TUNER_ABSENT,        "None" },
-       { TUNER_ABSENT,        "External" },
-       { TUNER_ABSENT,        "Unspecified" },
-       { TUNER_PHILIPS_PAL,   "Philips FI1216" },
-       { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
-       { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
-       { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
-       { TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
-       { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
-       { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
+       { TUNER_ABSENT,                 "None" },
+       { TUNER_ABSENT,                 "External" },
+       { TUNER_ABSENT,                 "Unspecified" },
+       { TUNER_PHILIPS_PAL,            "Philips FI1216" },
+       { TUNER_PHILIPS_SECAM,          "Philips FI1216MF" },
+       { TUNER_PHILIPS_NTSC,           "Philips FI1236" },
+       { TUNER_PHILIPS_PAL_I,          "Philips FI1246" },
+       { TUNER_PHILIPS_PAL_DK,         "Philips FI1256" },
+       { TUNER_PHILIPS_PAL,            "Philips FI1216 MK2" },
+       { TUNER_PHILIPS_SECAM,          "Philips FI1216MF MK2" },
        /* 10-19 */
-       { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
-       { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
-       { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
-       { TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
-       { TUNER_TEMIC_PAL,     "Temic 4002FH5" },
-       { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
-       { TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
-       { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
-       { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
-       { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
+       { TUNER_PHILIPS_NTSC,           "Philips FI1236 MK2" },
+       { TUNER_PHILIPS_PAL_I,          "Philips FI1246 MK2" },
+       { TUNER_PHILIPS_PAL_DK,         "Philips FI1256 MK2" },
+       { TUNER_TEMIC_NTSC,             "Temic 4032FY5" },
+       { TUNER_TEMIC_PAL,              "Temic 4002FH5" },
+       { TUNER_TEMIC_PAL_I,            "Temic 4062FY5" },
+       { TUNER_PHILIPS_PAL,            "Philips FR1216 MK2" },
+       { TUNER_PHILIPS_SECAM,          "Philips FR1216MF MK2" },
+       { TUNER_PHILIPS_NTSC,           "Philips FR1236 MK2" },
+       { TUNER_PHILIPS_PAL_I,          "Philips FR1246 MK2" },
        /* 20-29 */
-       { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
-       { TUNER_PHILIPS_PAL,   "Philips FM1216" },
-       { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
-       { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
-       { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
-       { TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
-       { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
-       { TUNER_ABSENT,        "Samsung TCPN9082D" },
-       { TUNER_ABSENT,        "Samsung TCPM9092P" },
-       { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
+       { TUNER_PHILIPS_PAL_DK,         "Philips FR1256 MK2" },
+       { TUNER_PHILIPS_PAL,            "Philips FM1216" },
+       { TUNER_PHILIPS_SECAM,          "Philips FM1216MF" },
+       { TUNER_PHILIPS_NTSC,           "Philips FM1236" },
+       { TUNER_PHILIPS_PAL_I,          "Philips FM1246" },
+       { TUNER_PHILIPS_PAL_DK,         "Philips FM1256" },
+       { TUNER_TEMIC_4036FY5_NTSC,     "Temic 4036FY5" },
+       { TUNER_ABSENT,                 "Samsung TCPN9082D" },
+       { TUNER_ABSENT,                 "Samsung TCPM9092P" },
+       { TUNER_TEMIC_4006FH5_PAL,      "Temic 4006FH5" },
        /* 30-39 */
-       { TUNER_ABSENT,        "Samsung TCPN9085D" },
-       { TUNER_ABSENT,        "Samsung TCPB9085P" },
-       { TUNER_ABSENT,        "Samsung TCPL9091P" },
-       { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
-       { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
-       { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
-       { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
-       { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
-       { TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
-       { TUNER_ABSENT,        "Philips FI1256MP" },
+       { TUNER_ABSENT,                 "Samsung TCPN9085D" },
+       { TUNER_ABSENT,                 "Samsung TCPB9085P" },
+       { TUNER_ABSENT,                 "Samsung TCPL9091P" },
+       { TUNER_TEMIC_4039FR5_NTSC,     "Temic 4039FR5" },
+       { TUNER_PHILIPS_FQ1216ME,       "Philips FQ1216 ME" },
+       { TUNER_TEMIC_4066FY5_PAL_I,    "Temic 4066FY5" },
+       { TUNER_PHILIPS_NTSC,           "Philips TD1536" },
+       { TUNER_PHILIPS_NTSC,           "Philips TD1536D" },
+       { TUNER_PHILIPS_NTSC,           "Philips FMR1236" }, /* mono radio */
+       { TUNER_ABSENT,                 "Philips FI1256MP" },
        /* 40-49 */
-       { TUNER_ABSENT,        "Samsung TCPQ9091P" },
+       { TUNER_ABSENT,                 "Samsung TCPQ9091P" },
        { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
-       { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
-       { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
+       { TUNER_TEMIC_4009FR5_PAL,      "Temic 4009FR5" },
+       { TUNER_TEMIC_4046FM5,          "Temic 4046FM5" },
        { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
-       { TUNER_ABSENT,        "Philips TD1536D FH 44"},
-       { TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
-       { TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
-       { TUNER_LG_PAL,        "LG TP18PSB11D"},
-       { TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
+       { TUNER_ABSENT,                 "Philips TD1536D FH 44"},
+       { TUNER_LG_NTSC_FM,             "LG TP18NSR01F"},
+       { TUNER_LG_PAL_FM,              "LG TP18PSB01D"},
+       { TUNER_LG_PAL,                 "LG TP18PSB11D"},
+       { TUNER_LG_PAL_I_FM,            "LG TAPC-I001D"},
        /* 50-59 */
-       { TUNER_LG_PAL_I,      "LG TAPC-I701D"},
-       { TUNER_ABSENT,        "Temic 4042FI5"},
-       { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
-       { TUNER_ABSENT,        "LG TPI8NSR11F"},
-       { TUNER_ABSENT,        "Microtune 4049 FM5 Alt I2C"},
-       { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
-       { TUNER_ABSENT,        "Philips FI1236 MK3"},
-       { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
-       { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
-       { TUNER_ABSENT,        "Philips FM1216MP MK3"},
+       { TUNER_LG_PAL_I,               "LG TAPC-I701D"},
+       { TUNER_ABSENT,                 "Temic 4042FI5"},
+       { TUNER_MICROTUNE_4049FM5,      "Microtune 4049 FM5"},
+       { TUNER_ABSENT,                 "LG TPI8NSR11F"},
+       { TUNER_ABSENT,                 "Microtune 4049 FM5 Alt I2C"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "Philips FQ1216ME MK3"},
+       { TUNER_ABSENT,                 "Philips FI1236 MK3"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "Philips FM1216 ME MK3"},
+       { TUNER_PHILIPS_FM1236_MK3,     "Philips FM1236 MK3"},
+       { TUNER_ABSENT,                 "Philips FM1216MP MK3"},
        /* 60-69 */
-       { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
-       { TUNER_ABSENT,        "LG M001D MK3"},
-       { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
-       { TUNER_ABSENT,        "LG M701D MK3"},
-       { TUNER_ABSENT,        "Temic 4146FM5"},
-       { TUNER_ABSENT,        "Temic 4136FY5"},
-       { TUNER_ABSENT,        "Temic 4106FH5"},
-       { TUNER_ABSENT,        "Philips FQ1216LMP MK3"},
-       { TUNER_LG_NTSC_TAPE,  "LG TAPE H001F MK3"},
-       { TUNER_LG_NTSC_TAPE,  "LG TAPE H701F MK3"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "LG S001D MK3"},
+       { TUNER_ABSENT,                 "LG M001D MK3"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "LG S701D MK3"},
+       { TUNER_ABSENT,                 "LG M701D MK3"},
+       { TUNER_ABSENT,                 "Temic 4146FM5"},
+       { TUNER_ABSENT,                 "Temic 4136FY5"},
+       { TUNER_ABSENT,                 "Temic 4106FH5"},
+       { TUNER_ABSENT,                 "Philips FQ1216LMP MK3"},
+       { TUNER_LG_NTSC_TAPE,           "LG TAPE H001F MK3"},
+       { TUNER_LG_NTSC_TAPE,           "LG TAPE H701F MK3"},
        /* 70-79 */
-       { TUNER_ABSENT,        "LG TALN H200T"},
-       { TUNER_ABSENT,        "LG TALN H250T"},
-       { TUNER_ABSENT,        "LG TALN M200T"},
-       { TUNER_ABSENT,        "LG TALN Z200T"},
-       { TUNER_ABSENT,        "LG TALN S200T"},
-       { TUNER_ABSENT,        "Thompson DTT7595"},
-       { TUNER_ABSENT,        "Thompson DTT7592"},
-       { TUNER_ABSENT,        "Silicon TDA8275C1 8290"},
-       { TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
-       { TUNER_ABSENT,        "Thompson DTT757"},
+       { TUNER_ABSENT,                 "LG TALN H200T"},
+       { TUNER_ABSENT,                 "LG TALN H250T"},
+       { TUNER_ABSENT,                 "LG TALN M200T"},
+       { TUNER_ABSENT,                 "LG TALN Z200T"},
+       { TUNER_ABSENT,                 "LG TALN S200T"},
+       { TUNER_ABSENT,                 "Thompson DTT7595"},
+       { TUNER_ABSENT,                 "Thompson DTT7592"},
+       { TUNER_ABSENT,                 "Silicon TDA8275C1 8290"},
+       { TUNER_ABSENT,                 "Silicon TDA8275C1 8290 FM"},
+       { TUNER_ABSENT,                 "Thompson DTT757"},
        /* 80-89 */
-       { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
-       { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
-       { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
-       { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
-       { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
-       { TUNER_TCL_2002N,     "TCL 2002N 6A"},
-       { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
-       { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
-       { TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
-       { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "Philips FQ1216LME MK3"},
+       { TUNER_LG_PAL_NEW_TAPC,        "LG TAPC G701D"},
+       { TUNER_LG_NTSC_NEW_TAPC,       "LG TAPC H791F"},
+       { TUNER_LG_PAL_NEW_TAPC,        "TCL 2002MB 3"},
+       { TUNER_LG_PAL_NEW_TAPC,        "TCL 2002MI 3"},
+       { TUNER_TCL_2002N,              "TCL 2002N 6A"},
+       { TUNER_PHILIPS_FM1236_MK3,     "Philips FQ1236 MK3"},
+       { TUNER_SAMSUNG_TCPN_2121P30A,  "Samsung TCPN 2121P30A"},
+       { TUNER_ABSENT,                 "Samsung TCPE 4121P30A"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "TCL MFPE05 2"},
        /* 90-99 */
-       { TUNER_ABSENT,        "LG TALN H202T"},
-       { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
-       { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
-       { TUNER_ABSENT,        "Philips FQ1286A MK4"},
-       { TUNER_ABSENT,        "Philips FQ1216ME MK5"},
-       { TUNER_ABSENT,        "Philips FQ1236 MK5"},
-       { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
-       { TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
-       { TUNER_ABSENT,        "TCL 2002MI_3H"},
-       { TUNER_TCL_2002N,     "TCL 2002N 5H"},
+       { TUNER_ABSENT,                 "LG TALN H202T"},
+       { TUNER_PHILIPS_FQ1216AME_MK4,  "Philips FQ1216AME MK4"},
+       { TUNER_PHILIPS_FQ1236A_MK4,    "Philips FQ1236A MK4"},
+       { TUNER_ABSENT,                 "Philips FQ1286A MK4"},
+       { TUNER_ABSENT,                 "Philips FQ1216ME MK5"},
+       { TUNER_ABSENT,                 "Philips FQ1236 MK5"},
+       { TUNER_SAMSUNG_TCPG_6121P30A,  "Samsung TCPG 6121P30A"},
+       { TUNER_TCL_2002MB,             "TCL 2002MB_3H"},
+       { TUNER_ABSENT,                 "TCL 2002MI_3H"},
+       { TUNER_TCL_2002N,              "TCL 2002N 5H"},
        /* 100-109 */
-       { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
-       { TUNER_TEA5767,       "Philips TEA5768HL FM Radio"},
-       { TUNER_ABSENT,        "Panasonic ENV57H12D5"},
-       { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
-       { TUNER_ABSENT,        "TCL MNM05-4"},
-       { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
-       { TUNER_ABSENT,        "TCL MQNM05-4"},
-       { TUNER_ABSENT,        "LG TAPC-W701D"},
-       { TUNER_ABSENT,        "TCL 9886P-WM"},
-       { TUNER_ABSENT,        "TCL 1676NM-WM"},
+       { TUNER_PHILIPS_FMD1216ME_MK3,  "Philips FMD1216ME"},
+       { TUNER_TEA5767,                "Philips TEA5768HL FM Radio"},
+       { TUNER_ABSENT,                 "Panasonic ENV57H12D5"},
+       { TUNER_PHILIPS_FM1236_MK3,     "TCL MFNM05-4"},
+       { TUNER_ABSENT,                 "TCL MNM05-4"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "TCL MPE05-2"},
+       { TUNER_ABSENT,                 "TCL MQNM05-4"},
+       { TUNER_ABSENT,                 "LG TAPC-W701D"},
+       { TUNER_ABSENT,                 "TCL 9886P-WM"},
+       { TUNER_ABSENT,                 "TCL 1676NM-WM"},
        /* 110-119 */
-       { TUNER_ABSENT,        "Thompson DTT75105"},
-       { TUNER_ABSENT,        "Conexant_CX24109"},
-       { TUNER_TCL_2002N,     "TCL M2523_5N_E"},
-       { TUNER_TCL_2002MB,    "TCL M2523_3DB_E"},
-       { TUNER_ABSENT,        "Philips 8275A"},
-       { TUNER_ABSENT,        "Microtune MT2060"},
-       { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
-       { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
-       { TUNER_ABSENT,        "TCL M2523_3DI_E"},
-       { TUNER_ABSENT,        "Samsung THPD5222FG30A"},
+       { TUNER_ABSENT,                 "Thompson DTT75105"},
+       { TUNER_ABSENT,                 "Conexant_CX24109"},
+       { TUNER_TCL_2002N,              "TCL M2523_5N_E"},
+       { TUNER_TCL_2002MB,             "TCL M2523_3DB_E"},
+       { TUNER_ABSENT,                 "Philips 8275A"},
+       { TUNER_ABSENT,                 "Microtune MT2060"},
+       { TUNER_PHILIPS_FM1236_MK3,     "Philips FM1236 MK5"},
+       { TUNER_PHILIPS_FM1216ME_MK3,   "Philips FM1216ME MK5"},
+       { TUNER_ABSENT,                 "TCL M2523_3DI_E"},
+       { TUNER_ABSENT,                 "Samsung THPD5222FG30A"},
        /* 120-129 */
-       { TUNER_ABSENT,        "Xceive XC3028"},
-       { TUNER_ABSENT,        "Philips FQ1216LME MK5"},
-       { TUNER_ABSENT,        "Philips FQD1216LME"},
-       { TUNER_ABSENT,        "Conexant CX24118A"},
-       { TUNER_ABSENT,        "TCL DMF11WIP"},
-       { TUNER_ABSENT,        "TCL MFNM05_4H_E"},
-       { TUNER_ABSENT,        "TCL MNM05_4H_E"},
-       { TUNER_ABSENT,        "TCL MPE05_2H_E"},
-       { TUNER_ABSENT,        "TCL MQNM05_4_U"},
-       { TUNER_ABSENT,        "TCL M2523_5NH_E"},
+       { TUNER_XC2028,                 "Xceive XC3028"},
+       { TUNER_ABSENT,                 "Philips FQ1216LME MK5"},
+       { TUNER_ABSENT,                 "Philips FQD1216LME"},
+       { TUNER_ABSENT,                 "Conexant CX24118A"},
+       { TUNER_ABSENT,                 "TCL DMF11WIP"},
+       { TUNER_ABSENT,                 "TCL MFNM05_4H_E"},
+       { TUNER_ABSENT,                 "TCL MNM05_4H_E"},
+       { TUNER_ABSENT,                 "TCL MPE05_2H_E"},
+       { TUNER_ABSENT,                 "TCL MQNM05_4_U"},
+       { TUNER_ABSENT,                 "TCL M2523_5NH_E"},
        /* 130-139 */
-       { TUNER_ABSENT,        "TCL M2523_3DBH_E"},
-       { TUNER_ABSENT,        "TCL M2523_3DIH_E"},
-       { TUNER_ABSENT,        "TCL MFPE05_2_U"},
-       { TUNER_ABSENT,        "Philips FMD1216MEX"},
-       { TUNER_ABSENT,        "Philips FRH2036B"},
-       { TUNER_ABSENT,        "Panasonic ENGF75_01GF"},
-       { TUNER_ABSENT,        "MaxLinear MXL5005"},
-       { TUNER_ABSENT,        "MaxLinear MXL5003"},
-       { TUNER_ABSENT,        "Xceive XC2028"},
-       { TUNER_ABSENT,        "Microtune MT2131"},
+       { TUNER_ABSENT,                 "TCL M2523_3DBH_E"},
+       { TUNER_ABSENT,                 "TCL M2523_3DIH_E"},
+       { TUNER_ABSENT,                 "TCL MFPE05_2_U"},
+       { TUNER_ABSENT,                 "Philips FMD1216MEX"},
+       { TUNER_ABSENT,                 "Philips FRH2036B"},
+       { TUNER_ABSENT,                 "Panasonic ENGF75_01GF"},
+       { TUNER_ABSENT,                 "MaxLinear MXL5005"},
+       { TUNER_ABSENT,                 "MaxLinear MXL5003"},
+       { TUNER_ABSENT,                 "Xceive XC2028"},
+       { TUNER_ABSENT,                 "Microtune MT2131"},
        /* 140-149 */
-       { TUNER_ABSENT,        "Philips 8275A_8295"},
-       { TUNER_ABSENT,        "TCL MF02GIP_5N_E"},
-       { TUNER_ABSENT,        "TCL MF02GIP_3DB_E"},
-       { TUNER_ABSENT,        "TCL MF02GIP_3DI_E"},
-       { TUNER_ABSENT,        "Microtune MT2266"},
-       { TUNER_ABSENT,        "TCL MF10WPP_4N_E"},
-       { TUNER_ABSENT,        "LG TAPQ_H702F"},
-       { TUNER_ABSENT,        "TCL M09WPP_4N_E"},
-       { TUNER_ABSENT,        "MaxLinear MXL5005_v2"},
-       { TUNER_ABSENT,        "Philips 18271_8295"},
+       { TUNER_ABSENT,                 "Philips 8275A_8295"},
+       { TUNER_ABSENT,                 "TCL MF02GIP_5N_E"},
+       { TUNER_ABSENT,                 "TCL MF02GIP_3DB_E"},
+       { TUNER_ABSENT,                 "TCL MF02GIP_3DI_E"},
+       { TUNER_ABSENT,                 "Microtune MT2266"},
+       { TUNER_ABSENT,                 "TCL MF10WPP_4N_E"},
+       { TUNER_ABSENT,                 "LG TAPQ_H702F"},
+       { TUNER_ABSENT,                 "TCL M09WPP_4N_E"},
+       { TUNER_ABSENT,                 "MaxLinear MXL5005_v2"},
+       { TUNER_PHILIPS_TDA8290,        "Philips 18271_8295"},
+       /* 150-159 */
+       { TUNER_ABSENT,        "Xceive XC5000"},
 };
 
 static struct HAUPPAUGE_AUDIOIC
@@ -344,37 +348,37 @@ static const char *decoderIC[] = {
 static int hasRadioTuner(int tunerType)
 {
        switch (tunerType) {
-               case 18: //PNPEnv_TUNER_FR1236_MK2:
-               case 23: //PNPEnv_TUNER_FM1236:
-               case 38: //PNPEnv_TUNER_FMR1236:
-               case 16: //PNPEnv_TUNER_FR1216_MK2:
-               case 19: //PNPEnv_TUNER_FR1246_MK2:
-               case 21: //PNPEnv_TUNER_FM1216:
-               case 24: //PNPEnv_TUNER_FM1246:
-               case 17: //PNPEnv_TUNER_FR1216MF_MK2:
-               case 22: //PNPEnv_TUNER_FM1216MF:
-               case 20: //PNPEnv_TUNER_FR1256_MK2:
-               case 25: //PNPEnv_TUNER_FM1256:
-               case 33: //PNPEnv_TUNER_4039FR5:
-               case 42: //PNPEnv_TUNER_4009FR5:
-               case 52: //PNPEnv_TUNER_4049FM5:
-               case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
-               case 44: //PNPEnv_TUNER_4009FN5:
-               case 31: //PNPEnv_TUNER_TCPB9085P:
-               case 30: //PNPEnv_TUNER_TCPN9085D:
-               case 46: //PNPEnv_TUNER_TP18NSR01F:
-               case 47: //PNPEnv_TUNER_TP18PSB01D:
-               case 49: //PNPEnv_TUNER_TAPC_I001D:
-               case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
-               case 57: //PNPEnv_TUNER_FM1216ME_MK3:
-               case 59: //PNPEnv_TUNER_FM1216MP_MK3:
-               case 58: //PNPEnv_TUNER_FM1236_MK3:
-               case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
-               case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
-               case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
-               case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
-               case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
-               case 105:
+       case 18: /* PNPEnv_TUNER_FR1236_MK2 */
+       case 23: /* PNPEnv_TUNER_FM1236 */
+       case 38: /* PNPEnv_TUNER_FMR1236 */
+       case 16: /* PNPEnv_TUNER_FR1216_MK2 */
+       case 19: /* PNPEnv_TUNER_FR1246_MK2 */
+       case 21: /* PNPEnv_TUNER_FM1216 */
+       case 24: /* PNPEnv_TUNER_FM1246 */
+       case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */
+       case 22: /* PNPEnv_TUNER_FM1216MF */
+       case 20: /* PNPEnv_TUNER_FR1256_MK2 */
+       case 25: /* PNPEnv_TUNER_FM1256 */
+       case 33: /* PNPEnv_TUNER_4039FR5 */
+       case 42: /* PNPEnv_TUNER_4009FR5 */
+       case 52: /* PNPEnv_TUNER_4049FM5 */
+       case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */
+       case 44: /* PNPEnv_TUNER_4009FN5 */
+       case 31: /* PNPEnv_TUNER_TCPB9085P */
+       case 30: /* PNPEnv_TUNER_TCPN9085D */
+       case 46: /* PNPEnv_TUNER_TP18NSR01F */
+       case 47: /* PNPEnv_TUNER_TP18PSB01D */
+       case 49: /* PNPEnv_TUNER_TAPC_I001D */
+       case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */
+       case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */
+       case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */
+       case 58: /* PNPEnv_TUNER_FM1236_MK3 */
+       case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */
+       case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */
+       case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */
+       case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */
+       case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */
+       case 105:
                return 1;
        }
        return 0;
@@ -392,7 +396,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
        **
        ** In our (ivtv) case we're interested in the following:
        ** tuner type:   tag [00].05 or [0a].01 (index into hauppauge_tuner)
-       ** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt)
+       ** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into
+       **               hauppauge_tuner_fmt)
        ** radio:        tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
        ** audio proc:   tag [02].01 or [05].00 (mask with 0x7f)
        ** decoder proc: tag [09].01)
@@ -405,9 +410,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
        ** # of inputs/outputs ???
        */
 
-       int i, j, len, done, beenhere, tag,start;
+       int i, j, len, done, beenhere, tag, start;
 
-       int tuner1 = 0, t_format1 = 0, audioic=-1;
+       int tuner1 = 0, t_format1 = 0, audioic = -1;
        char *t_name1 = NULL;
        const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
 
@@ -418,17 +423,24 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
        memset(tvee, 0, sizeof(*tvee));
        done = len = beenhere = 0;
 
-       /* Hack for processing eeprom for em28xx and cx 2388x*/
-       if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
-                       (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
-               start=0xa0; /* Generic em28xx offset */
-       else if (((eeprom_data[0] & 0xe1) == 0x01) &&
-                                       (eeprom_data[1] == 0x00) &&
-                                       (eeprom_data[2] == 0x00) &&
-                                       (eeprom_data[8] == 0x84))
-               start=8; /* Generic cx2388x offset */
+       /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */
+       if (eeprom_data[0] == 0x1a &&
+           eeprom_data[1] == 0xeb &&
+           eeprom_data[2] == 0x67 &&
+           eeprom_data[3] == 0x95)
+               start = 0xa0; /* Generic em28xx offset */
+       else if ((eeprom_data[0] & 0xe1) == 0x01 &&
+                eeprom_data[1] == 0x00 &&
+                eeprom_data[2] == 0x00 &&
+                eeprom_data[8] == 0x84)
+               start = 8; /* Generic cx2388x offset */
+       else if (eeprom_data[1] == 0x70 &&
+                eeprom_data[2] == 0x00 &&
+                eeprom_data[4] == 0x74 &&
+                eeprom_data[8] == 0x84)
+               start = 8; /* Generic cx23418 offset (models 74xxx) */
        else
-               start=0;
+               start = 0;
 
        for (i = start; !done && i < 256; i += len) {
                if (eeprom_data[i] == 0x84) {
@@ -444,16 +456,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        ++i;
                } else {
                        tveeprom_warn("Encountered bad packet header [%02x]. "
-                               "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
+                               "Corrupt or not a Hauppauge eeprom.\n",
+                               eeprom_data[i]);
                        return;
                }
 
                if (debug) {
-                       tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
-                       for(j = 1; j < len; j++) {
-                               printk(" %02x", eeprom_data[i + j]);
-                       }
-                       printk("\n");
+                       tveeprom_info("Tag [%02x] + %d bytes:",
+                                       eeprom_data[i], len - 1);
+                       for (j = 1; j < len; j++)
+                               printk(KERN_CONT " %02x", eeprom_data[i + j]);
+                       printk(KERN_CONT "\n");
                }
 
                /* process by tag */
@@ -504,16 +517,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                                (eeprom_data[i+6] << 8) +
                                (eeprom_data[i+7] << 16);
 
-                               if ( (eeprom_data[i + 8] & 0xf0) &&
-                                       (tvee->serial_number < 0xffffff) ) {
-                                       tvee->MAC_address[0] = 0x00;
-                                       tvee->MAC_address[1] = 0x0D;
-                                       tvee->MAC_address[2] = 0xFE;
-                                       tvee->MAC_address[3] = eeprom_data[i + 7];
-                                       tvee->MAC_address[4] = eeprom_data[i + 6];
-                                       tvee->MAC_address[5] = eeprom_data[i + 5];
-                                       tvee->has_MAC_address = 1;
-                               }
+                       if ((eeprom_data[i + 8] & 0xf0) &&
+                                       (tvee->serial_number < 0xffffff)) {
+                               tvee->MAC_address[0] = 0x00;
+                               tvee->MAC_address[1] = 0x0D;
+                               tvee->MAC_address[2] = 0xFE;
+                               tvee->MAC_address[3] = eeprom_data[i + 7];
+                               tvee->MAC_address[4] = eeprom_data[i + 6];
+                               tvee->MAC_address[5] = eeprom_data[i + 5];
+                               tvee->has_MAC_address = 1;
+                       }
                        break;
 
                case 0x05:
@@ -537,7 +550,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                                (eeprom_data[i + 3] << 16) +
                                (eeprom_data[i + 4] << 24);
                        tvee->revision =
-                               eeprom_data[i +] +
+                               eeprom_data[i + 5] +
                                (eeprom_data[i + 6] << 8) +
                                (eeprom_data[i + 7] << 16);
                        break;
@@ -557,16 +570,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                case 0x0a:
                        /* tag 'Tuner' */
                        if (beenhere == 0) {
-                               tuner1 = eeprom_data[i+2];
-                               t_format1 = eeprom_data[i+1];
+                               tuner1 = eeprom_data[i + 2];
+                               t_format1 = eeprom_data[i + 1];
                                beenhere = 1;
                        } else {
                                /* a second (radio) tuner may be present */
-                               tuner2 = eeprom_data[i+2];
-                               t_format2 = eeprom_data[i+1];
-                               if (t_format2 == 0) {  /* not a TV tuner? */
+                               tuner2 = eeprom_data[i + 2];
+                               t_format2 = eeprom_data[i + 1];
+                               /* not a TV tuner? */
+                               if (t_format2 == 0)
                                        tvee->has_radio = 1; /* must be radio */
-                               }
                        }
                        break;
 
@@ -594,7 +607,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                /* case 0x12: tag 'InfoBits' */
 
                default:
-                       tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
+                       tveeprom_dbg("Not sure what to do with tag [%02x]\n",
+                                       tag);
                        /* dump the rest of the packet? */
                }
        }
@@ -608,7 +622,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
                tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
                tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
-               tvee->rev_str[3] = 32 + ( tvee->revision        & 0x3f);
+               tvee->rev_str[3] = 32 + (tvee->revision & 0x3f);
                tvee->rev_str[4] = 0;
        }
 
@@ -651,44 +665,40 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 
        tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
                tvee->model, tvee->rev_str, tvee->serial_number);
-       if (tvee->has_MAC_address == 1) {
+       if (tvee->has_MAC_address == 1)
                tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n",
                        tvee->MAC_address[0], tvee->MAC_address[1],
                        tvee->MAC_address[2], tvee->MAC_address[3],
                        tvee->MAC_address[4], tvee->MAC_address[5]);
-       }
        tveeprom_info("tuner model is %s (idx %d, type %d)\n",
                t_name1, tuner1, tvee->tuner_type);
        tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-               t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
-               t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
-               t_format1);
-       if (tuner2) {
+               t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2],
+               t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5],
+               t_fmt_name1[6], t_fmt_name1[7], t_format1);
+       if (tuner2)
                tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
                                        t_name2, tuner2, tvee->tuner2_type);
-       }
-       if (t_format2) {
+       if (t_format2)
                tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-                       t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
-                       t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
-                       t_format2);
-       }
-       if (audioic<0) {
+                       t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2],
+                       t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5],
+                       t_fmt_name2[6], t_fmt_name2[7], t_format2);
+       if (audioic < 0) {
                tveeprom_info("audio processor is unknown (no idx)\n");
-               tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
+               tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
        } else {
                if (audioic < ARRAY_SIZE(audioIC))
                        tveeprom_info("audio processor is %s (idx %d)\n",
-                                       audioIC[audioic].name,audioic);
+                                       audioIC[audioic].name, audioic);
                else
                        tveeprom_info("audio processor is unknown (idx %d)\n",
                                                                audioic);
        }
-       if (tvee->decoder_processor) {
+       if (tvee->decoder_processor)
                tveeprom_info("decoder processor is %s (idx %d)\n",
                        STRM(decoderIC, tvee->decoder_processor),
                        tvee->decoder_processor);
-       }
        if (tvee->has_ir == -1)
                tveeprom_info("has %sradio\n",
                                tvee->has_radio ? "" : "no ");
@@ -709,11 +719,13 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
        int err;
 
        buf = 0;
-       if (1 != (err = i2c_master_send(c, &buf, 1))) {
+       err = i2c_master_send(c, &buf, 1);
+       if (err != 1) {
                tveeprom_info("Huh, no eeprom present (err=%d)?\n", err);
                return -1;
        }
-       if (len != (err = i2c_master_recv(c, eedata, len))) {
+       err = i2c_master_recv(c, eedata, len);
+       if (err != len) {
                tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
                return -1;
        }
@@ -724,9 +736,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
                for (i = 0; i < len; i++) {
                        if (0 == (i % 16))
                                tveeprom_info("%02x:", i);
-                       printk(" %02x", eedata[i]);
+                       printk(KERN_CONT " %02x", eedata[i]);
                        if (15 == (i % 16))
-                               printk("\n");
+                               printk(KERN_CONT "\n");
                }
        }
        return 0;
@@ -758,9 +770,9 @@ tveeprom_command(struct i2c_client *client,
 
        switch (cmd) {
        case 0:
-               buf = kzalloc(256,GFP_KERNEL);
-               tveeprom_read(client,buf,256);
-               tveeprom_hauppauge_analog(client, &eeprom,buf);
+               buf = kzalloc(256, GFP_KERNEL);
+               tveeprom_read(client, buf, 256);
+               tveeprom_hauppauge_analog(client, &eeprom, buf);
                kfree(buf);
                eeprom_props[0] = eeprom.tuner_type;
                eeprom_props[1] = eeprom.tuner_formats;
@@ -794,7 +806,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter,
 }
 
 static int
-tveeprom_attach_adapter (struct i2c_adapter *adapter)
+tveeprom_attach_adapter(struct i2c_adapter *adapter)
 {
        if (adapter->class & I2C_CLASS_TV_ANALOG)
                return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
@@ -802,7 +814,7 @@ tveeprom_attach_adapter (struct i2c_adapter *adapter)
 }
 
 static int
-tveeprom_detach_client (struct i2c_client *client)
+tveeprom_detach_client(struct i2c_client *client)
 {
        int err;
 
index 0b2a961efd2215100863ee7a01b48c801b000dd6..bd201397a2acdb350824f7062119dfb93e5ee1b7 100644 (file)
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/upd64031a.h>
 
-// --------------------- read registers functions define -----------------------
+/* --------------------- read registers functions define -------------------- */
 
 /* bit masks */
 #define GR_MODE_MASK              0xc0
 #define DIRECT_3DYCS_CONNECT_MASK 0xc0
 #define SYNC_CIRCUIT_MASK         0xa0
 
-// -----------------------------------------------------------------------------
+/* -------------------------------------------------------------------------- */
 
 MODULE_DESCRIPTION("uPD64031A driver");
 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 enum {
        R00 = 0, R01, R02, R03, R04,
@@ -99,7 +96,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val)
 
        buf[0] = reg;
        buf[1] = val;
-       v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val);
+       v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val);
        if (i2c_master_send(client, buf, 2) != 2)
                v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
 }
@@ -119,7 +116,7 @@ static void upd64031a_change(struct i2c_client *client)
 
 /* ------------------------------------------------------------------------ */
 
-static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct upd64031a_state *state = i2c_get_clientdata(client);
        struct v4l2_routing *route = arg;
@@ -143,8 +140,10 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
 
                state->gr_mode = (route->input & 3) << 6;
                state->direct_3dycs_connect = (route->input & 0xc) << 4;
-               state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
-               state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
+               state->ext_comp_sync =
+                       (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
+               state->ext_vert_sync =
+                       (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
                r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
                r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
                        state->ext_comp_sync | state->ext_vert_sync;
@@ -168,20 +167,23 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
        {
                struct v4l2_register *reg = arg;
 
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+               if (!v4l2_chip_match_i2c_client(client,
+                                       reg->match_type, reg->match_chip))
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
+               if (cmd == VIDIOC_DBG_G_REGISTER) {
                        reg->val = upd64031a_read(client, reg->reg & 0xff);
-               else
-                       upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
+                       break;
+               }
+               upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0);
+               return v4l2_chip_ident_i2c_client(client, arg,
+                               V4L2_IDENT_UPD64031A, 0);
 
        default:
                break;
@@ -193,90 +195,43 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
 
 /* i2c implementation */
 
-static struct i2c_driver i2c_driver;
-
-static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind)
+static int upd64031a_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct upd64031a_state *state;
        int i;
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == NULL) {
-               return -ENOMEM;
-       }
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
-       snprintf(client->name, sizeof(client->name) - 1, "uPD64031A");
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
-       if (state == NULL) {
-               kfree(client);
+       if (state == NULL)
                return -ENOMEM;
-       }
        i2c_set_clientdata(client, state);
        memcpy(state->regs, upd64031a_init, sizeof(state->regs));
        state->gr_mode = UPD64031A_GR_ON << 6;
        state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
        state->ext_comp_sync = state->ext_vert_sync = 0;
-       for (i = 0; i < TOT_REGS; i++) {
+       for (i = 0; i < TOT_REGS; i++)
                upd64031a_write(client, i, state->regs[i]);
-       }
-
-       i2c_attach_client(client);
-
        return 0;
 }
 
-static int upd64031a_probe(struct i2c_adapter *adapter)
+static int upd64031a_remove(struct i2c_client *client)
 {
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, upd64031a_attach);
-       return 0;
-}
-
-static int upd64031a_detach(struct i2c_client *client)
-{
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err)
-               return err;
-
-       kfree(client);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "upd64031a",
-       },
-       .id = I2C_DRIVERID_UPD64031A,
-       .attach_adapter = upd64031a_probe,
-       .detach_client  = upd64031a_detach,
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "upd64031a",
+       .driverid = I2C_DRIVERID_UPD64031A,
        .command = upd64031a_command,
+       .probe = upd64031a_probe,
+       .remove = upd64031a_remove,
 };
-
-
-static int __init upd64031a_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit upd64031a_exit_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(upd64031a_init_module);
-module_exit(upd64031a_exit_module);
index 401bd21f46ebdc817432715e258119211caed9c4..2d9a88f70c85ba2ac2efdebb9ac02d895ddea50c 100644 (file)
@@ -17,7 +17,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <linux/version.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/upd64083.h>
 
 MODULE_DESCRIPTION("uPD64083 driver");
 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 enum {
        R00 = 0, R01, R02, R03, R04,
@@ -88,7 +86,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val)
 
        buf[0] = reg;
        buf[1] = val;
-       v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val);
+       v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val);
        if (i2c_master_send(client, buf, 2) != 2)
                v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
 }
@@ -109,7 +107,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg)
 
 /* ------------------------------------------------------------------------ */
 
-static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct upd64083_state *state = i2c_get_clientdata(client);
        struct v4l2_routing *route = arg;
@@ -145,20 +143,23 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
        {
                struct v4l2_register *reg = arg;
 
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+               if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
+               if (cmd == VIDIOC_DBG_G_REGISTER) {
                        reg->val = upd64083_read(client, reg->reg & 0xff);
-               else
-                       upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
+                       break;
+               }
+               upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0);
+               return v4l2_chip_ident_i2c_client(client, arg,
+                               V4L2_IDENT_UPD64083, 0);
 
        default:
                break;
@@ -171,89 +172,43 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
 
 /* i2c implementation */
 
-static struct i2c_driver i2c_driver;
-
-static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind)
+static int upd64083_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct upd64083_state *state;
        int i;
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == NULL) {
-               return -ENOMEM;
-       }
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
-       snprintf(client->name, sizeof(client->name) - 1, "uPD64083");
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
-       if (state == NULL) {
-               kfree(client);
+       if (state == NULL)
                return -ENOMEM;
-       }
        i2c_set_clientdata(client, state);
        /* Initially assume that a ghost reduction chip is present */
        state->mode = 0;  /* YCS mode */
        state->ext_y_adc = (1 << 5);
        memcpy(state->regs, upd64083_init, TOT_REGS);
-       for (i = 0; i < TOT_REGS; i++) {
+       for (i = 0; i < TOT_REGS; i++)
                upd64083_write(client, i, state->regs[i]);
-       }
-       i2c_attach_client(client);
-
-       return 0;
-}
-
-static int upd64083_probe(struct i2c_adapter *adapter)
-{
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, upd64083_attach);
        return 0;
 }
 
-static int upd64083_detach(struct i2c_client *client)
+static int upd64083_remove(struct i2c_client *client)
 {
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err)
-               return err;
-
-       kfree(client);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "upd64083",
-       },
-       .id = I2C_DRIVERID_UPD64083,
-       .attach_adapter = upd64083_probe,
-       .detach_client  = upd64083_detach,
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "upd64083",
+       .driverid = I2C_DRIVERID_UPD64083,
        .command = upd64083_command,
+       .probe = upd64083_probe,
+       .remove = upd64083_remove,
 };
-
-
-static int __init upd64083_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit upd64083_exit_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(upd64083_init_module);
-module_exit(upd64083_exit_module);
index f09eb102731b25693e818eb83700120ad16f68ff..503b13beb922451185a268fcb290bcfbd4b97667 100644 (file)
@@ -901,6 +901,20 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .Y_Offset      = -1,
                .ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM",
        },
+       [PINNA_PCTV_USB_NTSC_FM_V3] = {
+               .Interface     = -1,
+               .Codec         = CODEC_SAA7111,
+               .VideoChannels = 3,
+               .VideoNorm     = V4L2_STD_NTSC,
+               .AudioChannels = 1,
+               .Radio         = 1,
+               .vbi           = 1,
+               .Tuner         = 1,
+               .TunerType     = TUNER_PHILIPS_NTSC_M,
+               .X_Offset      = -1,
+               .Y_Offset      = -1,
+               .ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM V3",
+       },
        [PINNA_PCTV_USB_PAL_FM_V2] = {
                .Interface     = -1,
                .Codec         = CODEC_SAA7113,
@@ -1044,7 +1058,7 @@ struct usb_device_id usbvision_table [] = {
        { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
        { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
        { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
-       { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 },
+       { USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 },
        { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
        { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
        { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
@@ -1074,6 +1088,8 @@ struct usb_device_id usbvision_table [] = {
        { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
        { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
        { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
+       { USB_DEVICE(0x2304, 0x0113),
+         .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
        { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
        { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
        { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
index 512c5cee4145d2ac15735b140c13778970864510..9c6ad22960d852def8155e759aeb8c58473c7437 100644 (file)
@@ -62,5 +62,6 @@
 #define PINNA_LINX_VD_IN_CAB_PAL                 61
 #define PINNA_PCTV_BUNGEE_PAL_FM                 62
 #define HPG_WINTV                                63
+#define PINNA_PCTV_USB_NTSC_FM_V3                64
 
 extern const int usbvision_device_data_size;
index c7d5f9ed22d7add7a5997caad00cb050377204d0..56775ab8b75d386809183403b492dd05671d03ae 100644 (file)
@@ -69,6 +69,15 @@ static int SwitchSVideoInput = 0;                    // To help people with Black and White outpu
 module_param(SwitchSVideoInput, int, 0444);
 MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");
 
+static unsigned int adjust_X_Offset = -1;
+module_param(adjust_X_Offset, int, 0644);
+MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");
+
+static unsigned int adjust_Y_Offset = -1;
+module_param(adjust_Y_Offset, int, 0644);
+MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
+
+
 #define        ENABLE_HEXDUMP  0       /* Enable if you need it */
 
 
@@ -624,25 +633,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
 
                        YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
                        switch (frame->v4l2_format.format) {
-                               case V4L2_PIX_FMT_RGB565:
-                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
-                                       *f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
-                                       break;
-                               case V4L2_PIX_FMT_RGB24:
-                                       *f++ = bv;
-                                       *f++ = gv;
-                                       *f++ = rv;
-                                       break;
-                               case V4L2_PIX_FMT_RGB32:
-                                       *f++ = bv;
-                                       *f++ = gv;
-                                       *f++ = rv;
-                                       f++;
-                                       break;
-                               case V4L2_PIX_FMT_RGB555:
-                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
-                                       *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
-                                       break;
+                       case V4L2_PIX_FMT_RGB565:
+                               *f++ = (0x1F & rv) |
+                                       (0xE0 & (gv << 5));
+                               *f++ = (0x07 & (gv >> 3)) |
+                                       (0xF8 &  bv);
+                               break;
+                       case V4L2_PIX_FMT_RGB24:
+                               *f++ = rv;
+                               *f++ = gv;
+                               *f++ = bv;
+                               break;
+                       case V4L2_PIX_FMT_RGB32:
+                               *f++ = rv;
+                               *f++ = gv;
+                               *f++ = bv;
+                               f++;
+                               break;
+                       case V4L2_PIX_FMT_RGB555:
+                               *f++ = (0x1F & rv) |
+                                       (0xE0 & (gv << 5));
+                               *f++ = (0x03 & (gv >> 3)) |
+                                       (0x7C & (bv << 2));
+                               break;
                        }
                }
                clipmask_index += clipmask_add;
@@ -656,25 +669,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
 
                        YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
                        switch (frame->v4l2_format.format) {
-                               case V4L2_PIX_FMT_RGB565:
-                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
-                                       *f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
-                                       break;
-                               case V4L2_PIX_FMT_RGB24:
-                                       *f++ = bv;
-                                       *f++ = gv;
-                                       *f++ = rv;
-                                       break;
-                               case V4L2_PIX_FMT_RGB32:
-                                       *f++ = bv;
-                                       *f++ = gv;
-                                       *f++ = rv;
-                                       f++;
-                                       break;
-                               case V4L2_PIX_FMT_RGB555:
-                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
-                                       *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
-                                       break;
+                       case V4L2_PIX_FMT_RGB565:
+                               *f++ = (0x1F & rv) |
+                                       (0xE0 & (gv << 5));
+                               *f++ = (0x07 & (gv >> 3)) |
+                                       (0xF8 &  bv);
+                               break;
+                       case V4L2_PIX_FMT_RGB24:
+                               *f++ = rv;
+                               *f++ = gv;
+                               *f++ = bv;
+                               break;
+                       case V4L2_PIX_FMT_RGB32:
+                               *f++ = rv;
+                               *f++ = gv;
+                               *f++ = bv;
+                               f++;
+                               break;
+                       case V4L2_PIX_FMT_RGB555:
+                               *f++ = (0x1F & rv) |
+                                       (0xE0 & (gv << 5));
+                               *f++ = (0x03 & (gv >> 3)) |
+                                       (0x7C & (bv << 2));
+                               break;
                        }
                }
                clipmask_index += clipmask_add;
@@ -942,22 +959,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
                                        *f++ = Y[Idx];
                                        break;
                                case V4L2_PIX_FMT_RGB555:
-                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
-                                       *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+                                       *f++ = (0x1F & rv) |
+                                               (0xE0 & (gv << 5));
+                                       *f++ = (0x03 & (gv >> 3)) |
+                                               (0x7C & (bv << 2));
                                        break;
                                case V4L2_PIX_FMT_RGB565:
-                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
-                                       *f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+                                       *f++ = (0x1F & rv) |
+                                               (0xE0 & (gv << 5));
+                                       *f++ = (0x07 & (gv >> 3)) |
+                                               (0xF8 &  bv);
                                        break;
                                case V4L2_PIX_FMT_RGB24:
-                                       *f++ = bv;
-                                       *f++ = gv;
                                        *f++ = rv;
+                                       *f++ = gv;
+                                       *f++ = bv;
                                        break;
                                case V4L2_PIX_FMT_RGB32:
-                                       *f++ = bv;
-                                       *f++ = gv;
                                        *f++ = rv;
+                                       *f++ = gv;
+                                       *f++ = bv;
                                        f++;
                                        break;
                        }
@@ -1071,28 +1092,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
                                r_ = (y_ + ur) >> 16;
 
                                switch (frame->v4l2_format.format) {
-                                       case V4L2_PIX_FMT_RGB565:
-                                               g = LIMIT_RGB(g_);
-                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-                                               *f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-                                               break;
-                                       case V4L2_PIX_FMT_RGB24:
-                                               *f_even++ = LIMIT_RGB(b_);
-                                               *f_even++ = LIMIT_RGB(g_);
-                                               *f_even++ = LIMIT_RGB(r_);
-                                               break;
-                                       case V4L2_PIX_FMT_RGB32:
-                                               *f_even++ = LIMIT_RGB(b_);
-                                               *f_even++ = LIMIT_RGB(g_);
-                                               *f_even++ = LIMIT_RGB(r_);
-                                               f_even++;
-                                               break;
-                                       case V4L2_PIX_FMT_RGB555:
-                                               g = LIMIT_RGB(g_);
-                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-                                               *f_even++ = (0x03 & (          g   >> 6)) |
-                                                           (0x7C & (LIMIT_RGB(r_) >> 1));
-                                               break;
+                               case V4L2_PIX_FMT_RGB565:
+                                       g = LIMIT_RGB(g_);
+                                       *f_even++ =
+                                               (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_even++ =
+                                               (0x07 & (g >> 3)) |
+                                               (0xF8 &  LIMIT_RGB(b_));
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f_even++ = LIMIT_RGB(r_);
+                                       *f_even++ = LIMIT_RGB(g_);
+                                       *f_even++ = LIMIT_RGB(b_);
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f_even++ = LIMIT_RGB(r_);
+                                       *f_even++ = LIMIT_RGB(g_);
+                                       *f_even++ = LIMIT_RGB(b_);
+                                       f_even++;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       g = LIMIT_RGB(g_);
+                                       *f_even++ = (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_even++ = (0x03 & (g >> 3)) |
+                                               (0x7C & (LIMIT_RGB(b_) << 2));
+                                       break;
                                }
                        }
                        clipmask_even_index += clipmask_add;
@@ -1110,28 +1136,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
                                r_ = (y_ + ur) >> 16;
 
                                switch (frame->v4l2_format.format) {
-                                       case V4L2_PIX_FMT_RGB565:
-                                               g = LIMIT_RGB(g_);
-                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-                                               *f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-                                               break;
-                                       case V4L2_PIX_FMT_RGB24:
-                                               *f_even++ = LIMIT_RGB(b_);
-                                               *f_even++ = LIMIT_RGB(g_);
-                                               *f_even++ = LIMIT_RGB(r_);
-                                               break;
-                                       case V4L2_PIX_FMT_RGB32:
-                                               *f_even++ = LIMIT_RGB(b_);
-                                               *f_even++ = LIMIT_RGB(g_);
-                                               *f_even++ = LIMIT_RGB(r_);
-                                               f_even++;
-                                               break;
-                                       case V4L2_PIX_FMT_RGB555:
-                                               g = LIMIT_RGB(g_);
-                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-                                               *f_even++ = (0x03 & (          g   >> 6)) |
-                                                           (0x7C & (LIMIT_RGB(r_) >> 1));
-                                               break;
+                               case V4L2_PIX_FMT_RGB565:
+                                       g = LIMIT_RGB(g_);
+                                       *f_even++ =
+                                               (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_even++ =
+                                               (0x07 & (g >> 3)) |
+                                               (0xF8 &  LIMIT_RGB(b_));
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f_even++ = LIMIT_RGB(r_);
+                                       *f_even++ = LIMIT_RGB(g_);
+                                       *f_even++ = LIMIT_RGB(b_);
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f_even++ = LIMIT_RGB(r_);
+                                       *f_even++ = LIMIT_RGB(g_);
+                                       *f_even++ = LIMIT_RGB(b_);
+                                       f_even++;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       g = LIMIT_RGB(g_);
+                                       *f_even++ = (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_even++ = (0x03 & (g >> 3)) |
+                                               (0x7C & (LIMIT_RGB(b_) << 2));
+                                       break;
                                }
                        }
                        clipmask_even_index += clipmask_add;
@@ -1151,28 +1182,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
                                r_ = (y_ + ur) >> 16;
 
                                switch (frame->v4l2_format.format) {
-                                       case V4L2_PIX_FMT_RGB565:
-                                               g = LIMIT_RGB(g_);
-                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-                                               *f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-                                               break;
-                                       case V4L2_PIX_FMT_RGB24:
-                                               *f_odd++ = LIMIT_RGB(b_);
-                                               *f_odd++ = LIMIT_RGB(g_);
-                                               *f_odd++ = LIMIT_RGB(r_);
-                                               break;
-                                       case V4L2_PIX_FMT_RGB32:
-                                               *f_odd++ = LIMIT_RGB(b_);
-                                               *f_odd++ = LIMIT_RGB(g_);
-                                               *f_odd++ = LIMIT_RGB(r_);
-                                               f_odd++;
-                                               break;
-                                       case V4L2_PIX_FMT_RGB555:
-                                               g = LIMIT_RGB(g_);
-                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-                                               *f_odd++ = (0x03 & (          g   >> 6)) |
-                                                          (0x7C & (LIMIT_RGB(r_) >> 1));
-                                               break;
+                               case V4L2_PIX_FMT_RGB565:
+                                       g = LIMIT_RGB(g_);
+                                       *f_odd++ =
+                                               (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_odd++ =
+                                               (0x07 & (g >> 3)) |
+                                               (0xF8 &  LIMIT_RGB(b_));
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f_odd++ = LIMIT_RGB(r_);
+                                       *f_odd++ = LIMIT_RGB(g_);
+                                       *f_odd++ = LIMIT_RGB(b_);
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f_odd++ = LIMIT_RGB(r_);
+                                       *f_odd++ = LIMIT_RGB(g_);
+                                       *f_odd++ = LIMIT_RGB(b_);
+                                       f_odd++;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       g = LIMIT_RGB(g_);
+                                       *f_odd++ = (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_odd++ = (0x03 & (g >> 3)) |
+                                               (0x7C & (LIMIT_RGB(b_) << 2));
+                                       break;
                                }
                        }
                        clipmask_odd_index += clipmask_add;
@@ -1190,28 +1226,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
                                r_ = (y_ + ur) >> 16;
 
                                switch (frame->v4l2_format.format) {
-                                       case V4L2_PIX_FMT_RGB565:
-                                               g = LIMIT_RGB(g_);
-                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-                                               *f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-                                               break;
-                                       case V4L2_PIX_FMT_RGB24:
-                                               *f_odd++ = LIMIT_RGB(b_);
-                                               *f_odd++ = LIMIT_RGB(g_);
-                                               *f_odd++ = LIMIT_RGB(r_);
-                                               break;
-                                       case V4L2_PIX_FMT_RGB32:
-                                               *f_odd++ = LIMIT_RGB(b_);
-                                               *f_odd++ = LIMIT_RGB(g_);
-                                               *f_odd++ = LIMIT_RGB(r_);
-                                               f_odd++;
-                                               break;
-                                       case V4L2_PIX_FMT_RGB555:
-                                               g = LIMIT_RGB(g_);
-                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-                                               *f_odd++ = (0x03 & (          g   >> 6)) |
-                                                          (0x7C & (LIMIT_RGB(r_) >> 1));
-                                               break;
+                               case V4L2_PIX_FMT_RGB565:
+                                       g = LIMIT_RGB(g_);
+                                       *f_odd++ =
+                                               (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_odd++ =
+                                               (0x07 & (g >> 3)) |
+                                               (0xF8 &  LIMIT_RGB(b_));
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f_odd++ = LIMIT_RGB(r_);
+                                       *f_odd++ = LIMIT_RGB(g_);
+                                       *f_odd++ = LIMIT_RGB(b_);
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f_odd++ = LIMIT_RGB(r_);
+                                       *f_odd++ = LIMIT_RGB(g_);
+                                       *f_odd++ = LIMIT_RGB(b_);
+                                       f_odd++;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       g = LIMIT_RGB(g_);
+                                       *f_odd++ = (0x1F & LIMIT_RGB(r_)) |
+                                               (0xE0 & (g << 5));
+                                       *f_odd++ = (0x03 & (g >> 3)) |
+                                               (0x7C & (LIMIT_RGB(b_) << 2));
+                                       break;
                                }
                        }
                        clipmask_odd_index += clipmask_add;
@@ -1561,13 +1602,10 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
        if (len > 8) {
                return -EFAULT;
        }
-//     down(&usbvision->ctrlUrbLock);
        if (usbvision->ctrlUrbBusy) {
-//             up(&usbvision->ctrlUrbLock);
                return -EBUSY;
        }
        usbvision->ctrlUrbBusy = 1;
-//     up(&usbvision->ctrlUrbLock);
 
        usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
        usbvision->ctrlUrbSetup.bRequest     = USBVISION_OP_CODE;
@@ -2100,11 +2138,21 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
                value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
        }
 
+       if (adjust_X_Offset != -1) {
+               value[4] = adjust_X_Offset & 0xff;
+               value[5] = (adjust_X_Offset & 0x0300) >> 8;
+       }
+
        if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
                value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
                value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
        }
 
+       if (adjust_Y_Offset != -1) {
+               value[6] = adjust_Y_Offset & 0xff;
+               value[7] = (adjust_Y_Offset & 0x0300) >> 8;
+       }
+
        rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
                             USBVISION_OP_CODE, /* USBVISION specific code */
                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0,
@@ -2242,14 +2290,18 @@ static void call_usbvision_power_off(struct work_struct *work)
        struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
 
        PDEBUG(DBG_FUNC, "");
-       down_interruptible(&usbvision->lock);
+       if(mutex_lock_interruptible(&usbvision->lock)) {
+               return;
+       }
+
+
        if(usbvision->user == 0) {
                usbvision_i2c_unregister(usbvision);
 
                usbvision_power_off(usbvision);
                usbvision->initialized = 0;
        }
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 }
 
 static void usbvision_powerOffTimer(unsigned long data)
index 36e689fa16c09f1b0afdbbd25b4a2fbf5f260125..b52b826a30be8b5fb38f03ed38de20dc3e338ee9 100644 (file)
@@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 
        /* If so far no errors then we shall start the camera */
        if (!errCode) {
-               down(&usbvision->lock);
+               mutex_lock(&usbvision->lock);
                if (usbvision->power == 0) {
                        usbvision_power_on(usbvision);
                        usbvision_i2c_register(usbvision);
@@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
                                usbvision->initialized = 0;
                        }
                }
-               up(&usbvision->lock);
+               mutex_unlock(&usbvision->lock);
        }
 
        if (errCode) {
@@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
                (struct usb_usbvision *) video_get_drvdata(dev);
 
        PDEBUG(DBG_IO, "close");
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        usbvision_audio_off(usbvision);
        usbvision_restart_isoc(usbvision);
@@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
                usbvision->initialized = 0;
        }
 
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 
        if (usbvision->remove_pending) {
                printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
@@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
        if ((input >= usbvision->video_inputs) || (input < 0) )
                return -EINVAL;
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
        usbvision_muxsel(usbvision, input);
        usbvision_set_input(usbvision);
        usbvision_set_output(usbvision,
                             usbvision->curwidth,
                             usbvision->curheight);
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
        return 0;
 }
 
@@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
                (struct usb_usbvision *) video_get_drvdata(dev);
        usbvision->tvnormId=*id;
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
        call_i2c_clients(usbvision, VIDIOC_S_STD,
                         &usbvision->tvnormId);
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
        /* propagate the change to the decoder */
        usbvision_muxsel(usbvision, usbvision->ctl_input);
 
@@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
        usbvision->curFrame = NULL;
 
        /* by now we are committed to the new data... */
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
        usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 
        return 0;
 }
@@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 
        PDEBUG(DBG_MMAP, "mmap");
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        if (!USBVISION_IS_OPERATIONAL(usbvision)) {
-               up(&usbvision->lock);
+               mutex_unlock(&usbvision->lock);
                return -EFAULT;
        }
 
        if (!(vma->vm_flags & VM_WRITE) ||
            size != PAGE_ALIGN(usbvision->max_frame_size)) {
-               up(&usbvision->lock);
+               mutex_unlock(&usbvision->lock);
                return -EINVAL;
        }
 
@@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        if (i == usbvision->num_frames) {
                PDEBUG(DBG_MMAP,
                       "mmap: user supplied mapping address is out of range");
-               up(&usbvision->lock);
+               mutex_unlock(&usbvision->lock);
                return -EINVAL;
        }
 
@@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 
                if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
                        PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
-                       up(&usbvision->lock);
+                       mutex_unlock(&usbvision->lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
                size -= PAGE_SIZE;
        }
 
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
        return 0;
 }
 
@@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
 
        PDEBUG(DBG_IO, "%s:", __FUNCTION__);
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        if (usbvision->user) {
                err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
@@ -1290,7 +1290,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
                errCode = usbvision_set_alternate(usbvision);
                if (errCode < 0) {
                        usbvision->last_error = errCode;
-                       return -EBUSY;
+                       errCode = -EBUSY;
+                       goto out;
                }
 
                // If so far no errors then we shall start the radio
@@ -1307,7 +1308,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
                        usbvision->initialized = 0;
                }
        }
-       up(&usbvision->lock);
+out:
+       mutex_unlock(&usbvision->lock);
        return errCode;
 }
 
@@ -1321,7 +1323,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
 
        PDEBUG(DBG_IO, "");
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        /* Set packet size to 0 */
        usbvision->ifaceAlt=0;
@@ -1337,7 +1339,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
                usbvision->initialized = 0;
        }
 
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 
        if (usbvision->remove_pending) {
                printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
@@ -1641,7 +1643,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
 
        usbvision->dev = dev;
 
-       init_MUTEX(&usbvision->lock);   /* to 1 == available */
+       mutex_init(&usbvision->lock);   /* available */
 
        // prepare control urb for control messages during interrupts
        usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
@@ -1649,7 +1651,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
                goto err_exit;
        }
        init_waitqueue_head(&usbvision->ctrlUrb_wq);
-       init_MUTEX(&usbvision->ctrlUrbLock);    /* to 1 == available */
 
        usbvision_init_powerOffTimer(usbvision);
 
@@ -1676,13 +1677,13 @@ static void usbvision_release(struct usb_usbvision *usbvision)
 {
        PDEBUG(DBG_PROBE, "");
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        usbvision_reset_powerOffTimer(usbvision);
 
        usbvision->initialized = 0;
 
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 
        usbvision_remove_sysfs(usbvision->vdev);
        usbvision_unregister_video(usbvision);
@@ -1796,7 +1797,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
        }
        PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        /* compute alternate max packet sizes */
        uif = dev->actconfig->interface[0];
@@ -1807,6 +1808,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
                                              usbvision->num_alt,GFP_KERNEL);
        if (usbvision->alt_max_pkt_size == NULL) {
                err("usbvision: out of memory!\n");
+               mutex_unlock(&usbvision->lock);
                return -ENOMEM;
        }
 
@@ -1840,7 +1842,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
        usbvision->streaming = Stream_Off;
        usbvision_register_video(usbvision);
        usbvision_configure_video(usbvision);
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 
 
        usb_set_intfdata (intf, usbvision);
@@ -1871,7 +1873,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        }
        usb_set_intfdata (intf, NULL);
 
-       down(&usbvision->lock);
+       mutex_lock(&usbvision->lock);
 
        // At this time we ask to cancel outstanding URBs
        usbvision_stop_isoc(usbvision);
@@ -1885,7 +1887,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        usb_put_dev(usbvision->dev);
        usbvision->dev = NULL;  // USB device is no more
 
-       up(&usbvision->lock);
+       mutex_unlock(&usbvision->lock);
 
        if (usbvision->user) {
                printk(KERN_INFO "%s: In use, disconnect pending\n",
index c5b6c501c869fc638dfa6aea3a7bdae7e8833247..20d7ec624999d677037dea1cb5ff26d8345ef71f 100644 (file)
 #include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <linux/videodev2.h>
 
 #define USBVISION_DEBUG                /* Turn on debug messages */
 
-#ifndef VID_HARDWARE_USBVISION
-       #define VID_HARDWARE_USBVISION 34   /* USBVision Video Grabber */
-#endif
-
 #define USBVISION_PWR_REG              0x00
        #define USBVISION_SSPND_EN              (1 << 1)
        #define USBVISION_RES2                  (1 << 2)
@@ -373,7 +370,6 @@ struct usb_usbvision {
        int ctrlUrbBusy;
        struct usb_ctrlrequest ctrlUrbSetup;
        wait_queue_head_t ctrlUrb_wq;                                   // Processes waiting
-       struct semaphore ctrlUrbLock;
 
        /* configuration part */
        int have_tuner;
@@ -396,7 +392,7 @@ struct usb_usbvision {
        unsigned char iface;                                            /* Video interface number */
        unsigned char ifaceAlt;                 /* Alt settings */
        unsigned char Vin_Reg2_Preset;
-       struct semaphore lock;
+       struct mutex               lock;
        struct timer_list powerOffTimer;
        struct work_struct powerOffWork;
        int power;                                                      /* is the device powered on? */
index 1141b4bf41ce059ee69349edeb1ad4fde7315167..c056ff6d810c8e4d18026529d4aa96caad8ba5fa 100644 (file)
@@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = {
 
        [_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
        [_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
-       [_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
+       [_IOC_NR(TUNER_SET_CONFIG)]            = "TUNER_SET_CONFIG",
 
        [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)]     = "VIDIOC_INT_S_TUNER_MODE",
        [_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
@@ -1013,6 +1013,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip)
 
 /* ----------------------------------------------------------------- */
 
+/* Helper function for I2C legacy drivers */
+
+int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
+               const char *name, int (*probe)(struct i2c_client *))
+{
+       struct i2c_client *client;
+       int err;
+
+       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = driver;
+       strlcpy(client->name, name, sizeof(client->name));
+
+       err = probe(client);
+       if (err == 0) {
+               i2c_attach_client(client);
+       } else {
+               kfree(client);
+       }
+       return err != -ENOMEM ? 0 : err;
+}
+
+/* ----------------------------------------------------------------- */
+
 EXPORT_SYMBOL(v4l2_norm_to_name);
 EXPORT_SYMBOL(v4l2_video_std_construct);
 
@@ -1038,6 +1066,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
 EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
 EXPORT_SYMBOL(v4l2_chip_match_host);
 
+EXPORT_SYMBOL(v4l2_i2c_attach);
+
 /*
  * Local variables:
  * c-basic-offset: 8
index 8b4ef530a3a8a60c58013e5a865efaac9776d578..a545dcaf857f72ee646405aeffff9ced4a3fedd8 100644 (file)
@@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void)
                        if (!try_module_get(m->module))
                                continue;
 
-                       if (m->u.master->attach(m, s)) {
+                       s->u.slave->master = m;
+                       if (m->u.master->attach(s)) {
+                               s->u.slave->master = NULL;
                                module_put(m->module);
                                continue;
                        }
-
-                       s->u.slave->master = m;
                }
        }
 }
index c8a5cb57963b07bc75c6be6c75b7fdda4025d8a5..80a14da9acefa939842e9d6806ca5dea99d199c1 100644 (file)
 #include <media/videobuf-core.h>
 
 #define MAGIC_BUFFER 0x20070728
-#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
-       { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+#define MAGIC_CHECK(is, should) do {                                      \
+       if (unlikely((is) != (should))) {                                  \
+       printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
+       BUG(); } } while (0)
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
 MODULE_DESCRIPTION("helper module to manage video4linux buffers");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
-#define dprintk(level, fmt, arg...)    if (debug >= level) \
-       printk(KERN_DEBUG "vbuf: " fmt , ## arg)
+#define dprintk(level, fmt, arg...) do {                       \
+       if (debug >= level)                                     \
+       printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
 
 /* --------------------------------------------------------------------- */
 
 #define CALL(q, f, arg...)                                             \
-       ( (q->int_ops->f)? q->int_ops->f(arg) : 0)
+       ((q->int_ops->f) ? q->int_ops->f(arg) : 0)
 
-void* videobuf_alloc(struct videobuf_queue* q)
+void *videobuf_alloc(struct videobuf_queue *q)
 {
        struct videobuf_buffer *vb;
 
-       BUG_ON (q->msize<sizeof(*vb));
+       BUG_ON(q->msize < sizeof(*vb));
 
        if (!q->int_ops || !q->int_ops->alloc) {
                printk(KERN_ERR "No specific ops defined!\n");
@@ -66,20 +69,21 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
        int retval = 0;
        DECLARE_WAITQUEUE(wait, current);
 
-       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+       MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
        add_wait_queue(&vb->done, &wait);
-       while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
+       while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) {
                if (non_blocking) {
                        retval = -EAGAIN;
                        break;
                }
                set_current_state(intr  ? TASK_INTERRUPTIBLE
                                        : TASK_UNINTERRUPTIBLE);
-               if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
+               if (vb->state == VIDEOBUF_ACTIVE ||
+                   vb->state == VIDEOBUF_QUEUED)
                        schedule();
                set_current_state(TASK_RUNNING);
                if (intr && signal_pending(current)) {
-                       dprintk(1,"buffer waiton: -EINTR\n");
+                       dprintk(1, "buffer waiton: -EINTR\n");
                        retval = -EINTR;
                        break;
                }
@@ -88,27 +92,33 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
        return retval;
 }
 
-int videobuf_iolock(struct videobuf_queueq, struct videobuf_buffer *vb,
+int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
                    struct v4l2_framebuffer *fbuf)
 {
-       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
-          method should be called before _iolock.
+       /* This is required to avoid OOPS on some cases,
+          since mmap_mapper() method should be called before _iolock.
           On some cases, the mmap_mapper() is called only after scheduling.
-
-          However, this way is just too dirty! Better to wait for some event.
         */
-       schedule_timeout(HZ);
+       if (vb->memory == V4L2_MEMORY_MMAP) {
+               wait_event_timeout(vb->done, q->is_mmapped,
+                                  msecs_to_jiffies(100));
+               if (!q->is_mmapped) {
+                       printk(KERN_ERR
+                              "Error: mmap_mapper() never called!\n");
+                       return -EINVAL;
+               }
+       }
 
-       return CALL(q,iolock,q,vb,fbuf);
+       return CALL(q, iolock, q, vb, fbuf);
 }
 
 /* --------------------------------------------------------------------- */
 
 
-void videobuf_queue_core_init(struct videobuf_queueq,
+void videobuf_queue_core_init(struct videobuf_queue *q,
                         struct videobuf_queue_ops *ops,
                         void *dev,
                         spinlock_t *irqlock,
@@ -118,7 +128,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
                         void *priv,
                         struct videobuf_qtype_ops *int_ops)
 {
-       memset(q,0,sizeof(*q));
+       memset(q, 0, sizeof(*q));
        q->irqlock   = irqlock;
        q->dev       = dev;
        q->type      = type;
@@ -129,13 +139,13 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
        q->int_ops   = int_ops;
 
        /* All buffer operations are mandatory */
-       BUG_ON (!q->ops->buf_setup);
-       BUG_ON (!q->ops->buf_prepare);
-       BUG_ON (!q->ops->buf_queue);
-       BUG_ON (!q->ops->buf_release);
+       BUG_ON(!q->ops->buf_setup);
+       BUG_ON(!q->ops->buf_prepare);
+       BUG_ON(!q->ops->buf_queue);
+       BUG_ON(!q->ops->buf_release);
 
        /* Having implementations for abstract methods are mandatory */
-       BUG_ON (!q->int_ops);
+       BUG_ON(!q->int_ops);
 
        mutex_init(&q->lock);
        INIT_LIST_HEAD(&q->stream);
@@ -146,33 +156,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
 {
        int i;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        if (q->streaming) {
-               dprintk(1,"busy: streaming active\n");
+               dprintk(1, "busy: streaming active\n");
                return 1;
        }
        if (q->reading) {
-               dprintk(1,"busy: pending read #1\n");
+               dprintk(1, "busy: pending read #1\n");
                return 1;
        }
        if (q->read_buf) {
-               dprintk(1,"busy: pending read #2\n");
+               dprintk(1, "busy: pending read #2\n");
                return 1;
        }
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
                if (q->bufs[i]->map) {
-                       dprintk(1,"busy: buffer #%d mapped\n",i);
+                       dprintk(1, "busy: buffer #%d mapped\n", i);
                        return 1;
                }
-               if (q->bufs[i]->state == STATE_QUEUED) {
-                       dprintk(1,"busy: buffer #%d queued\n",i);
+               if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
+                       dprintk(1, "busy: buffer #%d queued\n", i);
                        return 1;
                }
-               if (q->bufs[i]->state == STATE_ACTIVE) {
-                       dprintk(1,"busy: buffer #%d avtive\n",i);
+               if (q->bufs[i]->state == VIDEOBUF_ACTIVE) {
+                       dprintk(1, "busy: buffer #%d avtive\n", i);
                        return 1;
                }
        }
@@ -182,28 +192,28 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
 /* Locking: Caller holds q->lock */
 void videobuf_queue_cancel(struct videobuf_queue *q)
 {
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int i;
 
        /* remove queued buffers from list */
        if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
+               spin_lock_irqsave(q->irqlock, flags);
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
-               if (q->bufs[i]->state == STATE_QUEUED) {
+               if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
                        list_del(&q->bufs[i]->queue);
-                       q->bufs[i]->state = STATE_ERROR;
+                       q->bufs[i]->state = VIDEOBUF_ERROR;
                }
        }
        if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
+               spin_unlock_irqrestore(q->irqlock, flags);
 
        /* free all buffers + clear queue */
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
-               q->ops->buf_release(q,q->bufs[i]);
+               q->ops->buf_release(q, q->bufs[i]);
        }
        INIT_LIST_HEAD(&q->stream);
 }
@@ -233,8 +243,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
 static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
                            struct videobuf_buffer *vb, enum v4l2_buf_type type)
 {
-       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        b->index    = vb->i;
        b->type     = type;
@@ -259,17 +269,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
                b->flags |= V4L2_BUF_FLAG_MAPPED;
 
        switch (vb->state) {
-       case STATE_PREPARED:
-       case STATE_QUEUED:
-       case STATE_ACTIVE:
+       case VIDEOBUF_PREPARED:
+       case VIDEOBUF_QUEUED:
+       case VIDEOBUF_ACTIVE:
                b->flags |= V4L2_BUF_FLAG_QUEUED;
                break;
-       case STATE_DONE:
-       case STATE_ERROR:
+       case VIDEOBUF_DONE:
+       case VIDEOBUF_ERROR:
                b->flags |= V4L2_BUF_FLAG_DONE;
                break;
-       case STATE_NEEDS_INIT:
-       case STATE_IDLE:
+       case VIDEOBUF_NEEDS_INIT:
+       case VIDEOBUF_IDLE:
                /* nothing */
                break;
        }
@@ -294,16 +304,20 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
        if (!q)
                return 0;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+
+       rc  = CALL(q, mmap_free, q);
+
+       q->is_mmapped = 0;
 
-       rc  = CALL(q,mmap_free,q);
-       if (rc<0)
+       if (rc < 0)
                return rc;
 
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
-               q->ops->buf_release(q,q->bufs[i]);
+               q->ops->buf_release(q, q->bufs[i]);
                kfree(q->bufs[i]);
                q->bufs[i] = NULL;
        }
@@ -328,7 +342,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
        unsigned int i;
        int err;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        err = __videobuf_mmap_free(q);
        if (0 != err)
@@ -359,7 +373,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
        if (!i)
                return -ENOMEM;
 
-       dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
+       dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
                i, bsize);
 
        return i;
@@ -379,35 +393,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
 int videobuf_reqbufs(struct videobuf_queue *q,
                 struct v4l2_requestbuffers *req)
 {
-       unsigned int size,count;
+       unsigned int size, count;
        int retval;
 
        if (req->count < 1) {
-               dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
+               dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
                return -EINVAL;
        }
 
        if (req->memory != V4L2_MEMORY_MMAP     &&
            req->memory != V4L2_MEMORY_USERPTR  &&
            req->memory != V4L2_MEMORY_OVERLAY) {
-               dprintk(1,"reqbufs: memory type invalid\n");
+               dprintk(1, "reqbufs: memory type invalid\n");
                return -EINVAL;
        }
 
        mutex_lock(&q->lock);
        if (req->type != q->type) {
-               dprintk(1,"reqbufs: queue type invalid\n");
+               dprintk(1, "reqbufs: queue type invalid\n");
                retval = -EINVAL;
                goto done;
        }
 
        if (q->streaming) {
-               dprintk(1,"reqbufs: streaming already exists\n");
+               dprintk(1, "reqbufs: streaming already exists\n");
                retval = -EBUSY;
                goto done;
        }
        if (!list_empty(&q->stream)) {
-               dprintk(1,"reqbufs: stream running\n");
+               dprintk(1, "reqbufs: stream running\n");
                retval = -EBUSY;
                goto done;
        }
@@ -416,14 +430,14 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        if (count > VIDEO_MAX_FRAME)
                count = VIDEO_MAX_FRAME;
        size = 0;
-       q->ops->buf_setup(q,&count,&size);
+       q->ops->buf_setup(q, &count, &size);
        size = PAGE_ALIGN(size);
-       dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
+       dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
                count, size, (count*size)>>PAGE_SHIFT);
 
-       retval = __videobuf_mmap_setup(q,count,size,req->memory);
+       retval = __videobuf_mmap_setup(q, count, size, req->memory);
        if (retval < 0) {
-               dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
+               dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
                goto done;
        }
 
@@ -440,19 +454,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 
        mutex_lock(&q->lock);
        if (unlikely(b->type != q->type)) {
-               dprintk(1,"querybuf: Wrong type.\n");
+               dprintk(1, "querybuf: Wrong type.\n");
                goto done;
        }
        if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
-               dprintk(1,"querybuf: index out of range.\n");
+               dprintk(1, "querybuf: index out of range.\n");
                goto done;
        }
        if (unlikely(NULL == q->bufs[b->index])) {
-               dprintk(1,"querybuf: buffer is null.\n");
+               dprintk(1, "querybuf: buffer is null.\n");
                goto done;
        }
 
-       videobuf_status(q,b,q->bufs[b->index],q->type);
+       videobuf_status(q, b, q->bufs[b->index], q->type);
 
        ret = 0;
 done:
@@ -465,10 +479,10 @@ int videobuf_qbuf(struct videobuf_queue *q,
 {
        struct videobuf_buffer *buf;
        enum v4l2_field field;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        if (b->memory == V4L2_MEMORY_MMAP)
                down_read(&current->mm->mmap_sem);
@@ -476,36 +490,36 @@ int videobuf_qbuf(struct videobuf_queue *q,
        mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->reading) {
-               dprintk(1,"qbuf: Reading running...\n");
+               dprintk(1, "qbuf: Reading running...\n");
                goto done;
        }
        retval = -EINVAL;
        if (b->type != q->type) {
-               dprintk(1,"qbuf: Wrong type.\n");
+               dprintk(1, "qbuf: Wrong type.\n");
                goto done;
        }
        if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
-               dprintk(1,"qbuf: index out of range.\n");
+               dprintk(1, "qbuf: index out of range.\n");
                goto done;
        }
        buf = q->bufs[b->index];
        if (NULL == buf) {
-               dprintk(1,"qbuf: buffer is null.\n");
+               dprintk(1, "qbuf: buffer is null.\n");
                goto done;
        }
-       MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
+       MAGIC_CHECK(buf->magic, MAGIC_BUFFER);
        if (buf->memory != b->memory) {
-               dprintk(1,"qbuf: memory type is wrong.\n");
+               dprintk(1, "qbuf: memory type is wrong.\n");
                goto done;
        }
-       if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
-               dprintk(1,"qbuf: buffer is already queued or active.\n");
+       if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) {
+               dprintk(1, "qbuf: buffer is already queued or active.\n");
                goto done;
        }
 
        if (b->flags & V4L2_BUF_FLAG_INPUT) {
                if (b->input >= q->inputs) {
-                       dprintk(1,"qbuf: wrong input.\n");
+                       dprintk(1, "qbuf: wrong input.\n");
                        goto done;
                }
                buf->input = b->input;
@@ -516,44 +530,46 @@ int videobuf_qbuf(struct videobuf_queue *q,
        switch (b->memory) {
        case V4L2_MEMORY_MMAP:
                if (0 == buf->baddr) {
-                       dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
+                       dprintk(1, "qbuf: mmap requested "
+                                  "but buffer addr is zero!\n");
                        goto done;
                }
                break;
        case V4L2_MEMORY_USERPTR:
                if (b->length < buf->bsize) {
-                       dprintk(1,"qbuf: buffer length is not enough\n");
+                       dprintk(1, "qbuf: buffer length is not enough\n");
                        goto done;
                }
-               if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
-                       q->ops->buf_release(q,buf);
+               if (VIDEOBUF_NEEDS_INIT != buf->state &&
+                   buf->baddr != b->m.userptr)
+                       q->ops->buf_release(q, buf);
                buf->baddr = b->m.userptr;
                break;
        case V4L2_MEMORY_OVERLAY:
                buf->boff = b->m.offset;
                break;
        default:
-               dprintk(1,"qbuf: wrong memory type\n");
+               dprintk(1, "qbuf: wrong memory type\n");
                goto done;
        }
 
-       dprintk(1,"qbuf: requesting next field\n");
+       dprintk(1, "qbuf: requesting next field\n");
        field = videobuf_next_field(q);
-       retval = q->ops->buf_prepare(q,buf,field);
+       retval = q->ops->buf_prepare(q, buf, field);
        if (0 != retval) {
-               dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
+               dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);
                goto done;
        }
 
-       list_add_tail(&buf->stream,&q->stream);
+       list_add_tail(&buf->stream, &q->stream);
        if (q->streaming) {
                if (q->irqlock)
-                       spin_lock_irqsave(q->irqlock,flags);
-               q->ops->buf_queue(q,buf);
+                       spin_lock_irqsave(q->irqlock, flags);
+               q->ops->buf_queue(q, buf);
                if (q->irqlock)
-                       spin_unlock_irqrestore(q->irqlock,flags);
+                       spin_unlock_irqrestore(q->irqlock, flags);
        }
-       dprintk(1,"qbuf: succeded\n");
+       dprintk(1, "qbuf: succeded\n");
        retval = 0;
 
  done:
@@ -571,49 +587,49 @@ int videobuf_dqbuf(struct videobuf_queue *q,
        struct videobuf_buffer *buf;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->reading) {
-               dprintk(1,"dqbuf: Reading running...\n");
+               dprintk(1, "dqbuf: Reading running...\n");
                goto done;
        }
        retval = -EINVAL;
        if (b->type != q->type) {
-               dprintk(1,"dqbuf: Wrong type.\n");
+               dprintk(1, "dqbuf: Wrong type.\n");
                goto done;
        }
        if (list_empty(&q->stream)) {
-               dprintk(1,"dqbuf: stream running\n");
+               dprintk(1, "dqbuf: stream running\n");
                goto done;
        }
        buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
        retval = videobuf_waiton(buf, nonblocking, 1);
        if (retval < 0) {
-               dprintk(1,"dqbuf: waiton returned %d\n",retval);
+               dprintk(1, "dqbuf: waiton returned %d\n", retval);
                goto done;
        }
        switch (buf->state) {
-       case STATE_ERROR:
-               dprintk(1,"dqbuf: state is error\n");
+       case VIDEOBUF_ERROR:
+               dprintk(1, "dqbuf: state is error\n");
                retval = -EIO;
-               CALL(q,sync,q, buf);
-               buf->state = STATE_IDLE;
+               CALL(q, sync, q, buf);
+               buf->state = VIDEOBUF_IDLE;
                break;
-       case STATE_DONE:
-               dprintk(1,"dqbuf: state is done\n");
-               CALL(q,sync,q, buf);
-               buf->state = STATE_IDLE;
+       case VIDEOBUF_DONE:
+               dprintk(1, "dqbuf: state is done\n");
+               CALL(q, sync, q, buf);
+               buf->state = VIDEOBUF_IDLE;
                break;
        default:
-               dprintk(1,"dqbuf: state invalid\n");
+               dprintk(1, "dqbuf: state invalid\n");
                retval = -EINVAL;
                goto done;
        }
        list_del(&buf->stream);
-       memset(b,0,sizeof(*b));
-       videobuf_status(q,b,buf,q->type);
+       memset(b, 0, sizeof(*b));
+       videobuf_status(q, b, buf, q->type);
 
  done:
        mutex_unlock(&q->lock);
@@ -623,7 +639,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
 int videobuf_streamon(struct videobuf_queue *q)
 {
        struct videobuf_buffer *buf;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int retval;
 
        mutex_lock(&q->lock);
@@ -635,12 +651,12 @@ int videobuf_streamon(struct videobuf_queue *q)
                goto done;
        q->streaming = 1;
        if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
+               spin_lock_irqsave(q->irqlock, flags);
        list_for_each_entry(buf, &q->stream, stream)
-               if (buf->state == STATE_PREPARED)
-                       q->ops->buf_queue(q,buf);
+               if (buf->state == VIDEOBUF_PREPARED)
+                       q->ops->buf_queue(q, buf);
        if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
+               spin_unlock_irqrestore(q->irqlock, flags);
 
  done:
        mutex_unlock(&q->lock);
@@ -676,10 +692,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
                                      size_t count, loff_t *ppos)
 {
        enum v4l2_field field;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        /* setup stuff */
        q->read_buf = videobuf_alloc(q);
@@ -691,20 +707,20 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
        q->read_buf->bsize  = count;
 
        field = videobuf_next_field(q);
-       retval = q->ops->buf_prepare(q,q->read_buf,field);
+       retval = q->ops->buf_prepare(q, q->read_buf, field);
        if (0 != retval)
                goto done;
 
        /* start capture & wait */
        if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
-       q->ops->buf_queue(q,q->read_buf);
+               spin_lock_irqsave(q->irqlock, flags);
+       q->ops->buf_queue(q, q->read_buf);
        if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
-       retval = videobuf_waiton(q->read_buf,0,0);
+               spin_unlock_irqrestore(q->irqlock, flags);
+       retval = videobuf_waiton(q->read_buf, 0, 0);
        if (0 == retval) {
-               CALL(q,sync,q,q->read_buf);
-               if (STATE_ERROR == q->read_buf->state)
+               CALL(q, sync, q, q->read_buf);
+               if (VIDEOBUF_ERROR == q->read_buf->state)
                        retval = -EIO;
                else
                        retval = q->read_buf->size;
@@ -712,7 +728,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
 
  done:
        /* cleanup */
-       q->ops->buf_release(q,q->read_buf);
+       q->ops->buf_release(q, q->read_buf);
        kfree(q->read_buf);
        q->read_buf = NULL;
        return retval;
@@ -723,21 +739,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                          int nonblocking)
 {
        enum v4l2_field field;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        unsigned size, nbufs;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        mutex_lock(&q->lock);
 
        nbufs = 1; size = 0;
-       q->ops->buf_setup(q,&nbufs,&size);
+       q->ops->buf_setup(q, &nbufs, &size);
 
        if (NULL == q->read_buf  &&
            count >= size        &&
            !nonblocking) {
-               retval = videobuf_read_zerocopy(q,data,count,ppos);
+               retval = videobuf_read_zerocopy(q, data, count, ppos);
                if (retval >= 0  ||  retval == -EIO)
                        /* ok, all done */
                        goto done;
@@ -749,25 +765,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                retval = -ENOMEM;
                q->read_buf = videobuf_alloc(q);
 
-               dprintk(1,"video alloc=0x%p\n", q->read_buf);
+               dprintk(1, "video alloc=0x%p\n", q->read_buf);
                if (NULL == q->read_buf)
                        goto done;
                q->read_buf->memory = V4L2_MEMORY_USERPTR;
                q->read_buf->bsize = count; /* preferred size */
                field = videobuf_next_field(q);
-               retval = q->ops->buf_prepare(q,q->read_buf,field);
+               retval = q->ops->buf_prepare(q, q->read_buf, field);
 
                if (0 != retval) {
-                       kfree (q->read_buf);
+                       kfree(q->read_buf);
                        q->read_buf = NULL;
                        goto done;
                }
                if (q->irqlock)
-                       spin_lock_irqsave(q->irqlock,flags);
+                       spin_lock_irqsave(q->irqlock, flags);
 
-               q->ops->buf_queue(q,q->read_buf);
+               q->ops->buf_queue(q, q->read_buf);
                if (q->irqlock)
-                       spin_unlock_irqrestore(q->irqlock,flags);
+                       spin_unlock_irqrestore(q->irqlock, flags);
                q->read_off = 0;
        }
 
@@ -776,11 +792,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        if (0 != retval)
                goto done;
 
-       CALL(q,sync,q,q->read_buf);
+       CALL(q, sync, q, q->read_buf);
 
-       if (STATE_ERROR == q->read_buf->state) {
+       if (VIDEOBUF_ERROR == q->read_buf->state) {
                /* catch I/O errors */
-               q->ops->buf_release(q,q->read_buf);
+               q->ops->buf_release(q, q->read_buf);
                kfree(q->read_buf);
                q->read_buf = NULL;
                retval = -EIO;
@@ -788,14 +804,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* Copy to userspace */
-       retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
-       if (retval<0)
+       retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
+       if (retval < 0)
                goto done;
 
        q->read_off += retval;
        if (q->read_off == q->read_buf->size) {
                /* all data copied, cleanup */
-               q->ops->buf_release(q,q->read_buf);
+               q->ops->buf_release(q, q->read_buf);
                kfree(q->read_buf);
                q->read_buf = NULL;
        }
@@ -806,14 +822,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 }
 
 /* Locking: Caller holds q->lock */
-int __videobuf_read_start(struct videobuf_queue *q)
+static int __videobuf_read_start(struct videobuf_queue *q)
 {
        enum v4l2_field field;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        unsigned int count = 0, size = 0;
        int err, i;
 
-       q->ops->buf_setup(q,&count,&size);
+       q->ops->buf_setup(q, &count, &size);
        if (count < 2)
                count = 2;
        if (count > VIDEO_MAX_FRAME)
@@ -828,17 +844,17 @@ int __videobuf_read_start(struct videobuf_queue *q)
 
        for (i = 0; i < count; i++) {
                field = videobuf_next_field(q);
-               err = q->ops->buf_prepare(q,q->bufs[i],field);
+               err = q->ops->buf_prepare(q, q->bufs[i], field);
                if (err)
                        return err;
                list_add_tail(&q->bufs[i]->stream, &q->stream);
        }
        if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
+               spin_lock_irqsave(q->irqlock, flags);
        for (i = 0; i < count; i++)
-               q->ops->buf_queue(q,q->bufs[i]);
+               q->ops->buf_queue(q, q->bufs[i]);
        if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
+               spin_unlock_irqrestore(q->irqlock, flags);
        q->reading = 1;
        return 0;
 }
@@ -859,7 +875,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
        }
        q->read_buf = NULL;
        q->reading  = 0;
-       
+
 }
 
 int videobuf_read_start(struct videobuf_queue *q)
@@ -899,11 +915,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                             int vbihack, int nonblocking)
 {
        int rc, retval;
-       unsigned long flags=0;
+       unsigned long flags = 0;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       dprintk(2,"%s\n",__FUNCTION__);
+       dprintk(2, "%s\n", __FUNCTION__);
        mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->streaming)
@@ -931,8 +947,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                        break;
                }
 
-               if (q->read_buf->state == STATE_DONE) {
-                       rc = CALL (q,copy_stream, q, data + retval, count,
+               if (q->read_buf->state == VIDEOBUF_DONE) {
+                       rc = CALL(q, copy_stream, q, data + retval, count,
                                        retval, vbihack, nonblocking);
                        if (rc < 0) {
                                retval = rc;
@@ -953,10 +969,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                        list_add_tail(&q->read_buf->stream,
                                      &q->stream);
                        if (q->irqlock)
-                               spin_lock_irqsave(q->irqlock,flags);
-                       q->ops->buf_queue(q,q->read_buf);
+                               spin_lock_irqsave(q->irqlock, flags);
+                       q->ops->buf_queue(q, q->read_buf);
                        if (q->irqlock)
-                               spin_unlock_irqrestore(q->irqlock,flags);
+                               spin_unlock_irqrestore(q->irqlock, flags);
                        q->read_buf = NULL;
                }
                if (retval < 0)
@@ -999,8 +1015,8 @@ unsigned int videobuf_poll_stream(struct file *file,
 
        if (0 == rc) {
                poll_wait(file, &buf->done, wait);
-               if (buf->state == STATE_DONE ||
-                   buf->state == STATE_ERROR)
+               if (buf->state == VIDEOBUF_DONE ||
+                   buf->state == VIDEOBUF_ERROR)
                        rc = POLLIN|POLLRDNORM;
        }
        mutex_unlock(&q->lock);
@@ -1012,10 +1028,11 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
 {
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        mutex_lock(&q->lock);
-       retval=CALL(q,mmap_mapper,q,vma);
+       retval = CALL(q, mmap_mapper, q, vma);
+       q->is_mmapped = 1;
        mutex_unlock(&q->lock);
 
        return retval;
@@ -1026,15 +1043,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
                    struct video_mbuf *mbuf, int count)
 {
        struct v4l2_requestbuffers req;
-       int rc,i;
+       int rc, i;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       memset(&req,0,sizeof(req));
+       memset(&req, 0, sizeof(req));
        req.type   = q->type;
        req.count  = count;
        req.memory = V4L2_MEMORY_MMAP;
-       rc = videobuf_reqbufs(q,&req);
+       rc = videobuf_reqbufs(q, &req);
        if (rc < 0)
                return rc;
 
@@ -1079,9 +1096,3 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream);
 EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
 EXPORT_SYMBOL_GPL(videobuf_mmap_free);
 EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 44ee408e145ff51e950c8a152cf44aa073359a1b..98efd7ab1f50a5467c5d543cdbb37573df5f8571 100644 (file)
@@ -385,30 +385,27 @@ videobuf_vm_close(struct vm_area_struct *vma)
  * now ...).  Bounce buffers don't work very well for the data rates
  * video capture has.
  */
-static struct page*
-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
-                  int *type)
+static int
+videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct page *page;
 
-       dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
-               vaddr,vma->vm_start,vma->vm_end);
-       if (vaddr > vma->vm_end)
-               return NOPAGE_SIGBUS;
+       dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n",
+               (unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end);
        page = alloc_page(GFP_USER | __GFP_DMA32);
        if (!page)
-               return NOPAGE_OOM;
-       clear_user_page(page_address(page), vaddr, page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+               return VM_FAULT_OOM;
+       clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
+                       page);
+       vmf->page = page;
+       return 0;
 }
 
 static struct vm_operations_struct videobuf_vm_ops =
 {
        .open     = videobuf_vm_open,
        .close    = videobuf_vm_close,
-       .nopage   = videobuf_vm_nopage,
+       .fault    = videobuf_vm_fault,
 };
 
 /* ---------------------------------------------------------------------
index 880317e04a02ba057462955235910bf109428708..b73aba65d21d00850e7604fbb6b408c7a62879ce 100644 (file)
@@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data)
 
                /* feed buffer data to demux */
                dma=videobuf_to_dma(buf);
-               if (buf->state == STATE_DONE)
+               if (buf->state == VIDEOBUF_DONE)
                        dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
                                         buf->size);
 
index e01259438bb2755bd8bf284554675145282086aa..9b3898347ca54a70e8d016ab428f85526a013285 100644 (file)
@@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
 #define dprintk(level, fmt, arg...)    if (debug >= level) \
-       printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+       printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
 
 
 /***************************************************************************/
index 9611c3990285d45133276f22082ec7c4fb8bf73b..28655f8983c6949386d6bdc6465613256e369423 100644 (file)
@@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                *id = vfd->current_norm;
 
-               dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+               dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
 
                ret=0;
                break;
@@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        {
                v4l2_std_id *id = arg,norm;
 
-               dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+               dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
 
                norm = (*id) & vfd->tvnorms;
                if ( vfd->tvnorms && !norm)     /* Check if std is supported */
@@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                        break;
                ret=vfd->vidioc_querystd(file, fh, arg);
                if (!ret)
-                       dbgarg (cmd, "detected std=%Lu\n",
+                       dbgarg (cmd, "detected std=%08Lx\n",
                                                (unsigned long long)*p);
                break;
        }
@@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                if (!ret)
                        dbgarg (cmd, "index=%d, name=%s, type=%d, "
                                        "audioset=%d, "
-                                       "tuner=%d, std=%Ld, status=%d\n",
+                                       "tuner=%d, std=%08Lx, status=%d\n",
                                        p->index,p->name,p->type,p->audioset,
                                        p->tuner,
                                        (unsigned long long)p->std,
index 9b54ff9d2e36210209d2335489fb5fb1fd901ad6..1db067c028157609c895b0124e72143acd94c8b2 100644 (file)
 #define WAKE_DENOMINATOR 1001
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
-/* These timers are for 1 fps - used only for testing */
-//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */
-//#define BUFFER_TIMEOUT     msecs_to_jiffies(5000)  /* 5 seconds */
-
 #include "font.h"
 
 #define VIVI_MAJOR_VERSION 0
 #define VIVI_MINOR_VERSION 4
 #define VIVI_RELEASE 0
-#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+#define VIVI_VERSION \
+       KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
 
 /* Declare static vars that will be used as parameters */
 static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
-static struct video_device vivi;       /* Video device */
 static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
+static int n_devs = 1;                 /* Number of virtual devices */
 
 /* supported controls */
 static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -71,7 +68,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
                .default_value = 65535,
                .flags         = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
+       }, {
                .id            = V4L2_CID_BRIGHTNESS,
                .type          = V4L2_CTRL_TYPE_INTEGER,
                .name          = "Brightness",
@@ -112,9 +109,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
 
 static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
 
-#define dprintk(level,fmt, arg...)                                     \
+#define dprintk(dev, level, fmt, arg...)                               \
        do {                                                            \
-               if (vivi.debug >= (level))                              \
+               if (dev->vfd->debug >= (level))                         \
                        printk(KERN_DEBUG "vivi: " fmt , ## arg);       \
        } while (0)
 
@@ -166,17 +163,21 @@ struct vivi_dev {
        struct list_head           vivi_devlist;
 
        struct mutex               lock;
+       spinlock_t                 slock;
 
        int                        users;
 
        /* various device info */
-       struct video_device        vfd;
+       struct video_device        *vfd;
 
        struct vivi_dmaqueue       vidq;
 
        /* Several counters */
-       int                        h,m,s,us,jiffies;
+       int                        h, m, s, ms;
+       unsigned long              jiffies;
        char                       timestr[13];
+
+       int                        mv_count;    /* Controls bars movement */
 };
 
 struct vivi_fh {
@@ -184,7 +185,7 @@ struct vivi_fh {
 
        /* video capture */
        struct vivi_fmt            *fmt;
-       unsigned int               width,height;
+       unsigned int               width, height;
        struct videobuf_queue      vb_vidq;
 
        enum v4l2_buf_type         type;
@@ -203,109 +204,113 @@ enum colors {
        GREEN,
        MAGENTA,
        RED,
-       BLUE
+       BLUE,
+       BLACK,
 };
 
 static u8 bars[8][3] = {
        /* R   G   B */
-       {204,204,204},  /* white */
-       {208,208,  0},  /* ambar */
-       {  0,206,206},  /* cyan */
-       {  0,239,  0},  /* green */
-       {239,  0,239},  /* magenta */
-       {205,  0,  0},  /* red */
-       {  0,  0,255},  /* blue */
-       {  0,  0,  0}
+       {204, 204, 204},  /* white */
+       {208, 208,   0},  /* ambar */
+       {  0, 206, 206},  /* cyan */
+       {  0, 239,   0},  /* green */
+       {239,   0, 239},  /* magenta */
+       {205,   0,   0},  /* red */
+       {  0,   0, 255},  /* blue */
+       {  0,   0,   0},  /* black */
 };
 
-#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b  + 32768)>>16)+16)
+#define TO_Y(r, g, b) \
+       (((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
 /* RGB to  V(Cr) Color transform */
-#define TO_V(r,g,b) (((28784*r -24103*g -4681*b  + 32768)>>16)+128)
+#define TO_V(r, g, b) \
+       (((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
 /* RGB to  U(Cb) Color transform */
-#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128)
+#define TO_U(r, g, b) \
+       (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
 #define TSTAMP_MIN_Y 24
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-static void gen_line(char *basep,int inipos,int wmax,
-                    int hmax, int line, int count, char *timestr)
+static void gen_line(char *basep, int inipos, int wmax,
+               int hmax, int line, int count, char *timestr)
 {
-       int  w,i,j,pos=inipos,y;
-       char *p,*s;
-       u8   chr,r,g,b,color;
+       int  w, i, j, y;
+       int pos = inipos;
+       char *p, *s;
+       u8   chr, r, g, b, color;
 
        /* We will just duplicate the second pixel at the packet */
-       wmax/=2;
+       wmax /= 2;
 
        /* Generate a standard color bar pattern */
-       for (w=0;w<wmax;w++) {
-               int colorpos=((w+count)*8/(wmax+1)) % 8;
-               r=bars[colorpos][0];
-               g=bars[colorpos][1];
-               b=bars[colorpos][2];
+       for (w = 0; w < wmax; w++) {
+               int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
+               r = bars[colorpos][0];
+               g = bars[colorpos][1];
+               b = bars[colorpos][2];
 
-               for (color=0;color<4;color++) {
-                       p=basep+pos;
+               for (color = 0; color < 4; color++) {
+                       p = basep + pos;
 
                        switch (color) {
-                               case 0:
-                               case 2:
-                                       *p=TO_Y(r,g,b);         /* Luminance */
-                                       break;
-                               case 1:
-                                       *p=TO_U(r,g,b);         /* Cb */
-                                       break;
-                               case 3:
-                                       *p=TO_V(r,g,b);         /* Cr */
-                                       break;
+                       case 0:
+                       case 2:
+                               *p = TO_Y(r, g, b);     /* Luma */
+                               break;
+                       case 1:
+                               *p = TO_U(r, g, b);     /* Cb */
+                               break;
+                       case 3:
+                               *p = TO_V(r, g, b);     /* Cr */
+                               break;
                        }
                        pos++;
                }
        }
 
        /* Checks if it is possible to show timestamp */
-       if (TSTAMP_MAX_Y>=hmax)
+       if (TSTAMP_MAX_Y >= hmax)
                goto end;
-       if (TSTAMP_MIN_X+strlen(timestr)>=wmax)
+       if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
                goto end;
 
        /* Print stream time */
-       if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) {
-               j=TSTAMP_MIN_X;
-               for (s=timestr;*s;s++) {
-                       chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
-                       for (i=0;i<7;i++) {
-                               if (chr&1<<(7-i)) { /* Font color*/
-                                       r=bars[BLUE][0];
-                                       g=bars[BLUE][1];
-                                       b=bars[BLUE][2];
-                                       r=g=b=0;
-                                       g=198;
-                               } else { /* Background color */
-                                       r=bars[WHITE][0];
-                                       g=bars[WHITE][1];
-                                       b=bars[WHITE][2];
-                                       r=g=b=0;
+       if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
+               j = TSTAMP_MIN_X;
+               for (s = timestr; *s; s++) {
+                       chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
+                       for (i = 0; i < 7; i++) {
+                               if (chr & 1 << (7 - i)) {
+                                       /* Font color*/
+                                       r = 0;
+                                       g = 198;
+                                       b = 0;
+                               } else {
+                                       /* Background color */
+                                       r = bars[BLACK][0];
+                                       g = bars[BLACK][1];
+                                       b = bars[BLACK][2];
                                }
 
-                               pos=inipos+j*2;
-                               for (color=0;color<4;color++) {
-                                       p=basep+pos;
+                               pos = inipos + j * 2;
+                               for (color = 0; color < 4; color++) {
+                                       p = basep + pos;
 
-                                       y=TO_Y(r,g,b);
+                                       y = TO_Y(r, g, b);
 
                                        switch (color) {
-                                               case 0:
-                                               case 2:
-                                                       *p=TO_Y(r,g,b);         /* Luminance */
-                                                       break;
-                                               case 1:
-                                                       *p=TO_U(r,g,b);         /* Cb */
-                                                       break;
-                                               case 3:
-                                                       *p=TO_V(r,g,b);         /* Cr */
-                                                       break;
+                                       case 0:
+                                       case 2:
+                                               *p = TO_Y(r, g, b); /* Luma */
+                                               break;
+                                       case 1:
+                                               *p = TO_U(r, g, b); /* Cb */
+                                               break;
+                                       case 3:
+                                               *p = TO_V(r, g, b); /* Cr */
+                                               break;
                                        }
                                        pos++;
                                }
@@ -314,63 +319,60 @@ static void gen_line(char *basep,int inipos,int wmax,
                }
        }
 
-
 end:
        return;
 }
-static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-       int h,pos=0;
+       int h , pos = 0;
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
        struct timeval ts;
-       char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
-       void *vbuf=videobuf_to_vmalloc (&buf->vb);
-       /* FIXME: move to dev struct */
-       static int mv_count=0;
+       char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL);
+       void *vbuf = videobuf_to_vmalloc(&buf->vb);
 
        if (!tmpbuf)
                return;
 
-       for (h=0;h<hmax;h++) {
-               gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
+       for (h = 0; h < hmax; h++) {
+               gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
                         dev->timestr);
                /* FIXME: replacing to __copy_to_user */
-               if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
-                       dprintk(2,"vivifill copy_to_user failed.\n");
+               if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0)
+                       dprintk(dev, 2, "vivifill copy_to_user failed.\n");
                pos += wmax*2;
        }
 
-       mv_count++;
+       dev->mv_count++;
 
        kfree(tmpbuf);
 
        /* Updates stream time */
 
-       dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
-       dev->jiffies=jiffies;
-       if (dev->us>=1000000) {
-               dev->us-=1000000;
+       dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
+       dev->jiffies = jiffies;
+       if (dev->ms >= 1000) {
+               dev->ms -= 1000;
                dev->s++;
-               if (dev->s>=60) {
-                       dev->s-=60;
+               if (dev->s >= 60) {
+                       dev->s -= 60;
                        dev->m++;
-                       if (dev->m>60) {
-                               dev->m-=60;
+                       if (dev->m > 60) {
+                               dev->m -= 60;
                                dev->h++;
-                               if (dev->h>24)
-                                       dev->h-=24;
+                               if (dev->h > 24)
+                                       dev->h -= 24;
                        }
                }
        }
-       sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
-                       dev->h,dev->m,dev->s,(dev->us+500)/1000);
+       sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
+                       dev->h, dev->m, dev->s, dev->ms);
 
-       dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
-                       (unsigned long)tmpbuf,pos);
+       dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
+                       dev->timestr, (unsigned long)tmpbuf, pos);
 
        /* Advice that buffer was filled */
-       buf->vb.state = STATE_DONE;
+       buf->vb.state = VIDEOBUF_DONE;
        buf->vb.field_count++;
        do_gettimeofday(&ts);
        buf->vb.ts = ts;
@@ -384,14 +386,15 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q);
 static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
 {
        struct vivi_buffer    *buf;
-       struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq);
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
        int bc;
 
+       spin_lock(&dev->slock);
        /* Announces videobuf that all went ok */
        for (bc = 0;; bc++) {
                if (list_empty(&dma_q->active)) {
-                       dprintk(1,"No active queue to serve\n");
+                       dprintk(dev, 1, "No active queue to serve\n");
                        break;
                }
 
@@ -401,65 +404,89 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
                /* Nobody is waiting something to be done, just return */
                if (!waitqueue_active(&buf->vb.done)) {
                        mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+                       spin_unlock(&dev->slock);
                        return;
                }
 
                do_gettimeofday(&buf->vb.ts);
-               dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i);
+               dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
 
                /* Fill buffer */
-               vivi_fillbuff(dev,buf);
+               vivi_fillbuff(dev, buf);
 
                if (list_empty(&dma_q->active)) {
                        del_timer(&dma_q->timeout);
                } else {
-                       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+                       mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT);
                }
        }
        if (bc != 1)
-               dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+               dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
+                       __FUNCTION__, bc);
+       spin_unlock(&dev->slock);
 }
 
+#define frames_to_ms(frames)                                   \
+       ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+
 static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
 {
-       int timeout;
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+       int timeout, running_time;
        DECLARE_WAITQUEUE(wait, current);
 
-       dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
+       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
+               (unsigned long)dma_q);
 
        add_wait_queue(&dma_q->wq, &wait);
-       if (!kthread_should_stop()) {
-               dma_q->frame++;
+       if (kthread_should_stop())
+               goto stop_task;
 
-               /* Calculate time to wake up */
-               timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
+       running_time = jiffies - dma_q->ini_jiffies;
+       dma_q->frame++;
 
-               if (timeout <= 0) {
-                       int old=dma_q->frame;
-                       dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1;
+       /* Calculate time to wake up */
+       timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
 
-                       timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
+       if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
+               int old = dma_q->frame;
+               int nframes;
 
-                       dprintk(1,"underrun, losed %d frames. "
-                                 "Now, frame is %d. Waking on %d jiffies\n",
-                                       dma_q->frame-old,dma_q->frame,timeout);
-               } else
-                       dprintk(1,"will sleep for %i jiffies\n",timeout);
+               dma_q->frame = (jiffies_to_msecs(running_time) /
+                              frames_to_ms(1)) + 1;
 
-               vivi_thread_tick(dma_q);
+               timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
+                         - running_time;
 
-               schedule_timeout_interruptible (timeout);
-       }
+               if (unlikely (timeout <= 0))
+                       timeout = 1;
+
+               nframes = (dma_q->frame > old)?
+                                 dma_q->frame - old : old - dma_q->frame;
+
+               dprintk(dev, 1, "%ld: %s %d frames. "
+                       "Current frame is %d. Will sleep for %d jiffies\n",
+                       jiffies,
+                       (dma_q->frame > old)? "Underrun, losed" : "Overrun of",
+                       nframes, dma_q->frame, timeout);
+       } else
+               dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
 
+       vivi_thread_tick(dma_q);
+
+       schedule_timeout_interruptible(timeout);
+
+stop_task:
        remove_wait_queue(&dma_q->wq, &wait);
        try_to_freeze();
 }
 
 static int vivi_thread(void *data)
 {
-       struct vivi_dmaqueue  *dma_q=data;
+       struct vivi_dmaqueue  *dma_q = data;
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
-       dprintk(1,"thread started\n");
+       dprintk(dev, 1, "thread started\n");
 
        mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
        set_freezable();
@@ -470,16 +497,18 @@ static int vivi_thread(void *data)
                if (kthread_should_stop())
                        break;
        }
-       dprintk(1, "thread: exit\n");
+       dprintk(dev, 1, "thread: exit\n");
        return 0;
 }
 
 static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
 {
-       dma_q->frame=0;
-       dma_q->ini_jiffies=jiffies;
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
-       dprintk(1,"%s\n",__FUNCTION__);
+       dma_q->frame = 0;
+       dma_q->ini_jiffies = jiffies;
+
+       dprintk(dev, 1, "%s\n", __FUNCTION__);
 
        dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
 
@@ -490,39 +519,43 @@ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
        /* Wakes thread */
        wake_up_interruptible(&dma_q->wq);
 
-       dprintk(1,"returning from %s\n",__FUNCTION__);
+       dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
        return 0;
 }
 
 static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
 {
-       dprintk(1,"%s\n",__FUNCTION__);
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+
+       dprintk(dev, 1, "%s\n", __FUNCTION__);
        /* shutdown control thread */
        if (dma_q->kthread) {
                kthread_stop(dma_q->kthread);
-               dma_q->kthread=NULL;
+               dma_q->kthread = NULL;
        }
 }
 
 static int restart_video_queue(struct vivi_dmaqueue *dma_q)
 {
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
        struct vivi_buffer *buf, *prev;
 
-       dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
+       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
+               (unsigned long)dma_q);
 
        if (!list_empty(&dma_q->active)) {
-               buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue);
-               dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+               buf = list_entry(dma_q->active.next,
+                                struct vivi_buffer, vb.queue);
+               dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n",
                        buf, buf->vb.i);
 
-               dprintk(1,"Restarting video dma\n");
+               dprintk(dev, 1, "Restarting video dma\n");
                vivi_stop_thread(dma_q);
-//             vivi_start_thread(dma_q);
 
                /* cancel all outstanding capture / vbi requests */
                list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
                        list_del(&buf->vb.queue);
-                       buf->vb.state = STATE_ERROR;
+                       buf->vb.state = VIDEOBUF_ERROR;
                        wake_up(&buf->vb.done);
                }
                mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
@@ -534,28 +567,31 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
        for (;;) {
                if (list_empty(&dma_q->queued))
                        return 0;
-               buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue);
+               buf = list_entry(dma_q->queued.next,
+                                struct vivi_buffer, vb.queue);
                if (NULL == prev) {
                        list_del(&buf->vb.queue);
-                       list_add_tail(&buf->vb.queue,&dma_q->active);
+                       list_add_tail(&buf->vb.queue, &dma_q->active);
 
-                       dprintk(1,"Restarting video dma\n");
+                       dprintk(dev, 1, "Restarting video dma\n");
                        vivi_stop_thread(dma_q);
                        vivi_start_thread(dma_q);
 
-                       buf->vb.state = STATE_ACTIVE;
+                       buf->vb.state = VIDEOBUF_ACTIVE;
                        mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-                       dprintk(2,"[%p/%d] restart_queue - first active\n",
-                               buf,buf->vb.i);
+                       dprintk(dev, 2,
+                               "[%p/%d] restart_queue - first active\n",
+                               buf, buf->vb.i);
 
                } else if (prev->vb.width  == buf->vb.width  &&
                           prev->vb.height == buf->vb.height &&
                           prev->fmt       == buf->fmt) {
                        list_del(&buf->vb.queue);
-                       list_add_tail(&buf->vb.queue,&dma_q->active);
-                       buf->vb.state = STATE_ACTIVE;
-                       dprintk(2,"[%p/%d] restart_queue - move to active\n",
-                               buf,buf->vb.i);
+                       list_add_tail(&buf->vb.queue, &dma_q->active);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       dprintk(dev, 2,
+                               "[%p/%d] restart_queue - move to active\n",
+                               buf, buf->vb.i);
                } else {
                        return 0;
                }
@@ -565,19 +601,23 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
 
 static void vivi_vid_timeout(unsigned long data)
 {
-       struct vivi_dev      *dev  = (struct vivi_dev*)data;
+       struct vivi_dev      *dev  = (struct vivi_dev *)data;
        struct vivi_dmaqueue *vidq = &dev->vidq;
        struct vivi_buffer   *buf;
 
+       spin_lock(&dev->slock);
+
        while (!list_empty(&vidq->active)) {
-               buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue);
+               buf = list_entry(vidq->active.next,
+                                struct vivi_buffer, vb.queue);
                list_del(&buf->vb.queue);
-               buf->vb.state = STATE_ERROR;
+               buf->vb.state = VIDEOBUF_ERROR;
                wake_up(&buf->vb.done);
-               printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
+               printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
        }
-
        restart_video_queue(vidq);
+
+       spin_unlock(&dev->slock);
 }
 
 /* ------------------------------------------------------------------
@@ -586,7 +626,8 @@ static void vivi_vid_timeout(unsigned long data)
 static int
 buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
 {
-       struct vivi_fh *fh = vq->priv_data;
+       struct vivi_fh  *fh = vq->priv_data;
+       struct vivi_dev *dev  = fh->dev;
 
        *size = fh->width*fh->height*2;
 
@@ -596,21 +637,25 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        while (*size * *count > vid_limit * 1024 * 1024)
                (*count)--;
 
-       dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
+       dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
+               *count, *size);
 
        return 0;
 }
 
 static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
-       dprintk(1,"%s\n",__FUNCTION__);
+       struct vivi_fh  *fh = vq->priv_data;
+       struct vivi_dev *dev  = fh->dev;
+
+       dprintk(dev, 1, "%s\n", __FUNCTION__);
 
        if (in_interrupt())
                BUG();
 
-       videobuf_waiton(&buf->vb,0,0);
+       videobuf_waiton(&buf->vb, 0, 0);
        videobuf_vmalloc_free(&buf->vb);
-       buf->vb.state = STATE_NEEDS_INIT;
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 #define norm_maxw() 1024
@@ -620,10 +665,11 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                                                enum v4l2_field field)
 {
        struct vivi_fh     *fh  = vq->priv_data;
-       struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
+       struct vivi_dev    *dev = fh->dev;
+       struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
        int rc, init_buffer = 0;
 
-       dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+       dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
 
        BUG_ON(NULL == fh->fmt);
        if (fh->width  < 48 || fh->width  > norm_maxw() ||
@@ -644,75 +690,81 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                init_buffer = 1;
        }
 
-       if (STATE_NEEDS_INIT == buf->vb.state) {
-               if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc < 0)
                        goto fail;
        }
 
-       buf->vb.state = STATE_PREPARED;
+       buf->vb.state = VIDEOBUF_PREPARED;
 
        return 0;
 
 fail:
-       free_buffer(vq,buf);
+       free_buffer(vq, buf);
        return rc;
 }
 
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-       struct vivi_buffer    *buf     = container_of(vb,struct vivi_buffer,vb);
-       struct vivi_fh        *fh      = vq->priv_data;
-       struct vivi_dev       *dev     = fh->dev;
-       struct vivi_dmaqueue  *vidq    = &dev->vidq;
+       struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
+       struct vivi_fh        *fh   = vq->priv_data;
+       struct vivi_dev       *dev  = fh->dev;
+       struct vivi_dmaqueue  *vidq = &dev->vidq;
        struct vivi_buffer    *prev;
 
        if (!list_empty(&vidq->queued)) {
-               dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue);
-               list_add_tail(&buf->vb.queue,&vidq->queued);
-               buf->vb.state = STATE_QUEUED;
-               dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
+               dprintk(dev, 1, "adding vb queue=0x%08lx\n",
+                       (unsigned long)&buf->vb.queue);
+               list_add_tail(&buf->vb.queue, &vidq->queued);
+               buf->vb.state = VIDEOBUF_QUEUED;
+               dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n",
                        buf, buf->vb.i);
        } else if (list_empty(&vidq->active)) {
-               list_add_tail(&buf->vb.queue,&vidq->active);
+               list_add_tail(&buf->vb.queue, &vidq->active);
 
-               buf->vb.state = STATE_ACTIVE;
+               buf->vb.state = VIDEOBUF_ACTIVE;
                mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
-               dprintk(2,"[%p/%d] buffer_queue - first active\n",
+               dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n",
                        buf, buf->vb.i);
 
                vivi_start_thread(vidq);
        } else {
-               prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue);
+               prev = list_entry(vidq->active.prev,
+                                 struct vivi_buffer, vb.queue);
                if (prev->vb.width  == buf->vb.width  &&
                    prev->vb.height == buf->vb.height &&
                    prev->fmt       == buf->fmt) {
-                       list_add_tail(&buf->vb.queue,&vidq->active);
-                       buf->vb.state = STATE_ACTIVE;
-                       dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+                       list_add_tail(&buf->vb.queue, &vidq->active);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       dprintk(dev, 2,
+                               "[%p/%d] buffer_queue - append to active\n",
                                buf, buf->vb.i);
 
                } else {
-                       list_add_tail(&buf->vb.queue,&vidq->queued);
-                       buf->vb.state = STATE_QUEUED;
-                       dprintk(2,"[%p/%d] buffer_queue - first queued\n",
+                       list_add_tail(&buf->vb.queue, &vidq->queued);
+                       buf->vb.state = VIDEOBUF_QUEUED;
+                       dprintk(dev, 2,
+                               "[%p/%d] buffer_queue - first queued\n",
                                buf, buf->vb.i);
                }
        }
 }
 
-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_release(struct videobuf_queue *vq,
+                          struct videobuf_buffer *vb)
 {
-       struct vivi_buffer   *buf  = container_of(vb,struct vivi_buffer,vb);
+       struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
        struct vivi_fh       *fh   = vq->priv_data;
-       struct vivi_dev      *dev  = (struct vivi_dev*)fh->dev;
+       struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
        struct vivi_dmaqueue *vidq = &dev->vidq;
 
-       dprintk(1,"%s\n",__FUNCTION__);
+       dprintk(dev, 1, "%s\n", __FUNCTION__);
 
        vivi_stop_thread(vidq);
 
-       free_buffer(vq,buf);
+       free_buffer(vq, buf);
 }
 
 static struct videobuf_queue_ops vivi_video_qops = {
@@ -725,7 +777,7 @@ static struct videobuf_queue_ops vivi_video_qops = {
 /* ------------------------------------------------------------------
        IOCTL vidioc handling
    ------------------------------------------------------------------*/
-static int vidioc_querycap (struct file *file, void  *priv,
+static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *cap)
 {
        strcpy(cap->driver, "vivi");
@@ -737,21 +789,21 @@ static int vidioc_querycap (struct file *file, void  *priv,
        return 0;
 }
 
-static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
        if (f->index > 0)
                return -EINVAL;
 
-       strlcpy(f->description,format.name,sizeof(f->description));
+       strlcpy(f->description, format.name, sizeof(f->description));
        f->pixelformat = format.fourcc;
        return 0;
 }
 
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh *fh = priv;
 
        f->fmt.pix.width        = fh->width;
        f->fmt.pix.height       = fh->height;
@@ -765,26 +817,29 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
        return (0);
 }
 
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
+       struct vivi_fh  *fh  = priv;
+       struct vivi_dev *dev = fh->dev;
        struct vivi_fmt *fmt;
        enum v4l2_field field;
        unsigned int maxw, maxh;
 
        if (format.fourcc != f->fmt.pix.pixelformat) {
-               dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
-                       "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
+               dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
+                       "Driver accepts only 0x%08x\n",
+                       f->fmt.pix.pixelformat, format.fourcc);
                return -EINVAL;
        }
-       fmt=&format;
+       fmt = &format;
 
        field = f->fmt.pix.field;
 
        if (field == V4L2_FIELD_ANY) {
-               field=V4L2_FIELD_INTERLACED;
+               field = V4L2_FIELD_INTERLACED;
        } else if (V4L2_FIELD_INTERLACED != field) {
-               dprintk(1,"Field type invalid.\n");
+               dprintk(dev, 1, "Field type invalid.\n");
                return -EINVAL;
        }
 
@@ -810,11 +865,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
 }
 
 /*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
-       struct vivi_fh  *fh=priv;
-       int ret = vidioc_try_fmt_cap(file,fh,f);
+       struct vivi_fh  *fh = priv;
+       int ret = vidioc_try_fmt_cap(file, fh, f);
        if (ret < 0)
                return (ret);
 
@@ -827,47 +882,48 @@ static int vidioc_s_fmt_cap (struct file *file, void *priv,
        return (0);
 }
 
-static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh  *fh = priv;
 
        return (videobuf_reqbufs(&fh->vb_vidq, p));
 }
 
-static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh  *fh = priv;
 
        return (videobuf_querybuf(&fh->vb_vidq, p));
 }
 
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh *fh = priv;
 
        return (videobuf_qbuf(&fh->vb_vidq, p));
 }
 
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh  *fh = priv;
 
        return (videobuf_dqbuf(&fh->vb_vidq, p,
                                file->f_flags & O_NONBLOCK));
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh  *fh = priv;
 
-       return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
+       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
 }
 #endif
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh  *fh = priv;
 
        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -879,7 +935,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-       struct vivi_fh  *fh=priv;
+       struct vivi_fh  *fh = priv;
 
        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -889,32 +945,32 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        return videobuf_streamoff(&fh->vb_vidq);
 }
 
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
        return 0;
 }
 
 /* only one input in this sample driver */
-static int vidioc_enum_input (struct file *file, void *priv,
+static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *inp)
 {
        if (inp->index != 0)
                return -EINVAL;
 
        inp->type = V4L2_INPUT_TYPE_CAMERA;
-       inp->std = V4L2_STD_NTSC_M;
-       strcpy(inp->name,"Camera");
+       inp->std = V4L2_STD_525_60;
+       strcpy(inp->name, "Camera");
 
        return (0);
 }
 
-static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
        *i = 0;
 
        return (0);
 }
-static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
        if (i > 0)
                return -EINVAL;
@@ -923,8 +979,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
 }
 
        /* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl (struct file *file, void *priv,
-                               struct v4l2_queryctrl *qc)
+static int vidioc_queryctrl(struct file *file, void *priv,
+                           struct v4l2_queryctrl *qc)
 {
        int i;
 
@@ -938,33 +994,31 @@ static int vidioc_queryctrl (struct file *file, void *priv,
        return -EINVAL;
 }
 
-static int vidioc_g_ctrl (struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *ctrl)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
                if (ctrl->id == vivi_qctrl[i].id) {
-                       ctrl->value=qctl_regs[i];
+                       ctrl->value = qctl_regs[i];
                        return (0);
                }
 
        return -EINVAL;
 }
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
                if (ctrl->id == vivi_qctrl[i].id) {
-                       if (ctrl->value <
-                               vivi_qctrl[i].minimum
-                               || ctrl->value >
-                               vivi_qctrl[i].maximum) {
+                       if (ctrl->value < vivi_qctrl[i].minimum
+                           || ctrl->value > vivi_qctrl[i].maximum) {
                                        return (-ERANGE);
                                }
-                       qctl_regs[i]=ctrl->value;
+                       qctl_regs[i] = ctrl->value;
                        return (0);
                }
        return -EINVAL;
@@ -983,24 +1037,22 @@ static int vivi_open(struct inode *inode, struct file *file)
        struct vivi_fh *fh;
        int i;
 
-       printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
+       printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
 
        list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
-               if (dev->vfd.minor == minor)
+               if (dev->vfd->minor == minor)
                        goto found;
        return -ENODEV;
-found:
-
-
 
+found:
        /* If more than one user, mutex should be added */
        dev->users++;
 
-       dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+       dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
                v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
 
        /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
        if (NULL == fh) {
                dev->users--;
                return -ENOMEM;
@@ -1016,27 +1068,21 @@ found:
 
        /* Put all controls at a sane state */
        for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-               qctl_regs[i] =vivi_qctrl[i].default_value;
-
-       dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
-               (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
-       dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued));
-       dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active));
+               qctl_regs[i] = vivi_qctrl[i].default_value;
 
        /* Resets frame counters */
-       dev->h=0;
-       dev->m=0;
-       dev->s=0;
-       dev->us=0;
-       dev->jiffies=jiffies;
-       sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
-                       dev->h,dev->m,dev->s,(dev->us+500)/1000);
+       dev->h = 0;
+       dev->m = 0;
+       dev->s = 0;
+       dev->ms = 0;
+       dev->mv_count = 0;
+       dev->jiffies = jiffies;
+       sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
+                       dev->h, dev->m, dev->s, dev->ms);
 
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
-                       NULL, NULL,
-                       fh->type,
-                       V4L2_FIELD_INTERLACED,
-                       sizeof(struct vivi_buffer),fh);
+                       NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
+                       sizeof(struct vivi_buffer), fh);
 
        return 0;
 }
@@ -1044,9 +1090,9 @@ found:
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-       struct vivi_fh        *fh = file->private_data;
+       struct vivi_fh *fh = file->private_data;
 
-       if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
                                        file->f_flags & O_NONBLOCK);
        }
@@ -1057,9 +1103,10 @@ static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct vivi_fh        *fh = file->private_data;
+       struct vivi_dev       *dev = fh->dev;
        struct videobuf_queue *q = &fh->vb_vidq;
 
-       dprintk(1,"%s\n",__FUNCTION__);
+       dprintk(dev, 1, "%s\n", __FUNCTION__);
 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
                return POLLERR;
@@ -1067,7 +1114,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
        return videobuf_poll_stream(file, q, wait);
 }
 
-static int vivi_release(struct inode *inode, struct file *file)
+static int vivi_close(struct inode *inode, struct file *file)
 {
        struct vivi_fh         *fh = file->private_data;
        struct vivi_dev *dev       = fh->dev;
@@ -1079,26 +1126,48 @@ static int vivi_release(struct inode *inode, struct file *file)
        videobuf_stop(&fh->vb_vidq);
        videobuf_mmap_free(&fh->vb_vidq);
 
-       kfree (fh);
+       kfree(fh);
 
        dev->users--;
 
-       printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users);
+       dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
+               minor, dev->users);
 
        return 0;
 }
 
-static int
-vivi_mmap(struct file *file, struct vm_area_struct * vma)
+static int vivi_release(void)
 {
-       struct vivi_fh        *fh = file->private_data;
+       struct vivi_dev *dev;
+       struct list_head *list;
+
+       while (!list_empty(&vivi_devlist)) {
+               list = vivi_devlist.next;
+               list_del(list);
+               dev = list_entry(list, struct vivi_dev, vivi_devlist);
+
+               if (-1 != dev->vfd->minor)
+                       video_unregister_device(dev->vfd);
+               else
+                       video_device_release(dev->vfd);
+
+               kfree(dev);
+       }
+
+       return 0;
+}
+
+static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct vivi_fh  *fh = file->private_data;
+       struct vivi_dev *dev = fh->dev;
        int ret;
 
-       dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
+       dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-       ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
-       dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n",
+       dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
                (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
                ret);
@@ -1109,7 +1178,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma)
 static const struct file_operations vivi_fops = {
        .owner          = THIS_MODULE,
        .open           = vivi_open,
-       .release        = vivi_release,
+       .release        = vivi_close,
        .read           = vivi_read,
        .poll           = vivi_poll,
        .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
@@ -1117,12 +1186,12 @@ static const struct file_operations vivi_fops = {
        .llseek         = no_llseek,
 };
 
-static struct video_device vivi = {
+static struct video_device vivi_template = {
        .name           = "vivi",
        .type           = VID_TYPE_CAPTURE,
        .fops           = &vivi_fops,
        .minor          = -1,
-//     .release        = video_device_release,
+       .release        = video_device_release,
 
        .vidioc_querycap      = vidioc_querycap,
        .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
@@ -1145,7 +1214,7 @@ static struct video_device vivi = {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf          = vidiocgmbuf,
 #endif
-       .tvnorms              = V4L2_STD_NTSC_M,
+       .tvnorms              = V4L2_STD_525_60,
        .current_norm         = V4L2_STD_NTSC_M,
 };
 /* -----------------------------------------------------------------
@@ -1154,43 +1223,61 @@ static struct video_device vivi = {
 
 static int __init vivi_init(void)
 {
-       int ret;
+       int ret = -ENOMEM, i;
        struct vivi_dev *dev;
+       struct video_device *vfd;
 
-       dev = kzalloc(sizeof(*dev),GFP_KERNEL);
-       if (NULL == dev)
-               return -ENOMEM;
-       list_add_tail(&dev->vivi_devlist,&vivi_devlist);
+       for (i = 0; i < n_devs; i++) {
+               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+               if (NULL == dev)
+                       break;
 
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-       init_waitqueue_head(&dev->vidq.wq);
+               list_add_tail(&dev->vivi_devlist, &vivi_devlist);
 
-       /* initialize locks */
-       mutex_init(&dev->lock);
+               /* init video dma queues */
+               INIT_LIST_HEAD(&dev->vidq.active);
+               INIT_LIST_HEAD(&dev->vidq.queued);
+               init_waitqueue_head(&dev->vidq.wq);
 
-       dev->vidq.timeout.function = vivi_vid_timeout;
-       dev->vidq.timeout.data     = (unsigned long)dev;
-       init_timer(&dev->vidq.timeout);
+               /* initialize locks */
+               mutex_init(&dev->lock);
+               spin_lock_init(&dev->slock);
 
-       ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
-       printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
+               dev->vidq.timeout.function = vivi_vid_timeout;
+               dev->vidq.timeout.data     = (unsigned long)dev;
+               init_timer(&dev->vidq.timeout);
+
+               vfd = video_device_alloc();
+               if (NULL == vfd)
+                       break;
+
+               *vfd = vivi_template;
+
+               ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+               if (ret < 0)
+                       break;
+
+               snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
+                        vivi_template.name, vfd->minor);
+
+               if (video_nr >= 0)
+                       video_nr++;
+
+               dev->vfd = vfd;
+       }
+
+       if (ret < 0) {
+               vivi_release();
+               printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
+       } else
+               printk(KERN_INFO "Video Technology Magazine Virtual Video "
+                                "Capture Board successfully loaded.\n");
        return ret;
 }
 
 static void __exit vivi_exit(void)
 {
-       struct vivi_dev *h;
-       struct list_head *list;
-
-       while (!list_empty(&vivi_devlist)) {
-               list = vivi_devlist.next;
-               list_del(list);
-               h = list_entry(list, struct vivi_dev, vivi_devlist);
-               kfree (h);
-       }
-       video_unregister_device(&vivi);
+       vivi_release();
 }
 
 module_init(vivi_init);
@@ -1201,10 +1288,13 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
 MODULE_LICENSE("Dual BSD/GPL");
 
 module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "video iminor start number");
 
-module_param_named(debug,vivi.debug, int, 0644);
-MODULE_PARM_DESC(debug,"activates debug info");
+module_param(n_devs, int, 0);
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
 
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+module_param_named(debug, vivi_template.debug, int, 0444);
+MODULE_PARM_DESC(debug, "activates debug info");
 
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
index 63002e0ac764d51064d42492fe025e967995348f..282c81403c976a2c1ecfefc693e9019aa24613b0 100644 (file)
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("vp27smpx driver");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
 
@@ -53,28 +50,26 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
        u8 data[3] = { 0x00, 0x00, 0x04 };
 
        switch (audmode) {
-               case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_LANG1:
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       data[1] = 0x01;
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       data[1] = 0x02;
-                       break;
+       case V4L2_TUNER_MODE_MONO:
+       case V4L2_TUNER_MODE_LANG1:
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               data[1] = 0x01;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               data[1] = 0x02;
+               break;
        }
 
-       if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
-               v4l_err(client, "%s: I/O error setting audmode\n", client->name);
-       }
-       else {
+       if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
+               v4l_err(client, "%s: I/O error setting audmode\n",
+                               client->name);
+       else
                state->audmode = audmode;
-       }
 }
 
-static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
-                         void *arg)
+static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct vp27smpx_state *state = i2c_get_clientdata(client);
        struct v4l2_tuner *vt = arg;
@@ -103,7 +98,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
+               return v4l2_chip_ident_i2c_client(client, arg,
+                               V4L2_IDENT_VP27SMPX, 0);
 
        case VIDIOC_LOG_STATUS:
                v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
@@ -125,88 +121,43 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
+static int vp27smpx_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct vp27smpx_state *state;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
        snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
-       if (state == NULL) {
-               kfree(client);
+       if (state == NULL)
                return -ENOMEM;
-       }
        state->audmode = V4L2_TUNER_MODE_STEREO;
        i2c_set_clientdata(client, state);
 
        /* initialize vp27smpx */
        vp27smpx_set_audmode(client, state->audmode);
-       i2c_attach_client(client);
-
        return 0;
 }
 
-static int vp27smpx_probe(struct i2c_adapter *adapter)
+static int vp27smpx_remove(struct i2c_client *client)
 {
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, vp27smpx_attach);
-       return 0;
-}
-
-static int vp27smpx_detach(struct i2c_client *client)
-{
-       struct vp27smpx_state *state = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-       kfree(state);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "vp27smpx",
-       },
-       .id             = I2C_DRIVERID_VP27SMPX,
-       .attach_adapter = vp27smpx_probe,
-       .detach_client  = vp27smpx_detach,
-       .command        = vp27smpx_command,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "vp27smpx",
+       .driverid = I2C_DRIVERID_VP27SMPX,
+       .command = vp27smpx_command,
+       .probe = vp27smpx_probe,
+       .remove = vp27smpx_remove,
 };
 
-
-static int __init vp27smpx_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit vp27smpx_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(vp27smpx_init_module);
-module_exit(vp27smpx_cleanup_module);
index 1bf4cbec6a87a7a738a7334db4dbfd4104d6ac8b..31795b4f8b6316e2e480ac838a53d52840660de4 100644 (file)
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("wm8739 driver");
 MODULE_AUTHOR("T. Adachi, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
-static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END };
+static int debug;
 
 module_param(debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 
-I2C_CLIENT_INSMOD;
-
 /* ------------------------------------------------------------------------ */
 
 enum {
@@ -75,12 +73,10 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val)
 
        v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
 
-       for (i = 0; i < 3; i++) {
-               if (i2c_smbus_write_byte_data(client, (reg << 1) |
-                                       (val >> 8), val & 0xff) == 0) {
+       for (i = 0; i < 3; i++)
+               if (i2c_smbus_write_byte_data(client,
+                               (reg << 1) | (val >> 8), val & 0xff) == 0)
                        return 0;
-               }
-       }
        v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
@@ -167,7 +163,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
                .default_value = 58880,
                .flags         = 0,
                .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
+       }, {
                .id            = V4L2_CID_AUDIO_MUTE,
                .name          = "Mute",
                .minimum       = 0,
@@ -176,7 +172,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
                .default_value = 1,
                .flags         = 0,
                .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
+       }, {
                .id            = V4L2_CID_AUDIO_BALANCE,
                .name          = "Balance",
                .minimum       = 0,
@@ -190,7 +186,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
 
 /* ------------------------------------------------------------------------ */
 
-static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct wm8739_state *state = i2c_get_clientdata(client);
 
@@ -200,21 +196,26 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
                u32 audiofreq = *(u32 *)arg;
 
                state->clock_freq = audiofreq;
-               wm8739_write(client, R9, 0x000);        /* de-activate */
+               /* de-activate */
+               wm8739_write(client, R9, 0x000);
                switch (audiofreq) {
                case 44100:
-                       wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k     */
+                       /* 256fps, fs=44.1k */
+                       wm8739_write(client, R8, 0x020);
                        break;
                case 48000:
-                       wm8739_write(client, R8, 0x000); /* 256fps, fs=48k       */
+                       /* 256fps, fs=48k */
+                       wm8739_write(client, R8, 0x000);
                        break;
                case 32000:
-                       wm8739_write(client, R8, 0x018); /* 256fps, fs=32k       */
+                       /* 256fps, fs=32k */
+                       wm8739_write(client, R8, 0x018);
                        break;
                default:
                        break;
                }
-               wm8739_write(client, R9, 0x001);        /* activate */
+               /* activate */
+               wm8739_write(client, R9, 0x001);
                break;
        }
 
@@ -238,7 +239,8 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
        }
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0);
+               return v4l2_chip_ident_i2c_client(client,
+                               arg, V4L2_IDENT_WM8739, 0);
 
        case VIDIOC_LOG_STATUS:
                v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
@@ -259,27 +261,16 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
 
 /* i2c implementation */
 
-static struct i2c_driver i2c_driver;
-
-static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
+static int wm8739_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct wm8739_state *state;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == NULL)
-               return -ENOMEM;
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
-       snprintf(client->name, sizeof(client->name) - 1, "wm8739");
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
        if (state == NULL) {
@@ -295,67 +286,37 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
        state->clock_freq = 48000;
        i2c_set_clientdata(client, state);
 
-       /* initialize wm8739 */
-       wm8739_write(client, R15, 0x00); /* reset */
-       wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */
-       wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */
-       wm8739_write(client, R7, 0x049); /* Digital Audio interface format */
-                                        /* Enable Master mode */
-                                        /* 24 bit, MSB first/left justified */
-       wm8739_write(client, R8, 0x000); /* sampling control */
-                                        /* normal, 256fs, 48KHz sampling rate */
-       wm8739_write(client, R9, 0x001); /* activate */
-       wm8739_set_audio(client);        /* set volume/mute */
-
-       i2c_attach_client(client);
-
-       return 0;
-}
-
-static int wm8739_probe(struct i2c_adapter *adapter)
-{
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, wm8739_attach);
+       /* Initialize wm8739 */
+
+       /* reset */
+       wm8739_write(client, R15, 0x00);
+       /* filter setting, high path, offet clear */
+       wm8739_write(client, R5, 0x000);
+       /* ADC, OSC, Power Off mode Disable */
+       wm8739_write(client, R6, 0x000);
+       /* Digital Audio interface format:
+          Enable Master mode, 24 bit, MSB first/left justified */
+       wm8739_write(client, R7, 0x049);
+       /* sampling control: normal, 256fs, 48KHz sampling rate */
+       wm8739_write(client, R8, 0x000);
+       /* activate */
+       wm8739_write(client, R9, 0x001);
+       /* set volume/mute */
+       wm8739_set_audio(client);
        return 0;
 }
 
-static int wm8739_detach(struct i2c_client *client)
+static int wm8739_remove(struct i2c_client *client)
 {
-       struct wm8739_state *state = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err)
-               return err;
-
-       kfree(state);
-       kfree(client);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "wm8739",
-       },
-       .id = I2C_DRIVERID_WM8739,
-       .attach_adapter = wm8739_probe,
-       .detach_client  = wm8739_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "wm8739",
+       .driverid = I2C_DRIVERID_WM8739,
        .command = wm8739_command,
+       .probe = wm8739_probe,
+       .remove = wm8739_remove,
 };
 
-
-static int __init wm8739_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit wm8739_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(wm8739_init_module);
-module_exit(wm8739_cleanup_module);
index 9f7e894ef962cdc4d76baec111aacb99fa700261..869f9e7946b6082bb9df221ccc056d13e808e0d9 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
 
 I2C_CLIENT_INSMOD;
 
+
 /* ----------------------------------------------------------------------- */
 
 enum {
@@ -66,18 +68,15 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
                return -1;
        }
 
-       for (i = 0; i < 3; i++) {
-               if (i2c_smbus_write_byte_data(client, (reg << 1) |
-                                       (val >> 8), val & 0xff) == 0) {
+       for (i = 0; i < 3; i++)
+               if (i2c_smbus_write_byte_data(client,
+                               (reg << 1) | (val >> 8), val & 0xff) == 0)
                        return 0;
-               }
-       }
        v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
 
-static int wm8775_command(struct i2c_client *client, unsigned int cmd,
-                         void *arg)
+static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct wm8775_state *state = i2c_get_clientdata(client);
        struct v4l2_routing *route = arg;
@@ -126,7 +125,8 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0);
+               return v4l2_chip_ident_i2c_client(client,
+                               arg, V4L2_IDENT_WM8775, 0);
 
        case VIDIOC_LOG_STATUS:
                v4l_info(client, "Input: %d%s\n", state->input,
@@ -159,105 +159,67 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
+static int wm8775_probe(struct i2c_client *client)
 {
-       struct i2c_client *client;
        struct wm8775_state *state;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
-               return -ENOMEM;
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver;
-       snprintf(client->name, sizeof(client->name) - 1, "wm8775");
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
-       if (state == NULL) {
-               kfree(client);
+       if (state == NULL)
                return -ENOMEM;
-       }
        state->input = 2;
        state->muted = 0;
        i2c_set_clientdata(client, state);
 
-       /* initialize wm8775 */
-       wm8775_write(client, R23, 0x000);       /* RESET */
-       wm8775_write(client, R7, 0x000);        /* Disable zero cross detect timeout */
-       wm8775_write(client, R11, 0x021);       /* Left justified, 24-bit mode */
-       wm8775_write(client, R12, 0x102);       /* Master mode, clock ratio 256fs */
-       wm8775_write(client, R13, 0x000);       /* Powered up */
-       wm8775_write(client, R14, 0x1d4);       /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(client, R15, 0x1d4);       /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(client, R16, 0x1bf);       /* ALC Stereo, ALC target level -1dB FS */
-       /* max gain +8dB */
-       wm8775_write(client, R17, 0x185);       /* Enable gain control, use zero cross */
-       /* detection, ALC hold time 42.6 ms */
-       wm8775_write(client, R18, 0x0a2);       /* ALC gain ramp up delay 34 s, */
-       /* ALC gain ramp down delay 33 ms */
-       wm8775_write(client, R19, 0x005);       /* Enable noise gate, threshold -72dBfs */
-       wm8775_write(client, R20, 0x07a);       /* Transient window 4ms, lower PGA gain */
-       /* limit -1dB */
-       wm8775_write(client, R21, 0x102);       /* LRBOTH = 1, use input 2. */
-       i2c_attach_client(client);
-
+       /* Initialize wm8775 */
+
+       /* RESET */
+       wm8775_write(client, R23, 0x000);
+       /* Disable zero cross detect timeout */
+       wm8775_write(client, R7, 0x000);
+       /* Left justified, 24-bit mode */
+       wm8775_write(client, R11, 0x021);
+       /* Master mode, clock ratio 256fs */
+       wm8775_write(client, R12, 0x102);
+       /* Powered up */
+       wm8775_write(client, R13, 0x000);
+       /* ADC gain +2.5dB, enable zero cross */
+       wm8775_write(client, R14, 0x1d4);
+       /* ADC gain +2.5dB, enable zero cross */
+       wm8775_write(client, R15, 0x1d4);
+       /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
+       wm8775_write(client, R16, 0x1bf);
+       /* Enable gain control, use zero cross detection,
+          ALC hold time 42.6 ms */
+       wm8775_write(client, R17, 0x185);
+       /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
+       wm8775_write(client, R18, 0x0a2);
+       /* Enable noise gate, threshold -72dBfs */
+       wm8775_write(client, R19, 0x005);
+       /* Transient window 4ms, lower PGA gain limit -1dB */
+       wm8775_write(client, R20, 0x07a);
+       /* LRBOTH = 1, use input 2. */
+       wm8775_write(client, R21, 0x102);
        return 0;
 }
 
-static int wm8775_probe(struct i2c_adapter *adapter)
+static int wm8775_remove(struct i2c_client *client)
 {
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adapter, &addr_data, wm8775_attach);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static int wm8775_detach(struct i2c_client *client)
-{
-       struct wm8775_state *state = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-       kfree(state);
-       kfree(client);
-
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-       .driver = {
-               .name = "wm8775",
-       },
-       .id             = I2C_DRIVERID_WM8775,
-       .attach_adapter = wm8775_probe,
-       .detach_client  = wm8775_detach,
-       .command        = wm8775_command,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "wm8775",
+       .driverid = I2C_DRIVERID_WM8775,
+       .command = wm8775_command,
+       .probe = wm8775_probe,
+       .remove = wm8775_remove,
 };
 
-
-static int __init wm8775_init_module(void)
-{
-       return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit wm8775_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver);
-}
-
-module_init(wm8775_init_module);
-module_exit(wm8775_cleanup_module);
index 6f1892585cbbac304eae05df4324fb6931c7f58b..1fdbb46de7f3ed94760b3dce16c963909b25e285 100644 (file)
@@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 
-static struct file_operations zr364xx_fops = {
+static const struct file_operations zr364xx_fops = {
        .owner = THIS_MODULE,
        .open = zr364xx_open,
        .release = zr364xx_release,
index 52fb216dfe7448ee0c5dbdfdac3db24c4787db2f..425f60c21fddb19c44d0821fdafe0b663a3d2bda 100644 (file)
@@ -2056,7 +2056,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                                ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                                                    "mpt_upload:  alt_%s has cached_fw=%p \n",
                                                    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
-                                               ioc->alt_ioc->cached_fw = NULL;
+                                               ioc->cached_fw = NULL;
                                        }
                                } else {
                                        printk(MYIOC_s_WARN_FMT
@@ -2262,10 +2262,12 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
        int ret;
 
        if (ioc->cached_fw != NULL) {
-               ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
-                   "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
-               if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
-                       printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
+                   "adapter\n", __FUNCTION__, ioc->name));
+               if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
+                   ioc->cached_fw, CAN_SLEEP)) < 0) {
+                       printk(MYIOC_s_WARN_FMT
+                           ": firmware downloadboot failure (%d)!\n",
                            ioc->name, ret);
                }
        }
@@ -2303,13 +2305,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
                ioc->alloc_total -= sz;
        }
 
-       if (ioc->cached_fw != NULL) {
-               sz = ioc->facts.FWImageSize;
-               pci_free_consistent(ioc->pcidev, sz,
-                       ioc->cached_fw, ioc->cached_fw_dma);
-               ioc->cached_fw = NULL;
-               ioc->alloc_total -= sz;
-       }
+       mpt_free_fw_memory(ioc);
 
        kfree(ioc->spi_data.nvram);
        mpt_inactive_raid_list_free(ioc);
@@ -3047,44 +3043,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
  *
  *     If memory has already been allocated, the same (cached) value
  *     is returned.
- */
-void
+ *
+ *     Return 0 if successfull, or non-zero for failure
+ **/
+int
 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
 {
-       if (ioc->cached_fw)
-               return;  /* use already allocated memory */
-       if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
+       int rc;
+
+       if (ioc->cached_fw) {
+               rc = 0;  /* use already allocated memory */
+               goto out;
+       }
+       else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
                ioc->cached_fw = ioc->alt_ioc->cached_fw;  /* use alt_ioc's memory */
                ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
-               ioc->alloc_total += size;
-               ioc->alt_ioc->alloc_total -= size;
+               rc = 0;
+               goto out;
+       }
+       ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
+       if (!ioc->cached_fw) {
+               printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
+                   ioc->name);
+               rc = -1;
        } else {
-               if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
-                       ioc->alloc_total += size;
+               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+                   ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
+               ioc->alloc_total += size;
+               rc = 0;
        }
+ out:
+       return rc;
 }
+
 /**
  *     mpt_free_fw_memory - free firmware memory
  *     @ioc: Pointer to MPT_ADAPTER structure
  *
  *     If alt_img is NULL, delete from ioc structure.
  *     Else, delete a secondary image in same format.
- */
+ **/
 void
 mpt_free_fw_memory(MPT_ADAPTER *ioc)
 {
        int sz;
 
+       if (!ioc->cached_fw)
+               return;
+
        sz = ioc->facts.FWImageSize;
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-           ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+                ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
        pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
+       ioc->alloc_total -= sz;
        ioc->cached_fw = NULL;
-
-       return;
 }
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
@@ -3116,17 +3130,12 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        if ((sz = ioc->facts.FWImageSize) == 0)
                return 0;
 
-       mpt_alloc_fw_memory(ioc, sz);
+       if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
+               return -ENOMEM;
 
        dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
            ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
 
-       if (ioc->cached_fw == NULL) {
-               /* Major Failure.
-                */
-               return -ENOMEM;
-       }
-
        prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
            kzalloc(ioc->req_sz, GFP_KERNEL);
        if (!prequest) {
@@ -3498,12 +3507,12 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
 static int
 mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 {
-       MPT_ADAPTER     *iocp=NULL;
        u32 diag0val;
        u32 doorbell;
        int hard_reset_done = 0;
        int count = 0;
        u32 diag1val = 0;
+       MpiFwHeader_t *cached_fw;       /* Pointer to FW */
 
        /* Clear any existing interrupts */
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -3635,22 +3644,24 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                }
 
                if (ioc->cached_fw)
-                       iocp = ioc;
+                       cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
                else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
-                       iocp = ioc->alt_ioc;
-               if (iocp) {
+                       cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
+               else
+                       cached_fw = NULL;
+               if (cached_fw) {
                        /* If the DownloadBoot operation fails, the
                         * IOC will be left unusable. This is a fatal error
                         * case.  _diag_reset will return < 0
                         */
                        for (count = 0; count < 30; count ++) {
-                               diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
+                               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
                                if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
                                        break;
                                }
 
                                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
-                                       iocp->name, diag0val, count));
+                                       ioc->name, diag0val, count));
                                /* wait 1 sec */
                                if (sleepFlag == CAN_SLEEP) {
                                        msleep (1000);
@@ -3658,8 +3669,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                        mdelay (1000);
                                }
                        }
-                       if ((count = mpt_downloadboot(ioc,
-                               (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
+                       if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
                                printk(MYIOC_s_WARN_FMT
                                        "firmware downloadboot failure (%d)!\n", ioc->name, count);
                        }
index d7682e083f590c8ca39a49a346797300cff02f7e..b49b706c002035e3ae42e69a53c7d3646cc6702c 100644 (file)
@@ -907,7 +907,7 @@ extern u32   mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void     mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
 extern int      mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int      mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
-extern void     mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
+extern int      mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
 extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int      mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int      mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
index e4c94f93de16a98462518419c923bb24f24d9414..f77b329f6923baab6e4b23742981b97b58393046 100644 (file)
@@ -1343,6 +1343,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
                memcpy(req->sense, smprep, sizeof(*smprep));
                req->sense_len = sizeof(*smprep);
+               req->data_len = 0;
+               rsp->data_len -= smprep->ResponseDataLength;
        } else {
                printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
                    ioc->name, __FUNCTION__);
index 626bb3c9af2b0d6614d2313753b4c9796e64bb5e..5c614ec38cc494da6671db10a964302cca993127 100644 (file)
@@ -111,7 +111,7 @@ int                 mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
 int            mptscsih_resume(struct pci_dev *pdev);
 #endif
 
-#define SNS_LEN(scp)   sizeof((scp)->sense_buffer)
+#define SNS_LEN(scp)   SCSI_SENSE_BUFFERSIZE
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
index aa6fb9429d58a06f84621324d682c7b25f9edf36..1bcdbbb9e7d39853015153cab1a4315a4f23c832 100644 (file)
@@ -370,7 +370,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
         */
        if (cmd->result)
                memcpy(cmd->sense_buffer, &msg->body[3],
-                      min(sizeof(cmd->sense_buffer), (size_t) 40));
+                      min(SCSI_SENSE_BUFFERSIZE, 40));
 
        /* only output error code if AdapterStatus is not HBA_SUCCESS */
        if ((error >> 8) & 0xff)
index e325fa71f38ba2ad05ebfdb923f4b4c9b3227e11..b7c8e78138653c33611ed98d8d58973454a7ab27 100644 (file)
@@ -20,7 +20,8 @@
 #include "ucb1x00.h"
 
 #define UCB1X00_ATTR(name,input)\
-static ssize_t name##_show(struct class_device *dev, char *buf)        \
+static ssize_t name##_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)   \
 {                                                              \
        struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);         \
        int val;                                                \
@@ -29,7 +30,7 @@ static ssize_t name##_show(struct class_device *dev, char *buf)       \
        ucb1x00_adc_disable(ucb);                               \
        return sprintf(buf, "%d\n", val);                       \
 }                                                              \
-static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
+static DEVICE_ATTR(name,0444,name##_show,NULL)
 
 UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
 UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
@@ -37,17 +38,17 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
 
 static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
 {
-       class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt);
-       class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger);
-       class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
+       device_create_file(&dev->ucb->dev, &device_attr_vbatt);
+       device_create_file(&dev->ucb->dev, &device_attr_vcharger);
+       device_create_file(&dev->ucb->dev, &device_attr_batt_temp);
        return 0;
 }
 
 static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
 {
-       class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
-       class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger);
-       class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt);
+       device_remove_file(&dev->ucb->cdev, &device_attr_batt_temp);
+       device_remove_file(&dev->ucb->cdev, &device_attr_vcharger);
+       device_remove_file(&dev->ucb->cdev, &device_attr_vbatt);
 }
 
 static struct ucb1x00_driver ucb1x00_assabet_driver = {
index e03f1bcd4f9f2621be307cba72b35b3ac4df75dd..f6b10dda31fdfd3f09bc070446956b1113b61f3f 100644 (file)
@@ -458,7 +458,7 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
        return probe_irq_off(mask);
 }
 
-static void ucb1x00_release(struct class_device *dev)
+static void ucb1x00_release(struct device *dev)
 {
        struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
        kfree(ucb);
@@ -466,7 +466,7 @@ static void ucb1x00_release(struct class_device *dev)
 
 static struct class ucb1x00_class = {
        .name           = "ucb1x00",
-       .release        = ucb1x00_release,
+       .dev_release    = ucb1x00_release,
 };
 
 static int ucb1x00_probe(struct mcp *mcp)
@@ -490,9 +490,9 @@ static int ucb1x00_probe(struct mcp *mcp)
                goto err_disable;
 
 
-       ucb->cdev.class = &ucb1x00_class;
-       ucb->cdev.dev = &mcp->attached_device;
-       strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
+       ucb->dev.class = &ucb1x00_class;
+       ucb->dev.parent = &mcp->attached_device;
+       strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id));
 
        spin_lock_init(&ucb->lock);
        spin_lock_init(&ucb->io_lock);
@@ -517,7 +517,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 
        mcp_set_drvdata(mcp, ucb);
 
-       ret = class_device_register(&ucb->cdev);
+       ret = device_register(&ucb->dev);
        if (ret)
                goto err_irq;
 
@@ -554,7 +554,7 @@ static void ucb1x00_remove(struct mcp *mcp)
        mutex_unlock(&ucb1x00_mutex);
 
        free_irq(ucb->irq, ucb);
-       class_device_unregister(&ucb->cdev);
+       device_unregister(&ucb->dev);
 }
 
 int ucb1x00_register_driver(struct ucb1x00_driver *drv)
index ca8df8072d433ff77b04218dbb81c00f1e0e029d..a8ad8a0ed5dbbf0f763cf2e900ada34e55311daf 100644 (file)
@@ -120,7 +120,7 @@ struct ucb1x00 {
        u16                     irq_fal_enbl;
        u16                     irq_ris_enbl;
        struct ucb1x00_irq      irq_handler[16];
-       struct class_device     cdev;
+       struct device           dev;
        struct list_head        node;
        struct list_head        devs;
 };
@@ -144,7 +144,7 @@ struct ucb1x00_driver {
        int     (*resume)(struct ucb1x00_dev *dev);
 };
 
-#define classdev_to_ucb1x00(cd)        container_of(cd, struct ucb1x00, cdev)
+#define classdev_to_ucb1x00(cd)        container_of(cd, struct ucb1x00, dev)
 
 int ucb1x00_register_driver(struct ucb1x00_driver *);
 void ucb1x00_unregister_driver(struct ucb1x00_driver *);
index 6497872df524167e6121d6aca87b8ea2d58281e9..1a0e7978226a6b593e048e31ef00e4e40dd13d41 100644 (file)
 #include "lowlevel.h"
 
 static void exec_next_command(struct service_processor *sp);
-static void free_command(struct kobject *kobj);
-
-static struct kobj_type ibmasm_cmd_kobj_type = {
-       .release = free_command,
-};
 
 static atomic_t command_count = ATOMIC_INIT(0);
 
@@ -53,8 +48,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
        }
        cmd->buffer_size = buffer_size;
 
-       kobject_init(&cmd->kobj);
-       cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
+       kref_init(&cmd->kref);
        cmd->lock = &sp->lock;
 
        cmd->status = IBMASM_CMD_PENDING;
@@ -67,9 +61,9 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
        return cmd;
 }
 
-static void free_command(struct kobject *kobj)
+void ibmasm_free_command(struct kref *kref)
 {
-       struct command *cmd = to_command(kobj);
+       struct command *cmd = to_command(kref);
 
        list_del(&cmd->queue_node);
        atomic_dec(&command_count);
index de860bc6d3f5eb51ea57e210e98e4446b606640d..4d8a4e248b345aec3a2ce128d425f60add73856a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/kref.h>
 #include <linux/device.h>
 #include <linux/input.h>
 
@@ -92,24 +93,25 @@ struct command {
        unsigned char           *buffer;
        size_t                  buffer_size;
        int                     status;
-       struct kobject          kobj;
+       struct kref             kref;
        spinlock_t              *lock;
 };
-#define to_command(c) container_of(c, struct command, kobj)
+#define to_command(c) container_of(c, struct command, kref)
 
+void ibmasm_free_command(struct kref *kref);
 static inline void command_put(struct command *cmd)
 {
        unsigned long flags;
        spinlock_t *lock = cmd->lock;
 
        spin_lock_irqsave(lock, flags);
-       kobject_put(&cmd->kobj);
+       kref_put(&cmd->kref, ibmasm_free_command);
        spin_unlock_irqrestore(lock, flags);
 }
 
 static inline void command_get(struct command *cmd)
 {
-       kobject_get(&cmd->kobj);
+       kref_get(&cmd->kref);
 }
 
 
index 2d1b3df95c5bfbb138f5d0c509fe33345dc2a7b4..54380da343a530ab4a4513eef7501d9e52b6d487 100644 (file)
@@ -149,7 +149,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
        socket_change_set = fm->socket_change_set;
        fm->socket_change_set = 0;
 
-       dev_dbg(fm->cdev.dev, "checking media set %x\n",
+       dev_dbg(fm->dev.parent, "checking media set %x\n",
                socket_change_set);
 
        if (!socket_change_set) {
@@ -164,7 +164,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
                if (sock) {
                        printk(KERN_INFO
                               "%s : demand removing card from socket %u:%u\n",
-                              fm->cdev.class_id, fm->id, cnt);
+                              fm->dev.bus_id, fm->id, cnt);
                        fm->sockets[cnt] = NULL;
                        sock_addr = sock->addr;
                        spin_unlock_irqrestore(&fm->lock, flags);
index 8f77949f93dd879097604fcc817122bfcef60fbc..97544052e7684dda18611c356ca65eab5d9da839 100644 (file)
@@ -160,16 +160,16 @@ static struct bus_type tifm_bus_type = {
        .resume    = tifm_device_resume
 };
 
-static void tifm_free(struct class_device *cdev)
+static void tifm_free(struct device *dev)
 {
-       struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
+       struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
 
        kfree(fm);
 }
 
 static struct class tifm_adapter_class = {
        .name    = "tifm_adapter",
-       .release = tifm_free
+       .dev_release = tifm_free
 };
 
 struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
@@ -180,9 +180,9 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
        fm = kzalloc(sizeof(struct tifm_adapter)
                     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
        if (fm) {
-               fm->cdev.class = &tifm_adapter_class;
-               fm->cdev.dev = dev;
-               class_device_initialize(&fm->cdev);
+               fm->dev.class = &tifm_adapter_class;
+               fm->dev.parent = dev;
+               device_initialize(&fm->dev);
                spin_lock_init(&fm->lock);
                fm->num_sockets = num_sockets;
        }
@@ -203,8 +203,8 @@ int tifm_add_adapter(struct tifm_adapter *fm)
        if (rc)
                return rc;
 
-       snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
-       rc = class_device_add(&fm->cdev);
+       snprintf(fm->dev.bus_id, BUS_ID_SIZE, "tifm%u", fm->id);
+       rc = device_add(&fm->dev);
        if (rc) {
                spin_lock(&tifm_adapter_lock);
                idr_remove(&tifm_adapter_idr, fm->id);
@@ -228,13 +228,13 @@ void tifm_remove_adapter(struct tifm_adapter *fm)
        spin_lock(&tifm_adapter_lock);
        idr_remove(&tifm_adapter_idr, fm->id);
        spin_unlock(&tifm_adapter_lock);
-       class_device_del(&fm->cdev);
+       device_del(&fm->dev);
 }
 EXPORT_SYMBOL(tifm_remove_adapter);
 
 void tifm_free_adapter(struct tifm_adapter *fm)
 {
-       class_device_put(&fm->cdev);
+       put_device(&fm->dev);
 }
 EXPORT_SYMBOL(tifm_free_adapter);
 
@@ -261,9 +261,9 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
                sock->card_event = tifm_dummy_event;
                sock->data_event = tifm_dummy_event;
 
-               sock->dev.parent = fm->cdev.dev;
+               sock->dev.parent = fm->dev.parent;
                sock->dev.bus = &tifm_bus_type;
-               sock->dev.dma_mask = fm->cdev.dev->dma_mask;
+               sock->dev.dma_mask = fm->dev.parent->dma_mask;
                sock->dev.release = tifm_free_device;
 
                snprintf(sock->dev.bus_id, BUS_ID_SIZE,
index a9eb1c516247ef5b69104682bb20e208877041cd..1707f98c322c589c144b59d19cd9a52cbb22377a 100644 (file)
@@ -1504,9 +1504,12 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        int ret, wbufsize, word_gap, words;
        const struct kvec *vec;
        unsigned long vec_seek;
+       unsigned long initial_adr;
+       int initial_len = len;
 
        wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        adr += chip->start;
+       initial_adr = adr;
        cmd_adr = adr & ~(wbufsize-1);
 
        /* Let's determine this according to the interleave only once */
@@ -1519,7 +1522,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                return ret;
        }
 
-       XIP_INVAL_CACHED_RANGE(map, adr, len);
+       XIP_INVAL_CACHED_RANGE(map, initial_adr, initial_len);
        ENABLE_VPP(map);
        xip_disable(map, chip, cmd_adr);
 
@@ -1610,7 +1613,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        chip->state = FL_WRITING;
 
        ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
-                                  adr, len,
+                                  initial_adr, initial_len,
                                   chip->buffer_write_time);
        if (ret) {
                map_write(map, CMD(0x70), cmd_adr);
index 22ed96c4b7bd75a7bedd4a9936f78f9094a7a95a..a0cee86464cae51646b148939d49b6c61b8725a1 100644 (file)
@@ -27,12 +27,10 @@ static void mtd_notify_add(struct mtd_info* mtd)
        if (!mtd)
                return;
 
-       class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
-                           NULL, "mtd%d", mtd->index);
+       device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index);
 
-       class_device_create(mtd_class, NULL,
-                           MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
-                           NULL, "mtd%dro", mtd->index);
+       device_create(mtd_class, NULL,
+                     MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index);
 }
 
 static void mtd_notify_remove(struct mtd_info* mtd)
@@ -40,8 +38,8 @@ static void mtd_notify_remove(struct mtd_info* mtd)
        if (!mtd)
                return;
 
-       class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
-       class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
+       device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
+       device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
 }
 
 static struct mtd_notifier notifier = {
index edda6e10ebe50144304316737f2e9884197c16bf..8fafac987e0bea25df8b53d562a4b8dbc19c763a 100644 (file)
@@ -385,6 +385,7 @@ static int __init el3_probe(int card_idx)
 #if defined(__ISAPNP__)
        static int pnp_cards;
        struct pnp_dev *idev = NULL;
+       int pnp_found = 0;
 
        if (nopnp == 1)
                goto no_pnp;
@@ -430,6 +431,7 @@ __again:
                        pnp_cards++;
 
                        netdev_boot_setup_check(dev);
+                       pnp_found = 1;
                        goto found;
                }
        }
@@ -560,6 +562,8 @@ no_pnp:
        lp = netdev_priv(dev);
 #if defined(__ISAPNP__)
        lp->dev = &idev->dev;
+       if (pnp_found)
+               lp->type = EL3_PNP;
 #endif
        err = el3_common_init(dev);
 
index 275e7510ebaf64a67e2835f1adbdfc978cadc1a5..684bab7810156998f3fd366b27ac1b645d5169e7 100644 (file)
@@ -243,14 +243,16 @@ enum eeprom_offset {
 enum Window3 {                 /* Window 3: MAC/config bits. */
        Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
 };
-union wn3_config {
-       int i;
-       struct w3_config_fields {
-               unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
-               int pad8:8;
-               unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
-               int pad24:7;
-       } u;
+enum wn3_config {
+       Ram_size = 7,
+       Ram_width = 8,
+       Ram_speed = 0x30,
+       Rom_size = 0xc0,
+       Ram_split_shift = 16,
+       Ram_split = 3 << Ram_split_shift,
+       Xcvr_shift = 20,
+       Xcvr = 7 << Xcvr_shift,
+       Autoselect = 0x1000000,
 };
 
 enum Window4 {
@@ -614,7 +616,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
        /* Read the station address from the EEPROM. */
        EL3WINDOW(0);
        for (i = 0; i < 0x18; i++) {
-               short *phys_addr = (short *) dev->dev_addr;
+               __be16 *phys_addr = (__be16 *) dev->dev_addr;
                int timer;
                outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
                /* Pause for at least 162 us. for the read to take place. */
@@ -646,22 +648,22 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
 
        {
                char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
-               union wn3_config config;
+               __u32 config;
                EL3WINDOW(3);
                vp->available_media = inw(ioaddr + Wn3_Options);
-               config.i = inl(ioaddr + Wn3_Config);
+               config = inl(ioaddr + Wn3_Config);
                if (corkscrew_debug > 1)
                        printk(KERN_INFO "  Internal config register is %4.4x, transceivers %#x.\n",
-                               config.i, inw(ioaddr + Wn3_Options));
+                               config, inw(ioaddr + Wn3_Options));
                printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-                       8 << config.u.ram_size,
-                       config.u.ram_width ? "word" : "byte",
-                       ram_split[config.u.ram_split],
-                       config.u.autoselect ? "autoselect/" : "",
-                       media_tbl[config.u.xcvr].name);
-               dev->if_port = config.u.xcvr;
-               vp->default_media = config.u.xcvr;
-               vp->autoselect = config.u.autoselect;
+                       8 << config & Ram_size,
+                       config & Ram_width ? "word" : "byte",
+                       ram_split[(config & Ram_split) >> Ram_split_shift],
+                       config & Autoselect ? "autoselect/" : "",
+                       media_tbl[(config & Xcvr) >> Xcvr_shift].name);
+               vp->default_media = (config & Xcvr) >> Xcvr_shift;
+               vp->autoselect = config & Autoselect ? 1 : 0;
+               dev->if_port = vp->default_media;
        }
        if (vp->media_override != 7) {
                printk(KERN_INFO "  Media override to transceiver type %d (%s).\n",
@@ -694,14 +696,14 @@ static int corkscrew_open(struct net_device *dev)
 {
        int ioaddr = dev->base_addr;
        struct corkscrew_private *vp = netdev_priv(dev);
-       union wn3_config config;
+       __u32 config;
        int i;
 
        /* Before initializing select the active media port. */
        EL3WINDOW(3);
        if (vp->full_duplex)
                outb(0x20, ioaddr + Wn3_MAC_Ctrl);      /* Set the full-duplex bit. */
-       config.i = inl(ioaddr + Wn3_Config);
+       config = inl(ioaddr + Wn3_Config);
 
        if (vp->media_override != 7) {
                if (corkscrew_debug > 1)
@@ -727,12 +729,12 @@ static int corkscrew_open(struct net_device *dev)
        } else
                dev->if_port = vp->default_media;
 
-       config.u.xcvr = dev->if_port;
-       outl(config.i, ioaddr + Wn3_Config);
+       config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
+       outl(config, ioaddr + Wn3_Config);
 
        if (corkscrew_debug > 1) {
                printk("%s: corkscrew_open() InternalConfig %8.8x.\n",
-                      dev->name, config.i);
+                      dev->name, config);
        }
 
        outw(TxReset, ioaddr + EL3_CMD);
@@ -901,7 +903,7 @@ static void corkscrew_timer(unsigned long data)
                        ok = 1;
                }
                if (!ok) {
-                       union wn3_config config;
+                       __u32 config;
 
                        do {
                                dev->if_port =
@@ -928,9 +930,9 @@ static void corkscrew_timer(unsigned long data)
                             ioaddr + Wn4_Media);
 
                        EL3WINDOW(3);
-                       config.i = inl(ioaddr + Wn3_Config);
-                       config.u.xcvr = dev->if_port;
-                       outl(config.i, ioaddr + Wn3_Config);
+                       config = inl(ioaddr + Wn3_Config);
+                       config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
+                       outl(config, ioaddr + Wn3_Config);
 
                        outw(dev->if_port == 3 ? StartCoax : StopCoax,
                             ioaddr + EL3_CMD);
index d9107e542dface363ef53d71339361d99f7619de..9af05a2f4af3c433064b245b2aa383d761d99d4e 100644 (file)
@@ -166,16 +166,6 @@ config NET_SB1000
 
          If you don't have this card, of course say N.
 
-config IP1000
-       tristate "IP1000 Gigabit Ethernet support"
-       depends on PCI && EXPERIMENTAL
-       select MII
-       ---help---
-         This driver supports IP1000 gigabit Ethernet cards.
-
-         To compile this driver as a module, choose M here: the module
-         will be called ipg.  This is recommended.
-
 source "drivers/net/arcnet/Kconfig"
 
 source "drivers/net/phy/Kconfig"
@@ -1986,12 +1976,19 @@ config E1000E
 
          <http://support.intel.com>
 
-         More specific information on configuring the driver is in
-         <file:Documentation/networking/e1000e.txt>.
-
          To compile this driver as a module, choose M here. The module
          will be called e1000e.
 
+config IP1000
+       tristate "IP1000 Gigabit Ethernet support"
+       depends on PCI && EXPERIMENTAL
+       select MII
+       ---help---
+         This driver supports IP1000 gigabit Ethernet cards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ipg.  This is recommended.
+
 source "drivers/net/ixp2000/Kconfig"
 
 config MYRI_SBUS
@@ -2468,9 +2465,6 @@ config IXGBE
 
          <http://support.intel.com>
 
-         More specific information on configuring the driver is in
-         <file:Documentation/networking/ixgbe.txt>.
-
          To compile this driver as a module, choose M here. The module
          will be called ixgbe.
 
index 35b0a7dd4ef465cca27f5619d1f98965f99b83bc..9200ee59d854aba57ab2e845c2d31bb44f07c5d1 100644 (file)
@@ -120,7 +120,7 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
        struct atl1_hw *hw = &adapter->hw;
        struct net_device *netdev = adapter->netdev;
 
-       hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+       hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
        hw->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
        adapter->wol = 0;
@@ -688,7 +688,7 @@ static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct atl1_adapter *adapter = netdev_priv(netdev);
        int old_mtu = netdev->mtu;
-       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
 
        if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
            (max_frame > MAX_JUMBO_FRAME_SIZE)) {
@@ -853,8 +853,8 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
        /* set Interrupt Clear Timer */
        iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER);
 
-       /* set MTU, 4 : VLAN */
-       iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU);
+       /* set max frame size hw will accept */
+       iowrite32(hw->max_frame_size, hw->hw_addr + REG_MTU);
 
        /* jumbo size & rrd retirement timer */
        value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
index 25b8dbf6cfd73c0193fd12add9da4d4906956926..b57bc9467dbe7a22d1c609fffa1ca5154daf9382 100644 (file)
@@ -979,7 +979,7 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct
 /*
  * Send learning packets after MAC address swap.
  *
- * Called with RTNL and bond->lock held for read.
+ * Called with RTNL and no other locks
  */
 static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
                                struct slave *slave2)
@@ -987,6 +987,8 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
        int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
        struct slave *disabled_slave = NULL;
 
+       ASSERT_RTNL();
+
        /* fasten the change in the switch */
        if (SLAVE_IS_OK(slave1)) {
                alb_send_learning_packets(slave1, slave1->dev->dev_addr);
@@ -1031,7 +1033,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
  * a slave that has @slave's permanet address as its current address.
  * We'll make sure that that slave no longer uses @slave's permanent address.
  *
- * Caller must hold bond lock
+ * Caller must hold RTNL and no other locks
  */
 static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave)
 {
@@ -1542,7 +1544,12 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
        return 0;
 }
 
-/* Caller must hold bond lock for write */
+/*
+ * Remove slave from tlb and rlb hash tables, and fix up MAC addresses
+ * if necessary.
+ *
+ * Caller must hold RTNL and no other locks
+ */
 void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
 {
        if (bond->slave_cnt > 1) {
@@ -1601,9 +1608,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
        struct slave *swap_slave;
        int i;
 
-       if (new_slave)
-               ASSERT_RTNL();
-
        if (bond->curr_active_slave == new_slave) {
                return;
        }
@@ -1649,6 +1653,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
        write_unlock_bh(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
 
+       ASSERT_RTNL();
+
        /* curr_active_slave must be set before calling alb_swap_mac_addr */
        if (swap_slave) {
                /* swap mac address */
@@ -1659,12 +1665,11 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
                                       bond->alb_info.rlb_enabled);
        }
 
-       read_lock(&bond->lock);
-
        if (swap_slave) {
                alb_fasten_mac_swap(bond, swap_slave, new_slave);
+               read_lock(&bond->lock);
        } else {
-               /* fasten bond mac on new current slave */
+               read_lock(&bond->lock);
                alb_send_learning_packets(new_slave, bond->dev->dev_addr);
        }
 
index b0b26036266b51fc381e5e2eede8cf3de2cc270d..49a198206e3de901a74f34fc40694bb056ad922c 100644 (file)
@@ -1746,7 +1746,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                 * has been cleared (if our_slave == old_current),
                 * but before a new active slave is selected.
                 */
+               write_unlock_bh(&bond->lock);
                bond_alb_deinit_slave(bond, slave);
+               write_lock_bh(&bond->lock);
        }
 
        if (oldcurrent == slave) {
@@ -1905,6 +1907,12 @@ static int bond_release_all(struct net_device *bond_dev)
                slave_dev = slave->dev;
                bond_detach_slave(bond, slave);
 
+               /* now that the slave is detached, unlock and perform
+                * all the undo steps that should not be called from
+                * within a lock.
+                */
+               write_unlock_bh(&bond->lock);
+
                if ((bond->params.mode == BOND_MODE_TLB) ||
                    (bond->params.mode == BOND_MODE_ALB)) {
                        /* must be called only after the slave
@@ -1915,12 +1923,6 @@ static int bond_release_all(struct net_device *bond_dev)
 
                bond_compute_features(bond);
 
-               /* now that the slave is detached, unlock and perform
-                * all the undo steps that should not be called from
-                * within a lock.
-                */
-               write_unlock_bh(&bond->lock);
-
                bond_destroy_slave_symlinks(bond_dev, slave_dev);
                bond_del_vlans_from_slave(bond, slave_dev);
 
@@ -2384,7 +2386,9 @@ void bond_mii_monitor(struct work_struct *work)
                rtnl_lock();
                read_lock(&bond->lock);
                __bond_mii_monitor(bond, 1);
-               rtnl_unlock();
+               read_unlock(&bond->lock);
+               rtnl_unlock();  /* might sleep, hold no other locks */
+               read_lock(&bond->lock);
        }
 
        delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
@@ -3399,9 +3403,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond
        case NETDEV_CHANGENAME:
                return bond_event_changename(event_bond);
        case NETDEV_UNREGISTER:
-               /*
-                * TODO: remove a bond from the list?
-                */
+               bond_release_all(event_bond->dev);
                break;
        default:
                break;
@@ -4540,18 +4542,27 @@ static void bond_free_all(void)
 
 /*
  * Convert string input module parms.  Accept either the
- * number of the mode or its string name.
+ * number of the mode or its string name.  A bit complicated because
+ * some mode names are substrings of other names, and calls from sysfs
+ * may have whitespace in the name (trailing newlines, for example).
  */
-int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
+int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
 {
-       int i;
+       int mode = -1, i, rv;
+       char modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
+
+       rv = sscanf(buf, "%d", &mode);
+       if (!rv) {
+               rv = sscanf(buf, "%20s", modestr);
+               if (!rv)
+                       return -1;
+       }
 
        for (i = 0; tbl[i].modename; i++) {
-               if ((isdigit(*mode_arg) &&
-                    tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) ||
-                   (strcmp(mode_arg, tbl[i].modename) == 0)) {
+               if (mode == tbl[i].mode)
+                       return tbl[i].mode;
+               if (strcmp(modestr, tbl[i].modename) == 0)
                        return tbl[i].mode;
-               }
        }
 
        return -1;
@@ -4865,9 +4876,22 @@ static struct lock_class_key bonding_netdev_xmit_lock_key;
 int bond_create(char *name, struct bond_params *params, struct bonding **newbond)
 {
        struct net_device *bond_dev;
+       struct bonding *bond, *nxt;
        int res;
 
        rtnl_lock();
+       down_write(&bonding_rwsem);
+
+       /* Check to see if the bond already exists. */
+       list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+               if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
+                       printk(KERN_ERR DRV_NAME
+                              ": cannot add bond %s; it already exists\n",
+                              name);
+                       res = -EPERM;
+                       goto out_rtnl;
+               }
+
        bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
                                ether_setup);
        if (!bond_dev) {
@@ -4906,10 +4930,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
 
        netif_carrier_off(bond_dev);
 
+       up_write(&bonding_rwsem);
        rtnl_unlock(); /* allows sysfs registration of net device */
        res = bond_create_sysfs_entry(bond_dev->priv);
        if (res < 0) {
                rtnl_lock();
+               down_write(&bonding_rwsem);
                goto out_bond;
        }
 
@@ -4920,6 +4946,7 @@ out_bond:
 out_netdev:
        free_netdev(bond_dev);
 out_rtnl:
+       up_write(&bonding_rwsem);
        rtnl_unlock();
        return res;
 }
@@ -4940,6 +4967,9 @@ static int __init bonding_init(void)
 #ifdef CONFIG_PROC_FS
        bond_create_proc_dir();
 #endif
+
+       init_rwsem(&bonding_rwsem);
+
        for (i = 0; i < max_bonds; i++) {
                res = bond_create(NULL, &bonding_defaults, NULL);
                if (res)
index 11b76b352415f6dedad302133b97e952728032dd..90a1f31e8e637bd104a09490b8d05db80b0b5acc 100644 (file)
@@ -109,11 +109,10 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
 {
        char command[IFNAMSIZ + 1] = {0, };
        char *ifname;
-       int res = count;
+       int rv, res = count;
        struct bonding *bond;
        struct bonding *nxt;
 
-       down_write(&(bonding_rwsem));
        sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
        ifname = command + 1;
        if ((strlen(command) <= 1) ||
@@ -121,39 +120,28 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
                goto err_no_cmd;
 
        if (command[0] == '+') {
-
-               /* Check to see if the bond already exists. */
-               list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
-                       if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
-                               printk(KERN_ERR DRV_NAME
-                                       ": cannot add bond %s; it already exists\n",
-                                       ifname);
-                               res = -EPERM;
-                               goto out;
-                       }
-
                printk(KERN_INFO DRV_NAME
                        ": %s is being created...\n", ifname);
-               if (bond_create(ifname, &bonding_defaults, &bond)) {
-                       printk(KERN_INFO DRV_NAME
-                       ": %s interface already exists. Bond creation failed.\n",
-                       ifname);
-                       res = -EPERM;
+               rv = bond_create(ifname, &bonding_defaults, &bond);
+               if (rv) {
+                       printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");
+                       res = rv;
                }
                goto out;
        }
 
        if (command[0] == '-') {
+               rtnl_lock();
+               down_write(&bonding_rwsem);
+
                list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
                        if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
-                               rtnl_lock();
                                /* check the ref count on the bond's kobject.
                                 * If it's > expected, then there's a file open,
                                 * and we have to fail.
                                 */
                                if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
                                                        > expected_refcount){
-                                       rtnl_unlock();
                                        printk(KERN_INFO DRV_NAME
                                                ": Unable remove bond %s due to open references.\n",
                                                ifname);
@@ -164,6 +152,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
                                        ": %s is being deleted...\n",
                                        bond->dev->name);
                                bond_destroy(bond);
+                               up_write(&bonding_rwsem);
                                rtnl_unlock();
                                goto out;
                        }
@@ -171,6 +160,8 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
                printk(KERN_ERR DRV_NAME
                        ": unable to delete non-existent bond %s\n", ifname);
                res = -ENODEV;
+               up_write(&bonding_rwsem);
+               rtnl_unlock();
                goto out;
        }
 
@@ -183,7 +174,6 @@ err_no_cmd:
         * get called forever, which is bad.
         */
 out:
-       up_write(&(bonding_rwsem));
        return res;
 }
 /* class attribute for bond_masters file.  This ends up in /sys/class/net */
@@ -271,6 +261,9 @@ static ssize_t bonding_store_slaves(struct device *d,
 
        /* Note:  We can't hold bond->lock here, as bond_create grabs it. */
 
+       rtnl_lock();
+       down_write(&(bonding_rwsem));
+
        sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
        ifname = command + 1;
        if ((strlen(command) <= 1) ||
@@ -336,12 +329,10 @@ static ssize_t bonding_store_slaves(struct device *d,
                                dev->mtu = bond->dev->mtu;
                        }
                }
-               rtnl_lock();
                res = bond_enslave(bond->dev, dev);
                bond_for_each_slave(bond, slave, i)
                        if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
                                slave->original_mtu = original_mtu;
-               rtnl_unlock();
                if (res) {
                        ret = res;
                }
@@ -359,12 +350,10 @@ static ssize_t bonding_store_slaves(struct device *d,
                if (dev) {
                        printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
                                bond->dev->name, dev->name);
-                       rtnl_lock();
                        if (bond->setup_by_slave)
                                res = bond_release_and_destroy(bond->dev, dev);
                        else
                                res = bond_release(bond->dev, dev);
-                       rtnl_unlock();
                        if (res) {
                                ret = res;
                                goto out;
@@ -389,6 +378,8 @@ err_no_cmd:
        ret = -EPERM;
 
 out:
+       up_write(&(bonding_rwsem));
+       rtnl_unlock();
        return ret;
 }
 
@@ -423,7 +414,7 @@ static ssize_t bonding_store_mode(struct device *d,
                goto out;
        }
 
-       new_value = bond_parse_parm((char *)buf, bond_mode_tbl);
+       new_value = bond_parse_parm(buf, bond_mode_tbl);
        if (new_value < 0)  {
                printk(KERN_ERR DRV_NAME
                       ": %s: Ignoring invalid mode value %.*s.\n",
@@ -478,7 +469,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
                goto out;
        }
 
-       new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl);
+       new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
        if (new_value < 0)  {
                printk(KERN_ERR DRV_NAME
                       ": %s: Ignoring invalid xmit hash policy value %.*s.\n",
@@ -518,7 +509,7 @@ static ssize_t bonding_store_arp_validate(struct device *d,
        int new_value;
        struct bonding *bond = to_bond(d);
 
-       new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
+       new_value = bond_parse_parm(buf, arp_validate_tbl);
        if (new_value < 0) {
                printk(KERN_ERR DRV_NAME
                       ": %s: Ignoring invalid arp_validate value %s\n",
@@ -941,7 +932,7 @@ static ssize_t bonding_store_lacp(struct device *d,
                goto out;
        }
 
-       new_value = bond_parse_parm((char *)buf, bond_lacp_tbl);
+       new_value = bond_parse_parm(buf, bond_lacp_tbl);
 
        if ((new_value == 1) || (new_value == 0)) {
                bond->params.lacp_fast = new_value;
@@ -1075,7 +1066,10 @@ static ssize_t bonding_store_primary(struct device *d,
        struct slave *slave;
        struct bonding *bond = to_bond(d);
 
-       write_lock_bh(&bond->lock);
+       rtnl_lock();
+       read_lock(&bond->lock);
+       write_lock_bh(&bond->curr_slave_lock);
+
        if (!USES_PRIMARY(bond->params.mode)) {
                printk(KERN_INFO DRV_NAME
                       ": %s: Unable to set primary slave; %s is in mode %d\n",
@@ -1109,8 +1103,8 @@ static ssize_t bonding_store_primary(struct device *d,
                }
        }
 out:
-       write_unlock_bh(&bond->lock);
-
+       write_unlock_bh(&bond->curr_slave_lock);
+       read_unlock(&bond->lock);
        rtnl_unlock();
 
        return count;
@@ -1190,7 +1184,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
        struct bonding *bond = to_bond(d);
 
        rtnl_lock();
-       write_lock_bh(&bond->lock);
+       read_lock(&bond->lock);
+       write_lock_bh(&bond->curr_slave_lock);
 
        if (!USES_PRIMARY(bond->params.mode)) {
                printk(KERN_INFO DRV_NAME
@@ -1247,7 +1242,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
                }
        }
 out:
-       write_unlock_bh(&bond->lock);
+       write_unlock_bh(&bond->curr_slave_lock);
+       read_unlock(&bond->lock);
        rtnl_unlock();
 
        return count;
@@ -1418,8 +1414,6 @@ int bond_create_sysfs(void)
        int ret = 0;
        struct bonding *firstbond;
 
-       init_rwsem(&bonding_rwsem);
-
        /* get the netdev class pointer */
        firstbond = container_of(bond_dev_list.next, struct bonding, bond_list);
        if (!firstbond)
index e1e4734e23ce7191d0ddb23809c5a710bafa3190..6d83be49899a496fe5125ad3e95d081634a7c269 100644 (file)
@@ -141,6 +141,8 @@ struct bond_parm_tbl {
        int mode;
 };
 
+#define BOND_MAX_MODENAME_LEN 20
+
 struct vlan_entry {
        struct list_head vlan_list;
        __be32 vlan_ip;
@@ -314,7 +316,7 @@ void bond_mii_monitor(struct work_struct *);
 void bond_loadbalance_arp_mon(struct work_struct *);
 void bond_activebackup_arp_mon(struct work_struct *);
 void bond_set_mode_ops(struct bonding *bond, int mode);
-int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
+int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
 void bond_register_arp(struct bonding *);
index 7df31b5561cc02000cbc44d1ea2048bd016f4e58..d66915d82b24a7795ce040b3a785c3f6532aac14 100644 (file)
 
 #define DRV_MODULE_NAME                "cassini"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.4"
-#define DRV_MODULE_RELDATE     "1 July 2004"
+#define DRV_MODULE_VERSION     "1.5"
+#define DRV_MODULE_RELDATE     "4 Jan 2008"
 
 #define CAS_DEF_MSG_ENABLE       \
        (NETIF_MSG_DRV          | \
@@ -336,30 +336,6 @@ static inline void cas_mask_intr(struct cas *cp)
                cas_disable_irq(cp, i);
 }
 
-static inline void cas_buffer_init(cas_page_t *cp)
-{
-       struct page *page = cp->buffer;
-       atomic_set((atomic_t *)&page->lru.next, 1);
-}
-
-static inline int cas_buffer_count(cas_page_t *cp)
-{
-       struct page *page = cp->buffer;
-       return atomic_read((atomic_t *)&page->lru.next);
-}
-
-static inline void cas_buffer_inc(cas_page_t *cp)
-{
-       struct page *page = cp->buffer;
-       atomic_inc((atomic_t *)&page->lru.next);
-}
-
-static inline void cas_buffer_dec(cas_page_t *cp)
-{
-       struct page *page = cp->buffer;
-       atomic_dec((atomic_t *)&page->lru.next);
-}
-
 static void cas_enable_irq(struct cas *cp, const int ring)
 {
        if (ring == 0) { /* all but TX_DONE */
@@ -497,7 +473,6 @@ static int cas_page_free(struct cas *cp, cas_page_t *page)
 {
        pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
                       PCI_DMA_FROMDEVICE);
-       cas_buffer_dec(page);
        __free_pages(page->buffer, cp->page_order);
        kfree(page);
        return 0;
@@ -527,7 +502,6 @@ static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags)
        page->buffer = alloc_pages(flags, cp->page_order);
        if (!page->buffer)
                goto page_err;
-       cas_buffer_init(page);
        page->dma_addr = pci_map_page(cp->pdev, page->buffer, 0,
                                      cp->page_size, PCI_DMA_FROMDEVICE);
        return page;
@@ -606,7 +580,7 @@ static void cas_spare_recover(struct cas *cp, const gfp_t flags)
        list_for_each_safe(elem, tmp, &list) {
                cas_page_t *page = list_entry(elem, cas_page_t, list);
 
-               if (cas_buffer_count(page) > 1)
+               if (page_count(page->buffer) > 1)
                        continue;
 
                list_del(elem);
@@ -1374,7 +1348,7 @@ static inline cas_page_t *cas_page_spare(struct cas *cp, const int index)
        cas_page_t *page = cp->rx_pages[1][index];
        cas_page_t *new;
 
-       if (cas_buffer_count(page) == 1)
+       if (page_count(page->buffer) == 1)
                return page;
 
        new = cas_page_dequeue(cp);
@@ -1394,7 +1368,7 @@ static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
        cas_page_t **page1 = cp->rx_pages[1];
 
        /* swap if buffer is in use */
-       if (cas_buffer_count(page0[index]) > 1) {
+       if (page_count(page0[index]->buffer) > 1) {
                cas_page_t *new = cas_page_spare(cp, index);
                if (new) {
                        page1[index] = page0[index];
@@ -1979,6 +1953,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
        struct cas_page *page;
        struct sk_buff *skb;
        void *addr, *crcaddr;
+       __sum16 csum;
        char *p;
 
        hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
@@ -2062,10 +2037,10 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
 
                skb_shinfo(skb)->nr_frags++;
                skb->data_len += hlen - swivel;
+               skb->truesize += hlen - swivel;
                skb->len      += hlen - swivel;
 
                get_page(page->buffer);
-               cas_buffer_inc(page);
                frag->page = page->buffer;
                frag->page_offset = off;
                frag->size = hlen - swivel;
@@ -2090,7 +2065,6 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
                        frag++;
 
                        get_page(page->buffer);
-                       cas_buffer_inc(page);
                        frag->page = page->buffer;
                        frag->page_offset = 0;
                        frag->size = hlen;
@@ -2158,14 +2132,15 @@ end_copy_pkt:
                skb_put(skb, alloclen);
        }
 
-       i = CAS_VAL(RX_COMP4_TCP_CSUM, words[3]);
+       csum = (__force __sum16)htons(CAS_VAL(RX_COMP4_TCP_CSUM, words[3]));
        if (cp->crc_size) {
                /* checksum includes FCS. strip it out. */
-               i = csum_fold(csum_partial(crcaddr, cp->crc_size, i));
+               csum = csum_fold(csum_partial(crcaddr, cp->crc_size,
+                                             csum_unfold(csum)));
                if (addr)
                        cas_page_unmap(addr);
        }
-       skb->csum = ntohs(i ^ 0xffff);
+       skb->csum = csum_unfold(~csum);
        skb->ip_summed = CHECKSUM_COMPLETE;
        skb->protocol = eth_type_trans(skb, cp->dev);
        return len;
@@ -2253,7 +2228,7 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
        released = 0;
        while (entry != last) {
                /* make a new buffer if it's still in use */
-               if (cas_buffer_count(page[entry]) > 1) {
+               if (page_count(page[entry]->buffer) > 1) {
                        cas_page_t *new = cas_page_dequeue(cp);
                        if (!new) {
                                /* let the timer know that we need to
@@ -2611,7 +2586,7 @@ static int cas_poll(struct napi_struct *napi, int budget)
 {
        struct cas *cp = container_of(napi, struct cas, napi);
        struct net_device *dev = cp->dev;
-       int i, enable_intr, todo, credits;
+       int i, enable_intr, credits;
        u32 status = readl(cp->regs + REG_INTR_STATUS);
        unsigned long flags;
 
@@ -4375,7 +4350,7 @@ static int cas_close(struct net_device *dev)
        struct cas *cp = netdev_priv(dev);
 
 #ifdef USE_NAPI
-       napi_enable(&cp->napi);
+       napi_disable(&cp->napi);
 #endif
        /* Make sure we don't get distracted by suspend/resume */
        mutex_lock(&cp->pm_mutex);
@@ -4872,6 +4847,90 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return rc;
 }
 
+/* When this chip sits underneath an Intel 31154 bridge, it is the
+ * only subordinate device and we can tweak the bridge settings to
+ * reflect that fact.
+ */
+static void __devinit cas_program_bridge(struct pci_dev *cas_pdev)
+{
+       struct pci_dev *pdev = cas_pdev->bus->self;
+       u32 val;
+
+       if (!pdev)
+               return;
+
+       if (pdev->vendor != 0x8086 || pdev->device != 0x537c)
+               return;
+
+       /* Clear bit 10 (Bus Parking Control) in the Secondary
+        * Arbiter Control/Status Register which lives at offset
+        * 0x41.  Using a 32-bit word read/modify/write at 0x40
+        * is much simpler so that's how we do this.
+        */
+       pci_read_config_dword(pdev, 0x40, &val);
+       val &= ~0x00040000;
+       pci_write_config_dword(pdev, 0x40, val);
+
+       /* Max out the Multi-Transaction Timer settings since
+        * Cassini is the only device present.
+        *
+        * The register is 16-bit and lives at 0x50.  When the
+        * settings are enabled, it extends the GRANT# signal
+        * for a requestor after a transaction is complete.  This
+        * allows the next request to run without first needing
+        * to negotiate the GRANT# signal back.
+        *
+        * Bits 12:10 define the grant duration:
+        *
+        *      1       --      16 clocks
+        *      2       --      32 clocks
+        *      3       --      64 clocks
+        *      4       --      128 clocks
+        *      5       --      256 clocks
+        *
+        * All other values are illegal.
+        *
+        * Bits 09:00 define which REQ/GNT signal pairs get the
+        * GRANT# signal treatment.  We set them all.
+        */
+       pci_write_config_word(pdev, 0x50, (5 << 10) | 0x3ff);
+
+       /* The Read Prefecth Policy register is 16-bit and sits at
+        * offset 0x52.  It enables a "smart" pre-fetch policy.  We
+        * enable it and max out all of the settings since only one
+        * device is sitting underneath and thus bandwidth sharing is
+        * not an issue.
+        *
+        * The register has several 3 bit fields, which indicates a
+        * multiplier applied to the base amount of prefetching the
+        * chip would do.  These fields are at:
+        *
+        *      15:13   ---     ReRead Primary Bus
+        *      12:10   ---     FirstRead Primary Bus
+        *      09:07   ---     ReRead Secondary Bus
+        *      06:04   ---     FirstRead Secondary Bus
+        *
+        * Bits 03:00 control which REQ/GNT pairs the prefetch settings
+        * get enabled on.  Bit 3 is a grouped enabler which controls
+        * all of the REQ/GNT pairs from [8:3].  Bits 2 to 0 control
+        * the individual REQ/GNT pairs [2:0].
+        */
+       pci_write_config_word(pdev, 0x52,
+                             (0x7 << 13) |
+                             (0x7 << 10) |
+                             (0x7 <<  7) |
+                             (0x7 <<  4) |
+                             (0xf <<  0));
+
+       /* Force cacheline size to 0x8 */
+       pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
+
+       /* Force latency timer to maximum setting so Cassini can
+        * sit on the bus as long as it likes.
+        */
+       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xff);
+}
+
 static int __devinit cas_init_one(struct pci_dev *pdev,
                                  const struct pci_device_id *ent)
 {
@@ -4927,6 +4986,8 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
                printk(KERN_WARNING PFX "Could not enable MWI for %s\n",
                       pci_name(pdev));
 
+       cas_program_bridge(pdev);
+
        /*
         * On some architectures, the default cache line size set
         * by pci_try_set_mwi reduces perforamnce.  We have to increase
index 2f93f83342d2575e146f8999ff37bafb55170dd6..552af89ca1cf04f49165248293570132bdaa189a 100644 (file)
@@ -4122,8 +4122,8 @@ cas_saturn_patch_t cas_saturn_patch[] = {
                                                             inserted into
                                                             outgoing frame. */
 struct cas_tx_desc {
-       u64     control;
-       u64     buffer;
+       __le64     control;
+       __le64     buffer;
 };
 
 /* descriptor ring for free buffers contains page-sized buffers. the index
@@ -4131,8 +4131,8 @@ struct cas_tx_desc {
  * the completion ring.
  */
 struct cas_rx_desc {
-       u64     index;
-       u64     buffer;
+       __le64     index;
+       __le64     buffer;
 };
 
 /* received packets are put on the completion ring. */
@@ -4210,10 +4210,10 @@ struct cas_rx_desc {
 #define RX_INDEX_RELEASE                  0x0000000000002000ULL
 
 struct cas_rx_comp {
-       u64     word1;
-       u64     word2;
-       u64     word3;
-       u64     word4;
+       __le64     word1;
+       __le64     word2;
+       __le64     word3;
+       __le64     word4;
 };
 
 enum link_state {
@@ -4252,7 +4252,7 @@ struct cas_init_block {
        struct cas_rx_comp rxcs[N_RX_COMP_RINGS][INIT_BLOCK_RX_COMP];
        struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
        struct cas_tx_desc txds[N_TX_RINGS][INIT_BLOCK_TX];
-       u64 tx_compwb;
+       __le64 tx_compwb;
 };
 
 /* tiny buffers to deal with target abort issue. we allocate a bit
index 6fd95a2c8cecaaa1fb8c8b6d38e7687aa02fba75..6e12d48351b8e1a4b243efd80b5c669c689e6830 100644 (file)
@@ -459,7 +459,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_OK;
 
        len = max(skb->len, ETH_ZLEN);
-       queue = skb->queue_mapping;
+       queue = skb_get_queue_mapping(skb);
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
        netif_stop_subqueue(dev, queue);
 #else
index 47cce9cad30f0a6bc3bace63522b0c43956ac358..e233d04a2132fcca328f3000dd546df963b7a356 100644 (file)
@@ -1316,9 +1316,10 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
                            ("%02x:cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
                             i,
                             (u32) (np->tx_ring_dma + i * sizeof (*desc)),
-                            (u32) desc->next_desc,
-                            (u32) desc->status, (u32) (desc->fraginfo >> 32),
-                            (u32) desc->fraginfo);
+                            (u32)le64_to_cpu(desc->next_desc),
+                            (u32)le64_to_cpu(desc->status),
+                            (u32)(le64_to_cpu(desc->fraginfo) >> 32),
+                            (u32)le64_to_cpu(desc->fraginfo));
                        printk ("\n");
                }
                printk ("\n");
@@ -1435,7 +1436,7 @@ mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
 static int
 mii_wait_link (struct net_device *dev, int wait)
 {
-       BMSR_t bmsr;
+       __u16 bmsr;
        int phy_addr;
        struct netdev_private *np;
 
@@ -1443,8 +1444,8 @@ mii_wait_link (struct net_device *dev, int wait)
        phy_addr = np->phy_addr;
 
        do {
-               bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
-               if (bmsr.bits.link_status)
+               bmsr = mii_read (dev, phy_addr, MII_BMSR);
+               if (bmsr & MII_BMSR_LINK_STATUS)
                        return 0;
                mdelay (1);
        } while (--wait > 0);
@@ -1453,70 +1454,72 @@ mii_wait_link (struct net_device *dev, int wait)
 static int
 mii_get_media (struct net_device *dev)
 {
-       ANAR_t negotiate;
-       BMSR_t bmsr;
-       BMCR_t bmcr;
-       MSCR_t mscr;
-       MSSR_t mssr;
+       __u16 negotiate;
+       __u16 bmsr;
+       __u16 mscr;
+       __u16 mssr;
        int phy_addr;
        struct netdev_private *np;
 
        np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
-       bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+       bmsr = mii_read (dev, phy_addr, MII_BMSR);
        if (np->an_enable) {
-               if (!bmsr.bits.an_complete) {
+               if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
                        /* Auto-Negotiation not completed */
                        return -1;
                }
-               negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
+               negotiate = mii_read (dev, phy_addr, MII_ANAR) &
                        mii_read (dev, phy_addr, MII_ANLPAR);
-               mscr.image = mii_read (dev, phy_addr, MII_MSCR);
-               mssr.image = mii_read (dev, phy_addr, MII_MSSR);
-               if (mscr.bits.media_1000BT_FD & mssr.bits.lp_1000BT_FD) {
+               mscr = mii_read (dev, phy_addr, MII_MSCR);
+               mssr = mii_read (dev, phy_addr, MII_MSSR);
+               if (mscr & MII_MSCR_1000BT_FD && mssr & MII_MSSR_LP_1000BT_FD) {
                        np->speed = 1000;
                        np->full_duplex = 1;
                        printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
-               } else if (mscr.bits.media_1000BT_HD & mssr.bits.lp_1000BT_HD) {
+               } else if (mscr & MII_MSCR_1000BT_HD && mssr & MII_MSSR_LP_1000BT_HD) {
                        np->speed = 1000;
                        np->full_duplex = 0;
                        printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n");
-               } else if (negotiate.bits.media_100BX_FD) {
+               } else if (negotiate & MII_ANAR_100BX_FD) {
                        np->speed = 100;
                        np->full_duplex = 1;
                        printk (KERN_INFO "Auto 100 Mbps, Full duplex\n");
-               } else if (negotiate.bits.media_100BX_HD) {
+               } else if (negotiate & MII_ANAR_100BX_HD) {
                        np->speed = 100;
                        np->full_duplex = 0;
                        printk (KERN_INFO "Auto 100 Mbps, Half duplex\n");
-               } else if (negotiate.bits.media_10BT_FD) {
+               } else if (negotiate & MII_ANAR_10BT_FD) {
                        np->speed = 10;
                        np->full_duplex = 1;
                        printk (KERN_INFO "Auto 10 Mbps, Full duplex\n");
-               } else if (negotiate.bits.media_10BT_HD) {
+               } else if (negotiate & MII_ANAR_10BT_HD) {
                        np->speed = 10;
                        np->full_duplex = 0;
                        printk (KERN_INFO "Auto 10 Mbps, Half duplex\n");
                }
-               if (negotiate.bits.pause) {
+               if (negotiate & MII_ANAR_PAUSE) {
                        np->tx_flow &= 1;
                        np->rx_flow &= 1;
-               } else if (negotiate.bits.asymmetric) {
+               } else if (negotiate & MII_ANAR_ASYMMETRIC) {
                        np->tx_flow = 0;
                        np->rx_flow &= 1;
                }
                /* else tx_flow, rx_flow = user select  */
        } else {
-               bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
-               if (bmcr.bits.speed100 == 1 && bmcr.bits.speed1000 == 0) {
+               __u16 bmcr = mii_read (dev, phy_addr, MII_BMCR);
+               switch (bmcr & (MII_BMCR_SPEED_100 | MII_BMCR_SPEED_1000)) {
+               case MII_BMCR_SPEED_1000:
+                       printk (KERN_INFO "Operating at 1000 Mbps, ");
+                       break;
+               case MII_BMCR_SPEED_100:
                        printk (KERN_INFO "Operating at 100 Mbps, ");
-               } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 0) {
+                       break;
+               case 0:
                        printk (KERN_INFO "Operating at 10 Mbps, ");
-               } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 1) {
-                       printk (KERN_INFO "Operating at 1000 Mbps, ");
                }
-               if (bmcr.bits.duplex_mode) {
+               if (bmcr & MII_BMCR_DUPLEX_MODE) {
                        printk ("Full duplex\n");
                } else {
                        printk ("Half duplex\n");
@@ -1537,10 +1540,10 @@ mii_get_media (struct net_device *dev)
 static int
 mii_set_media (struct net_device *dev)
 {
-       PHY_SCR_t pscr;
-       BMCR_t bmcr;
-       BMSR_t bmsr;
-       ANAR_t anar;
+       __u16 pscr;
+       __u16 bmcr;
+       __u16 bmsr;
+       __u16 anar;
        int phy_addr;
        struct netdev_private *np;
        np = netdev_priv(dev);
@@ -1549,76 +1552,77 @@ mii_set_media (struct net_device *dev)
        /* Does user set speed? */
        if (np->an_enable) {
                /* Advertise capabilities */
-               bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
-               anar.image = mii_read (dev, phy_addr, MII_ANAR);
-               anar.bits.media_100BX_FD = bmsr.bits.media_100BX_FD;
-               anar.bits.media_100BX_HD = bmsr.bits.media_100BX_HD;
-               anar.bits.media_100BT4 = bmsr.bits.media_100BT4;
-               anar.bits.media_10BT_FD = bmsr.bits.media_10BT_FD;
-               anar.bits.media_10BT_HD = bmsr.bits.media_10BT_HD;
-               anar.bits.pause = 1;
-               anar.bits.asymmetric = 1;
-               mii_write (dev, phy_addr, MII_ANAR, anar.image);
+               bmsr = mii_read (dev, phy_addr, MII_BMSR);
+               anar = mii_read (dev, phy_addr, MII_ANAR) &
+                            ~MII_ANAR_100BX_FD &
+                            ~MII_ANAR_100BX_HD &
+                            ~MII_ANAR_100BT4 &
+                            ~MII_ANAR_10BT_FD &
+                            ~MII_ANAR_10BT_HD;
+               if (bmsr & MII_BMSR_100BX_FD)
+                       anar |= MII_ANAR_100BX_FD;
+               if (bmsr & MII_BMSR_100BX_HD)
+                       anar |= MII_ANAR_100BX_HD;
+               if (bmsr & MII_BMSR_100BT4)
+                       anar |= MII_ANAR_100BT4;
+               if (bmsr & MII_BMSR_10BT_FD)
+                       anar |= MII_ANAR_10BT_FD;
+               if (bmsr & MII_BMSR_10BT_HD)
+                       anar |= MII_ANAR_10BT_HD;
+               anar |= MII_ANAR_PAUSE | MII_ANAR_ASYMMETRIC;
+               mii_write (dev, phy_addr, MII_ANAR, anar);
 
                /* Enable Auto crossover */
-               pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
-               pscr.bits.mdi_crossover_mode = 3;       /* 11'b */
-               mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+               pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
+               pscr |= 3 << 5; /* 11'b */
+               mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
 
                /* Soft reset PHY */
                mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
-               bmcr.image = 0;
-               bmcr.bits.an_enable = 1;
-               bmcr.bits.restart_an = 1;
-               bmcr.bits.reset = 1;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN | MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
                mdelay(1);
        } else {
                /* Force speed setting */
                /* 1) Disable Auto crossover */
-               pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
-               pscr.bits.mdi_crossover_mode = 0;
-               mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+               pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
+               pscr &= ~(3 << 5);
+               mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
 
                /* 2) PHY Reset */
-               bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
-               bmcr.bits.reset = 1;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               bmcr = mii_read (dev, phy_addr, MII_BMCR);
+               bmcr |= MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
 
                /* 3) Power Down */
-               bmcr.image = 0x1940;    /* must be 0x1940 */
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               bmcr = 0x1940;  /* must be 0x1940 */
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
                mdelay (100);   /* wait a certain time */
 
                /* 4) Advertise nothing */
                mii_write (dev, phy_addr, MII_ANAR, 0);
 
                /* 5) Set media and Power Up */
-               bmcr.image = 0;
-               bmcr.bits.power_down = 1;
+               bmcr = MII_BMCR_POWER_DOWN;
                if (np->speed == 100) {
-                       bmcr.bits.speed100 = 1;
-                       bmcr.bits.speed1000 = 0;
+                       bmcr |= MII_BMCR_SPEED_100;
                        printk (KERN_INFO "Manual 100 Mbps, ");
                } else if (np->speed == 10) {
-                       bmcr.bits.speed100 = 0;
-                       bmcr.bits.speed1000 = 0;
                        printk (KERN_INFO "Manual 10 Mbps, ");
                }
                if (np->full_duplex) {
-                       bmcr.bits.duplex_mode = 1;
+                       bmcr |= MII_BMCR_DUPLEX_MODE;
                        printk ("Full duplex\n");
                } else {
-                       bmcr.bits.duplex_mode = 0;
                        printk ("Half duplex\n");
                }
 #if 0
                /* Set 1000BaseT Master/Slave setting */
-               mscr.image = mii_read (dev, phy_addr, MII_MSCR);
-               mscr.bits.cfg_enable = 1;
-               mscr.bits.cfg_value = 0;
+               mscr = mii_read (dev, phy_addr, MII_MSCR);
+               mscr |= MII_MSCR_CFG_ENABLE;
+               mscr &= ~MII_MSCR_CFG_VALUE = 0;
 #endif
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
                mdelay(10);
        }
        return 0;
@@ -1627,43 +1631,42 @@ mii_set_media (struct net_device *dev)
 static int
 mii_get_media_pcs (struct net_device *dev)
 {
-       ANAR_PCS_t negotiate;
-       BMSR_t bmsr;
-       BMCR_t bmcr;
+       __u16 negotiate;
+       __u16 bmsr;
        int phy_addr;
        struct netdev_private *np;
 
        np = netdev_priv(dev);
        phy_addr = np->phy_addr;
 
-       bmsr.image = mii_read (dev, phy_addr, PCS_BMSR);
+       bmsr = mii_read (dev, phy_addr, PCS_BMSR);
        if (np->an_enable) {
-               if (!bmsr.bits.an_complete) {
+               if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
                        /* Auto-Negotiation not completed */
                        return -1;
                }
-               negotiate.image = mii_read (dev, phy_addr, PCS_ANAR) &
+               negotiate = mii_read (dev, phy_addr, PCS_ANAR) &
                        mii_read (dev, phy_addr, PCS_ANLPAR);
                np->speed = 1000;
-               if (negotiate.bits.full_duplex) {
+               if (negotiate & PCS_ANAR_FULL_DUPLEX) {
                        printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
                        np->full_duplex = 1;
                } else {
                        printk (KERN_INFO "Auto 1000 Mbps, half duplex\n");
                        np->full_duplex = 0;
                }
-               if (negotiate.bits.pause) {
+               if (negotiate & PCS_ANAR_PAUSE) {
                        np->tx_flow &= 1;
                        np->rx_flow &= 1;
-               } else if (negotiate.bits.asymmetric) {
+               } else if (negotiate & PCS_ANAR_ASYMMETRIC) {
                        np->tx_flow = 0;
                        np->rx_flow &= 1;
                }
                /* else tx_flow, rx_flow = user select  */
        } else {
-               bmcr.image = mii_read (dev, phy_addr, PCS_BMCR);
+               __u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR);
                printk (KERN_INFO "Operating at 1000 Mbps, ");
-               if (bmcr.bits.duplex_mode) {
+               if (bmcr & MII_BMCR_DUPLEX_MODE) {
                        printk ("Full duplex\n");
                } else {
                        printk ("Half duplex\n");
@@ -1684,9 +1687,9 @@ mii_get_media_pcs (struct net_device *dev)
 static int
 mii_set_media_pcs (struct net_device *dev)
 {
-       BMCR_t bmcr;
-       ESR_t esr;
-       ANAR_PCS_t anar;
+       __u16 bmcr;
+       __u16 esr;
+       __u16 anar;
        int phy_addr;
        struct netdev_private *np;
        np = netdev_priv(dev);
@@ -1695,41 +1698,37 @@ mii_set_media_pcs (struct net_device *dev)
        /* Auto-Negotiation? */
        if (np->an_enable) {
                /* Advertise capabilities */
-               esr.image = mii_read (dev, phy_addr, PCS_ESR);
-               anar.image = mii_read (dev, phy_addr, MII_ANAR);
-               anar.bits.half_duplex =
-                       esr.bits.media_1000BT_HD | esr.bits.media_1000BX_HD;
-               anar.bits.full_duplex =
-                       esr.bits.media_1000BT_FD | esr.bits.media_1000BX_FD;
-               anar.bits.pause = 1;
-               anar.bits.asymmetric = 1;
-               mii_write (dev, phy_addr, MII_ANAR, anar.image);
+               esr = mii_read (dev, phy_addr, PCS_ESR);
+               anar = mii_read (dev, phy_addr, MII_ANAR) &
+                       ~PCS_ANAR_HALF_DUPLEX &
+                       ~PCS_ANAR_FULL_DUPLEX;
+               if (esr & (MII_ESR_1000BT_HD | MII_ESR_1000BX_HD))
+                       anar |= PCS_ANAR_HALF_DUPLEX;
+               if (esr & (MII_ESR_1000BT_FD | MII_ESR_1000BX_FD))
+                       anar |= PCS_ANAR_FULL_DUPLEX;
+               anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC;
+               mii_write (dev, phy_addr, MII_ANAR, anar);
 
                /* Soft reset PHY */
                mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
-               bmcr.image = 0;
-               bmcr.bits.an_enable = 1;
-               bmcr.bits.restart_an = 1;
-               bmcr.bits.reset = 1;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN |
+                      MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
                mdelay(1);
        } else {
                /* Force speed setting */
                /* PHY Reset */
-               bmcr.image = 0;
-               bmcr.bits.reset = 1;
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               bmcr = MII_BMCR_RESET;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
                mdelay(10);
-               bmcr.image = 0;
-               bmcr.bits.an_enable = 0;
                if (np->full_duplex) {
-                       bmcr.bits.duplex_mode = 1;
+                       bmcr = MII_BMCR_DUPLEX_MODE;
                        printk (KERN_INFO "Manual full duplex\n");
                } else {
-                       bmcr.bits.duplex_mode = 0;
+                       bmcr = 0;
                        printk (KERN_INFO "Manual half duplex\n");
                }
-               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               mii_write (dev, phy_addr, MII_BMCR, bmcr);
                mdelay(10);
 
                /*  Advertise nothing */
index 014b77ce96df251701b5213f56af1864b6539ea4..d66c605b4075bc3650f2717af9dc4ea583754fa5 100644 (file)
@@ -298,23 +298,6 @@ enum _pcs_reg {
 };
 
 /* Basic Mode Control Register */
-typedef union t_MII_BMCR {
-       u16 image;
-       struct {
-               u16 _bit_5_0:6; // bit 5:0
-               u16 speed1000:1;        // bit 6
-               u16 col_test_enable:1;  // bit 7
-               u16 duplex_mode:1;      // bit 8
-               u16 restart_an:1;       // bit 9
-               u16 isolate:1;  // bit 10
-               u16 power_down:1;       // bit 11
-               u16 an_enable:1;        // bit 12
-               u16 speed100:1; // bit 13
-               u16 loopback:1; // bit 14
-               u16 reset:1;    // bit 15
-       } bits;
-} BMCR_t, *PBMCR_t;
-
 enum _mii_bmcr {
        MII_BMCR_RESET = 0x8000,
        MII_BMCR_LOOP_BACK = 0x4000,
@@ -333,28 +316,6 @@ enum _mii_bmcr {
 };
 
 /* Basic Mode Status Register */
-typedef union t_MII_BMSR {
-       u16 image;
-       struct {
-               u16 ext_capability:1;   // bit 0
-               u16 japper_detect:1;    // bit 1
-               u16 link_status:1;      // bit 2
-               u16 an_ability:1;       // bit 3
-               u16 remote_fault:1;     // bit 4
-               u16 an_complete:1;      // bit 5
-               u16 preamble_supp:1;    // bit 6
-               u16 _bit_7:1;   // bit 7
-               u16 ext_status:1;       // bit 8
-               u16 media_100BT2_HD:1;  // bit 9
-               u16 media_100BT2_FD:1;  // bit 10
-               u16 media_10BT_HD:1;    // bit 11
-               u16 media_10BT_FD:1;    // bit 12
-               u16 media_100BX_HD:1;   // bit 13
-               u16 media_100BX_FD:1;   // bit 14
-               u16 media_100BT4:1;     // bit 15
-       } bits;
-} BMSR_t, *PBMSR_t;
-
 enum _mii_bmsr {
        MII_BMSR_100BT4 = 0x8000,
        MII_BMSR_100BX_FD = 0x4000,
@@ -374,24 +335,6 @@ enum _mii_bmsr {
 };
 
 /* ANAR */
-typedef union t_MII_ANAR {
-       u16 image;
-       struct {
-               u16 selector:5; // bit 4:0
-               u16 media_10BT_HD:1;    // bit 5
-               u16 media_10BT_FD:1;    // bit 6
-               u16 media_100BX_HD:1;   // bit 7
-               u16 media_100BX_FD:1;   // bit 8
-               u16 media_100BT4:1;     // bit 9
-               u16 pause:1;    // bit 10
-               u16 asymmetric:1;       // bit 11
-               u16 _bit12:1;   // bit 12
-               u16 remote_fault:1;     // bit 13
-               u16 _bit14:1;   // bit 14
-               u16 next_page:1;        // bit 15
-       } bits;
-} ANAR_t, *PANAR_t;
-
 enum _mii_anar {
        MII_ANAR_NEXT_PAGE = 0x8000,
        MII_ANAR_REMOTE_FAULT = 0x4000,
@@ -407,24 +350,6 @@ enum _mii_anar {
 };
 
 /* ANLPAR */
-typedef union t_MII_ANLPAR {
-       u16 image;
-       struct {
-               u16 selector:5; // bit 4:0
-               u16 media_10BT_HD:1;    // bit 5
-               u16 media_10BT_FD:1;    // bit 6
-               u16 media_100BX_HD:1;   // bit 7
-               u16 media_100BX_FD:1;   // bit 8
-               u16 media_100BT4:1;     // bit 9
-               u16 pause:1;    // bit 10
-               u16 asymmetric:1;       // bit 11
-               u16 _bit12:1;   // bit 12
-               u16 remote_fault:1;     // bit 13
-               u16 _bit14:1;   // bit 14
-               u16 next_page:1;        // bit 15
-       } bits;
-} ANLPAR_t, *PANLPAR_t;
-
 enum _mii_anlpar {
        MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
        MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
@@ -439,18 +364,6 @@ enum _mii_anlpar {
 };
 
 /* Auto-Negotiation Expansion Register */
-typedef union t_MII_ANER {
-       u16 image;
-       struct {
-               u16 lp_negotiable:1;    // bit 0
-               u16 page_received:1;    // bit 1
-               u16 nextpagable:1;      // bit 2
-               u16 lp_nextpagable:1;   // bit 3
-               u16 pdetect_fault:1;    // bit 4
-               u16 _bit15_5:11;        // bit 15:5
-       } bits;
-} ANER_t, *PANER_t;
-
 enum _mii_aner {
        MII_ANER_PAR_DETECT_FAULT = 0x0010,
        MII_ANER_LP_NEXTPAGABLE = 0x0008,
@@ -460,19 +373,6 @@ enum _mii_aner {
 };
 
 /* MASTER-SLAVE Control Register */
-typedef union t_MII_MSCR {
-       u16 image;
-       struct {
-               u16 _bit_7_0:8; // bit 7:0
-               u16 media_1000BT_HD:1;  // bit 8
-               u16 media_1000BT_FD:1;  // bit 9
-               u16 port_type:1;        // bit 10
-               u16 cfg_value:1;        // bit 11
-               u16 cfg_enable:1;       // bit 12
-               u16 test_mode:3;        // bit 15:13
-       } bits;
-} MSCR_t, *PMSCR_t;
-
 enum _mii_mscr {
        MII_MSCR_TEST_MODE = 0xe000,
        MII_MSCR_CFG_ENABLE = 0x1000,
@@ -483,20 +383,6 @@ enum _mii_mscr {
 };
 
 /* MASTER-SLAVE Status Register */
-typedef union t_MII_MSSR {
-       u16 image;
-       struct {
-               u16 idle_err_count:8;   // bit 7:0
-               u16 _bit_9_8:2; // bit 9:8
-               u16 lp_1000BT_HD:1;     // bit 10
-               u16 lp_1000BT_FD:1;     // bit 11
-               u16 remote_rcv_status:1;        // bit 12
-               u16 local_rcv_status:1; // bit 13
-               u16 cfg_resolution:1;   // bit 14
-               u16 cfg_fault:1;        // bit 15
-       } bits;
-} MSSR_t, *PMSSR_t;
-
 enum _mii_mssr {
        MII_MSSR_CFG_FAULT = 0x8000,
        MII_MSSR_CFG_RES = 0x4000,
@@ -508,17 +394,6 @@ enum _mii_mssr {
 };
 
 /* IEEE Extened Status Register */
-typedef union t_MII_ESR {
-       u16 image;
-       struct {
-               u16 _bit_11_0:12;       // bit 11:0
-               u16 media_1000BT_HD:2;  // bit 12
-               u16 media_1000BT_FD:1;  // bit 13
-               u16 media_1000BX_HD:1;  // bit 14
-               u16 media_1000BX_FD:1;  // bit 15
-       } bits;
-} ESR_t, *PESR_t;
-
 enum _mii_esr {
        MII_ESR_1000BX_FD = 0x8000,
        MII_ESR_1000BX_HD = 0x4000,
@@ -526,6 +401,7 @@ enum _mii_esr {
        MII_ESR_1000BT_HD = 0x1000,
 };
 /* PHY Specific Control Register */
+#if 0
 typedef union t_MII_PHY_SCR {
        u16 image;
        struct {
@@ -543,6 +419,7 @@ typedef union t_MII_PHY_SCR {
                u16 xmit_fifo_depth:2;  // bit 15:14
        } bits;
 } PHY_SCR_t, *PPHY_SCR_t;
+#endif
 
 typedef enum t_MII_ADMIN_STATUS {
        adm_reset,
@@ -556,21 +433,6 @@ typedef enum t_MII_ADMIN_STATUS {
 /* PCS control and status registers bitmap as the same as MII */
 /* PCS Extended Status register bitmap as the same as MII */
 /* PCS ANAR */
-typedef union t_PCS_ANAR {
-       u16 image;
-       struct {
-               u16 _bit_4_0:5;         // bit 4:0
-               u16 full_duplex:1;      // bit 5
-               u16 half_duplex:1;      // bit 6
-               u16 asymmetric:1;       // bit 7
-               u16 pause:1;            // bit 8
-               u16 _bit_11_9:3;        // bit 11:9
-               u16 remote_fault:2;     // bit 13:12
-               u16 _bit_14:1;          // bit 14
-               u16 next_page:1;        // bit 15
-       } bits;
-} ANAR_PCS_t, *PANAR_PCS_t;
-
 enum _pcs_anar {
        PCS_ANAR_NEXT_PAGE = 0x8000,
        PCS_ANAR_REMOTE_FAULT = 0x3000,
@@ -580,21 +442,6 @@ enum _pcs_anar {
        PCS_ANAR_FULL_DUPLEX = 0x0020,
 };
 /* PCS ANLPAR */
-typedef union t_PCS_ANLPAR {
-       u16 image;
-       struct {
-               u16 _bit_4_0:5;         // bit 4:0
-               u16 full_duplex:1;      // bit 5
-               u16 half_duplex:1;      // bit 6
-               u16 asymmetric:1;       // bit 7
-               u16 pause:1;            // bit 8
-               u16 _bit_11_9:3;        // bit 11:9
-               u16 remote_fault:2;     // bit 13:12
-               u16 _bit_14:1;          // bit 14
-               u16 next_page:1;        // bit 15
-       } bits;
-} ANLPAR_PCS_t, *PANLPAR_PCS_t;
-
 enum _pcs_anlpar {
        PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
        PCS_ANLPAR_REMOTE_FAULT = PCS_ANAR_REMOTE_FAULT,
index 2b06e4b4dabc1342fa66101c7a4f0628da5b3bf7..b87402bc83081fd808681b16166b25b1c20a2020 100644 (file)
@@ -1991,13 +1991,12 @@ static int e100_poll(struct napi_struct *napi, int budget)
        struct nic *nic = container_of(napi, struct nic, napi);
        struct net_device *netdev = nic->netdev;
        unsigned int work_done = 0;
-       int tx_cleaned;
 
        e100_rx_clean(nic, &work_done, budget);
-       tx_cleaned = e100_tx_clean(nic);
+       e100_tx_clean(nic);
 
-       /* If no Rx and Tx cleanup work was done, exit polling mode. */
-       if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+       /* If budget not fully consumed, exit the polling mode */
+       if (work_done < budget) {
                netif_rx_complete(netdev, napi);
                e100_enable_irq(nic);
        }
index 4f37506ad3744656c86d102f63fb66aac2185876..76c0fa690cc6adb60e0ab94d1e4cf7cbb6cbb00f 100644 (file)
@@ -632,6 +632,7 @@ e1000_down(struct e1000_adapter *adapter)
 
 #ifdef CONFIG_E1000_NAPI
        napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
 #endif
        e1000_irq_disable(adapter);
 
@@ -3924,27 +3925,24 @@ e1000_clean(struct napi_struct *napi, int budget)
        /* Must NOT use netdev_priv macro here. */
        adapter = poll_dev->priv;
 
-       /* Keep link state information with original netdev */
-       if (!netif_carrier_ok(poll_dev))
-               goto quit_polling;
-
        /* e1000_clean is called per-cpu.  This lock protects
         * tx_ring[0] from being cleaned by multiple cpus
         * simultaneously.  A failure obtaining the lock means
         * tx_ring[0] is currently being cleaned anyway. */
        if (spin_trylock(&adapter->tx_queue_lock)) {
                tx_cleaned = e1000_clean_tx_irq(adapter,
-                                               &adapter->tx_ring[0]);
+                                               &adapter->tx_ring[0]);
                spin_unlock(&adapter->tx_queue_lock);
        }
 
        adapter->clean_rx(adapter, &adapter->rx_ring[0],
                          &work_done, budget);
 
-       /* If no Tx and not enough Rx work done, exit the polling mode */
-       if ((!tx_cleaned && (work_done == 0)) ||
-          !netif_running(poll_dev)) {
-quit_polling:
+       if (tx_cleaned)
+               work_done = budget;
+
+       /* If budget not fully consumed, exit the polling mode */
+       if (work_done < budget) {
                if (likely(adapter->itr_setting & 3))
                        e1000_set_itr(adapter);
                netif_rx_complete(poll_dev, napi);
index 4fd2e23720b69f080569b9c9a789ba2b8fcb7964..9cc5a6b01bc1dcfb73ca17ec11a476e586837951 100644 (file)
@@ -1389,10 +1389,6 @@ static int e1000_clean(struct napi_struct *napi, int budget)
        /* Must NOT use netdev_priv macro here. */
        adapter = poll_dev->priv;
 
-       /* Keep link state information with original netdev */
-       if (!netif_carrier_ok(poll_dev))
-               goto quit_polling;
-
        /* e1000_clean is called per-cpu.  This lock protects
         * tx_ring from being cleaned by multiple cpus
         * simultaneously.  A failure obtaining the lock means
@@ -1404,10 +1400,11 @@ static int e1000_clean(struct napi_struct *napi, int budget)
 
        adapter->clean_rx(adapter, &work_done, budget);
 
-       /* If no Tx and not enough Rx work done, exit the polling mode */
-       if ((!tx_cleaned && (work_done < budget)) ||
-          !netif_running(poll_dev)) {
-quit_polling:
+       if (tx_cleaned)
+               work_done = budget;
+
+       /* If budget not fully consumed, exit the polling mode */
+       if (work_done < budget) {
                if (adapter->itr_setting & 3)
                        e1000_set_itr(adapter);
                netif_rx_complete(poll_dev, napi);
@@ -2186,6 +2183,7 @@ void e1000e_down(struct e1000_adapter *adapter)
        msleep(10);
 
        napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
        e1000_irq_disable(adapter);
 
        del_timer_sync(&adapter->watchdog_timer);
index ecdd3fc8d70ca8af89dc4fbd2f3033139a1fbeb0..0b365b8d947ba8dabd1dd28e94f1710d823cca77 100644 (file)
@@ -1273,7 +1273,7 @@ rx_action:
 
        epic_rx_err(dev, ep);
 
-       if (netif_running(dev) && (work_done < budget)) {
+       if (work_done < budget) {
                unsigned long flags;
                int more;
 
index 8d2904fa57896d33db21f274ca9181fb6f2f828a..ab9637ab3a8d9ccf9ff26e7356a70a559227139d 100644 (file)
@@ -476,11 +476,6 @@ static int fec_enet_rx_common(struct fec_enet_private *ep,
        __u16 pkt_len, sc;
        int curidx;
 
-       if (fpi->use_napi) {
-               if (!netif_running(dev))
-                       return 0;
-       }
-
        /*
         * First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index a96583cceb5ef77c1e374caa47a45ec43471f151..f84c752997a46c92e03133691ab08d61d37c0c27 100644 (file)
@@ -5199,10 +5199,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
                dev->dev_addr[4] = (np->orig_mac[0] >>  8) & 0xff;
                dev->dev_addr[5] = (np->orig_mac[0] >>  0) & 0xff;
-               /* set permanent address to be correct aswell */
-               np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
-                       (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
-               np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
                writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
        }
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
@@ -5414,6 +5410,8 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
         */
        writel(np->orig_mac[0], base + NvRegMacAddrA);
        writel(np->orig_mac[1], base + NvRegMacAddrB);
+       writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV,
+              base + NvRegTransmitPoll);
 
        /* free all structures */
        free_rings(dev);
index f2a4d399a6e5137f63fab69a52677317d6d7c9c9..c83bd65600883d721f40d54d17a8f7e37ab26480 100644 (file)
@@ -96,9 +96,6 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
        u16 pkt_len, sc;
        int curidx;
 
-       if (!netif_running(dev))
-               return 0;
-
        /*
         * First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
@@ -897,14 +894,21 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct fs_enet_private *fep = netdev_priv(dev);
+
+       if (!fep->phydev)
+               return -ENODEV;
+
        return phy_ethtool_gset(fep->phydev, cmd);
 }
 
 static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct fs_enet_private *fep = netdev_priv(dev);
-       phy_ethtool_sset(fep->phydev, cmd);
-       return 0;
+
+       if (!fep->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_sset(fep->phydev, cmd);
 }
 
 static int fs_nway_reset(struct net_device *dev)
index 7d7758f3ad8c1afb4d4b767d1e25061728f4fade..57772bebff56336cb50c3bde81c0823d13210787 100644 (file)
@@ -1179,13 +1179,15 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
 
        for(i = 0; i<IbmVethNumBufferPools; i++) {
                struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
+               int error;
+
                ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
                                         pool_count[i], pool_size[i],
                                         pool_active[i]);
-               kobj->parent = &dev->dev.kobj;
-               kobject_set_name(kobj, "pool%d", i);
-               kobj->ktype = &ktype_veth_pool;
-               kobject_register(kobj);
+               error = kobject_init_and_add(kobj, &ktype_veth_pool,
+                                            &dev->dev.kobj, "pool%d", i);
+               if (!error)
+                       kobject_uevent(kobj, KOBJ_ADD);
        }
 
        ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
@@ -1234,7 +1236,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
        int i;
 
        for(i = 0; i<IbmVethNumBufferPools; i++)
-               kobject_unregister(&adapter->rx_buff_pool[i].kobj);
+               kobject_put(&adapter->rx_buff_pool[i].kobj);
 
        unregister_netdev(netdev);
 
index dbd23bb65d1ec4cc634704f75db7e35f199cf06b..50f0c17451b10cccbafbb77d7c03bc55d9a70f91 100644 (file)
@@ -857,21 +857,14 @@ static void init_tfdlist(struct net_device *dev)
 static void ipg_nic_txfree(struct net_device *dev)
 {
        struct ipg_nic_private *sp = netdev_priv(dev);
-       void __iomem *ioaddr = sp->ioaddr;
-       unsigned int curr;
-       u64 txd_map;
-       unsigned int released, pending;
-
-       txd_map = (u64)sp->txd_map;
-       curr = ipg_r32(TFD_LIST_PTR_0) -
-               do_div(txd_map, sizeof(struct ipg_tx)) - 1;
+       unsigned int released, pending, dirty;
 
        IPG_DEBUG_MSG("_nic_txfree\n");
 
        pending = sp->tx_current - sp->tx_dirty;
+       dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
 
        for (released = 0; released < pending; released++) {
-               unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
                struct sk_buff *skb = sp->TxBuff[dirty];
                struct ipg_tx *txfd = sp->txd + dirty;
 
@@ -882,11 +875,8 @@ static void ipg_nic_txfree(struct net_device *dev)
                 * If the TFDDone bit is set, free the associated
                 * buffer.
                 */
-               if (dirty == curr)
-                       break;
-
-               /* Setup TFDDONE for compatible issue. */
-               txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE);
+               if (!(txfd->tfc & cpu_to_le64(IPG_TFC_TFDDONE)))
+                        break;
 
                /* Free the transmit buffer. */
                if (skb) {
@@ -898,6 +888,7 @@ static void ipg_nic_txfree(struct net_device *dev)
 
                        sp->TxBuff[dirty] = NULL;
                }
+               dirty = (dirty + 1) % IPG_TFDLIST_LENGTH;
        }
 
        sp->tx_dirty += released;
@@ -1630,6 +1621,8 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
 #ifdef JUMBO_FRAME
        ipg_nic_rxrestore(dev);
 #endif
+       spin_lock(&sp->lock);
+
        /* Get interrupt source information, and acknowledge
         * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
         * IntRequested, MacControlFrame, LinkEvent) interrupts
@@ -1647,9 +1640,7 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
        handled = 1;
 
        if (unlikely(!netif_running(dev)))
-               goto out;
-
-       spin_lock(&sp->lock);
+               goto out_unlock;
 
        /* If RFDListEnd interrupt, restore all used RFDs. */
        if (status & IPG_IS_RFD_LIST_END) {
@@ -1733,9 +1724,9 @@ out_enable:
        ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
                IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
                IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
-
+out_unlock:
        spin_unlock(&sp->lock);
-out:
+
        return IRQ_RETVAL(handled);
 }
 
@@ -1943,10 +1934,7 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        if (sp->tenmbpsmode)
                txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
-       else if (!((sp->tx_current - sp->tx_dirty + 1) >
-           IPG_FRAMESBETWEENTXDMACOMPLETES)) {
-               txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
-       }
+       txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
        /* Based on compilation option, determine if FCS is to be
         * appended to transmit frame by IPG.
         */
@@ -2003,7 +1991,7 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
 
        if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
-               netif_wake_queue(dev);
+               netif_stop_queue(dev);
 
        spin_unlock_irqrestore(&sp->lock, flags);
 
index 97bd9dc2e52e8a2aa1f42ef764e5119e53dc8aba..419861cbc65ecb23ae1172b6559b402bc0caa8d6 100644 (file)
@@ -815,7 +815,7 @@ static int veth_init_connection(u8 rlp)
 {
        struct veth_lpar_connection *cnx;
        struct veth_msg *msgs;
-       int i, rc;
+       int i;
 
        if ( (rlp == this_lp)
             || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
@@ -844,11 +844,7 @@ static int veth_init_connection(u8 rlp)
 
        /* This gets us 1 reference, which is held on behalf of the driver
         * infrastructure. It's released at module unload. */
-       kobject_init(&cnx->kobject);
-       cnx->kobject.ktype = &veth_lpar_connection_ktype;
-       rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
-       if (rc != 0)
-               return rc;
+       kobject_init(&cnx->kobject, &veth_lpar_connection_ktype);
 
        msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
        if (! msgs) {
@@ -1087,11 +1083,8 @@ static struct net_device * __init veth_probe_one(int vlan,
                return NULL;
        }
 
-       kobject_init(&port->kobject);
-       port->kobject.parent = &dev->dev.kobj;
-       port->kobject.ktype  = &veth_port_ktype;
-       kobject_set_name(&port->kobject, "veth_port");
-       if (0 != kobject_add(&port->kobject))
+       kobject_init(&port->kobject, &veth_port_ktype);
+       if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port"))
                veth_error("Failed adding port for %s to sysfs.\n", dev->name);
 
        veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
@@ -1711,9 +1704,9 @@ static int __init veth_module_init(void)
                        continue;
 
                kobj = &veth_cnx[i]->kobject;
-               kobj->parent = &veth_driver.driver.kobj;
                /* If the add failes, complain but otherwise continue */
-               if (0 != kobject_add(kobj))
+               if (0 != driver_add_kobj(&veth_driver.driver, kobj,
+                                       "cnx%.2d", veth_cnx[i]->remote_lp))
                        veth_error("cnx %d: Failed adding to sysfs.\n", i);
        }
 
index bf9085fe035aa6d4c6476c7fdf4540704494f9e0..4f63839051b05ca2d282e8e62dd0419713d0e124 100644 (file)
@@ -296,6 +296,11 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
 {
        struct net_device *netdev = adapter->netdev;
 
+#ifdef CONFIG_IXGB_NAPI
+       napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
+#endif
+
        ixgb_irq_disable(adapter);
        free_irq(adapter->pdev->irq, netdev);
 
@@ -304,9 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
 
        if(kill_watchdog)
                del_timer_sync(&adapter->watchdog_timer);
-#ifdef CONFIG_IXGB_NAPI
-       napi_disable(&adapter->napi);
-#endif
+
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
        netif_carrier_off(netdev);
@@ -1787,14 +1790,13 @@ ixgb_clean(struct napi_struct *napi, int budget)
 {
        struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi);
        struct net_device *netdev = adapter->netdev;
-       int tx_cleaned;
        int work_done = 0;
 
-       tx_cleaned = ixgb_clean_tx_irq(adapter);
+       ixgb_clean_tx_irq(adapter);
        ixgb_clean_rx_irq(adapter, &work_done, budget);
 
-       /* if no Tx and not enough Rx work done, exit the polling mode */
-       if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+       /* If budget not fully consumed, exit the polling mode */
+       if (work_done < budget) {
                netif_rx_complete(netdev, napi);
                ixgb_irq_enable(adapter);
        }
index 00bc525c656071aebb25b8c4151eba246ce72686..a4265bc1cebb7162fbbdcbc59ffd2590f292fc9e 100644 (file)
@@ -1409,9 +1409,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_FLUSH(&adapter->hw);
        msleep(10);
 
+       napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
+
        ixgbe_irq_disable(adapter);
 
-       napi_disable(&adapter->napi);
        del_timer_sync(&adapter->watchdog_timer);
 
        netif_carrier_off(netdev);
@@ -1470,19 +1472,16 @@ static int ixgbe_clean(struct napi_struct *napi, int budget)
        struct net_device *netdev = adapter->netdev;
        int tx_cleaned = 0, work_done = 0;
 
-       /* Keep link state information with original netdev */
-       if (!netif_carrier_ok(adapter->netdev))
-               goto quit_polling;
-
        /* In non-MSIX case, there is no multi-Tx/Rx queue */
        tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
        ixgbe_clean_rx_irq(adapter, &adapter->rx_ring[0], &work_done,
                           budget);
 
-       /* If no Tx and not enough Rx work done, exit the polling mode */
-       if ((!tx_cleaned && (work_done < budget)) ||
-           !netif_running(adapter->netdev)) {
-quit_polling:
+       if (tx_cleaned)
+               work_done = budget;
+
+       /* If budget not fully consumed, exit the polling mode */
+       if (work_done < budget) {
                netif_rx_complete(netdev, napi);
                ixgbe_irq_enable(adapter);
        }
index 6c0dd49149d0d3047d55059fd2c54889a3e7786b..484cb2ba717f97d1df4f84b43701a9b7cf7b4bca 100644 (file)
@@ -135,8 +135,6 @@ static int ixpdev_poll(struct napi_struct *napi, int budget)
        struct net_device *dev = ip->dev;
        int rx;
 
-       /* @@@ Have to stop polling when nds[0] is administratively
-        * downed while we are polling.  */
        rx = 0;
        do {
                ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
index 662b8d16803ce7fec85f59af645b60aabee75c41..fa147cd5d68c07e2b8e434ffad5db9c55891b58d 100644 (file)
@@ -242,7 +242,7 @@ static void loopback_setup(struct net_device *dev)
                | NETIF_F_NO_CSUM
                | NETIF_F_HIGHDMA
                | NETIF_F_LLTX
-               | NETIF_F_NETNS_LOCAL,
+               | NETIF_F_NETNS_LOCAL;
        dev->ethtool_ops        = &loopback_ethtool_ops;
        dev->header_ops         = &eth_header_ops;
        dev->init = loopback_dev_init;
index 2e4bcd5654c4c0b62db0e795f87c96d73c176207..e8dc2f44fec960d9d3b58127699e5a4ed9eee838 100644 (file)
@@ -384,6 +384,13 @@ static int macvlan_newlink(struct net_device *dev,
        if (lowerdev == NULL)
                return -ENODEV;
 
+       /* Don't allow macvlans on top of other macvlans - its not really
+        * wrong, but lockdep can't handle it and its not useful for anything
+        * you couldn't do directly on top of the real device.
+        */
+       if (lowerdev->rtnl_link_ops == dev->rtnl_link_ops)
+               return -ENODEV;
+
        if (!tb[IFLA_MTU])
                dev->mtu = lowerdev->mtu;
        else if (dev->mtu > lowerdev->mtu)
index 0c89b028a80c5f04c7b1ca0cdfe3ff62f6b974ce..cdaa8fc218091a947996280d27c63caa16f56f84 100644 (file)
@@ -95,11 +95,14 @@ static inline void load_eaddr(struct net_device *dev)
 {
        int i;
        DECLARE_MAC_BUF(mac);
+       u64 macaddr;
 
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = o2meth_eaddr[i];
        DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr));
-       mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16;
+       macaddr = 0;
+       for (i = 0; i < 6; i++)
+               macaddr |= dev->dev_addr[i] << ((5 - i) * 8);
+
+       mace->eth.mac_addr = macaddr;
 }
 
 /*
@@ -794,6 +797,7 @@ static int __init meth_probe(struct platform_device *pdev)
 #endif
        dev->irq             = MACE_ETHERNET_IRQ;
        dev->base_addr       = (unsigned long)&mace->eth;
+       memcpy(dev->dev_addr, o2meth_eaddr, 6);
 
        priv = netdev_priv(dev);
        spin_lock_init(&priv->meth_lock);
index 50648738d679b7e60aeb720eb8e6ba161c6d02a2..535a4461d88c6d720758e15d7fd21a67676a0fd9 100644 (file)
@@ -202,7 +202,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
        dev_cap->reserved_eqs = 1 << (field & 0xf);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
-       dev_cap->max_eqs = 1 << (field & 0x7);
+       dev_cap->max_eqs = 1 << (field & 0xf);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
        dev_cap->reserved_mtts = 1 << (field >> 4);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
index 8def8657251f19435fa50960cc9a0f69459f417e..c90958f6d3fe8a807976c79a8a1734b186969f1d 100644 (file)
@@ -1239,7 +1239,7 @@ static int myri10ge_poll(struct napi_struct *napi, int budget)
        /* process as many rx events as NAPI will allow */
        work_done = myri10ge_clean_rx_done(mgp, budget);
 
-       if (work_done < budget || !netif_running(netdev)) {
+       if (work_done < budget) {
                netif_rx_complete(netdev, napi);
                put_be32(htonl(3), mgp->irq_claim);
        }
index 87cde062fd63d3a58caa6cb7175e8c0bd56b68d3..c329a4f5840c7c22ee80a2882343888ea13ffbde 100644 (file)
@@ -2266,7 +2266,7 @@ static int natsemi_poll(struct napi_struct *napi, int budget)
        /* Reenable interrupts providing nothing is trying to shut
         * the chip down. */
        spin_lock(&np->lock);
-       if (!np->hands_off && netif_running(dev))
+       if (!np->hands_off)
                natsemi_irq_enable(dev);
        spin_unlock(&np->lock);
 
index 5267e031daa0b3ab27d3d1dde092cb2fdc8e6159..78d34af13a1ca8c59817a3c203b77e715ae6399d 100644 (file)
@@ -169,8 +169,8 @@ static void netx_eth_receive(struct net_device *ndev)
        ndev->last_rx = jiffies;
        skb->protocol = eth_type_trans(skb, ndev);
        netif_rx(skb);
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += len;
+       ndev->stats.rx_packets++;
+       ndev->stats.rx_bytes += len;
 }
 
 static irqreturn_t
index fbc2553275dc82d4dc0b671ba4d5147fb49fc159..a8f63c47b3cd5bcf5cf41826e078cffa7c7c2767 100644 (file)
@@ -65,8 +65,8 @@
 
 #define _NETXEN_NIC_LINUX_MAJOR 3
 #define _NETXEN_NIC_LINUX_MINOR 4
-#define _NETXEN_NIC_LINUX_SUBVERSION 2
-#define NETXEN_NIC_LINUX_VERSIONID  "3.4.2"
+#define _NETXEN_NIC_LINUX_SUBVERSION 18
+#define NETXEN_NIC_LINUX_VERSIONID  "3.4.18"
 
 #define NETXEN_NUM_FLASH_SECTORS (64)
 #define NETXEN_FLASH_SECTOR_SIZE (64 * 1024)
@@ -309,23 +309,26 @@ struct netxen_ring_ctx {
        ((cmd_desc)->port_ctxid |= ((var) & 0xF0))
 
 #define netxen_set_cmd_desc_flags(cmd_desc, val)       \
-       ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \
-       (cmd_desc)->flags_opcode |= cpu_to_le16((val) & 0x7f))
+       (cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \
+               ~cpu_to_le16(0x7f)) | cpu_to_le16((val) & 0x7f)
 #define netxen_set_cmd_desc_opcode(cmd_desc, val)      \
-       ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x3f<<7), \
-       (cmd_desc)->flags_opcode |= cpu_to_le16(((val & 0x3f)<<7)))
+       (cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \
+               ~cpu_to_le16((u16)0x3f << 7)) | cpu_to_le16(((val) & 0x3f) << 7)
 
 #define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \
-       ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xff), \
-       (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32((val) & 0xff))
+       (cmd_desc)->num_of_buffers_total_length = \
+               ((cmd_desc)->num_of_buffers_total_length & \
+               ~cpu_to_le32(0xff)) | cpu_to_le32((val) & 0xff)
 #define netxen_set_cmd_desc_totallength(cmd_desc, val) \
-       ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xffffff00), \
-       (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 8))
+       (cmd_desc)->num_of_buffers_total_length = \
+               ((cmd_desc)->num_of_buffers_total_length & \
+               ~cpu_to_le32((u32)0xffffff << 8)) | \
+               cpu_to_le32(((val) & 0xffffff) << 8)
 
 #define netxen_get_cmd_desc_opcode(cmd_desc)   \
-       ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003F)
+       ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003f)
 #define netxen_get_cmd_desc_totallength(cmd_desc)      \
-       (le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8)
+       ((le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8) & 0xffffff)
 
 struct cmd_desc_type0 {
        u8 tcp_hdr_offset;      /* For LSO only */
@@ -412,29 +415,29 @@ struct rcv_desc {
 #define netxen_get_sts_desc_lro_last_frag(status_desc) \
        (((status_desc)->lro & 0x80) >> 7)
 
-#define netxen_get_sts_port(status_desc)       \
-       (le64_to_cpu((status_desc)->status_desc_data) & 0x0F)
-#define netxen_get_sts_status(status_desc)     \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 4) & 0x0F)
-#define netxen_get_sts_type(status_desc)       \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 8) & 0x0F)
-#define netxen_get_sts_totallength(status_desc)        \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 12) & 0xFFFF)
-#define netxen_get_sts_refhandle(status_desc)  \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 28) & 0xFFFF)
-#define netxen_get_sts_prot(status_desc)       \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 44) & 0x0F)
+#define netxen_get_sts_port(sts_data)  \
+       ((sts_data) & 0x0F)
+#define netxen_get_sts_status(sts_data)        \
+       (((sts_data) >> 4) & 0x0F)
+#define netxen_get_sts_type(sts_data)  \
+       (((sts_data) >> 8) & 0x0F)
+#define netxen_get_sts_totallength(sts_data)   \
+       (((sts_data) >> 12) & 0xFFFF)
+#define netxen_get_sts_refhandle(sts_data)     \
+       (((sts_data) >> 28) & 0xFFFF)
+#define netxen_get_sts_prot(sts_data)  \
+       (((sts_data) >> 44) & 0x0F)
+#define netxen_get_sts_opcode(sts_data)        \
+       (((sts_data) >> 58) & 0x03F)
+
 #define netxen_get_sts_owner(status_desc)      \
        ((le64_to_cpu((status_desc)->status_desc_data) >> 56) & 0x03)
-#define netxen_get_sts_opcode(status_desc)     \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 58) & 0x03F)
-
-#define netxen_clear_sts_owner(status_desc)    \
-       ((status_desc)->status_desc_data &=     \
-       ~cpu_to_le64(((unsigned long long)3) << 56 ))
-#define netxen_set_sts_owner(status_desc, val) \
-       ((status_desc)->status_desc_data |=     \
-       cpu_to_le64(((unsigned long long)((val) & 0x3)) << 56 ))
+#define netxen_set_sts_owner(status_desc, val) { \
+       (status_desc)->status_desc_data = \
+               ((status_desc)->status_desc_data & \
+               ~cpu_to_le64(0x3ULL << 56)) | \
+               cpu_to_le64((u64)((val) & 0x3) << 56); \
+}
 
 struct status_desc {
        /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
index 37589265297edd86fa6047f2181c6e72fec1e5c1..485ff93989109360f6db7d2607e0892c029146e0 100644 (file)
@@ -1070,16 +1070,17 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
 {
        struct pci_dev *pdev = adapter->pdev;
        struct net_device *netdev = adapter->netdev;
-       int index = netxen_get_sts_refhandle(desc);
+       u64 sts_data = le64_to_cpu(desc->status_desc_data);
+       int index = netxen_get_sts_refhandle(sts_data);
        struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
        struct netxen_rx_buffer *buffer;
        struct sk_buff *skb;
-       u32 length = netxen_get_sts_totallength(desc);
+       u32 length = netxen_get_sts_totallength(sts_data);
        u32 desc_ctx;
        struct netxen_rcv_desc_ctx *rcv_desc;
        int ret;
 
-       desc_ctx = netxen_get_sts_type(desc);
+       desc_ctx = netxen_get_sts_type(sts_data);
        if (unlikely(desc_ctx >= NUM_RCV_DESC_RINGS)) {
                printk("%s: %s Bad Rcv descriptor ring\n",
                       netxen_nic_driver_name, netdev->name);
@@ -1119,7 +1120,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
        skb = (struct sk_buff *)buffer->skb;
 
        if (likely(adapter->rx_csum &&
-                               netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
+                               netxen_get_sts_status(sts_data) == STATUS_CKSUM_OK)) {
                adapter->stats.csummed++;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else
@@ -1209,7 +1210,6 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max)
                        break;
                }
                netxen_process_rcv(adapter, ctxid, desc);
-               netxen_clear_sts_owner(desc);
                netxen_set_sts_owner(desc, STATUS_OWNER_PHANTOM);
                consumer = (consumer + 1) & (adapter->max_rx_desc_count - 1);
                count++;
@@ -1248,7 +1248,6 @@ int netxen_process_cmd_ring(unsigned long data)
        struct pci_dev *pdev;
        struct netxen_skb_frag *frag;
        u32 i;
-       struct sk_buff *skb = NULL;
        int done;
 
        spin_lock(&adapter->tx_lock);
@@ -1278,9 +1277,8 @@ int netxen_process_cmd_ring(unsigned long data)
        while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) {
                buffer = &adapter->cmd_buf_arr[last_consumer];
                pdev = adapter->pdev;
-               frag = &buffer->frag_array[0];
-               skb = buffer->skb;
-               if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) {
+               if (buffer->skb) {
+                       frag = &buffer->frag_array[0];
                        pci_unmap_single(pdev, frag->dma, frag->length,
                                         PCI_DMA_TODEVICE);
                        frag->dma = 0ULL;
@@ -1293,8 +1291,8 @@ int netxen_process_cmd_ring(unsigned long data)
                        }
 
                        adapter->stats.skbfreed++;
-                       dev_kfree_skb_any(skb);
-                       skb = NULL;
+                       dev_kfree_skb_any(buffer->skb);
+                       buffer->skb = NULL;
                } else if (adapter->proc_cmd_buf_counter == 1) {
                        adapter->stats.txnullskb++;
                }
index a80f0cd6b528878fcf55900a7967305838242289..263b55e36c7a1b0d477bfd6e1e3892fb54097bcc 100644 (file)
@@ -732,11 +732,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 
        unregister_netdev(netdev);
 
-       if (adapter->stop_port)
-               adapter->stop_port(adapter);
-
-       netxen_nic_disable_int(adapter);
-
        if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
                init_firmware_done++;
                netxen_free_hw_resources(adapter);
@@ -919,6 +914,9 @@ static int netxen_nic_close(struct net_device *netdev)
        netif_stop_queue(netdev);
        napi_disable(&adapter->napi);
 
+       if (adapter->stop_port)
+               adapter->stop_port(adapter);
+
        netxen_nic_disable_int(adapter);
 
        cmd_buff = adapter->cmd_buf_arr;
@@ -996,28 +994,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_OK;
        }
 
-       /*
-        * Everything is set up. Now, we just need to transmit it out.
-        * Note that we have to copy the contents of buffer over to
-        * right place. Later on, this can be optimized out by de-coupling the
-        * producer index from the buffer index.
-        */
-      retry_getting_window:
-       spin_lock_bh(&adapter->tx_lock);
-       if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
-               spin_unlock_bh(&adapter->tx_lock);
-               /*
-                * Yield CPU
-                */
-               if (!in_atomic())
-                       schedule();
-               else {
-                       for (i = 0; i < 20; i++)
-                               cpu_relax();    /*This a nop instr on i386 */
-               }
-               goto retry_getting_window;
-       }
-       local_producer = adapter->cmd_producer;
        /* There 4 fragments per descriptor */
        no_of_desc = (frag_count + 3) >> 2;
        if (netdev->features & NETIF_F_TSO) {
@@ -1031,16 +1007,19 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                        }
                }
        }
+
+       spin_lock_bh(&adapter->tx_lock);
+       if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
+               goto out_requeue;
+       }
+       local_producer = adapter->cmd_producer;
        k = adapter->cmd_producer;
        max_tx_desc_count = adapter->max_tx_desc_count;
        last_cmd_consumer = adapter->last_cmd_consumer;
        if ((k + no_of_desc) >=
            ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
             last_cmd_consumer)) {
-               netif_stop_queue(netdev);
-               adapter->flags |= NETXEN_NETDEV_STATUS;
-               spin_unlock_bh(&adapter->tx_lock);
-               return NETDEV_TX_BUSY;
+               goto out_requeue;
        }
        k = get_index_range(k, max_tx_desc_count, no_of_desc);
        adapter->cmd_producer = k;
@@ -1093,6 +1072,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                                                  adapter->max_tx_desc_count);
                        hwdesc = &hw->cmd_desc_head[producer];
                        memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
+                       pbuf = &adapter->cmd_buf_arr[producer];
+                       pbuf->skb = NULL;
                }
                frag = &skb_shinfo(skb)->frags[i - 1];
                len = frag->size;
@@ -1148,6 +1129,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                }
                /* copy the MAC/IP/TCP headers to the cmd descriptor list */
                hwdesc = &hw->cmd_desc_head[producer];
+               pbuf = &adapter->cmd_buf_arr[producer];
+               pbuf->skb = NULL;
 
                /* copy the first 64 bytes */
                memcpy(((void *)hwdesc) + 2,
@@ -1156,6 +1139,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
                if (more_hdr) {
                        hwdesc = &hw->cmd_desc_head[producer];
+                       pbuf = &adapter->cmd_buf_arr[producer];
+                       pbuf->skb = NULL;
                        /* copy the next 64 bytes - should be enough except
                         * for pathological case
                         */
@@ -1167,16 +1152,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                }
        }
 
-       i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
-
-       hw->cmd_desc_head[saved_producer].flags_opcode =
-               cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode);
-       hw->cmd_desc_head[saved_producer].num_of_buffers_total_length =
-         cpu_to_le32(hw->cmd_desc_head[saved_producer].
-                         num_of_buffers_total_length);
-
        spin_lock_bh(&adapter->tx_lock);
-       adapter->stats.txbytes += i;
+       adapter->stats.txbytes += skb->len;
 
        /* Code to update the adapter considering how many producer threads
           are currently working */
@@ -1189,14 +1166,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        }
 
        adapter->stats.xmitfinished++;
-       spin_unlock_bh(&adapter->tx_lock);
-
        netdev->trans_start = jiffies;
 
-       DPRINTK(INFO, "wrote CMD producer %x to phantom\n", producer);
-
-       DPRINTK(INFO, "Done. Send\n");
+       spin_unlock_bh(&adapter->tx_lock);
        return NETDEV_TX_OK;
+
+out_requeue:
+       netif_stop_queue(netdev);
+       adapter->flags |= NETXEN_NETDEV_STATUS;
+
+       spin_unlock_bh(&adapter->tx_lock);
+       return NETDEV_TX_BUSY;
 }
 
 static void netxen_watchdog(unsigned long v)
@@ -1321,7 +1301,7 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget)
                                                     budget / MAX_RCV_CTX);
        }
 
-       if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0)
+       if (work_done >= budget)
                done = 0;
 
        if (netxen_process_cmd_ring((unsigned long)adapter) == 0)
index 5b9e1b300fab24f06b879802fe00e3493ed69862..d04ecb77d08c5bd92c96475465ba4bf0fc3a9d89 100644 (file)
@@ -736,12 +736,12 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
        __u32 mac_cfg;
        u32 port = physical_port[adapter->portnum];
 
-       if (port != 0)
+       if (port > NETXEN_NIU_MAX_XG_PORTS)
                return -EINVAL;
+
        mac_cfg = 0;
-       netxen_xg_soft_reset(mac_cfg);
-       if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0,
-                                  &mac_cfg, 4))
+       if (netxen_nic_hw_write_wx(adapter,
+               NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), &mac_cfg, 4))
                return -EIO;
        return 0;
 }
index abfc61c3a38c36258450dc046a5ec48f706f0503..5f6beabf2d179d71e399d85a0f75af84c36b189a 100644 (file)
@@ -33,8 +33,8 @@
 
 #define DRV_MODULE_NAME                "niu"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "0.5"
-#define DRV_MODULE_RELDATE     "October 5, 2007"
+#define DRV_MODULE_VERSION     "0.6"
+#define DRV_MODULE_RELDATE     "January 5, 2008"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -801,22 +801,90 @@ static int bcm8704_init_user_dev3(struct niu *np)
        return 0;
 }
 
-static int xcvr_init_10g(struct niu *np)
+static int mrvl88x2011_act_led(struct niu *np, int val)
+{
+       int     err;
+
+       err  = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+               MRVL88X2011_LED_8_TO_11_CTL);
+       if (err < 0)
+               return err;
+
+       err &= ~MRVL88X2011_LED(MRVL88X2011_LED_ACT,MRVL88X2011_LED_CTL_MASK);
+       err |=  MRVL88X2011_LED(MRVL88X2011_LED_ACT,val);
+
+       return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+                         MRVL88X2011_LED_8_TO_11_CTL, err);
+}
+
+static int mrvl88x2011_led_blink_rate(struct niu *np, int rate)
+{
+       int     err;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+                       MRVL88X2011_LED_BLINK_CTL);
+       if (err >= 0) {
+               err &= ~MRVL88X2011_LED_BLKRATE_MASK;
+               err |= (rate << 4);
+
+               err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+                                MRVL88X2011_LED_BLINK_CTL, err);
+       }
+
+       return err;
+}
+
+static int xcvr_init_10g_mrvl88x2011(struct niu *np)
+{
+       int     err;
+
+       /* Set LED functions */
+       err = mrvl88x2011_led_blink_rate(np, MRVL88X2011_LED_BLKRATE_134MS);
+       if (err)
+               return err;
+
+       /* led activity */
+       err = mrvl88x2011_act_led(np, MRVL88X2011_LED_CTL_OFF);
+       if (err)
+               return err;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                       MRVL88X2011_GENERAL_CTL);
+       if (err < 0)
+               return err;
+
+       err |= MRVL88X2011_ENA_XFPREFCLK;
+
+       err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                        MRVL88X2011_GENERAL_CTL, err);
+       if (err < 0)
+               return err;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                       MRVL88X2011_PMA_PMD_CTL_1);
+       if (err < 0)
+               return err;
+
+       if (np->link_config.loopback_mode == LOOPBACK_MAC)
+               err |= MRVL88X2011_LOOPBACK;
+       else
+               err &= ~MRVL88X2011_LOOPBACK;
+
+       err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                        MRVL88X2011_PMA_PMD_CTL_1, err);
+       if (err < 0)
+               return err;
+
+       /* Enable PMD  */
+       return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                         MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX);
+}
+
+static int xcvr_init_10g_bcm8704(struct niu *np)
 {
        struct niu_link_config *lp = &np->link_config;
        u16 analog_stat0, tx_alarm_status;
        int err;
-       u64 val;
-
-       val = nr64_mac(XMAC_CONFIG);
-       val &= ~XMAC_CONFIG_LED_POLARITY;
-       val |= XMAC_CONFIG_FORCE_LED_ON;
-       nw64_mac(XMAC_CONFIG, val);
-
-       /* XXX shared resource, lock parent XXX */
-       val = nr64(MIF_CONFIG);
-       val |= MIF_CONFIG_INDIRECT_MODE;
-       nw64(MIF_CONFIG, val);
 
        err = bcm8704_reset(np);
        if (err)
@@ -896,6 +964,38 @@ static int xcvr_init_10g(struct niu *np)
        return 0;
 }
 
+static int xcvr_init_10g(struct niu *np)
+{
+       int phy_id, err;
+       u64 val;
+
+       val = nr64_mac(XMAC_CONFIG);
+       val &= ~XMAC_CONFIG_LED_POLARITY;
+       val |= XMAC_CONFIG_FORCE_LED_ON;
+       nw64_mac(XMAC_CONFIG, val);
+
+       /* XXX shared resource, lock parent XXX */
+       val = nr64(MIF_CONFIG);
+       val |= MIF_CONFIG_INDIRECT_MODE;
+       nw64(MIF_CONFIG, val);
+
+       phy_id = phy_decode(np->parent->port_phy, np->port);
+       phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];
+
+       /* handle different phy types */
+       switch (phy_id & NIU_PHY_ID_MASK) {
+       case NIU_PHY_ID_MRVL88X2011:
+               err = xcvr_init_10g_mrvl88x2011(np);
+               break;
+
+       default: /* bcom 8704 */
+               err = xcvr_init_10g_bcm8704(np);
+               break;
+       }
+
+       return 0;
+}
+
 static int mii_reset(struct niu *np)
 {
        int limit, err;
@@ -1082,19 +1182,68 @@ static int niu_link_status_common(struct niu *np, int link_up)
        return 0;
 }
 
-static int link_status_10g(struct niu *np, int *link_up_p)
+static int link_status_10g_mrvl(struct niu *np, int *link_up_p)
 {
-       unsigned long flags;
-       int err, link_up;
+       int err, link_up, pma_status, pcs_status;
 
        link_up = 0;
 
-       spin_lock_irqsave(&np->lock, flags);
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                       MRVL88X2011_10G_PMD_STATUS_2);
+       if (err < 0)
+               goto out;
 
-       err = -EINVAL;
-       if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+       /* Check PMA/PMD Register: 1.0001.2 == 1 */
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                       MRVL88X2011_PMA_PMD_STATUS_1);
+       if (err < 0)
+               goto out;
+
+       pma_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);
+
+        /* Check PMC Register : 3.0001.2 == 1: read twice */
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                       MRVL88X2011_PMA_PMD_STATUS_1);
+       if (err < 0)
+               goto out;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                       MRVL88X2011_PMA_PMD_STATUS_1);
+       if (err < 0)
                goto out;
 
+       pcs_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);
+
+        /* Check XGXS Register : 4.0018.[0-3,12] */
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV4_ADDR,
+                       MRVL88X2011_10G_XGXS_LANE_STAT);
+       if (err < 0)
+               goto out;
+
+       if (err == (PHYXS_XGXS_LANE_STAT_ALINGED | PHYXS_XGXS_LANE_STAT_LANE3 |
+                   PHYXS_XGXS_LANE_STAT_LANE2 | PHYXS_XGXS_LANE_STAT_LANE1 |
+                   PHYXS_XGXS_LANE_STAT_LANE0 | PHYXS_XGXS_LANE_STAT_MAGIC |
+                   0x800))
+               link_up = (pma_status && pcs_status) ? 1 : 0;
+
+       np->link_config.active_speed = SPEED_10000;
+       np->link_config.active_duplex = DUPLEX_FULL;
+       err = 0;
+out:
+       mrvl88x2011_act_led(np, (link_up ?
+                                MRVL88X2011_LED_CTL_PCS_ACT :
+                                MRVL88X2011_LED_CTL_OFF));
+
+       *link_up_p = link_up;
+       return err;
+}
+
+static int link_status_10g_bcom(struct niu *np, int *link_up_p)
+{
+       int err, link_up;
+
+       link_up = 0;
+
        err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
                        BCM8704_PMD_RCV_SIGDET);
        if (err < 0)
@@ -1134,14 +1283,43 @@ static int link_status_10g(struct niu *np, int *link_up_p)
        err = 0;
 
 out:
+       *link_up_p = link_up;
+       return err;
+}
+
+static int link_status_10g(struct niu *np, int *link_up_p)
+{
+       unsigned long flags;
+       int err = -EINVAL;
+
+       spin_lock_irqsave(&np->lock, flags);
+
+       if (np->link_config.loopback_mode == LOOPBACK_DISABLED) {
+               int phy_id;
+
+               phy_id = phy_decode(np->parent->port_phy, np->port);
+               phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];
+
+               /* handle different phy types */
+               switch (phy_id & NIU_PHY_ID_MASK) {
+               case NIU_PHY_ID_MRVL88X2011:
+                       err = link_status_10g_mrvl(np, link_up_p);
+                       break;
+
+               default: /* bcom 8704 */
+                       err = link_status_10g_bcom(np, link_up_p);
+                       break;
+               }
+       }
+
        spin_unlock_irqrestore(&np->lock, flags);
 
-       *link_up_p = link_up;
        return err;
 }
 
 static int link_status_1g(struct niu *np, int *link_up_p)
 {
+       struct niu_link_config *lp = &np->link_config;
        u16 current_speed, bmsr;
        unsigned long flags;
        u8 current_duplex;
@@ -1209,6 +1387,8 @@ static int link_status_1g(struct niu *np, int *link_up_p)
                                link_up = 0;
                }
        }
+       lp->active_speed = current_speed;
+       lp->active_duplex = current_duplex;
        err = 0;
 
 out:
@@ -2241,6 +2421,8 @@ static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp)
        skb->protocol = eth_type_trans(skb, np->dev);
        netif_receive_skb(skb);
 
+       np->dev->last_rx = jiffies;
+
        return num_rcr;
 }
 
@@ -2508,15 +2690,19 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
        u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
        int err = 0;
 
-       dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
-               np->dev->name, rp->rx_channel, (unsigned long long) stat);
-
-       niu_log_rxchan_errors(np, rp, stat);
 
        if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL |
                    RX_DMA_CTL_STAT_PORT_FATAL))
                err = -EINVAL;
 
+       if (err) {
+               dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
+                       np->dev->name, rp->rx_channel,
+                       (unsigned long long) stat);
+
+               niu_log_rxchan_errors(np, rp, stat);
+       }
+
        nw64(RX_DMA_CTL_STAT(rp->rx_channel),
             stat & RX_DMA_CTL_WRITE_CLEAR_ERRS);
 
@@ -2749,13 +2935,16 @@ static int niu_device_error(struct niu *np)
        return -ENODEV;
 }
 
-static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
+static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp,
+                             u64 v0, u64 v1, u64 v2)
 {
-       u64 v0 = lp->v0;
-       u64 v1 = lp->v1;
-       u64 v2 = lp->v2;
+
        int i, err = 0;
 
+       lp->v0 = v0;
+       lp->v1 = v1;
+       lp->v2 = v2;
+
        if (v1 & 0x00000000ffffffffULL) {
                u32 rx_vec = (v1 & 0xffffffff);
 
@@ -2764,8 +2953,13 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
 
                        if (rx_vec & (1 << rp->rx_channel)) {
                                int r = niu_rx_error(np, rp);
-                               if (r)
+                               if (r) {
                                        err = r;
+                               } else {
+                                       if (!v0)
+                                               nw64(RX_DMA_CTL_STAT(rp->rx_channel),
+                                                    RX_DMA_CTL_STAT_MEX);
+                               }
                        }
                }
        }
@@ -2803,7 +2997,7 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
        if (err)
                niu_enable_interrupts(np, 0);
 
-       return -EINVAL;
+       return err;
 }
 
 static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
@@ -2905,7 +3099,7 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id)
        }
 
        if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) {
-               int err = niu_slowpath_interrupt(np, lp);
+               int err = niu_slowpath_interrupt(np, lp, v0, v1, v2);
                if (err)
                        goto out;
        }
@@ -5194,7 +5388,8 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
                kfree_skb(skb);
                skb = skb_new;
-       }
+       } else
+               skb_orphan(skb);
 
        align = ((unsigned long) skb->data & (16 - 1));
        headroom = align + sizeof(struct tx_pkt_hdr);
@@ -6282,7 +6477,8 @@ static int __devinit phy_record(struct niu_parent *parent,
        if (dev_id_1 < 0 || dev_id_2 < 0)
                return 0;
        if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
-               if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704)
+               if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) &&
+                   ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011))
                        return 0;
        } else {
                if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
index 10e3f111b6d5d17ed9ed50ac3dfce729485eb791..0e8626adc573e2a2ce3bdbf7e6c03bad40a5d3ee 100644 (file)
@@ -2538,6 +2538,39 @@ struct fcram_hash_ipv6 {
 #define NIU_PHY_ID_MASK                        0xfffff0f0
 #define NIU_PHY_ID_BCM8704             0x00206030
 #define NIU_PHY_ID_BCM5464R            0x002060b0
+#define NIU_PHY_ID_MRVL88X2011         0x01410020
+
+/* MRVL88X2011 register addresses */
+#define MRVL88X2011_USER_DEV1_ADDR     1
+#define MRVL88X2011_USER_DEV2_ADDR     2
+#define MRVL88X2011_USER_DEV3_ADDR     3
+#define MRVL88X2011_USER_DEV4_ADDR     4
+#define MRVL88X2011_PMA_PMD_CTL_1      0x0000
+#define MRVL88X2011_PMA_PMD_STATUS_1   0x0001
+#define MRVL88X2011_10G_PMD_STATUS_2   0x0008
+#define MRVL88X2011_10G_PMD_TX_DIS     0x0009
+#define MRVL88X2011_10G_XGXS_LANE_STAT 0x0018
+#define MRVL88X2011_GENERAL_CTL                0x8300
+#define MRVL88X2011_LED_BLINK_CTL      0x8303
+#define MRVL88X2011_LED_8_TO_11_CTL    0x8306
+
+/* MRVL88X2011 register control */
+#define MRVL88X2011_ENA_XFPREFCLK      0x0001
+#define MRVL88X2011_ENA_PMDTX          0x0000
+#define MRVL88X2011_LOOPBACK            0x1
+#define MRVL88X2011_LED_ACT            0x1
+#define MRVL88X2011_LNK_STATUS_OK      0x4
+#define MRVL88X2011_LED_BLKRATE_MASK   0x70
+#define MRVL88X2011_LED_BLKRATE_034MS  0x0
+#define MRVL88X2011_LED_BLKRATE_067MS  0x1
+#define MRVL88X2011_LED_BLKRATE_134MS  0x2
+#define MRVL88X2011_LED_BLKRATE_269MS  0x3
+#define MRVL88X2011_LED_BLKRATE_538MS  0x4
+#define MRVL88X2011_LED_CTL_OFF                0x0
+#define MRVL88X2011_LED_CTL_PCS_ACT    0x5
+#define MRVL88X2011_LED_CTL_MASK       0x7
+#define MRVL88X2011_LED(n,v)           ((v)<<((n)*4))
+#define MRVL88X2011_LED_STAT(n,v)      ((v)>>((n)*4))
 
 #define BCM8704_PMA_PMD_DEV_ADDR       1
 #define BCM8704_PCS_DEV_ADDR           2
index 288177716a49f90e0c61dc7273960eeef7ddb1ae..36a7ba3134ce7468b643138f3d57ea95334b95bc 100644 (file)
@@ -187,14 +187,16 @@ enum Window1 {
 enum Window3 {                 /* Window 3: MAC/config bits. */
        Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
 };
-union wn3_config {
-       int i;
-       struct w3_config_fields {
-               unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
-               int pad8:8;
-               unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
-               int pad24:7;
-       } u;
+enum wn3_config {
+       Ram_size = 7,
+       Ram_width = 8,
+       Ram_speed = 0x30,
+       Rom_size = 0xc0,
+       Ram_split_shift = 16,
+       Ram_split = 3 << Ram_split_shift,
+       Xcvr_shift = 20,
+       Xcvr = 7 << Xcvr_shift,
+       Autoselect = 0x1000000,
 };
 
 enum Window4 {         /* Window 4: Xcvr/media bits. */
@@ -342,7 +344,7 @@ static int tc574_config(struct pcmcia_device *link)
        kio_addr_t ioaddr;
        __be16 *phys_addr;
        char *cardname;
-       union wn3_config config;
+       __u32 config;
        DECLARE_MAC_BUF(mac);
 
        phys_addr = (__be16 *)dev->dev_addr;
@@ -401,9 +403,9 @@ static int tc574_config(struct pcmcia_device *link)
                outw(0<<11, ioaddr + RunnerRdCtrl);
                printk(KERN_INFO "  ASIC rev %d,", mcr>>3);
                EL3WINDOW(3);
-               config.i = inl(ioaddr + Wn3_Config);
-               lp->default_media = config.u.xcvr;
-               lp->autoselect = config.u.autoselect;
+               config = inl(ioaddr + Wn3_Config);
+               lp->default_media = (config & Xcvr) >> Xcvr_shift;
+               lp->autoselect = config & Autoselect ? 1 : 0;
        }
 
        init_timer(&lp->media);
@@ -464,8 +466,9 @@ static int tc574_config(struct pcmcia_device *link)
               dev->name, cardname, dev->base_addr, dev->irq,
               print_mac(mac, dev->dev_addr));
        printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
-                  8 << config.u.ram_size, ram_split[config.u.ram_split],
-                  config.u.autoselect ? "autoselect " : "");
+                  8 << config & Ram_size,
+                  ram_split[(config & Ram_split) >> Ram_split_shift],
+                  config & Autoselect ? "autoselect " : "");
 
        return 0;
 
index ff92aca0a7b37ad82daf35a38dfd9190353b356a..90498ffe26f284427b599a2430db3b8941314c54 100644 (file)
@@ -455,9 +455,14 @@ static void pcnet32_netif_start(struct net_device *dev)
 {
 #ifdef CONFIG_PCNET32_NAPI
        struct pcnet32_private *lp = netdev_priv(dev);
+       ulong ioaddr = dev->base_addr;
+       u16 val;
 #endif
        netif_wake_queue(dev);
 #ifdef CONFIG_PCNET32_NAPI
+       val = lp->a.read_csr(ioaddr, CSR3);
+       val &= 0x00ff;
+       lp->a.write_csr(ioaddr, CSR3, val);
        napi_enable(&lp->napi);
 #endif
 }
index a5791114b7bde59eddd6aed9c0dc79c590a8d688..cf0774de6c4154fbf46956deaa0fc420a22358f9 100644 (file)
@@ -2320,14 +2320,9 @@ static int ql_poll(struct napi_struct *napi, int budget)
        unsigned long hw_flags;
        struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
 
-       if (!netif_carrier_ok(ndev))
-               goto quit_polling;
-
        ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget);
 
-       if (tx_cleaned + rx_cleaned != budget ||
-           !netif_running(ndev)) {
-quit_polling:
+       if (tx_cleaned + rx_cleaned != budget) {
                spin_lock_irqsave(&qdev->hw_lock, hw_flags);
                __netif_rx_complete(ndev, napi);
                ql_update_small_bufq_prod_index(qdev);
index 5863190894cc9ce9464ec02404e915b8367c0a3c..3acfeeabdee1ee44cc842695b0d0ddb905e2d044 100644 (file)
@@ -2002,7 +2002,7 @@ static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
        u32 clk;
 
        clk = RTL_R8(Config2) & PCI_Clock_66MHz;
-       for (i = 0; i < ARRAY_SIZE(cfg2_info); i++) {
+       for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
                if ((p->mac_version == mac_version) && (p->clk == clk)) {
                        RTL_W32(0x7c, p->val);
                        break;
@@ -2398,6 +2398,8 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
        rtl8169_irq_mask_and_ack(ioaddr);
 
 #ifdef CONFIG_R8169_NAPI
+       tp->intr_mask = 0xffff;
+       RTL_W16(IntrMask, tp->intr_event);
        napi_enable(&tp->napi);
 #endif
 }
index 9d80f1cf73acbbe70a9eb8df62ef6a9c2f6be871..f2ba944e035ec4ffa6718d3767f9224c5ace39d5 100644 (file)
@@ -84,7 +84,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.26.10"
+#define DRV_VERSION "2.0.26.17"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -2704,9 +2704,6 @@ static int s2io_poll(struct napi_struct *napi, int budget)
        struct XENA_dev_config __iomem *bar0 = nic->bar0;
        int i;
 
-       if (!is_s2io_card_up(nic))
-               return 0;
-
        mac_control = &nic->mac_control;
        config = &nic->config;
 
@@ -3851,8 +3848,6 @@ static int s2io_open(struct net_device *dev)
        netif_carrier_off(dev);
        sp->last_link_state = 0;
 
-       napi_enable(&sp->napi);
-
        if (sp->config.intr_type == MSI_X) {
                int ret = s2io_enable_msi_x(sp);
 
@@ -3895,7 +3890,6 @@ static int s2io_open(struct net_device *dev)
        return 0;
 
 hw_init_failed:
-       napi_disable(&sp->napi);
        if (sp->config.intr_type == MSI_X) {
                if (sp->entries) {
                        kfree(sp->entries);
@@ -3935,7 +3929,6 @@ static int s2io_close(struct net_device *dev)
                return 0;
 
        netif_stop_queue(dev);
-       napi_disable(&sp->napi);
        /* Reset card, kill tasklet and free Tx and Rx buffers. */
        s2io_card_down(sp);
 
@@ -6799,6 +6792,8 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
        struct XENA_dev_config __iomem *bar0 = sp->bar0;
        unsigned long flags;
        register u64 val64 = 0;
+       struct config_param *config;
+       config = &sp->config;
 
        if (!is_s2io_card_up(sp))
                return;
@@ -6810,6 +6805,10 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
        }
        clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
 
+       /* Disable napi */
+       if (config->napi)
+               napi_disable(&sp->napi);
+
        /* disable Tx and Rx traffic on the NIC */
        if (do_io)
                stop_nic(sp);
@@ -6903,6 +6902,11 @@ static int s2io_card_up(struct s2io_nic * sp)
                DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
                          atomic_read(&sp->rx_bufs_left[i]));
        }
+
+       /* Initialise napi */
+       if (config->napi)
+               napi_enable(&sp->napi);
+
        /* Maintain the state prior to the open */
        if (sp->promisc_flg)
                sp->promisc_flg = 0;
index 7eab072ae79212daad67932a34c0fc4bcb425672..b570402f7feda2a06fc975a5aaf82e19b1f45432 100644 (file)
@@ -372,7 +372,7 @@ static void __mdio_cmd(void __iomem *ioaddr, u32 ctl)
                msleep(1);
        }
 
-       if (i > 999)
+       if (i > 99)
                printk(KERN_ERR PFX "PHY command failed !\n");
 }
 
@@ -847,10 +847,8 @@ static void sis190_soft_reset(void __iomem *ioaddr)
 {
        SIS_W32(IntrControl, 0x8000);
        SIS_PCI_COMMIT();
-       msleep(1);
        SIS_W32(IntrControl, 0x0);
        sis190_asic_down(ioaddr);
-       msleep(1);
 }
 
 static void sis190_hw_start(struct net_device *dev)
@@ -1041,8 +1039,6 @@ static int sis190_open(struct net_device *dev)
        if (rc < 0)
                goto err_free_rx_1;
 
-       INIT_WORK(&tp->phy_task, sis190_phy_task);
-
        sis190_request_timer(dev);
 
        rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev);
@@ -1549,28 +1545,31 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
 }
 
 /**
- *     sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model
+ *     sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model
  *     @pdev: PCI device
  *     @dev:  network device to get address for
  *
- *     SiS965 model, use APC CMOS RAM to store MAC address.
+ *     SiS96x model, use APC CMOS RAM to store MAC address.
  *     APC CMOS RAM is accessed through ISA bridge.
  *     MAC address is read into @net_dev->dev_addr.
  */
 static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
                                                  struct net_device *dev)
 {
+       static const u16 __devinitdata ids[] = { 0x0965, 0x0966, 0x0968 };
        struct sis190_private *tp = netdev_priv(dev);
        struct pci_dev *isa_bridge;
        u8 reg, tmp8;
-       int i;
+       unsigned int i;
 
        net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n",
                  pci_name(pdev));
 
-       isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL);
-       if (!isa_bridge)
-               isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0966, NULL);
+       for (i = 0; i < ARRAY_SIZE(ids); i++) {
+               isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, ids[i], NULL);
+               if (isa_bridge)
+                       break;
+       }
 
        if (!isa_bridge) {
                net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
index a74fc11a6482c51e9a8f43f2562cbfeea10dde4e..bc15940ce1bc8ed74ba8127df49f0599d2262c48 100644 (file)
@@ -944,7 +944,6 @@ static void tx_init(struct sky2_port *sky2)
        le = get_tx_le(sky2);
        le->addr = 0;
        le->opcode = OP_ADDR64 | HW_OWNER;
-       sky2->tx_addr64 = 0;
 }
 
 static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
@@ -978,13 +977,11 @@ static void sky2_rx_add(struct sky2_port *sky2,  u8 op,
                        dma_addr_t map, unsigned len)
 {
        struct sky2_rx_le *le;
-       u32 hi = upper_32_bits(map);
 
-       if (sky2->rx_addr64 != hi) {
+       if (sizeof(dma_addr_t) > sizeof(u32)) {
                le = sky2_next_rx(sky2);
-               le->addr = cpu_to_le32(hi);
+               le->addr = cpu_to_le32(upper_32_bits(map));
                le->opcode = OP_ADDR64 | HW_OWNER;
-               sky2->rx_addr64 = upper_32_bits(map + len);
        }
 
        le = sky2_next_rx(sky2);
@@ -1168,6 +1165,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
                             TX_VLAN_TAG_OFF);
        }
 
+       sky2_read32(hw, B0_Y2_SP_LISR);
        napi_enable(&hw->napi);
        netif_tx_unlock_bh(dev);
 }
@@ -1479,7 +1477,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        struct tx_ring_info *re;
        unsigned i, len;
        dma_addr_t mapping;
-       u32 addr64;
        u16 mss;
        u8 ctrl;
 
@@ -1492,15 +1489,12 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
        len = skb_headlen(skb);
        mapping = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
-       addr64 = upper_32_bits(mapping);
 
-       /* Send high bits if changed or crosses boundary */
-       if (addr64 != sky2->tx_addr64 ||
-           upper_32_bits(mapping + len) != sky2->tx_addr64) {
+       /* Send high bits if needed */
+       if (sizeof(dma_addr_t) > sizeof(u32)) {
                le = get_tx_le(sky2);
-               le->addr = cpu_to_le32(addr64);
+               le->addr = cpu_to_le32(upper_32_bits(mapping));
                le->opcode = OP_ADDR64 | HW_OWNER;
-               sky2->tx_addr64 = upper_32_bits(mapping + len);
        }
 
        /* Check for TCP Segmentation Offload */
@@ -1581,13 +1575,12 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
                mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset,
                                       frag->size, PCI_DMA_TODEVICE);
-               addr64 = upper_32_bits(mapping);
-               if (addr64 != sky2->tx_addr64) {
+
+               if (sizeof(dma_addr_t) > sizeof(u32)) {
                        le = get_tx_le(sky2);
-                       le->addr = cpu_to_le32(addr64);
+                       le->addr = cpu_to_le32(upper_32_bits(mapping));
                        le->ctrl = 0;
                        le->opcode = OP_ADDR64 | HW_OWNER;
-                       sky2->tx_addr64 = addr64;
                }
 
                le = get_tx_le(sky2);
@@ -2043,6 +2036,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        err = sky2_rx_start(sky2);
        sky2_write32(hw, B0_IMSK, imask);
 
+       sky2_read32(hw, B0_Y2_SP_LISR);
        napi_enable(&hw->napi);
 
        if (err)
@@ -3861,6 +3855,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
                   last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
                   sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
 
+       sky2_read32(hw, B0_Y2_SP_LISR);
        napi_enable(&hw->napi);
        return 0;
 }
index bc646a47edd2f04b83a78a5b40da085a90915192..ffe9b8a50a1b75943d1d9b9fec9a07a917b2e71b 100644 (file)
@@ -1991,14 +1991,14 @@ struct sky2_port {
        u16                  tx_cons;           /* next le to check */
        u16                  tx_prod;           /* next le to use */
        u16                  tx_next;           /* debug only */
-       u32                  tx_addr64;
+
        u16                  tx_pending;
        u16                  tx_last_mss;
        u32                  tx_tcpsum;
 
        struct rx_ring_info  *rx_ring ____cacheline_aligned_in_smp;
        struct sky2_rx_le    *rx_le;
-       u32                  rx_addr64;
+
        u16                  rx_next;           /* next re to check */
        u16                  rx_put;            /* next le index to use */
        u16                  rx_pending;
index d887c05588d5c4504d31699fef3d452645cb1daa..370d329d15d91cb1b56955afe8888e89d1c1234d 100644 (file)
@@ -611,7 +611,7 @@ static int __devinit tc35815_mac_match(struct device *dev, void *data)
 {
        struct platform_device *plat_dev = to_platform_device(dev);
        struct pci_dev *pci_dev = data;
-       unsigned int id = (pci_dev->bus->number << 8) | pci_dev->devfn;
+       unsigned int id = pci_dev->irq;
        return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
 }
 
index 41f34bb91cad9d12dd0fdb245398d2d60e72a487..6e8b18a3b3ccbd366f7608632627a6f1eace9b57 100644 (file)
@@ -911,7 +911,7 @@ static int     de4x5_init(struct net_device *dev);
 static int     de4x5_sw_reset(struct net_device *dev);
 static int     de4x5_rx(struct net_device *dev);
 static int     de4x5_tx(struct net_device *dev);
-static int     de4x5_ast(struct net_device *dev);
+static void    de4x5_ast(struct net_device *dev);
 static int     de4x5_txur(struct net_device *dev);
 static int     de4x5_rx_ovfc(struct net_device *dev);
 
@@ -984,11 +984,9 @@ static int     test_bad_enet(struct net_device *dev, int status);
 static int     an_exception(struct de4x5_private *lp);
 static char    *build_setup_frame(struct net_device *dev, int mode);
 static void    disable_ast(struct net_device *dev);
-static void    enable_ast(struct net_device *dev, u32 time_out);
 static long    de4x5_switch_mac_port(struct net_device *dev);
 static int     gep_rd(struct net_device *dev);
 static void    gep_wr(s32 data, struct net_device *dev);
-static void    timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec);
 static void    yawn(struct net_device *dev, int state);
 static void    de4x5_parse_params(struct net_device *dev);
 static void    de4x5_dbg_open(struct net_device *dev);
@@ -1139,6 +1137,8 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
        lp->gendev = gendev;
        spin_lock_init(&lp->lock);
        init_timer(&lp->timer);
+       lp->timer.function = (void (*)(unsigned long))de4x5_ast;
+       lp->timer.data = (unsigned long)dev;
        de4x5_parse_params(dev);
 
        /*
@@ -1311,7 +1311,7 @@ de4x5_open(struct net_device *dev)
     lp->state = OPEN;
     de4x5_dbg_open(dev);
 
-    if (request_irq(dev->irq, (void *)de4x5_interrupt, IRQF_SHARED,
+    if (request_irq(dev->irq, de4x5_interrupt, IRQF_SHARED,
                                                     lp->adapter_name, dev)) {
        printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
        if (request_irq(dev->irq, de4x5_interrupt, IRQF_DISABLED | IRQF_SHARED,
@@ -1737,27 +1737,29 @@ de4x5_tx(struct net_device *dev)
     return 0;
 }
 
-static int
+static void
 de4x5_ast(struct net_device *dev)
 {
-    struct de4x5_private *lp = netdev_priv(dev);
-    int next_tick = DE4X5_AUTOSENSE_MS;
+       struct de4x5_private *lp = netdev_priv(dev);
+       int next_tick = DE4X5_AUTOSENSE_MS;
+       int dt;
 
-    disable_ast(dev);
+       if (lp->useSROM)
+               next_tick = srom_autoconf(dev);
+       else if (lp->chipset == DC21140)
+               next_tick = dc21140m_autoconf(dev);
+       else if (lp->chipset == DC21041)
+               next_tick = dc21041_autoconf(dev);
+       else if (lp->chipset == DC21040)
+               next_tick = dc21040_autoconf(dev);
+       lp->linkOK = 0;
 
-    if (lp->useSROM) {
-       next_tick = srom_autoconf(dev);
-    } else if (lp->chipset == DC21140) {
-       next_tick = dc21140m_autoconf(dev);
-    } else if (lp->chipset == DC21041) {
-       next_tick = dc21041_autoconf(dev);
-    } else if (lp->chipset == DC21040) {
-       next_tick = dc21040_autoconf(dev);
-    }
-    lp->linkOK = 0;
-    enable_ast(dev, next_tick);
+       dt = (next_tick * HZ) / 1000;
 
-    return 0;
+       if (!dt)
+               dt = 1;
+
+       mod_timer(&lp->timer, jiffies + dt);
 }
 
 static int
@@ -2174,7 +2176,7 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
        for (j=0, i=0; i<ETH_ALEN; i++) {
            j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
        }
-       if ((j != 0) && (j != 0x5fa)) {
+       if (j != 0 && j != 6 * 0xff) {
            last.chipset = device;
            last.bus = pb;
            last.irq = irq;
@@ -2371,30 +2373,19 @@ static struct pci_driver de4x5_pci_driver = {
 static int
 autoconf_media(struct net_device *dev)
 {
-    struct de4x5_private *lp = netdev_priv(dev);
-    u_long iobase = dev->base_addr;
-    int next_tick = DE4X5_AUTOSENSE_MS;
+       struct de4x5_private *lp = netdev_priv(dev);
+       u_long iobase = dev->base_addr;
 
-    lp->linkOK = 0;
-    lp->c_media = AUTO;                     /* Bogus last media */
-    disable_ast(dev);
-    inl(DE4X5_MFC);                         /* Zero the lost frames counter */
-    lp->media = INIT;
-    lp->tcount = 0;
+       disable_ast(dev);
 
-    if (lp->useSROM) {
-       next_tick = srom_autoconf(dev);
-    } else if (lp->chipset == DC21040) {
-       next_tick = dc21040_autoconf(dev);
-    } else if (lp->chipset == DC21041) {
-       next_tick = dc21041_autoconf(dev);
-    } else if (lp->chipset == DC21140) {
-       next_tick = dc21140m_autoconf(dev);
-    }
+       lp->c_media = AUTO;                     /* Bogus last media */
+       inl(DE4X5_MFC);                         /* Zero the lost frames counter */
+       lp->media = INIT;
+       lp->tcount = 0;
 
-    enable_ast(dev, next_tick);
+       de4x5_ast(dev);
 
-    return (lp->media);
+       return lp->media;
 }
 
 /*
@@ -4018,20 +4009,22 @@ DevicePresent(struct net_device *dev, u_long aprom_addr)
            outl(0, aprom_addr);       /* Reset Ethernet Address ROM Pointer */
        }
     } else {                           /* Read new srom */
-       u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
+       u_short tmp;
+       __le16 *p = (__le16 *)((char *)&lp->srom + SROM_HWADD);
        for (i=0; i<(ETH_ALEN>>1); i++) {
            tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
-           *p = le16_to_cpu(tmp);
-           j += *p++;
+           j += tmp;   /* for check for 0:0:0:0:0:0 or ff:ff:ff:ff:ff:ff */
+           *p = cpu_to_le16(tmp);
        }
-       if ((j == 0) || (j == 0x2fffd)) {
-           return;
+       if (j == 0 || j == 3 * 0xffff) {
+               /* could get 0 only from all-0 and 3 * 0xffff only from all-1 */
+               return;
        }
 
-       p=(short *)&lp->srom;
+       p = (__le16 *)&lp->srom;
        for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
            tmp = srom_rd(aprom_addr, i);
-           *p++ = le16_to_cpu(tmp);
+           *p++ = cpu_to_le16(tmp);
        }
        de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
     }
@@ -5160,22 +5153,11 @@ build_setup_frame(struct net_device *dev, int mode)
     return pa;                     /* Points to the next entry */
 }
 
-static void
-enable_ast(struct net_device *dev, u32 time_out)
-{
-    timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
-
-    return;
-}
-
 static void
 disable_ast(struct net_device *dev)
 {
-    struct de4x5_private *lp = netdev_priv(dev);
-
-    del_timer(&lp->timer);
-
-    return;
+       struct de4x5_private *lp = netdev_priv(dev);
+       del_timer_sync(&lp->timer);
 }
 
 static long
@@ -5244,29 +5226,6 @@ gep_rd(struct net_device *dev)
     return 0;
 }
 
-static void
-timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec)
-{
-    struct de4x5_private *lp = netdev_priv(dev);
-    int dt;
-
-    /* First, cancel any pending timer events */
-    del_timer(&lp->timer);
-
-    /* Convert msec to ticks */
-    dt = (msec * HZ) / 1000;
-    if (dt==0) dt=1;
-
-    /* Set up timer */
-    init_timer(&lp->timer);
-    lp->timer.expires = jiffies + dt;
-    lp->timer.function = fn;
-    lp->timer.data = data;
-    add_timer(&lp->timer);
-
-    return;
-}
-
 static void
 yawn(struct net_device *dev, int state)
 {
index b4891caeae5ad36aeeb0ed913ecdc85fe012ade3..656200472fa17aa3e5e8e5d592c4fc2fa1ff2077 100644 (file)
@@ -1909,7 +1909,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
        if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
                /* SROM V4.01 */
                /* Get NIC support media mode */
-               db->NIC_capability = le16_to_cpup((__le16 *)srom + 34/2);
+               db->NIC_capability = le16_to_cpup((__le16 *) (srom + 34));
                db->PHY_reg4 = 0;
                for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
                        switch( db->NIC_capability & tmp_reg ) {
@@ -1921,8 +1921,8 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
                }
 
                /* Media Mode Force or not check */
-               dmfe_mode = le32_to_cpup((__le32 *)srom + 34/4) &
-                               le32_to_cpup((__le32 *)srom + 36/4);
+               dmfe_mode = (le32_to_cpup((__le32 *) (srom + 34)) &
+                            le32_to_cpup((__le32 *) (srom + 36)));
                switch(dmfe_mode) {
                case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */
                case 0x2: dmfe_media_mode = DMFE_10MFD; break;  /* 10MFD */
index 365331446387395ca7e878adb45dd22d0065c156..6284afd14bbb5fe42789b0a6f9531172ef9adf12 100644 (file)
@@ -117,9 +117,6 @@ int tulip_poll(struct napi_struct *napi, int budget)
        int received = 0;
 #endif
 
-       if (!netif_running(dev))
-               goto done;
-
 #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
 
 /* that one buffer is needed for mit activation; or might be a
@@ -151,7 +148,8 @@ int tulip_poll(struct napi_struct *napi, int budget)
                        if (tulip_debug > 5)
                                printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
                                       dev->name, entry, status);
-                      if (work_done++ >= budget)
+
+                      if (++work_done >= budget)
                                goto not_done;
 
                        if ((status & 0x38008300) != 0x0300) {
@@ -260,8 +258,6 @@ int tulip_poll(struct napi_struct *napi, int budget)
                 * finally: amount of IO did not increase at all. */
        } while ((ioread32(tp->base_addr + CSR5) & RxIntr));
 
-done:
-
  #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
 
           /* We use this simplistic scheme for IM. It's proven by
index e5e2c9c4ebfee5cc1174e7c36130d8da5b516a65..ed600bf56e786d6186ad64a04ad16c57dcd16c31 100644 (file)
@@ -797,7 +797,8 @@ static int tulip_close (struct net_device *dev)
 
                tp->rx_ring[i].status = 0;      /* Not owned by Tulip chip. */
                tp->rx_ring[i].length = 0;
-               tp->rx_ring[i].buffer1 = 0xBADF00D0;    /* An invalid address. */
+               /* An invalid address. */
+               tp->rx_ring[i].buffer1 = cpu_to_le32(0xBADF00D0);
                if (skb) {
                        pci_unmap_single(tp->pdev, mapping, PKT_BUF_SZ,
                                         PCI_DMA_FROMDEVICE);
index 70befe33e454c63d1a8e4dd4ba2fab0fb728d4a3..8fc7274642eb41f851e78af59d66fb5468954090 100644 (file)
@@ -83,8 +83,8 @@ static int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};
 struct xircom_private {
        /* Send and receive buffers, kernel-addressable and dma addressable forms */
 
-       unsigned int *rx_buffer;
-       unsigned int *tx_buffer;
+       __le32 *rx_buffer;
+       __le32 *tx_buffer;
 
        dma_addr_t rx_dma_handle;
        dma_addr_t tx_dma_handle;
@@ -412,19 +412,20 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* FIXME: The specification tells us that the length we send HAS to be a multiple of
                           4 bytes. */
 
-                       card->tx_buffer[4*desc+1] = skb->len;
-                       if (desc == NUMDESCRIPTORS-1)
-                               card->tx_buffer[4*desc+1] |= (1<<25);  /* bit 25: last descriptor of the ring */
+                       card->tx_buffer[4*desc+1] = cpu_to_le32(skb->len);
+                       if (desc == NUMDESCRIPTORS - 1) /* bit 25: last descriptor of the ring */
+                               card->tx_buffer[4*desc+1] |= cpu_to_le32(1<<25);  
 
-                       card->tx_buffer[4*desc+1] |= 0xF0000000;
+                       card->tx_buffer[4*desc+1] |= cpu_to_le32(0xF0000000);
                                                 /* 0xF0... means want interrupts*/
                        card->tx_skb[desc] = skb;
 
                        wmb();
                        /* This gives the descriptor to the card */
-                       card->tx_buffer[4*desc] = 0x80000000;
+                       card->tx_buffer[4*desc] = cpu_to_le32(0x80000000);
                        trigger_transmit(card);
-                       if (((int)card->tx_buffer[nextdescriptor*4])<0) {       /* next descriptor is occupied... */
+                       if (card->tx_buffer[nextdescriptor*4] & cpu_to_le32(0x8000000)) {
+                               /* next descriptor is occupied... */
                                netif_stop_queue(dev);
                        }
                        card->transmit_used = nextdescriptor;
@@ -590,8 +591,7 @@ descriptors and programs the addresses into the card.
 */
 static void setup_descriptors(struct xircom_private *card)
 {
-       unsigned int val;
-       unsigned int address;
+       u32 address;
        int i;
        enter("setup_descriptors");
 
@@ -604,16 +604,16 @@ static void setup_descriptors(struct xircom_private *card)
        for (i=0;i<NUMDESCRIPTORS;i++ ) {
 
                /* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */
-               card->rx_buffer[i*4 + 0] = 0x80000000;
+               card->rx_buffer[i*4 + 0] = cpu_to_le32(0x80000000);
                /* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
-               card->rx_buffer[i*4 + 1] = 1536;
-               if (i==NUMDESCRIPTORS-1)
-                       card->rx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
+               card->rx_buffer[i*4 + 1] = cpu_to_le32(1536);
+               if (i == NUMDESCRIPTORS - 1) /* bit 25 is "last descriptor" */
+                       card->rx_buffer[i*4 + 1] |= cpu_to_le32(1 << 25);
 
                /* Rx Descr2: address of the buffer
                   we store the buffer at the 2nd half of the page */
 
-               address = (unsigned long) card->rx_dma_handle;
+               address = card->rx_dma_handle;
                card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
                /* Rx Desc3: address of 2nd buffer -> 0 */
                card->rx_buffer[i*4 + 3] = 0;
@@ -621,9 +621,8 @@ static void setup_descriptors(struct xircom_private *card)
 
        wmb();
        /* Write the receive descriptor ring address to the card */
-       address = (unsigned long) card->rx_dma_handle;
-       val = cpu_to_le32(address);
-       outl(val, card->io_port + CSR3);        /* Receive descr list address */
+       address = card->rx_dma_handle;
+       outl(address, card->io_port + CSR3);    /* Receive descr list address */
 
 
        /* transmit descriptors */
@@ -633,13 +632,13 @@ static void setup_descriptors(struct xircom_private *card)
                /* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */
                card->tx_buffer[i*4 + 0] = 0x00000000;
                /* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
-               card->tx_buffer[i*4 + 1] = 1536;
-               if (i==NUMDESCRIPTORS-1)
-                       card->tx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
+               card->tx_buffer[i*4 + 1] = cpu_to_le32(1536);
+               if (i == NUMDESCRIPTORS - 1) /* bit 25 is "last descriptor" */
+                       card->tx_buffer[i*4 + 1] |= cpu_to_le32(1 << 25);
 
                /* Tx Descr2: address of the buffer
                   we store the buffer at the 2nd half of the page */
-               address = (unsigned long) card->tx_dma_handle;
+               address = card->tx_dma_handle;
                card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
                /* Tx Desc3: address of 2nd buffer -> 0 */
                card->tx_buffer[i*4 + 3] = 0;
@@ -647,9 +646,8 @@ static void setup_descriptors(struct xircom_private *card)
 
        wmb();
        /* wite the transmit descriptor ring to the card */
-       address = (unsigned long) card->tx_dma_handle;
-       val =cpu_to_le32(address);
-       outl(val, card->io_port + CSR4);        /* xmit descr list address */
+       address = card->tx_dma_handle;
+       outl(address, card->io_port + CSR4);    /* xmit descr list address */
 
        leave("setup_descriptors");
 }
@@ -1180,7 +1178,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
                int status;
 
                enter("investigate_read_descriptor");
-               status = card->rx_buffer[4*descnr];
+               status = le32_to_cpu(card->rx_buffer[4*descnr]);
 
                if ((status > 0)) {     /* packet received */
 
@@ -1210,7 +1208,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
 
                      out:
                        /* give the buffer back to the card */
-                       card->rx_buffer[4*descnr] =  0x80000000;
+                       card->rx_buffer[4*descnr] =  cpu_to_le32(0x80000000);
                        trigger_receive(card);
                }
 
@@ -1226,7 +1224,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
 
                enter("investigate_write_descriptor");
 
-               status = card->tx_buffer[4*descnr];
+               status = le32_to_cpu(card->tx_buffer[4*descnr]);
 #if 0
                if (status & 0x8000) {  /* Major error */
                        printk(KERN_ERR "Major transmit error status %x \n", status);
index 1249f444039e5492883ef42d18cf0bbd73181d3d..569028b2baf2d8930a21bca17b775c764f793c39 100644 (file)
@@ -202,10 +202,10 @@ static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
                buf,
                size,
                USB_CTRL_GET_TIMEOUT);
-       if (err >= 0 && err < size)
-               err = -EINVAL;
-       if (!err)
+       if (err == size)
                memcpy(data, buf, size);
+       else if (err >= 0)
+               err = -EINVAL;
        kfree(buf);
 
 out:
index 58a53a641754ba74fefd04fa048c649cc6f4faee..569ad8bfd3833448aec6625f0b1bd87a6441d1a9 100644 (file)
@@ -70,7 +70,7 @@
 #define KAWETH_TX_TIMEOUT              (5 * HZ)
 #define KAWETH_SCRATCH_SIZE            32
 #define KAWETH_FIRMWARE_BUF_SIZE       4096
-#define KAWETH_CONTROL_TIMEOUT         (30 * HZ)
+#define KAWETH_CONTROL_TIMEOUT         (30000)
 
 #define KAWETH_STATUS_BROKEN           0x0000001
 #define KAWETH_STATUS_CLOSING          0x0000002
index f55a5951733ab56b44aaaae2af0939c71c10c15c..5ea7411e13375812f13aa3cb6ccd3a81d50c47bb 100644 (file)
@@ -94,7 +94,7 @@ static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
 
        ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
                              MCS7830_RD_BMREQ, 0x0000, index, data,
-                             size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
+                             size, MCS7830_CTRL_TIMEOUT);
        return ret;
 }
 
@@ -105,7 +105,7 @@ static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
 
        ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
                              MCS7830_WR_BMREQ, 0x0000, index, data,
-                             size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
+                             size, MCS7830_CTRL_TIMEOUT);
        return ret;
 }
 
index 43af9e9b26525ad1fcc4f96df93168d4bfe1990c..3f67a29593bc417fc94fb1f6a7bc15202a621251 100644 (file)
@@ -459,19 +459,7 @@ static __init int veth_init(void)
 
 static __exit void veth_exit(void)
 {
-       struct veth_priv *priv, *next;
-
-       rtnl_lock();
-       /*
-        * cannot trust __rtnl_link_unregister() to unregister all
-        * devices, as each ->dellink call will remove two devices
-        * from the list at once.
-        */
-       list_for_each_entry_safe(priv, next, &veth_list, list)
-               veth_dellink(priv->dev);
-
-       __rtnl_link_unregister(&veth_link_ops);
-       rtnl_unlock();
+       rtnl_link_unregister(&veth_link_ops);
 }
 
 module_init(veth_init);
index ff37bf437a99e3b955e373b12b2070c1ba37b62d..1d706eae30526003183555c0f897cc9f2e30fea9 100644 (file)
@@ -395,8 +395,7 @@ static int __init cosa_init(void)
                goto out_chrdev;
        }
        for (i=0; i<nr_cards; i++) {
-               class_device_create(cosa_class, NULL, MKDEV(cosa_major, i),
-                               NULL, "cosa%d", i);
+               device_create(cosa_class, NULL, MKDEV(cosa_major, i), "cosa%d", i);
        }
        err = 0;
        goto out;
@@ -415,7 +414,7 @@ static void __exit cosa_exit(void)
        printk(KERN_INFO "Unloading the cosa module\n");
 
        for (i=0; i<nr_cards; i++)
-               class_device_destroy(cosa_class, MKDEV(cosa_major, i));
+               device_destroy(cosa_class, MKDEV(cosa_major, i));
        class_destroy(cosa_class);
        for (cosa=cosa_cards; nr_cards--; cosa++) {
                /* Clean up the per-channel data */
index 33dc713b53017071acfcac25f7e5e9146534a4da..c6f26e28e3769ba12135a8dd7de19678956ee7ee 100644 (file)
@@ -139,19 +139,21 @@ struct thingie {
 };
 
 struct TxFD {
-       u32 state;
-       u32 next;
-       u32 data;
-       u32 complete;
+       __le32 state;
+       __le32 next;
+       __le32 data;
+       __le32 complete;
        u32 jiffies; /* Allows sizeof(TxFD) == sizeof(RxFD) + extra hack */
+                    /* FWIW, datasheet calls that "dummy" and says that card
+                     * never looks at it; neither does the driver */
 };
 
 struct RxFD {
-       u32 state1;
-       u32 next;
-       u32 data;
-       u32 state2;
-       u32 end;
+       __le32 state1;
+       __le32 next;
+       __le32 data;
+       __le32 state2;
+       __le32 end;
 };
 
 #define DUMMY_SKB_SIZE         64
@@ -181,7 +183,7 @@ struct RxFD {
 #define SCC_REG_START(dpriv)   (SCC_START+(dpriv->dev_id)*SCC_OFFSET)
 
 struct dscc4_pci_priv {
-        u32 *iqcfg;
+        __le32 *iqcfg;
         int cfg_cur;
         spinlock_t lock;
         struct pci_dev *pdev;
@@ -197,8 +199,8 @@ struct dscc4_dev_priv {
 
         struct RxFD *rx_fd;
         struct TxFD *tx_fd;
-        u32 *iqrx;
-        u32 *iqtx;
+        __le32 *iqrx;
+        __le32 *iqtx;
 
        /* FIXME: check all the volatile are required */
         volatile u32 tx_current;
@@ -298,7 +300,7 @@ struct dscc4_dev_priv {
 #define BrrExpMask     0x00000f00
 #define BrrMultMask    0x0000003f
 #define EncodingMask   0x00700000
-#define Hold           0x40000000
+#define Hold           cpu_to_le32(0x40000000)
 #define SccBusy                0x10000000
 #define PowerUp                0x80000000
 #define Vis            0x00001000
@@ -307,14 +309,14 @@ struct dscc4_dev_priv {
 #define FrameRdo       0x40
 #define FrameCrc       0x20
 #define FrameRab       0x10
-#define FrameAborted   0x00000200
-#define FrameEnd       0x80000000
-#define DataComplete   0x40000000
+#define FrameAborted   cpu_to_le32(0x00000200)
+#define FrameEnd       cpu_to_le32(0x80000000)
+#define DataComplete   cpu_to_le32(0x40000000)
 #define LengthCheck    0x00008000
 #define SccEvt         0x02000000
 #define NoAck          0x00000200
 #define Action         0x00000001
-#define HiDesc         0x20000000
+#define HiDesc         cpu_to_le32(0x20000000)
 
 /* SCC events */
 #define RxEvt          0xf0000000
@@ -489,8 +491,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
        skbuff = dpriv->tx_skbuff;
        for (i = 0; i < TX_RING_SIZE; i++) {
                if (*skbuff) {
-                       pci_unmap_single(pdev, tx_fd->data, (*skbuff)->len,
-                               PCI_DMA_TODEVICE);
+                       pci_unmap_single(pdev, le32_to_cpu(tx_fd->data),
+                               (*skbuff)->len, PCI_DMA_TODEVICE);
                        dev_kfree_skb(*skbuff);
                }
                skbuff++;
@@ -500,7 +502,7 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
        skbuff = dpriv->rx_skbuff;
        for (i = 0; i < RX_RING_SIZE; i++) {
                if (*skbuff) {
-                       pci_unmap_single(pdev, rx_fd->data,
+                       pci_unmap_single(pdev, le32_to_cpu(rx_fd->data),
                                RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(*skbuff);
                }
@@ -522,10 +524,10 @@ static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv,
        dpriv->rx_skbuff[dirty] = skb;
        if (skb) {
                skb->protocol = hdlc_type_trans(skb, dev);
-               rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
-                                            len, PCI_DMA_FROMDEVICE);
+               rx_fd->data = cpu_to_le32(pci_map_single(dpriv->pci_priv->pdev,
+                                         skb->data, len, PCI_DMA_FROMDEVICE));
        } else {
-               rx_fd->data = (u32) NULL;
+               rx_fd->data = 0;
                ret = -1;
        }
        return ret;
@@ -587,7 +589,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
 
        do {
                if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
-                   (dpriv->iqtx[cur] & Xpr))
+                   (dpriv->iqtx[cur] & cpu_to_le32(Xpr)))
                        break;
                smp_rmb();
                schedule_timeout_uninterruptible(10);
@@ -650,8 +652,9 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,
                printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__);
                goto refill;
        }
-       pkt_len = TO_SIZE(rx_fd->state2);
-       pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
+       pkt_len = TO_SIZE(le32_to_cpu(rx_fd->state2));
+       pci_unmap_single(pdev, le32_to_cpu(rx_fd->data),
+                        RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
        if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {
                stats->rx_packets++;
                stats->rx_bytes += pkt_len;
@@ -679,7 +682,7 @@ refill:
        }
        dscc4_rx_update(dpriv, dev);
        rx_fd->state2 = 0x00000000;
-       rx_fd->end = 0xbabeface;
+       rx_fd->end = cpu_to_le32(0xbabeface);
 }
 
 static void dscc4_free1(struct pci_dev *pdev)
@@ -772,8 +775,8 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
        }
        /* Global interrupt queue */
        writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1);
-       priv->iqcfg = (u32 *) pci_alloc_consistent(pdev,
-               IRQ_RING_SIZE*sizeof(u32), &priv->iqcfg_dma);
+       priv->iqcfg = (__le32 *) pci_alloc_consistent(pdev,
+               IRQ_RING_SIZE*sizeof(__le32), &priv->iqcfg_dma);
        if (!priv->iqcfg)
                goto err_free_irq_5;
        writel(priv->iqcfg_dma, ioaddr + IQCFG);
@@ -786,7 +789,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
         */
        for (i = 0; i < dev_per_card; i++) {
                dpriv = priv->root + i;
-               dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,
+               dpriv->iqtx = (__le32 *) pci_alloc_consistent(pdev,
                        IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);
                if (!dpriv->iqtx)
                        goto err_free_iqtx_6;
@@ -794,7 +797,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
        }
        for (i = 0; i < dev_per_card; i++) {
                dpriv = priv->root + i;
-               dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,
+               dpriv->iqrx = (__le32 *) pci_alloc_consistent(pdev,
                        IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);
                if (!dpriv->iqrx)
                        goto err_free_iqrx_7;
@@ -1156,8 +1159,8 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dpriv->tx_skbuff[next] = skb;
        tx_fd = dpriv->tx_fd + next;
        tx_fd->state = FrameEnd | TO_STATE_TX(skb->len);
-       tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
-                                    PCI_DMA_TODEVICE);
+       tx_fd->data = cpu_to_le32(pci_map_single(ppriv->pdev, skb->data, skb->len,
+                                    PCI_DMA_TODEVICE));
        tx_fd->complete = 0x00000000;
        tx_fd->jiffies = jiffies;
        mb();
@@ -1508,7 +1511,7 @@ static irqreturn_t dscc4_irq(int irq, void *token)
        if (state & Cfg) {
                if (debug > 0)
                        printk(KERN_DEBUG "%s: CfgIV\n", DRV_NAME);
-               if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf)
+               if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & cpu_to_le32(Arf))
                        printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG");
                if (!(state &= ~Cfg))
                        goto out;
@@ -1541,7 +1544,7 @@ static void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
 
 try:
        cur = dpriv->iqtx_current%IRQ_RING_SIZE;
-       state = dpriv->iqtx[cur];
+       state = le32_to_cpu(dpriv->iqtx[cur]);
        if (!state) {
                if (debug > 4)
                        printk(KERN_DEBUG "%s: Tx ISR = 0x%08x\n", dev->name,
@@ -1580,7 +1583,7 @@ try:
                        tx_fd = dpriv->tx_fd + cur;
                        skb = dpriv->tx_skbuff[cur];
                        if (skb) {
-                               pci_unmap_single(ppriv->pdev, tx_fd->data,
+                               pci_unmap_single(ppriv->pdev, le32_to_cpu(tx_fd->data),
                                                 skb->len, PCI_DMA_TODEVICE);
                                if (tx_fd->state & FrameEnd) {
                                        stats->tx_packets++;
@@ -1711,7 +1714,7 @@ static void dscc4_rx_irq(struct dscc4_pci_priv *priv,
 
 try:
        cur = dpriv->iqrx_current%IRQ_RING_SIZE;
-       state = dpriv->iqrx[cur];
+       state = le32_to_cpu(dpriv->iqrx[cur]);
        if (!state)
                return;
        dpriv->iqrx[cur] = 0;
@@ -1755,7 +1758,7 @@ try:
                                        goto try;
                                rx_fd->state1 &= ~Hold;
                                rx_fd->state2 = 0x00000000;
-                               rx_fd->end = 0xbabeface;
+                               rx_fd->end = cpu_to_le32(0xbabeface);
                        //}
                        goto try;
                }
@@ -1834,7 +1837,7 @@ try:
                                        hdlc_stats(dev)->rx_over_errors++;
                                        rx_fd->state1 |= Hold;
                                        rx_fd->state2 = 0x00000000;
-                                       rx_fd->end = 0xbabeface;
+                                       rx_fd->end = cpu_to_le32(0xbabeface);
                                } else
                                        dscc4_rx_skb(dpriv, dev);
                        } while (1);
@@ -1904,8 +1907,9 @@ static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv)
                skb_copy_to_linear_data(skb, version,
                                        strlen(version) % DUMMY_SKB_SIZE);
                tx_fd->state = FrameEnd | TO_STATE_TX(DUMMY_SKB_SIZE);
-               tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
-                                            DUMMY_SKB_SIZE, PCI_DMA_TODEVICE);
+               tx_fd->data = cpu_to_le32(pci_map_single(dpriv->pci_priv->pdev,
+                                            skb->data, DUMMY_SKB_SIZE,
+                                            PCI_DMA_TODEVICE));
                dpriv->tx_skbuff[last] = skb;
        }
        return skb;
@@ -1937,8 +1941,8 @@ static int dscc4_init_ring(struct net_device *dev)
                tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE);
                tx_fd->complete = 0x00000000;
                /* FIXME: NULL should be ok - to be tried */
-               tx_fd->data = dpriv->tx_fd_dma;
-               (tx_fd++)->next = (u32)(dpriv->tx_fd_dma +
+               tx_fd->data = cpu_to_le32(dpriv->tx_fd_dma);
+               (tx_fd++)->next = cpu_to_le32(dpriv->tx_fd_dma +
                                        (++i%TX_RING_SIZE)*sizeof(*tx_fd));
        } while (i < TX_RING_SIZE);
 
@@ -1951,12 +1955,12 @@ static int dscc4_init_ring(struct net_device *dev)
                /* size set by the host. Multiple of 4 bytes please */
                rx_fd->state1 = HiDesc;
                rx_fd->state2 = 0x00000000;
-               rx_fd->end = 0xbabeface;
+               rx_fd->end = cpu_to_le32(0xbabeface);
                rx_fd->state1 |= TO_STATE_RX(HDLC_MAX_MRU);
                // FIXME: return value verifiee mais traitement suspect
                if (try_get_rx_skb(dpriv, dev) >= 0)
                        dpriv->rx_dirty++;
-               (rx_fd++)->next = (u32)(dpriv->rx_fd_dma +
+               (rx_fd++)->next = cpu_to_le32(dpriv->rx_fd_dma +
                                        (++i%RX_RING_SIZE)*sizeof(*rx_fd));
        } while (i < RX_RING_SIZE);
 
index 574737b55f390739cdd3c0c35aac2f1957483562..c9c878cd5c72725e6bbc44df92b599afef466b3b 100644 (file)
@@ -890,16 +890,8 @@ write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v,
 static void
 lmc_ssi_watchdog (lmc_softc_t * const sc)
 {
-  u_int16_t mii17;
-  struct ssicsr2
-  {
-    unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1,
-      led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1;
-  };
-  struct ssicsr2 *ssicsr;
-  mii17 = lmc_mii_readreg (sc, 0, 17);
-  ssicsr = (struct ssicsr2 *) &mii17;
-  if (ssicsr->cable == 7)
+  u_int16_t mii17 = lmc_mii_readreg (sc, 0, 17);
+  if (((mii17 >> 3) & 7) == 7)
     {
       lmc_led_off (sc, LMC_MII16_LED2);
     }
index 27715e70f28b1ba599981b78e0e07689b9eb1e1e..84264510a8ed850bc1f5bbd963aeb5cd7eca6d8e 100644 (file)
@@ -44,9 +44,15 @@ enum {
 #define PR_RES 0x80
 
 struct sbni_csr1 {
-       unsigned rxl    : 5;
-       unsigned rate   : 2;
-       unsigned        : 1;
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       u8 rxl  : 5;
+       u8 rate : 2;
+       u8      : 1;
+#else
+       u8      : 1;
+       u8 rate : 2;
+       u8 rxl  : 5;
+#endif
 };
 
 /* fields in frame header */
index c98fc62a3e615ae54dae8efcdd395dd0d9290a8d..2c08c0a5a0df0221b561a4dc5ce6f45e0d8de583 100644 (file)
@@ -68,7 +68,7 @@ config WAVELAN
          <http://www.tldp.org/docs.html#howto>. Some more specific
          information is contained in
          <file:Documentation/networking/wavelan.txt> and in the source code
-         <file:drivers/net/wavelan.p.h>.
+         <file:drivers/net/wireless/wavelan.p.h>.
 
          You will also need the wireless tools package available from
          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
index a28ad230d63e884fee652d2fe420f3137f18e2c7..7b6fc1ab2b904fc607273d8d67946d159107d871 100644 (file)
@@ -273,6 +273,8 @@ enum {
 #define B43_PHYTYPE_A                  0x00
 #define B43_PHYTYPE_B                  0x01
 #define B43_PHYTYPE_G                  0x02
+#define B43_PHYTYPE_N                  0x04
+#define B43_PHYTYPE_LP                 0x05
 
 /* PHYRegisters */
 #define B43_PHY_ILT_A_CTRL             0x0072
index 284d17da17d1ae73c56deb79e389697cf69c9068..08e2e56e48f493ddd9ade9f66992606819f5a1b1 100644 (file)
 #define PAD_BYTES(nr_bytes)            P4D_BYTES( __LINE__ , (nr_bytes))
 
 /* Lightweight function to convert a frequency (in Mhz) to a channel number. */
-static inline u8 b43_freq_to_channel_a(int freq)
+static inline u8 b43_freq_to_channel_5ghz(int freq)
 {
        return ((freq - 5000) / 5);
 }
-static inline u8 b43_freq_to_channel_bg(int freq)
+static inline u8 b43_freq_to_channel_2ghz(int freq)
 {
        u8 channel;
 
@@ -54,19 +54,13 @@ static inline u8 b43_freq_to_channel_bg(int freq)
 
        return channel;
 }
-static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
-{
-       if (dev->phy.type == B43_PHYTYPE_A)
-               return b43_freq_to_channel_a(freq);
-       return b43_freq_to_channel_bg(freq);
-}
 
 /* Lightweight function to convert a channel number to a frequency (in Mhz). */
-static inline int b43_channel_to_freq_a(u8 channel)
+static inline int b43_channel_to_freq_5ghz(u8 channel)
 {
        return (5000 + (5 * channel));
 }
-static inline int b43_channel_to_freq_bg(u8 channel)
+static inline int b43_channel_to_freq_2ghz(u8 channel)
 {
        int freq;
 
@@ -77,12 +71,6 @@ static inline int b43_channel_to_freq_bg(u8 channel)
 
        return freq;
 }
-static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
-{
-       if (dev->phy.type == B43_PHYTYPE_A)
-               return b43_channel_to_freq_a(channel);
-       return b43_channel_to_freq_bg(channel);
-}
 
 static inline int b43_is_cck_rate(int rate)
 {
index 98cf70c5fd478d2ef766b02a7315bbd086a1781f..11f53cb1139ee58b3686dacf8e4f1ef24cc4d00c 100644 (file)
@@ -138,8 +138,11 @@ void b43_rfkill_init(struct b43_wldev *dev)
        rfk->rfkill->user_claim_unsupported = 1;
 
        rfk->poll_dev = input_allocate_polled_device();
-       if (!rfk->poll_dev)
-               goto err_free_rfk;
+       if (!rfk->poll_dev) {
+               rfkill_free(rfk->rfkill);
+               goto err_freed_rfk;
+       }
+
        rfk->poll_dev->private = dev;
        rfk->poll_dev->poll = b43_rfkill_poll;
        rfk->poll_dev->poll_interval = 1000; /* msecs */
@@ -175,8 +178,7 @@ err_unreg_rfk:
 err_free_polldev:
        input_free_polled_device(rfk->poll_dev);
        rfk->poll_dev = NULL;
-err_free_rfk:
-       rfkill_free(rfk->rfkill);
+err_freed_rfk:
        rfk->rfkill = NULL;
 out_error:
        rfk->registered = 0;
@@ -195,6 +197,5 @@ void b43_rfkill_exit(struct b43_wldev *dev)
        rfkill_unregister(rfk->rfkill);
        input_free_polled_device(rfk->poll_dev);
        rfk->poll_dev = NULL;
-       rfkill_free(rfk->rfkill);
        rfk->rfkill = NULL;
 }
index 0bd6f8a348a8a195821ff8ec5721c167b0443bca..3307ba1856b17ce36d0740784524a8a3ba7d3562 100644 (file)
@@ -531,21 +531,32 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        switch (chanstat & B43_RX_CHAN_PHYTYPE) {
        case B43_PHYTYPE_A:
                status.phymode = MODE_IEEE80211A;
-               status.freq = chanid;
-               status.channel = b43_freq_to_channel_a(chanid);
-               break;
-       case B43_PHYTYPE_B:
-               status.phymode = MODE_IEEE80211B;
-               status.freq = chanid + 2400;
-               status.channel = b43_freq_to_channel_bg(chanid + 2400);
+               B43_WARN_ON(1);
+               /* FIXME: We don't really know which value the "chanid" contains.
+                *        So the following assignment might be wrong. */
+               status.channel = chanid;
+               status.freq = b43_channel_to_freq_5ghz(status.channel);
                break;
        case B43_PHYTYPE_G:
                status.phymode = MODE_IEEE80211G;
+               /* chanid is the radio channel cookie value as used
+                * to tune the radio. */
                status.freq = chanid + 2400;
-               status.channel = b43_freq_to_channel_bg(chanid + 2400);
+               status.channel = b43_freq_to_channel_2ghz(status.freq);
+               break;
+       case B43_PHYTYPE_N:
+               status.phymode = 0xDEAD /*FIXME MODE_IEEE80211N*/;
+               /* chanid is the SHM channel cookie. Which is the plain
+                * channel number in b43. */
+               status.channel = chanid;
+               if (chanstat & B43_RX_CHAN_5GHZ)
+                       status.freq = b43_freq_to_channel_5ghz(status.freq);
+               else
+                       status.freq = b43_freq_to_channel_2ghz(status.freq);
                break;
        default:
                B43_WARN_ON(1);
+               goto drop;
        }
 
        dev->stats.last_rx = jiffies;
index 03bddd251618472b9f102c0973bd7dc8531741d3..6dc079382f7f105300806e502d148a0b1a86cf9a 100644 (file)
@@ -142,49 +142,56 @@ struct b43_rxhdr_fw4 {
 } __attribute__ ((__packed__));
 
 /* PHY RX Status 0 */
-#define B43_RX_PHYST0_GAINCTL  0x4000  /* Gain Control */
-#define B43_RX_PHYST0_PLCPHCF  0x0200
-#define B43_RX_PHYST0_PLCPFV   0x0100
-#define B43_RX_PHYST0_SHORTPRMBL       0x0080  /* Received with Short Preamble */
+#define B43_RX_PHYST0_GAINCTL          0x4000 /* Gain Control */
+#define B43_RX_PHYST0_PLCPHCF          0x0200
+#define B43_RX_PHYST0_PLCPFV           0x0100
+#define B43_RX_PHYST0_SHORTPRMBL       0x0080 /* Received with Short Preamble */
 #define B43_RX_PHYST0_LCRS             0x0040
-#define B43_RX_PHYST0_ANT              0x0020  /* Antenna */
-#define B43_RX_PHYST0_UNSRATE  0x0010
+#define B43_RX_PHYST0_ANT              0x0020 /* Antenna */
+#define B43_RX_PHYST0_UNSRATE          0x0010
 #define B43_RX_PHYST0_CLIP             0x000C
 #define B43_RX_PHYST0_CLIP_SHIFT       2
-#define B43_RX_PHYST0_FTYPE            0x0003  /* Frame type */
-#define  B43_RX_PHYST0_CCK             0x0000  /* Frame type: CCK */
-#define  B43_RX_PHYST0_OFDM            0x0001  /* Frame type: OFDM */
-#define  B43_RX_PHYST0_PRE_N   0x0002  /* Pre-standard N-PHY frame */
-#define  B43_RX_PHYST0_STD_N   0x0003  /* Standard N-PHY frame */
+#define B43_RX_PHYST0_FTYPE            0x0003 /* Frame type */
+#define  B43_RX_PHYST0_CCK             0x0000 /* Frame type: CCK */
+#define  B43_RX_PHYST0_OFDM            0x0001 /* Frame type: OFDM */
+#define  B43_RX_PHYST0_PRE_N           0x0002 /* Pre-standard N-PHY frame */
+#define  B43_RX_PHYST0_STD_N           0x0003 /* Standard N-PHY frame */
 
 /* PHY RX Status 2 */
-#define B43_RX_PHYST2_LNAG             0xC000  /* LNA Gain */
+#define B43_RX_PHYST2_LNAG             0xC000 /* LNA Gain */
 #define B43_RX_PHYST2_LNAG_SHIFT       14
-#define B43_RX_PHYST2_PNAG             0x3C00  /* PNA Gain */
+#define B43_RX_PHYST2_PNAG             0x3C00 /* PNA Gain */
 #define B43_RX_PHYST2_PNAG_SHIFT       10
-#define B43_RX_PHYST2_FOFF             0x03FF  /* F offset */
+#define B43_RX_PHYST2_FOFF             0x03FF /* F offset */
 
 /* PHY RX Status 3 */
-#define B43_RX_PHYST3_DIGG             0x1800  /* DIG Gain */
+#define B43_RX_PHYST3_DIGG             0x1800 /* DIG Gain */
 #define B43_RX_PHYST3_DIGG_SHIFT       11
-#define B43_RX_PHYST3_TRSTATE  0x0400  /* TR state */
+#define B43_RX_PHYST3_TRSTATE          0x0400 /* TR state */
 
 /* MAC RX Status */
-#define B43_RX_MAC_BEACONSENT  0x00008000      /* Beacon send flag */
-#define B43_RX_MAC_KEYIDX              0x000007E0      /* Key index */
-#define B43_RX_MAC_KEYIDX_SHIFT        5
-#define B43_RX_MAC_DECERR              0x00000010      /* Decrypt error */
-#define B43_RX_MAC_DEC         0x00000008      /* Decryption attempted */
-#define B43_RX_MAC_PADDING             0x00000004      /* Pad bytes present */
-#define B43_RX_MAC_RESP                0x00000002      /* Response frame transmitted */
-#define B43_RX_MAC_FCSERR              0x00000001      /* FCS error */
+#define B43_RX_MAC_RXST_VALID          0x01000000 /* PHY RXST valid */
+#define B43_RX_MAC_TKIP_MICERR         0x00100000 /* TKIP MIC error */
+#define B43_RX_MAC_TKIP_MICATT         0x00080000 /* TKIP MIC attempted */
+#define B43_RX_MAC_AGGTYPE             0x00060000 /* Aggregation type */
+#define B43_RX_MAC_AGGTYPE_SHIFT       17
+#define B43_RX_MAC_AMSDU               0x00010000 /* A-MSDU mask */
+#define B43_RX_MAC_BEACONSENT          0x00008000 /* Beacon sent flag */
+#define B43_RX_MAC_KEYIDX              0x000007E0 /* Key index */
+#define B43_RX_MAC_KEYIDX_SHIFT                5
+#define B43_RX_MAC_DECERR              0x00000010 /* Decrypt error */
+#define B43_RX_MAC_DEC                 0x00000008 /* Decryption attempted */
+#define B43_RX_MAC_PADDING             0x00000004 /* Pad bytes present */
+#define B43_RX_MAC_RESP                        0x00000002 /* Response frame transmitted */
+#define B43_RX_MAC_FCSERR              0x00000001 /* FCS error */
 
 /* RX channel */
-#define B43_RX_CHAN_GAIN               0xFC00  /* Gain */
-#define B43_RX_CHAN_GAIN_SHIFT 10
-#define B43_RX_CHAN_ID         0x03FC  /* Channel ID */
-#define B43_RX_CHAN_ID_SHIFT   2
-#define B43_RX_CHAN_PHYTYPE            0x0003  /* PHY type */
+#define B43_RX_CHAN_40MHZ              0x1000 /* 40 Mhz channel width */
+#define B43_RX_CHAN_5GHZ               0x0800 /* 5 Ghz band */
+#define B43_RX_CHAN_ID                 0x07F8 /* Channel ID */
+#define B43_RX_CHAN_ID_SHIFT           3
+#define B43_RX_CHAN_PHYTYPE            0x0007 /* PHY type */
+
 
 u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
 u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
index 040dc3e364101162bd3e7b511e3527758c1dab65..cbf15d703201f15dc323bffcd9461fd974fb4e1f 100644 (file)
@@ -608,7 +608,7 @@ static void prism2_plx_remove(struct pci_dev *pdev)
 
 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
 
-static struct pci_driver prism2_plx_drv_id = {
+static struct pci_driver prism2_plx_driver = {
        .name           = "hostap_plx",
        .id_table       = prism2_plx_id_table,
        .probe          = prism2_plx_probe,
@@ -618,13 +618,13 @@ static struct pci_driver prism2_plx_drv_id = {
 
 static int __init init_prism2_plx(void)
 {
-       return pci_register_driver(&prism2_plx_drv_id);
+       return pci_register_driver(&prism2_plx_driver);
 }
 
 
 static void __exit exit_prism2_plx(void)
 {
-       pci_unregister_driver(&prism2_plx_drv_id);
+       pci_unregister_driver(&prism2_plx_driver);
 }
 
 
index 88062c1318a89c0c16ab3e20707fdeb7b4afa72b..003f73f89efa66bda431e3322b1b2b35eb5dbf7e 100644 (file)
@@ -4935,7 +4935,7 @@ static int ipw_queue_reset(struct ipw_priv *priv)
 /**
  * Reclaim Tx queue entries no more used by NIC.
  *
- * When FW adwances 'R' index, all entries between old and
+ * When FW advances 'R' index, all entries between old and
  * new 'R' index need to be reclaimed. As result, some free space
  * forms. If there is enough free space (> low mark), wake Tx queue.
  *
index 1a6b0e0edf6f026d8f3c98bc1e1cd454936ef4c0..0b3ec7e4d93b30e4a78d7f5f674aafb4ba69a462 100644 (file)
@@ -6342,6 +6342,11 @@ static int __iwl_up(struct iwl_priv *priv)
                return 0;
        }
 
+       if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+               IWL_ERROR("ucode not available for device bringup\n");
+               return -EIO;
+       }
+
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
        rc = iwl_hw_nic_init(priv);
index 6cd57c220631919fd33ced7cdc01a94b84502c0b..15a45f4717104300f201866ab535a52ad35c7133 100644 (file)
@@ -6698,6 +6698,11 @@ static int __iwl_up(struct iwl_priv *priv)
                return 0;
        }
 
+       if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+               IWL_ERROR("ucode not available for device bringup\n");
+               return -EIO;
+       }
+
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
        rc = iwl_hw_nic_init(priv);
index b24425f748830b9767a290d3aac038cf6b64caf9..4f1efb108c28dfa7260ee7f1a1355fa67fccd576 100644 (file)
@@ -871,6 +871,10 @@ static int if_sdio_probe(struct sdio_func *func,
                if (sscanf(func->card->info[i],
                                "ID: %x", &model) == 1)
                        break;
+               if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
+                       model = 4;
+                       break;
+               }
        }
 
        if (i == func->card->num_info) {
index 50775f9234cc72fb8a2dc34bf52ff59fc1c1fb53..18b1f9145389975df1b28e5b8a1064b34b3e6aff 100644 (file)
@@ -257,7 +257,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
 static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev,
                                      __le32 *mac)
 {
-       rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, &mac,
+       rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
                                      (3 * sizeof(__le16)));
 }
 
index 2780df00623c4f9392e40087868326fbd8bb7522..04663eb319504f53d31af8e8fc0dfa509a836570 100644 (file)
@@ -124,7 +124,10 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
        struct data_entry *entry;
        struct data_desc *rxd;
        struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
        struct rxdata_entry_desc desc;
+       int header_size;
+       int align;
        u32 word;
 
        while (1) {
@@ -138,17 +141,26 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
                memset(&desc, 0x00, sizeof(desc));
                rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
 
+               hdr = (struct ieee80211_hdr *)entry->data_addr;
+               header_size =
+                   ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+
+               /*
+                * The data behind the ieee80211 header must be
+                * aligned on a 4 byte boundary.
+                */
+               align = header_size % 4;
+
                /*
                 * Allocate the sk_buffer, initialize it and copy
                 * all data into it.
                 */
-               skb = dev_alloc_skb(desc.size + NET_IP_ALIGN);
+               skb = dev_alloc_skb(desc.size + align);
                if (!skb)
                        return;
 
-               skb_reserve(skb, NET_IP_ALIGN);
-               skb_put(skb, desc.size);
-               memcpy(skb->data, entry->data_addr, desc.size);
+               skb_reserve(skb, align);
+               memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size);
 
                /*
                 * Send the frame to rt2x00lib for further processing.
index 1f5675dd329f78963fbd94a77976ab57687570f2..568d73847dca4eabcaf3d2ee974b5f20dcb26a00 100644 (file)
@@ -221,7 +221,9 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
        struct data_ring *ring = entry->ring;
        struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
        struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
        struct rxdata_entry_desc desc;
+       int header_size;
        int frame_size;
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
@@ -243,19 +245,37 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
         * Allocate a new sk buffer to replace the current one.
         * If allocation fails, we should drop the current frame
         * so we can recycle the existing sk buffer for the new frame.
+        * As alignment we use 2 and not NET_IP_ALIGN because we need
+        * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN
+        * can be 0 on some hardware). We use these 2 bytes for frame
+        * alignment later, we assume that the chance that
+        * header_size % 4 == 2 is bigger then header_size % 2 == 0
+        * and thus optimize alignment by reserving the 2 bytes in
+        * advance.
         */
        frame_size = entry->ring->data_size + entry->ring->desc_size;
-       skb = dev_alloc_skb(frame_size + NET_IP_ALIGN);
+       skb = dev_alloc_skb(frame_size + 2);
        if (!skb)
                goto skip_entry;
 
-       skb_reserve(skb, NET_IP_ALIGN);
+       skb_reserve(skb, 2);
        skb_put(skb, frame_size);
 
        /*
-        * Trim the skb_buffer to only contain the valid
-        * frame data (so ignore the device's descriptor).
+        * The data behind the ieee80211 header must be
+        * aligned on a 4 byte boundary.
+        * After that trim the entire buffer down to only
+        * contain the valid frame data excluding the device
+        * descriptor.
         */
+       hdr = (struct ieee80211_hdr *)entry->skb->data;
+       header_size =
+           ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+
+       if (header_size % 4 == 0) {
+               skb_push(entry->skb, 2);
+               memmove(entry->skb->data, entry->skb->data + 2, skb->len - 2);
+       }
        skb_trim(entry->skb, desc.size);
 
        /*
index 01dbef19d651f14f902805f451afa20246fc01a4..ecae968ce091ef595f2ab5e4e5a0394109da033d 100644 (file)
@@ -1738,6 +1738,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_ring *ring;
        struct data_entry *entry;
+       struct data_entry *entry_done;
        struct data_desc *txd;
        u32 word;
        u32 reg;
@@ -1791,6 +1792,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                    !rt2x00_get_field32(word, TXD_W0_VALID))
                        return;
 
+               entry_done = rt2x00_get_data_entry_done(ring);
+               while (entry != entry_done) {
+                       /* Catch up. Just report any entries we missed as
+                        * failed. */
+                       WARNING(rt2x00dev,
+                               "TX status report missed for entry %p\n",
+                               entry_done);
+                       rt2x00lib_txdone(entry_done, TX_FAIL_OTHER, 0);
+                       entry_done = rt2x00_get_data_entry_done(ring);
+               }
+
                /*
                 * Obtain the status about this packet.
                 */
index 2a8fc431099f6e1fcd5a652edd043a774629d002..bca37bf0f5455812913e448272749b5d55e7c1a6 100644 (file)
@@ -852,11 +852,6 @@ static int xennet_poll(struct napi_struct *napi, int budget)
 
        spin_lock(&np->rx_lock);
 
-       if (unlikely(!netif_carrier_ok(dev))) {
-               spin_unlock(&np->rx_lock);
-               return 0;
-       }
-
        skb_queue_head_init(&rxq);
        skb_queue_head_init(&errq);
        skb_queue_head_init(&tmpq);
index ebb09e98d215186201293db11260cc022b2d67c6..de34aa9d3136055566204767cd2f5b9cbb28bfb6 100644 (file)
@@ -120,7 +120,7 @@ struct pdcspath_entry pdcspath_entry_##_name = { \
 };
 
 #define PDCS_ATTR(_name, _mode, _show, _store) \
-struct subsys_attribute pdcs_attr_##_name = { \
+struct kobj_attribute pdcs_attr_##_name = { \
        .attr = {.name = __stringify(_name), .mode = _mode}, \
        .show = _show, \
        .store = _store, \
@@ -523,15 +523,15 @@ static struct pdcspath_entry *pdcspath_entries[] = {
 
 /**
  * pdcs_size_read - Stable Storage size output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static ssize_t
-pdcs_size_read(struct kset *kset, char *buf)
+static ssize_t pdcs_size_read(struct kobject *kobj,
+                             struct kobj_attribute *attr,
+                             char *buf)
 {
        char *out = buf;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        /* show the size of the stable storage */
@@ -542,17 +542,17 @@ pdcs_size_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_auto_read - Stable Storage autoboot/search flag output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
  */
-static ssize_t
-pdcs_auto_read(struct kset *kset, char *buf, int knob)
+static ssize_t pdcs_auto_read(struct kobject *kobj,
+                             struct kobj_attribute *attr,
+                             char *buf, int knob)
 {
        char *out = buf;
        struct pdcspath_entry *pathentry;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        /* Current flags are stored in primary boot path entry */
@@ -568,40 +568,37 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob)
 
 /**
  * pdcs_autoboot_read - Stable Storage autoboot flag output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static inline ssize_t
-pdcs_autoboot_read(struct kset *kset, char *buf)
+static ssize_t pdcs_autoboot_read(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
 {
-       return pdcs_auto_read(kset, buf, PF_AUTOBOOT);
+       return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT);
 }
 
 /**
  * pdcs_autosearch_read - Stable Storage autoboot flag output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static inline ssize_t
-pdcs_autosearch_read(struct kset *kset, char *buf)
+static ssize_t pdcs_autosearch_read(struct kobject *kobj,
+                                   struct kobj_attribute *attr, char *buf)
 {
-       return pdcs_auto_read(kset, buf, PF_AUTOSEARCH);
+       return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH);
 }
 
 /**
  * pdcs_timer_read - Stable Storage timer count output (in seconds).
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * The value of the timer field correponds to a number of seconds in powers of 2.
  */
-static ssize_t
-pdcs_timer_read(struct kset *kset, char *buf)
+static ssize_t pdcs_timer_read(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *buf)
 {
        char *out = buf;
        struct pdcspath_entry *pathentry;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        /* Current flags are stored in primary boot path entry */
@@ -618,15 +615,14 @@ pdcs_timer_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_osid_read - Stable Storage OS ID register output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static ssize_t
-pdcs_osid_read(struct kset *kset, char *buf)
+static ssize_t pdcs_osid_read(struct kobject *kobj,
+                             struct kobj_attribute *attr, char *buf)
 {
        char *out = buf;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        out += sprintf(out, "%s dependent data (0x%.4x)\n",
@@ -637,18 +633,17 @@ pdcs_osid_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This can hold 16 bytes of OS-Dependent data.
  */
-static ssize_t
-pdcs_osdep1_read(struct kset *kset, char *buf)
+static ssize_t pdcs_osdep1_read(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
 {
        char *out = buf;
        u32 result[4];
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
@@ -664,18 +659,17 @@ pdcs_osdep1_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * I have NFC how to interpret the content of that register ;-).
  */
-static ssize_t
-pdcs_diagnostic_read(struct kset *kset, char *buf)
+static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
+                                   struct kobj_attribute *attr, char *buf)
 {
        char *out = buf;
        u32 result;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        /* get diagnostic */
@@ -689,18 +683,17 @@ pdcs_diagnostic_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_fastsize_read - Stable Storage FastSize register output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This register holds the amount of system RAM to be tested during boot sequence.
  */
-static ssize_t
-pdcs_fastsize_read(struct kset *kset, char *buf)
+static ssize_t pdcs_fastsize_read(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
 {
        char *out = buf;
        u32 result;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        /* get fast-size */
@@ -718,13 +711,12 @@ pdcs_fastsize_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
  */
-static ssize_t
-pdcs_osdep2_read(struct kset *kset, char *buf)
+static ssize_t pdcs_osdep2_read(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
 {
        char *out = buf;
        unsigned long size;
@@ -736,7 +728,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
 
        size = pdcs_size - 224;
 
-       if (!kset || !buf)
+       if (!buf)
                return -EINVAL;
 
        for (i=0; i<size; i+=4) {
@@ -751,7 +743,6 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_auto_write - This function handles autoboot/search flag modifying.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
@@ -760,8 +751,9 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
  * We expect a precise syntax:
  *     \"n\" (n == 0 or 1) to toggle AutoBoot Off or On
  */
-static ssize_t
-pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
+static ssize_t pdcs_auto_write(struct kobject *kobj,
+                              struct kobj_attribute *attr, const char *buf,
+                              size_t count, int knob)
 {
        struct pdcspath_entry *pathentry;
        unsigned char flags;
@@ -771,7 +763,7 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       if (!kset || !buf || !count)
+       if (!buf || !count)
                return -EINVAL;
 
        /* We'll use a local copy of buf */
@@ -826,7 +818,6 @@ parse_error:
 
 /**
  * pdcs_autoboot_write - This function handles autoboot flag modifying.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -834,15 +825,15 @@ parse_error:
  * We expect a precise syntax:
  *     \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
  */
-static inline ssize_t
-pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_autoboot_write(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t count)
 {
-       return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT);
+       return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT);
 }
 
 /**
  * pdcs_autosearch_write - This function handles autosearch flag modifying.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -850,15 +841,15 @@ pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
  * We expect a precise syntax:
  *     \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
  */
-static inline ssize_t
-pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_autosearch_write(struct kobject *kobj,
+                                    struct kobj_attribute *attr,
+                                    const char *buf, size_t count)
 {
-       return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH);
+       return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH);
 }
 
 /**
  * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -866,15 +857,16 @@ pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
  * write approach. It's up to userspace to deal with it when constructing
  * its input buffer.
  */
-static ssize_t
-pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_osdep1_write(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf, size_t count)
 {
        u8 in[16];
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       if (!kset || !buf || !count)
+       if (!buf || !count)
                return -EINVAL;
 
        if (unlikely(pdcs_osid != OS_ID_LINUX))
@@ -895,7 +887,6 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
 
 /**
  * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -903,8 +894,9 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
  * byte-by-byte write approach. It's up to userspace to deal with it when
  * constructing its input buffer.
  */
-static ssize_t
-pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_osdep2_write(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf, size_t count)
 {
        unsigned long size;
        unsigned short i;
@@ -913,7 +905,7 @@ pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       if (!kset || !buf || !count)
+       if (!buf || !count)
                return -EINVAL;
 
        if (unlikely(pdcs_size <= 224))
@@ -951,21 +943,25 @@ static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
 static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
 static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
 
-static struct subsys_attribute *pdcs_subsys_attrs[] = {
-       &pdcs_attr_size,
-       &pdcs_attr_autoboot,
-       &pdcs_attr_autosearch,
-       &pdcs_attr_timer,
-       &pdcs_attr_osid,
-       &pdcs_attr_osdep1,
-       &pdcs_attr_diagnostic,
-       &pdcs_attr_fastsize,
-       &pdcs_attr_osdep2,
+static struct attribute *pdcs_subsys_attrs[] = {
+       &pdcs_attr_size.attr,
+       &pdcs_attr_autoboot.attr,
+       &pdcs_attr_autosearch.attr,
+       &pdcs_attr_timer.attr,
+       &pdcs_attr_osid.attr,
+       &pdcs_attr_osdep1.attr,
+       &pdcs_attr_diagnostic.attr,
+       &pdcs_attr_fastsize.attr,
+       &pdcs_attr_osdep2.attr,
        NULL,
 };
 
-static decl_subsys(paths, &ktype_pdcspath, NULL);
-static decl_subsys(stable, NULL, NULL);
+static struct attribute_group pdcs_attr_group = {
+       .attrs = pdcs_subsys_attrs,
+};
+
+static struct kobject *stable_kobj;
+static struct kset *paths_kset;
 
 /**
  * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
@@ -995,12 +991,12 @@ pdcs_register_pathentries(void)
                if (err < 0)
                        continue;
 
-               if ((err = kobject_set_name(&entry->kobj, "%s", entry->name)))
-                       return err;
-               kobj_set_kset_s(entry, paths_subsys);
-               if ((err = kobject_register(&entry->kobj)))
+               entry->kobj.kset = paths_kset;
+               err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
+                                          "%s", entry->name);
+               if (err)
                        return err;
-               
+
                /* kobject is now registered */
                write_lock(&entry->rw_lock);
                entry->ready = 2;
@@ -1012,6 +1008,7 @@ pdcs_register_pathentries(void)
                }
 
                write_unlock(&entry->rw_lock);
+               kobject_uevent(&entry->kobj, KOBJ_ADD);
        }
        
        return 0;
@@ -1029,7 +1026,7 @@ pdcs_unregister_pathentries(void)
        for (i = 0; (entry = pdcspath_entries[i]); i++) {
                read_lock(&entry->rw_lock);
                if (entry->ready >= 2)
-                       kobject_unregister(&entry->kobj);
+                       kobject_put(&entry->kobj);
                read_unlock(&entry->rw_lock);
        }
 }
@@ -1041,8 +1038,7 @@ pdcs_unregister_pathentries(void)
 static int __init
 pdc_stable_init(void)
 {
-       struct subsys_attribute *attr;
-       int i, rc = 0, error = 0;
+       int rc = 0, error = 0;
        u32 result;
 
        /* find the size of the stable storage */
@@ -1062,21 +1058,24 @@ pdc_stable_init(void)
        /* the actual result is 16 bits away */
        pdcs_osid = (u16)(result >> 16);
 
-       /* For now we'll register the stable subsys within this driver */
-       if ((rc = firmware_register(&stable_subsys)))
+       /* For now we'll register the directory at /sys/firmware/stable */
+       stable_kobj = kobject_create_and_add("stable", firmware_kobj);
+       if (!stable_kobj) {
+               rc = -ENOMEM;
                goto fail_firmreg;
+       }
 
        /* Don't forget the root entries */
-       for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++)
-               if (attr->show)
-                       error = subsys_create_file(&stable_subsys, attr);
-       
-       /* register the paths subsys as a subsystem of stable subsys */
-       kobj_set_kset_s(&paths_subsys, stable_subsys);
-       if ((rc = subsystem_register(&paths_subsys)))
-               goto fail_subsysreg;
+       error = sysfs_create_group(stable_kobj, pdcs_attr_group);
 
-       /* now we create all "files" for the paths subsys */
+       /* register the paths kset as a child of the stable kset */
+       paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
+       if (!paths_kset) {
+               rc = -ENOMEM;
+               goto fail_ksetreg;
+       }
+
+       /* now we create all "files" for the paths kset */
        if ((rc = pdcs_register_pathentries()))
                goto fail_pdcsreg;
 
@@ -1084,10 +1083,10 @@ pdc_stable_init(void)
        
 fail_pdcsreg:
        pdcs_unregister_pathentries();
-       subsystem_unregister(&paths_subsys);
+       kset_unregister(paths_kset);
        
-fail_subsysreg:
-       firmware_unregister(&stable_subsys);
+fail_ksetreg:
+       kobject_put(stable_kobj);
        
 fail_firmreg:
        printk(KERN_INFO PDCS_PREFIX " bailing out\n");
@@ -1098,9 +1097,8 @@ static void __exit
 pdc_stable_exit(void)
 {
        pdcs_unregister_pathentries();
-       subsystem_unregister(&paths_subsys);
-
-       firmware_unregister(&stable_subsys);
+       kset_unregister(paths_kset);
+       kobject_put(stable_kobj);
 }
 
 
index 47d26b65e99a88265db14a5004a429658b6b287e..750ebd7a4c1047a5144f47ba57e2a115dbdb0c78 100644 (file)
@@ -429,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
        int retval = 0;
        acpi_status status;
        struct acpi_device *device;
-       struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
+       struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
 
        dbg("%s\n", __FUNCTION__);
 
@@ -476,7 +476,7 @@ init_return:
 static void __exit ibm_acpiphp_exit(void)
 {
        acpi_status status;
-       struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
+       struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
 
        dbg("%s\n", __FUNCTION__);
 
index 01c351c176ac27267bc03cdfdcf6c2f0d64e1467..47bb0e1ff3faff303a72cbe17963da8e34f675fc 100644 (file)
@@ -61,7 +61,7 @@ static int debug;
 
 static LIST_HEAD(pci_hotplug_slot_list);
 
-struct kset pci_hotplug_slots_subsys;
+struct kset *pci_hotplug_slots_kset;
 
 static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
                struct attribute *attr, char *buf)
@@ -96,8 +96,6 @@ static struct kobj_type hotplug_slot_ktype = {
        .release = &hotplug_slot_release,
 };
 
-decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
-
 /* these strings match up with the values in pci_bus_speed */
 static char *pci_bus_speed_strings[] = {
        "33 MHz PCI",           /* 0x00 */
@@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot)
                return -EINVAL;
        }
 
-       kobject_set_name(&slot->kobj, "%s", slot->name);
-       kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
-
        /* this can fail if we have already registered a slot with the same name */
-       if (kobject_register(&slot->kobj)) {
-               err("Unable to register kobject");
+       slot->kobj.kset = pci_hotplug_slots_kset;
+       result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
+                                     "%s", slot->name);
+       if (result) {
+               err("Unable to register kobject '%s'", slot->name);
                return -EINVAL;
        }
-               
+
        list_add (&slot->slot_list, &pci_hotplug_slot_list);
 
        result = fs_add_slot (slot);
+       kobject_uevent(&slot->kobj, KOBJ_ADD);
        dbg ("Added slot %s to the list\n", slot->name);
        return result;
 }
@@ -672,7 +671,7 @@ int pci_hp_deregister (struct hotplug_slot *slot)
 
        fs_remove_slot (slot);
        dbg ("Removed slot %s from the list\n", slot->name);
-       kobject_unregister(&slot->kobj);
+       kobject_put(&slot->kobj);
        return 0;
 }
 
@@ -700,11 +699,15 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
 static int __init pci_hotplug_init (void)
 {
        int result;
+       struct kset *pci_bus_kset;
 
-       kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
-       result = subsystem_register(&pci_hotplug_slots_subsys);
-       if (result) {
-               err("Register subsys with error %d\n", result);
+       pci_bus_kset = bus_get_kset(&pci_bus_type);
+
+       pci_hotplug_slots_kset = kset_create_and_add("slots", NULL,
+                                                    &pci_bus_kset->kobj);
+       if (!pci_hotplug_slots_kset) {
+               result = -ENOMEM;
+               err("Register subsys error\n");
                goto exit;
        }
        result = cpci_hotplug_init(debug);
@@ -715,9 +718,9 @@ static int __init pci_hotplug_init (void)
 
        info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
        goto exit;
-       
+
 err_subsys:
-       subsystem_unregister(&pci_hotplug_slots_subsys);
+       kset_unregister(pci_hotplug_slots_kset);
 exit:
        return result;
 }
@@ -725,7 +728,7 @@ exit:
 static void __exit pci_hotplug_exit (void)
 {
        cpci_hotplug_exit();
-       subsystem_unregister(&pci_hotplug_slots_subsys);
+       kset_unregister(pci_hotplug_slots_kset);
 }
 
 module_init(pci_hotplug_init);
@@ -737,7 +740,7 @@ MODULE_LICENSE("GPL");
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
 
-EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
+EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset);
 EXPORT_SYMBOL_GPL(pci_hp_register);
 EXPORT_SYMBOL_GPL(pci_hp_deregister);
 EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
index a080fedf03327fb0b8fe92a940cc71f68ec25c2e..e32148a8fa125e0d6d7bcf9d017d0db0015d6329 100644 (file)
 
 #define MAX_DRC_NAME_LEN 64
 
-/* Store return code of dlpar operation in attribute struct */
-struct dlpar_io_attr {
-       int rc;
-       struct attribute attr;
-       ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf,
-               size_t nbytes);
-};
 
-/* Common show callback for all attrs, display the return code
- * of the dlpar op */
-static ssize_t
-dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
-{
-       struct dlpar_io_attr *dlpar_attr = container_of(attr,
-                                               struct dlpar_io_attr, attr);
-       return sprintf(buf, "%d\n", dlpar_attr->rc);
-}
-
-static ssize_t
-dlpar_attr_store(struct kobject * kobj, struct attribute * attr,
-                const char *buf, size_t nbytes)
-{
-       struct dlpar_io_attr *dlpar_attr = container_of(attr,
-                                               struct dlpar_io_attr, attr);
-       return dlpar_attr->store ?
-               dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO;
-}
-
-static struct sysfs_ops dlpar_attr_sysfs_ops = {
-       .show = dlpar_attr_show,
-       .store = dlpar_attr_store,
-};
-
-static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
-                               const char *buf, size_t nbytes)
+static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
+                             const char *buf, size_t nbytes)
 {
        char drc_name[MAX_DRC_NAME_LEN];
        char *end;
+       int rc;
 
        if (nbytes >= MAX_DRC_NAME_LEN)
                return 0;
@@ -72,15 +41,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
                end = &drc_name[nbytes];
        *end = '\0';
 
-       dlpar_attr->rc = dlpar_add_slot(drc_name);
+       rc = dlpar_add_slot(drc_name);
+       if (rc)
+               return rc;
 
        return nbytes;
 }
 
-static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
-                               const char *buf, size_t nbytes)
+static ssize_t add_slot_show(struct kobject *kobj,
+                            struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0\n");
+}
+
+static ssize_t remove_slot_store(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf, size_t nbytes)
 {
        char drc_name[MAX_DRC_NAME_LEN];
+       int rc;
        char *end;
 
        if (nbytes >= MAX_DRC_NAME_LEN)
@@ -93,22 +72,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
                end = &drc_name[nbytes];
        *end = '\0';
 
-       dlpar_attr->rc = dlpar_remove_slot(drc_name);
+       rc = dlpar_remove_slot(drc_name);
+       if (rc)
+               return rc;
 
        return nbytes;
 }
 
-static struct dlpar_io_attr add_slot_attr = {
-       .rc = 0,
-       .attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, },
-       .store = add_slot_store,
-};
+static ssize_t remove_slot_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0\n");
+}
 
-static struct dlpar_io_attr remove_slot_attr = {
-       .rc = 0,
-       .attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644},
-       .store = remove_slot_store,
-};
+static struct kobj_attribute add_slot_attr =
+       __ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store);
+
+static struct kobj_attribute remove_slot_attr =
+       __ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store);
 
 static struct attribute *default_attrs[] = {
        &add_slot_attr.attr,
@@ -116,37 +97,29 @@ static struct attribute *default_attrs[] = {
        NULL,
 };
 
-static void dlpar_io_release(struct kobject *kobj)
-{
-       /* noop */
-       return;
-}
-
-struct kobj_type ktype_dlpar_io = {
-       .release = dlpar_io_release,
-       .sysfs_ops = &dlpar_attr_sysfs_ops,
-       .default_attrs = default_attrs,
+static struct attribute_group dlpar_attr_group = {
+       .attrs = default_attrs,
 };
 
-struct kset dlpar_io_kset = {
-       .kobj = {.ktype = &ktype_dlpar_io,
-                .parent = &pci_hotplug_slots_subsys.kobj},
-       .ktype = &ktype_dlpar_io,
-};
+static struct kobject *dlpar_kobj;
 
 int dlpar_sysfs_init(void)
 {
-       kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
-       if (kset_register(&dlpar_io_kset)) {
-               printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
-                               kobject_name(&dlpar_io_kset.kobj));
+       int error;
+
+       dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME,
+                                           &pci_hotplug_slots_kset->kobj);
+       if (!dlpar_kobj)
                return -EINVAL;
-       }
 
-       return 0;
+       error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group);
+       if (error)
+               kobject_put(dlpar_kobj);
+       return error;
 }
 
 void dlpar_sysfs_exit(void)
 {
-       kset_unregister(&dlpar_io_kset);
+       sysfs_remove_group(dlpar_kobj, &dlpar_attr_group);
+       kobject_put(dlpar_kobj);
 }
index 6d1a21611818b92c5cd4524e61d046984cf4c476..c4fa35d1dd7721d7a8288b1bcba6978b6b9412a5 100644 (file)
@@ -1,6 +1,11 @@
 /*
  * drivers/pci/pci-driver.c
  *
+ * (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg@kroah.com>
+ * (C) Copyright 2007 Novell Inc.
+ *
+ * Released under the GPL v2 only.
+ *
  */
 
 #include <linux/pci.h>
@@ -96,17 +101,21 @@ pci_create_newid_file(struct pci_driver *drv)
 {
        int error = 0;
        if (drv->probe != NULL)
-               error = sysfs_create_file(&drv->driver.kobj,
-                                         &driver_attr_new_id.attr);
+               error = driver_create_file(&drv->driver, &driver_attr_new_id);
        return error;
 }
 
+static void pci_remove_newid_file(struct pci_driver *drv)
+{
+       driver_remove_file(&drv->driver, &driver_attr_new_id);
+}
 #else /* !CONFIG_HOTPLUG */
 static inline void pci_free_dynids(struct pci_driver *drv) {}
 static inline int pci_create_newid_file(struct pci_driver *drv)
 {
        return 0;
 }
+static inline void pci_remove_newid_file(struct pci_driver *drv) {}
 #endif
 
 /**
@@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev)
                drv->shutdown(pci_dev);
 }
 
-#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
-#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
-
-static ssize_t
-pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
-{
-       struct device_driver *driver = kobj_to_pci_driver(kobj);
-       struct driver_attribute *dattr = attr_to_driver_attribute(attr);
-       ssize_t ret;
-
-       if (!get_driver(driver))
-               return -ENODEV;
-
-       ret = dattr->show ? dattr->show(driver, buf) : -EIO;
-
-       put_driver(driver);
-       return ret;
-}
-
-static ssize_t
-pci_driver_attr_store(struct kobject * kobj, struct attribute *attr,
-                     const char *buf, size_t count)
-{
-       struct device_driver *driver = kobj_to_pci_driver(kobj);
-       struct driver_attribute *dattr = attr_to_driver_attribute(attr);
-       ssize_t ret;
-
-       if (!get_driver(driver))
-               return -ENODEV;
-
-       ret = dattr->store ? dattr->store(driver, buf, count) : -EIO;
-
-       put_driver(driver);
-       return ret;
-}
-
-static struct sysfs_ops pci_driver_sysfs_ops = {
-       .show = pci_driver_attr_show,
-       .store = pci_driver_attr_store,
-};
-static struct kobj_type pci_driver_kobj_type = {
-       .sysfs_ops = &pci_driver_sysfs_ops,
-};
-
 /**
  * __pci_register_driver - register a new pci driver
  * @drv: the driver structure to register
@@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
        drv->driver.bus = &pci_bus_type;
        drv->driver.owner = owner;
        drv->driver.mod_name = mod_name;
-       drv->driver.kobj.ktype = &pci_driver_kobj_type;
 
        spin_lock_init(&drv->dynids.lock);
        INIT_LIST_HEAD(&drv->dynids.list);
@@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
+       pci_remove_newid_file(drv);
        driver_unregister(&drv->driver);
        pci_free_dynids(drv);
 }
index c5ca3134513a6e848461c2546604c293d4ba2e51..5fd585293e7954c777094b6331e5a5fae9c094ca 100644 (file)
@@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void)
        struct klist_node *n;
        struct device *dev;
        struct pci_dev *pdev;
+       struct klist *device_klist;
 
-       spin_lock(&pci_bus_type.klist_devices.k_lock);
-       list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
+       device_klist = bus_get_device_klist(&pci_bus_type);
+
+       spin_lock(&device_klist->k_lock);
+       list_for_each_safe(pos, tmp, &device_klist->k_list) {
                n = container_of(pos, struct klist_node, n_node);
                dev = container_of(n, struct device, knode_bus);
                pdev = to_pci_dev(dev);
                pci_insertion_sort_klist(pdev, &sorted_devices);
        }
-       list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
-       spin_unlock(&pci_bus_type.klist_devices.k_lock);
+       list_splice(&sorted_devices, &device_klist->k_list);
+       spin_unlock(&device_klist->k_lock);
 }
 
 static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
index 26cc4dcf4f0e381c791c6dba3e6bb28ce3b5e236..72e0bd5d80aced43ef522ff52efdeebd65b86aa6 100644 (file)
@@ -465,6 +465,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,      PCI_DEVICE_ID_INTEL_ICH7_31, quirk
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi );
 
 /*
  * VIA ACPI: One IO region pointed to by longword at
index 5cf89a91da1ea275266da0a42d6dada7672e5466..15c18f5246d6d21bbd2c849892ef0f88d536395c 100644 (file)
@@ -312,8 +312,7 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv)
 {
        int error = 0;
        if (drv->probe != NULL)
-               error = sysfs_create_file(&drv->drv.kobj,
-                                         &driver_attr_new_id.attr);
+               error = driver_create_file(&drv->drv, &driver_attr_new_id);
        return error;
 }
 
index 3c5eb374adf8bbcc0a1d0a7dbb85ab6f55587a7d..6b9840cce0f4a8cdf9b1a2a51c48e186e53015f2 100644 (file)
@@ -76,6 +76,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
        int i = 0;
        int irq;
        int p, t;
+       static unsigned char warned;
 
        if (!valid_IRQ(gsi))
                return;
@@ -83,9 +84,10 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
        while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
               i < PNP_MAX_IRQ)
                i++;
-       if (i >= PNP_MAX_IRQ) {
+       if (i >= PNP_MAX_IRQ && !warned) {
                printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ "
                                "resources: %d \n", PNP_MAX_IRQ);
+               warned = 1;
                return;
        }
        /*
@@ -169,6 +171,7 @@ static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res,
                                                int bus_master, int transfer)
 {
        int i = 0;
+       static unsigned char warned;
 
        while (i < PNP_MAX_DMA &&
               !(res->dma_resource[i].flags & IORESOURCE_UNSET))
@@ -183,9 +186,10 @@ static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res,
                }
                res->dma_resource[i].start = dma;
                res->dma_resource[i].end = dma;
-       } else {
+       } else if (!warned) {
                printk(KERN_ERR "pnpacpi: exceeded the max number of DMA "
                                "resources: %d \n", PNP_MAX_DMA);
+               warned = 1;
        }
 }
 
@@ -193,6 +197,7 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
                                               u64 io, u64 len, int io_decode)
 {
        int i = 0;
+       static unsigned char warned;
 
        while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
               i < PNP_MAX_PORT)
@@ -207,9 +212,10 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
                }
                res->port_resource[i].start = io;
                res->port_resource[i].end = io + len - 1;
-       } else {
+       } else if (!warned) {
                printk(KERN_ERR "pnpacpi: exceeded the max number of IO "
                                "resources: %d \n", PNP_MAX_PORT);
+               warned = 1;
        }
 }
 
@@ -218,6 +224,7 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
                                                int write_protect)
 {
        int i = 0;
+       static unsigned char warned;
 
        while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
               (i < PNP_MAX_MEM))
@@ -233,9 +240,10 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
 
                res->mem_resource[i].start = mem;
                res->mem_resource[i].end = mem + len - 1;
-       } else {
+       } else if (!warned) {
                printk(KERN_ERR "pnpacpi: exceeded the max number of mem "
                                "resources: %d\n", PNP_MAX_MEM);
+               warned = 1;
        }
 }
 
index bbf3ee10da04ad433027963d9831379827cb715f..7e29b90a4f6377d51351828a8bf3daded4ad9d49 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 
+static DEFINE_MUTEX(apm_mutex);
 #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
                         POWER_SUPPLY_PROP_##prop, val)
 
 
 static struct power_supply *main_battery;
 
-static void find_main_battery(void)
-{
-       struct device *dev;
-       struct power_supply *bat = NULL;
-       struct power_supply *max_charge_bat = NULL;
-       struct power_supply *max_energy_bat = NULL;
+struct find_bat_param {
+       struct power_supply *main;
+       struct power_supply *bat;
+       struct power_supply *max_charge_bat;
+       struct power_supply *max_energy_bat;
        union power_supply_propval full;
-       int max_charge = 0;
-       int max_energy = 0;
+       int max_charge;
+       int max_energy;
+};
 
-       main_battery = NULL;
+static int __find_main_battery(struct device *dev, void *data)
+{
+       struct find_bat_param *bp = (struct find_bat_param *)data;
 
-       list_for_each_entry(dev, &power_supply_class->devices, node) {
-               bat = dev_get_drvdata(dev);
+       bp->bat = dev_get_drvdata(dev);
 
-               if (bat->use_for_apm) {
-                       /* nice, we explicitly asked to report this battery. */
-                       main_battery = bat;
-                       return;
-               }
+       if (bp->bat->use_for_apm) {
+               /* nice, we explicitly asked to report this battery. */
+               bp->main = bp->bat;
+               return 1;
+       }
 
-               if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
-                               !PSY_PROP(bat, CHARGE_FULL, &full)) {
-                       if (full.intval > max_charge) {
-                               max_charge_bat = bat;
-                               max_charge = full.intval;
-                       }
-               } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
-                               !PSY_PROP(bat, ENERGY_FULL, &full)) {
-                       if (full.intval > max_energy) {
-                               max_energy_bat = bat;
-                               max_energy = full.intval;
-                       }
+       if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) ||
+                       !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) {
+               if (bp->full.intval > bp->max_charge) {
+                       bp->max_charge_bat = bp->bat;
+                       bp->max_charge = bp->full.intval;
+               }
+       } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) ||
+                       !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) {
+               if (bp->full.intval > bp->max_energy) {
+                       bp->max_energy_bat = bp->bat;
+                       bp->max_energy = bp->full.intval;
                }
        }
+       return 0;
+}
+
+static void find_main_battery(void)
+{
+       struct find_bat_param bp;
+       int error;
+
+       memset(&bp, 0, sizeof(struct find_bat_param));
+       main_battery = NULL;
+       bp.main = main_battery;
+
+       error = class_for_each_device(power_supply_class, &bp,
+                                     __find_main_battery);
+       if (error) {
+               main_battery = bp.main;
+               return;
+       }
 
-       if ((max_energy_bat && max_charge_bat) &&
-                       (max_energy_bat != max_charge_bat)) {
+       if ((bp.max_energy_bat && bp.max_charge_bat) &&
+                       (bp.max_energy_bat != bp.max_charge_bat)) {
                /* try guess battery with more capacity */
-               if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
-                       if (max_energy > max_charge * full.intval)
-                               main_battery = max_energy_bat;
+               if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN,
+                             &bp.full)) {
+                       if (bp.max_energy > bp.max_charge * bp.full.intval)
+                               main_battery = bp.max_energy_bat;
                        else
-                               main_battery = max_charge_bat;
-               } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
-                                                                 &full)) {
-                       if (max_charge > max_energy / full.intval)
-                               main_battery = max_charge_bat;
+                               main_battery = bp.max_charge_bat;
+               } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN,
+                                                                 &bp.full)) {
+                       if (bp.max_charge > bp.max_energy / bp.full.intval)
+                               main_battery = bp.max_charge_bat;
                        else
-                               main_battery = max_energy_bat;
+                               main_battery = bp.max_energy_bat;
                } else {
                        /* give up, choice any */
-                       main_battery = max_energy_bat;
+                       main_battery = bp.max_energy_bat;
                }
-       } else if (max_charge_bat) {
-               main_battery = max_charge_bat;
-       } else if (max_energy_bat) {
-               main_battery = max_energy_bat;
+       } else if (bp.max_charge_bat) {
+               main_battery = bp.max_charge_bat;
+       } else if (bp.max_energy_bat) {
+               main_battery = bp.max_energy_bat;
        } else {
                /* give up, try the last if any */
-               main_battery = bat;
+               main_battery = bp.bat;
        }
 }
 
@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
        union power_supply_propval status;
        union power_supply_propval capacity, time_to_full, time_to_empty;
 
-       down(&power_supply_class->sem);
+       mutex_lock(&apm_mutex);
        find_main_battery();
        if (!main_battery) {
-               up(&power_supply_class->sem);
+               mutex_unlock(&apm_mutex);
                return;
        }
 
@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
                }
        }
 
-       up(&power_supply_class->sem);
+       mutex_unlock(&apm_mutex);
 }
 
 static int __init apm_battery_init(void)
index a63b75cf75e22569df77991c9a8fb2329832065b..03d6a38464ef8ca8d27c589b35735b0452d1aa97 100644 (file)
 
 struct class *power_supply_class;
 
+static int __power_supply_changed_work(struct device *dev, void *data)
+{
+       struct power_supply *psy = (struct power_supply *)data;
+       struct power_supply *pst = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < psy->num_supplicants; i++)
+               if (!strcmp(psy->supplied_to[i], pst->name)) {
+                       if (pst->external_power_changed)
+                               pst->external_power_changed(pst);
+               }
+       return 0;
+}
+
 static void power_supply_changed_work(struct work_struct *work)
 {
        struct power_supply *psy = container_of(work, struct power_supply,
                                                changed_work);
-       int i;
 
        dev_dbg(psy->dev, "%s\n", __FUNCTION__);
 
-       for (i = 0; i < psy->num_supplicants; i++) {
-               struct device *dev;
-
-               down(&power_supply_class->sem);
-               list_for_each_entry(dev, &power_supply_class->devices, node) {
-                       struct power_supply *pst = dev_get_drvdata(dev);
-
-                       if (!strcmp(psy->supplied_to[i], pst->name)) {
-                               if (pst->external_power_changed)
-                                       pst->external_power_changed(pst);
-                       }
-               }
-               up(&power_supply_class->sem);
-       }
+       class_for_each_device(power_supply_class, psy,
+                             __power_supply_changed_work);
 
        power_supply_update_leds(psy);
 
@@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy)
        schedule_work(&psy->changed_work);
 }
 
-int power_supply_am_i_supplied(struct power_supply *psy)
+static int __power_supply_am_i_supplied(struct device *dev, void *data)
 {
        union power_supply_propval ret = {0,};
-       struct device *dev;
-
-       down(&power_supply_class->sem);
-       list_for_each_entry(dev, &power_supply_class->devices, node) {
-               struct power_supply *epsy = dev_get_drvdata(dev);
-               int i;
-
-               for (i = 0; i < epsy->num_supplicants; i++) {
-                       if (!strcmp(epsy->supplied_to[i], psy->name)) {
-                               if (epsy->get_property(epsy,
-                                         POWER_SUPPLY_PROP_ONLINE, &ret))
-                                       continue;
-                               if (ret.intval)
-                                       goto out;
-                       }
+       struct power_supply *psy = (struct power_supply *)data;
+       struct power_supply *epsy = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < epsy->num_supplicants; i++) {
+               if (!strcmp(epsy->supplied_to[i], psy->name)) {
+                       if (epsy->get_property(epsy,
+                                 POWER_SUPPLY_PROP_ONLINE, &ret))
+                               continue;
+                       if (ret.intval)
+                               return ret.intval;
                }
        }
-out:
-       up(&power_supply_class->sem);
+       return 0;
+}
+
+int power_supply_am_i_supplied(struct power_supply *psy)
+{
+       int error;
+
+       error = class_for_each_device(power_supply_class, psy,
+                                     __power_supply_am_i_supplied);
 
-       dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
+       dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error);
 
-       return ret.intval;
+       return error;
 }
 
 int power_supply_register(struct device *parent, struct power_supply *psy)
index f1e00ff54ce880fb94c69a38064abe6680c83933..7e3ad4f3b3432aa89c8a7d9a4d9902453f9adbbf 100644 (file)
@@ -251,20 +251,23 @@ void rtc_update_irq(struct rtc_device *rtc,
 }
 EXPORT_SYMBOL_GPL(rtc_update_irq);
 
+static int __rtc_match(struct device *dev, void *data)
+{
+       char *name = (char *)data;
+
+       if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0)
+               return 1;
+       return 0;
+}
+
 struct rtc_device *rtc_class_open(char *name)
 {
        struct device *dev;
        struct rtc_device *rtc = NULL;
 
-       down(&rtc_class->sem);
-       list_for_each_entry(dev, &rtc_class->devices, node) {
-               if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
-                       dev = get_device(dev);
-                       if (dev)
-                               rtc = to_rtc_device(dev);
-                       break;
-               }
-       }
+       dev = class_find_device(rtc_class, name, __rtc_match);
+       if (dev)
+               rtc = to_rtc_device(dev);
 
        if (rtc) {
                if (!try_module_get(rtc->owner)) {
@@ -272,7 +275,6 @@ struct rtc_device *rtc_class_open(char *name)
                        rtc = NULL;
                }
        }
-       up(&rtc_class->sem);
 
        return rtc;
 }
index be9f22d52fd8e6f7ed01ae95c8492045e5a28129..0a89e080b3894b623603a6631318fbdedc982b1e 100644 (file)
@@ -2,8 +2,8 @@
 # S/390 block devices
 #
 
-dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
-dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o
+dasd_fba_mod-objs  := dasd_fba.o
 dasd_diag_mod-objs := dasd_diag.o
 dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
                        dasd_genhd.o dasd_erp.o
index e6bfce690ca338aa1ce7187668ac5b2213ec85a7..1db15f3e5d20cc5e21fe4d144dd8840c08e5d009 100644 (file)
@@ -48,13 +48,15 @@ MODULE_LICENSE("GPL");
 /*
  * SECTION: prototypes for static functions of dasd.c
  */
-static int  dasd_alloc_queue(struct dasd_device * device);
-static void dasd_setup_queue(struct dasd_device * device);
-static void dasd_free_queue(struct dasd_device * device);
-static void dasd_flush_request_queue(struct dasd_device *);
-static int dasd_flush_ccw_queue(struct dasd_device *, int);
-static void dasd_tasklet(struct dasd_device *);
+static int  dasd_alloc_queue(struct dasd_block *);
+static void dasd_setup_queue(struct dasd_block *);
+static void dasd_free_queue(struct dasd_block *);
+static void dasd_flush_request_queue(struct dasd_block *);
+static int dasd_flush_block_queue(struct dasd_block *);
+static void dasd_device_tasklet(struct dasd_device *);
+static void dasd_block_tasklet(struct dasd_block *);
 static void do_kick_device(struct work_struct *);
+static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
 
 /*
  * SECTION: Operations on the device structure.
@@ -65,26 +67,23 @@ static wait_queue_head_t dasd_flush_wq;
 /*
  * Allocate memory for a new device structure.
  */
-struct dasd_device *
-dasd_alloc_device(void)
+struct dasd_device *dasd_alloc_device(void)
 {
        struct dasd_device *device;
 
-       device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC);
-       if (device == NULL)
+       device = kzalloc(sizeof(struct dasd_device), GFP_ATOMIC);
+       if (!device)
                return ERR_PTR(-ENOMEM);
-       /* open_count = 0 means device online but not in use */
-       atomic_set(&device->open_count, -1);
 
        /* Get two pages for normal block device operations. */
        device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
-       if (device->ccw_mem == NULL) {
+       if (!device->ccw_mem) {
                kfree(device);
                return ERR_PTR(-ENOMEM);
        }
        /* Get one page for error recovery. */
        device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA);
-       if (device->erp_mem == NULL) {
+       if (!device->erp_mem) {
                free_pages((unsigned long) device->ccw_mem, 1);
                kfree(device);
                return ERR_PTR(-ENOMEM);
@@ -93,10 +92,9 @@ dasd_alloc_device(void)
        dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
        dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
        spin_lock_init(&device->mem_lock);
-       spin_lock_init(&device->request_queue_lock);
-       atomic_set (&device->tasklet_scheduled, 0);
+       atomic_set(&device->tasklet_scheduled, 0);
        tasklet_init(&device->tasklet,
-                    (void (*)(unsigned long)) dasd_tasklet,
+                    (void (*)(unsigned long)) dasd_device_tasklet,
                     (unsigned long) device);
        INIT_LIST_HEAD(&device->ccw_queue);
        init_timer(&device->timer);
@@ -110,8 +108,7 @@ dasd_alloc_device(void)
 /*
  * Free memory of a device structure.
  */
-void
-dasd_free_device(struct dasd_device *device)
+void dasd_free_device(struct dasd_device *device)
 {
        kfree(device->private);
        free_page((unsigned long) device->erp_mem);
@@ -119,11 +116,43 @@ dasd_free_device(struct dasd_device *device)
        kfree(device);
 }
 
+/*
+ * Allocate memory for a new device structure.
+ */
+struct dasd_block *dasd_alloc_block(void)
+{
+       struct dasd_block *block;
+
+       block = kzalloc(sizeof(*block), GFP_ATOMIC);
+       if (!block)
+               return ERR_PTR(-ENOMEM);
+       /* open_count = 0 means device online but not in use */
+       atomic_set(&block->open_count, -1);
+
+       spin_lock_init(&block->request_queue_lock);
+       atomic_set(&block->tasklet_scheduled, 0);
+       tasklet_init(&block->tasklet,
+                    (void (*)(unsigned long)) dasd_block_tasklet,
+                    (unsigned long) block);
+       INIT_LIST_HEAD(&block->ccw_queue);
+       spin_lock_init(&block->queue_lock);
+       init_timer(&block->timer);
+
+       return block;
+}
+
+/*
+ * Free memory of a device structure.
+ */
+void dasd_free_block(struct dasd_block *block)
+{
+       kfree(block);
+}
+
 /*
  * Make a new device known to the system.
  */
-static int
-dasd_state_new_to_known(struct dasd_device *device)
+static int dasd_state_new_to_known(struct dasd_device *device)
 {
        int rc;
 
@@ -133,12 +162,13 @@ dasd_state_new_to_known(struct dasd_device *device)
         */
        dasd_get_device(device);
 
-       rc = dasd_alloc_queue(device);
-       if (rc) {
-               dasd_put_device(device);
-               return rc;
+       if (device->block) {
+               rc = dasd_alloc_queue(device->block);
+               if (rc) {
+                       dasd_put_device(device);
+                       return rc;
+               }
        }
-
        device->state = DASD_STATE_KNOWN;
        return 0;
 }
@@ -146,21 +176,24 @@ dasd_state_new_to_known(struct dasd_device *device)
 /*
  * Let the system forget about a device.
  */
-static int
-dasd_state_known_to_new(struct dasd_device * device)
+static int dasd_state_known_to_new(struct dasd_device *device)
 {
        /* Disable extended error reporting for this device. */
        dasd_eer_disable(device);
        /* Forget the discipline information. */
-       if (device->discipline)
+       if (device->discipline) {
+               if (device->discipline->uncheck_device)
+                       device->discipline->uncheck_device(device);
                module_put(device->discipline->owner);
+       }
        device->discipline = NULL;
        if (device->base_discipline)
                module_put(device->base_discipline->owner);
        device->base_discipline = NULL;
        device->state = DASD_STATE_NEW;
 
-       dasd_free_queue(device);
+       if (device->block)
+               dasd_free_queue(device->block);
 
        /* Give up reference we took in dasd_state_new_to_known. */
        dasd_put_device(device);
@@ -170,19 +203,19 @@ dasd_state_known_to_new(struct dasd_device * device)
 /*
  * Request the irq line for the device.
  */
-static int
-dasd_state_known_to_basic(struct dasd_device * device)
+static int dasd_state_known_to_basic(struct dasd_device *device)
 {
        int rc;
 
        /* Allocate and register gendisk structure. */
-       rc = dasd_gendisk_alloc(device);
-       if (rc)
-               return rc;
-
+       if (device->block) {
+               rc = dasd_gendisk_alloc(device->block);
+               if (rc)
+                       return rc;
+       }
        /* register 'device' debug area, used for all DBF_DEV_XXX calls */
-       device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
-                                           8 * sizeof (long));
+       device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
+                                           8 * sizeof(long));
        debug_register_view(device->debug_area, &debug_sprintf_view);
        debug_set_level(device->debug_area, DBF_WARNING);
        DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
@@ -194,16 +227,17 @@ dasd_state_known_to_basic(struct dasd_device * device)
 /*
  * Release the irq line for the device. Terminate any running i/o.
  */
-static int
-dasd_state_basic_to_known(struct dasd_device * device)
+static int dasd_state_basic_to_known(struct dasd_device *device)
 {
        int rc;
-
-       dasd_gendisk_free(device);
-       rc = dasd_flush_ccw_queue(device, 1);
+       if (device->block) {
+               dasd_gendisk_free(device->block);
+               dasd_block_clear_timer(device->block);
+       }
+       rc = dasd_flush_device_queue(device);
        if (rc)
                return rc;
-       dasd_clear_timer(device);
+       dasd_device_clear_timer(device);
 
        DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
        if (device->debug_area != NULL) {
@@ -228,26 +262,32 @@ dasd_state_basic_to_known(struct dasd_device * device)
  * In case the analysis returns an error, the device setup is stopped
  * (a fake disk was already added to allow formatting).
  */
-static int
-dasd_state_basic_to_ready(struct dasd_device * device)
+static int dasd_state_basic_to_ready(struct dasd_device *device)
 {
        int rc;
+       struct dasd_block *block;
 
        rc = 0;
-       if (device->discipline->do_analysis != NULL)
-               rc = device->discipline->do_analysis(device);
-       if (rc) {
-               if (rc != -EAGAIN)
-                       device->state = DASD_STATE_UNFMT;
-               return rc;
-       }
+       block = device->block;
        /* make disk known with correct capacity */
-       dasd_setup_queue(device);
-       set_capacity(device->gdp, device->blocks << device->s2b_shift);
-       device->state = DASD_STATE_READY;
-       rc = dasd_scan_partitions(device);
-       if (rc)
-               device->state = DASD_STATE_BASIC;
+       if (block) {
+               if (block->base->discipline->do_analysis != NULL)
+                       rc = block->base->discipline->do_analysis(block);
+               if (rc) {
+                       if (rc != -EAGAIN)
+                               device->state = DASD_STATE_UNFMT;
+                       return rc;
+               }
+               dasd_setup_queue(block);
+               set_capacity(block->gdp,
+                            block->blocks << block->s2b_shift);
+               device->state = DASD_STATE_READY;
+               rc = dasd_scan_partitions(block);
+               if (rc)
+                       device->state = DASD_STATE_BASIC;
+       } else {
+               device->state = DASD_STATE_READY;
+       }
        return rc;
 }
 
@@ -256,28 +296,31 @@ dasd_state_basic_to_ready(struct dasd_device * device)
  * Forget format information. Check if the target level is basic
  * and if it is create fake disk for formatting.
  */
-static int
-dasd_state_ready_to_basic(struct dasd_device * device)
+static int dasd_state_ready_to_basic(struct dasd_device *device)
 {
        int rc;
 
-       rc = dasd_flush_ccw_queue(device, 0);
-       if (rc)
-               return rc;
-       dasd_destroy_partitions(device);
-       dasd_flush_request_queue(device);
-       device->blocks = 0;
-       device->bp_block = 0;
-       device->s2b_shift = 0;
        device->state = DASD_STATE_BASIC;
+       if (device->block) {
+               struct dasd_block *block = device->block;
+               rc = dasd_flush_block_queue(block);
+               if (rc) {
+                       device->state = DASD_STATE_READY;
+                       return rc;
+               }
+               dasd_destroy_partitions(block);
+               dasd_flush_request_queue(block);
+               block->blocks = 0;
+               block->bp_block = 0;
+               block->s2b_shift = 0;
+       }
        return 0;
 }
 
 /*
  * Back to basic.
  */
-static int
-dasd_state_unfmt_to_basic(struct dasd_device * device)
+static int dasd_state_unfmt_to_basic(struct dasd_device *device)
 {
        device->state = DASD_STATE_BASIC;
        return 0;
@@ -291,17 +334,31 @@ dasd_state_unfmt_to_basic(struct dasd_device * device)
 static int
 dasd_state_ready_to_online(struct dasd_device * device)
 {
+       int rc;
+
+       if (device->discipline->ready_to_online) {
+               rc = device->discipline->ready_to_online(device);
+               if (rc)
+                       return rc;
+       }
        device->state = DASD_STATE_ONLINE;
-       dasd_schedule_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
        return 0;
 }
 
 /*
  * Stop the requeueing of requests again.
  */
-static int
-dasd_state_online_to_ready(struct dasd_device * device)
+static int dasd_state_online_to_ready(struct dasd_device *device)
 {
+       int rc;
+
+       if (device->discipline->online_to_ready) {
+               rc = device->discipline->online_to_ready(device);
+               if (rc)
+                       return rc;
+       }
        device->state = DASD_STATE_READY;
        return 0;
 }
@@ -309,8 +366,7 @@ dasd_state_online_to_ready(struct dasd_device * device)
 /*
  * Device startup state changes.
  */
-static int
-dasd_increase_state(struct dasd_device *device)
+static int dasd_increase_state(struct dasd_device *device)
 {
        int rc;
 
@@ -345,8 +401,7 @@ dasd_increase_state(struct dasd_device *device)
 /*
  * Device shutdown state changes.
  */
-static int
-dasd_decrease_state(struct dasd_device *device)
+static int dasd_decrease_state(struct dasd_device *device)
 {
        int rc;
 
@@ -381,8 +436,7 @@ dasd_decrease_state(struct dasd_device *device)
 /*
  * This is the main startup/shutdown routine.
  */
-static void
-dasd_change_state(struct dasd_device *device)
+static void dasd_change_state(struct dasd_device *device)
 {
         int rc;
 
@@ -409,17 +463,15 @@ dasd_change_state(struct dasd_device *device)
  * dasd_kick_device will schedule a call do do_kick_device to the kernel
  * event daemon.
  */
-static void
-do_kick_device(struct work_struct *work)
+static void do_kick_device(struct work_struct *work)
 {
        struct dasd_device *device = container_of(work, struct dasd_device, kick_work);
        dasd_change_state(device);
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
        dasd_put_device(device);
 }
 
-void
-dasd_kick_device(struct dasd_device *device)
+void dasd_kick_device(struct dasd_device *device)
 {
        dasd_get_device(device);
        /* queue call to dasd_kick_device to the kernel event daemon. */
@@ -429,8 +481,7 @@ dasd_kick_device(struct dasd_device *device)
 /*
  * Set the target state for a device and starts the state change.
  */
-void
-dasd_set_target_state(struct dasd_device *device, int target)
+void dasd_set_target_state(struct dasd_device *device, int target)
 {
        /* If we are in probeonly mode stop at DASD_STATE_READY. */
        if (dasd_probeonly && target > DASD_STATE_READY)
@@ -447,14 +498,12 @@ dasd_set_target_state(struct dasd_device *device, int target)
 /*
  * Enable devices with device numbers in [from..to].
  */
-static inline int
-_wait_for_device(struct dasd_device *device)
+static inline int _wait_for_device(struct dasd_device *device)
 {
        return (device->state == device->target);
 }
 
-void
-dasd_enable_device(struct dasd_device *device)
+void dasd_enable_device(struct dasd_device *device)
 {
        dasd_set_target_state(device, DASD_STATE_ONLINE);
        if (device->state <= DASD_STATE_KNOWN)
@@ -475,20 +524,20 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
 /*
  * Increments counter in global and local profiling structures.
  */
-#define dasd_profile_counter(value, counter, device) \
+#define dasd_profile_counter(value, counter, block) \
 { \
        int index; \
        for (index = 0; index < 31 && value >> (2+index); index++); \
        dasd_global_profile.counter[index]++; \
-       device->profile.counter[index]++; \
+       block->profile.counter[index]++; \
 }
 
 /*
  * Add profiling information for cqr before execution.
  */
-static void
-dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
-                  struct request *req)
+static void dasd_profile_start(struct dasd_block *block,
+                              struct dasd_ccw_req *cqr,
+                              struct request *req)
 {
        struct list_head *l;
        unsigned int counter;
@@ -498,19 +547,19 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 
        /* count the length of the chanq for statistics */
        counter = 0;
-       list_for_each(l, &device->ccw_queue)
+       list_for_each(l, &block->ccw_queue)
                if (++counter >= 31)
                        break;
        dasd_global_profile.dasd_io_nr_req[counter]++;
-       device->profile.dasd_io_nr_req[counter]++;
+       block->profile.dasd_io_nr_req[counter]++;
 }
 
 /*
  * Add profiling information for cqr after execution.
  */
-static void
-dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
-                struct request *req)
+static void dasd_profile_end(struct dasd_block *block,
+                            struct dasd_ccw_req *cqr,
+                            struct request *req)
 {
        long strtime, irqtime, endtime, tottime;        /* in microseconds */
        long tottimeps, sectors;
@@ -532,27 +581,27 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
 
        if (!dasd_global_profile.dasd_io_reqs)
                memset(&dasd_global_profile, 0,
-                      sizeof (struct dasd_profile_info_t));
+                      sizeof(struct dasd_profile_info_t));
        dasd_global_profile.dasd_io_reqs++;
        dasd_global_profile.dasd_io_sects += sectors;
 
-       if (!device->profile.dasd_io_reqs)
-               memset(&device->profile, 0,
-                      sizeof (struct dasd_profile_info_t));
-       device->profile.dasd_io_reqs++;
-       device->profile.dasd_io_sects += sectors;
+       if (!block->profile.dasd_io_reqs)
+               memset(&block->profile, 0,
+                      sizeof(struct dasd_profile_info_t));
+       block->profile.dasd_io_reqs++;
+       block->profile.dasd_io_sects += sectors;
 
-       dasd_profile_counter(sectors, dasd_io_secs, device);
-       dasd_profile_counter(tottime, dasd_io_times, device);
-       dasd_profile_counter(tottimeps, dasd_io_timps, device);
-       dasd_profile_counter(strtime, dasd_io_time1, device);
-       dasd_profile_counter(irqtime, dasd_io_time2, device);
-       dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device);
-       dasd_profile_counter(endtime, dasd_io_time3, device);
+       dasd_profile_counter(sectors, dasd_io_secs, block);
+       dasd_profile_counter(tottime, dasd_io_times, block);
+       dasd_profile_counter(tottimeps, dasd_io_timps, block);
+       dasd_profile_counter(strtime, dasd_io_time1, block);
+       dasd_profile_counter(irqtime, dasd_io_time2, block);
+       dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block);
+       dasd_profile_counter(endtime, dasd_io_time3, block);
 }
 #else
-#define dasd_profile_start(device, cqr, req) do {} while (0)
-#define dasd_profile_end(device, cqr, req) do {} while (0)
+#define dasd_profile_start(block, cqr, req) do {} while (0)
+#define dasd_profile_end(block, cqr, req) do {} while (0)
 #endif                         /* CONFIG_DASD_PROFILE */
 
 /*
@@ -562,9 +611,9 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
  * memory and 2) dasd_smalloc_request uses the static ccw memory
  * that gets allocated for each device.
  */
-struct dasd_ccw_req *
-dasd_kmalloc_request(char *magic, int cplength, int datasize,
-                  struct dasd_device * device)
+struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
+                                         int datasize,
+                                         struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
 
@@ -600,9 +649,9 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
        return cqr;
 }
 
-struct dasd_ccw_req *
-dasd_smalloc_request(char *magic, int cplength, int datasize,
-                  struct dasd_device * device)
+struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
+                                         int datasize,
+                                         struct dasd_device *device)
 {
        unsigned long flags;
        struct dasd_ccw_req *cqr;
@@ -649,8 +698,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
  * idal lists that might have been created by dasd_set_cda and the
  * struct dasd_ccw_req itself.
  */
-void
-dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
 #ifdef CONFIG_64BIT
        struct ccw1 *ccw;
@@ -667,8 +715,7 @@ dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
        dasd_put_device(device);
 }
 
-void
-dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
        unsigned long flags;
 
@@ -681,14 +728,13 @@ dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
 /*
  * Check discipline magic in cqr.
  */
-static inline int
-dasd_check_cqr(struct dasd_ccw_req *cqr)
+static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
 
        if (cqr == NULL)
                return -EINVAL;
-       device = cqr->device;
+       device = cqr->startdev;
        if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
                DEV_MESSAGE(KERN_WARNING, device,
                            " dasd_ccw_req 0x%08x magic doesn't match"
@@ -706,8 +752,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
  * ccw_device_clear can fail if the i/o subsystem
  * is in a bad mood.
  */
-int
-dasd_term_IO(struct dasd_ccw_req * cqr)
+int dasd_term_IO(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int retries, rc;
@@ -717,13 +762,13 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
        if (rc)
                return rc;
        retries = 0;
-       device = (struct dasd_device *) cqr->device;
+       device = (struct dasd_device *) cqr->startdev;
        while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
                rc = ccw_device_clear(device->cdev, (long) cqr);
                switch (rc) {
                case 0: /* termination successful */
                        cqr->retries--;
-                       cqr->status = DASD_CQR_CLEAR;
+                       cqr->status = DASD_CQR_CLEAR_PENDING;
                        cqr->stopclk = get_clock();
                        cqr->starttime = 0;
                        DBF_DEV_EVENT(DBF_DEBUG, device,
@@ -753,7 +798,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
                }
                retries++;
        }
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
        return rc;
 }
 
@@ -761,8 +806,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
  * Start the i/o. This start_IO can fail if the channel is really busy.
  * In that case set up a timer to start the request later.
  */
-int
-dasd_start_IO(struct dasd_ccw_req * cqr)
+int dasd_start_IO(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int rc;
@@ -771,12 +815,12 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
        rc = dasd_check_cqr(cqr);
        if (rc)
                return rc;
-       device = (struct dasd_device *) cqr->device;
+       device = (struct dasd_device *) cqr->startdev;
        if (cqr->retries < 0) {
                DEV_MESSAGE(KERN_DEBUG, device,
                            "start_IO: request %p (%02x/%i) - no retry left.",
                            cqr, cqr->status, cqr->retries);
-               cqr->status = DASD_CQR_FAILED;
+               cqr->status = DASD_CQR_ERROR;
                return -EIO;
        }
        cqr->startclk = get_clock();
@@ -833,8 +877,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
  * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
  * DASD_CQR_QUEUED for 2) and 3).
  */
-static void
-dasd_timeout_device(unsigned long ptr)
+static void dasd_device_timeout(unsigned long ptr)
 {
        unsigned long flags;
        struct dasd_device *device;
@@ -844,14 +887,13 @@ dasd_timeout_device(unsigned long ptr)
        /* re-activate request queue */
         device->stopped &= ~DASD_STOPPED_PENDING;
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
 }
 
 /*
  * Setup timeout for a device in jiffies.
  */
-void
-dasd_set_timer(struct dasd_device *device, int expires)
+void dasd_device_set_timer(struct dasd_device *device, int expires)
 {
        if (expires == 0) {
                if (timer_pending(&device->timer))
@@ -862,7 +904,7 @@ dasd_set_timer(struct dasd_device *device, int expires)
                if (mod_timer(&device->timer, jiffies + expires))
                        return;
        }
-       device->timer.function = dasd_timeout_device;
+       device->timer.function = dasd_device_timeout;
        device->timer.data = (unsigned long) device;
        device->timer.expires = jiffies + expires;
        add_timer(&device->timer);
@@ -871,15 +913,14 @@ dasd_set_timer(struct dasd_device *device, int expires)
 /*
  * Clear timeout for a device.
  */
-void
-dasd_clear_timer(struct dasd_device *device)
+void dasd_device_clear_timer(struct dasd_device *device)
 {
        if (timer_pending(&device->timer))
                del_timer(&device->timer);
 }
 
-static void
-dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
+static void dasd_handle_killed_request(struct ccw_device *cdev,
+                                      unsigned long intparm)
 {
        struct dasd_ccw_req *cqr;
        struct dasd_device *device;
@@ -893,7 +934,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
                return;
        }
 
-       device = (struct dasd_device *) cqr->device;
+       device = (struct dasd_device *) cqr->startdev;
        if (device == NULL ||
            device != dasd_device_from_cdev_locked(cdev) ||
            strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
@@ -905,46 +946,32 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
        /* Schedule request to be retried. */
        cqr->status = DASD_CQR_QUEUED;
 
-       dasd_clear_timer(device);
-       dasd_schedule_bh(device);
+       dasd_device_clear_timer(device);
+       dasd_schedule_device_bh(device);
        dasd_put_device(device);
 }
 
-static void
-dasd_handle_state_change_pending(struct dasd_device *device)
+void dasd_generic_handle_state_change(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       struct list_head *l, *n;
-
        /* First of all start sense subsystem status request. */
        dasd_eer_snss(device);
 
        device->stopped &= ~DASD_STOPPED_PENDING;
-
-        /* restart all 'running' IO on queue */
-       list_for_each_safe(l, n, &device->ccw_queue) {
-               cqr = list_entry(l, struct dasd_ccw_req, list);
-                if (cqr->status == DASD_CQR_IN_IO) {
-                        cqr->status = DASD_CQR_QUEUED;
-               }
-        }
-       dasd_clear_timer(device);
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
 }
 
 /*
  * Interrupt handler for "normal" ssch-io based dasd devices.
  */
-void
-dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
-                struct irb *irb)
+void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+                     struct irb *irb)
 {
        struct dasd_ccw_req *cqr, *next;
        struct dasd_device *device;
        unsigned long long now;
        int expires;
-       dasd_era_t era;
-       char mask;
 
        if (IS_ERR(irb)) {
                switch (PTR_ERR(irb)) {
@@ -969,29 +996,25 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                  cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
                  (unsigned int) intparm);
 
-       /* first of all check for state change pending interrupt */
-       mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-       if ((irb->scsw.dstat & mask) == mask) {
+       /* check for unsolicited interrupts */
+       cqr = (struct dasd_ccw_req *) intparm;
+       if (!cqr || ((irb->scsw.cc == 1) &&
+                    (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
+                    (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
+               if (cqr && cqr->status == DASD_CQR_IN_IO)
+                       cqr->status = DASD_CQR_QUEUED;
                device = dasd_device_from_cdev_locked(cdev);
                if (!IS_ERR(device)) {
-                       dasd_handle_state_change_pending(device);
+                       dasd_device_clear_timer(device);
+                       device->discipline->handle_unsolicited_interrupt(device,
+                                                                        irb);
                        dasd_put_device(device);
                }
                return;
        }
 
-       cqr = (struct dasd_ccw_req *) intparm;
-
-       /* check for unsolicited interrupts */
-       if (cqr == NULL) {
-               MESSAGE(KERN_DEBUG,
-                       "unsolicited interrupt received: bus_id %s",
-                       cdev->dev.bus_id);
-               return;
-       }
-
-       device = (struct dasd_device *) cqr->device;
-       if (device == NULL ||
+       device = (struct dasd_device *) cqr->startdev;
+       if (!device ||
            strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
                MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
                        cdev->dev.bus_id);
@@ -999,12 +1022,12 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        }
 
        /* Check for clear pending */
-       if (cqr->status == DASD_CQR_CLEAR &&
+       if (cqr->status == DASD_CQR_CLEAR_PENDING &&
            irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
-               cqr->status = DASD_CQR_QUEUED;
-               dasd_clear_timer(device);
+               cqr->status = DASD_CQR_CLEARED;
+               dasd_device_clear_timer(device);
                wake_up(&dasd_flush_wq);
-               dasd_schedule_bh(device);
+               dasd_schedule_device_bh(device);
                return;
        }
 
@@ -1017,277 +1040,170 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        }
        DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
                      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
-
-       /* Find out the appropriate era_action. */
-       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
-               era = dasd_era_fatal;
-       else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
-                irb->scsw.cstat == 0 &&
-                !irb->esw.esw0.erw.cons)
-               era = dasd_era_none;
-       else if (irb->esw.esw0.erw.cons)
-               era = device->discipline->examine_error(cqr, irb);
-       else
-               era = dasd_era_recover;
-
-       DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
+       next = NULL;
        expires = 0;
-       if (era == dasd_era_none) {
-               cqr->status = DASD_CQR_DONE;
+       if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+           irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
+               /* request was completed successfully */
+               cqr->status = DASD_CQR_SUCCESS;
                cqr->stopclk = now;
                /* Start first request on queue if possible -> fast_io. */
-               if (cqr->list.next != &device->ccw_queue) {
-                       next = list_entry(cqr->list.next,
-                                         struct dasd_ccw_req, list);
-                       if ((next->status == DASD_CQR_QUEUED) &&
-                           (!device->stopped)) {
-                               if (device->discipline->start_IO(next) == 0)
-                                       expires = next->expires;
-                               else
-                                       DEV_MESSAGE(KERN_DEBUG, device, "%s",
-                                                   "Interrupt fastpath "
-                                                   "failed!");
-                       }
+               if (cqr->devlist.next != &device->ccw_queue) {
+                       next = list_entry(cqr->devlist.next,
+                                         struct dasd_ccw_req, devlist);
                }
-       } else {                /* error */
-               memcpy(&cqr->irb, irb, sizeof (struct irb));
+       } else {  /* error */
+               memcpy(&cqr->irb, irb, sizeof(struct irb));
                if (device->features & DASD_FEATURE_ERPLOG) {
-                       /* dump sense data */
                        dasd_log_sense(cqr, irb);
                }
-               switch (era) {
-               case dasd_era_fatal:
-                       cqr->status = DASD_CQR_FAILED;
-                       cqr->stopclk = now;
-                       break;
-               case dasd_era_recover:
+               /* If we have no sense data, or we just don't want complex ERP
+                * for this request, but if we have retries left, then just
+                * reset this request and retry it in the fastpath
+                */
+               if (!(cqr->irb.esw.esw0.erw.cons &&
+                     test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
+                   cqr->retries > 0) {
+                       DEV_MESSAGE(KERN_DEBUG, device,
+                                   "default ERP in fastpath (%i retries left)",
+                                   cqr->retries);
+                       cqr->lpm    = LPM_ANYPATH;
+                       cqr->status = DASD_CQR_QUEUED;
+                       next = cqr;
+               } else
                        cqr->status = DASD_CQR_ERROR;
-                       break;
-               default:
-                       BUG();
-               }
+       }
+       if (next && (next->status == DASD_CQR_QUEUED) &&
+           (!device->stopped)) {
+               if (device->discipline->start_IO(next) == 0)
+                       expires = next->expires;
+               else
+                       DEV_MESSAGE(KERN_DEBUG, device, "%s",
+                                   "Interrupt fastpath "
+                                   "failed!");
        }
        if (expires != 0)
-               dasd_set_timer(device, expires);
+               dasd_device_set_timer(device, expires);
        else
-               dasd_clear_timer(device);
-       dasd_schedule_bh(device);
+               dasd_device_clear_timer(device);
+       dasd_schedule_device_bh(device);
 }
 
 /*
- * posts the buffer_cache about a finalized request
+ * If we have an error on a dasd_block layer request then we cancel
+ * and return all further requests from the same dasd_block as well.
  */
-static inline void
-dasd_end_request(struct request *req, int uptodate)
+static void __dasd_device_recovery(struct dasd_device *device,
+                                  struct dasd_ccw_req *ref_cqr)
 {
-       if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
-               BUG();
-       add_disk_randomness(req->rq_disk);
-       end_that_request_last(req, uptodate);
-}
+       struct list_head *l, *n;
+       struct dasd_ccw_req *cqr;
 
-/*
- * Process finished error recovery ccw.
- */
-static inline void
-__dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
-{
-       dasd_erp_fn_t erp_fn;
+       /*
+        * only requeue request that came from the dasd_block layer
+        */
+       if (!ref_cqr->block)
+               return;
 
-       if (cqr->status == DASD_CQR_DONE)
-               DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
-       else
-               DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
-       erp_fn = device->discipline->erp_postaction(cqr);
-       erp_fn(cqr);
-}
+       list_for_each_safe(l, n, &device->ccw_queue) {
+               cqr = list_entry(l, struct dasd_ccw_req, devlist);
+               if (cqr->status == DASD_CQR_QUEUED &&
+                   ref_cqr->block == cqr->block) {
+                       cqr->status = DASD_CQR_CLEARED;
+               }
+       }
+};
 
 /*
- * Process ccw request queue.
+ * Remove those ccw requests from the queue that need to be returned
+ * to the upper layer.
  */
-static void
-__dasd_process_ccw_queue(struct dasd_device * device,
-                        struct list_head *final_queue)
+static void __dasd_device_process_ccw_queue(struct dasd_device *device,
+                                           struct list_head *final_queue)
 {
        struct list_head *l, *n;
        struct dasd_ccw_req *cqr;
-       dasd_erp_fn_t erp_fn;
 
-restart:
        /* Process request with final status. */
        list_for_each_safe(l, n, &device->ccw_queue) {
-               cqr = list_entry(l, struct dasd_ccw_req, list);
+               cqr = list_entry(l, struct dasd_ccw_req, devlist);
+
                /* Stop list processing at the first non-final request. */
-               if (cqr->status != DASD_CQR_DONE &&
-                   cqr->status != DASD_CQR_FAILED &&
-                   cqr->status != DASD_CQR_ERROR)
+               if (cqr->status == DASD_CQR_QUEUED ||
+                   cqr->status == DASD_CQR_IN_IO ||
+                   cqr->status == DASD_CQR_CLEAR_PENDING)
                        break;
-               /*  Process requests with DASD_CQR_ERROR */
                if (cqr->status == DASD_CQR_ERROR) {
-                       if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) {
-                               cqr->status = DASD_CQR_FAILED;
-                               cqr->stopclk = get_clock();
-                       } else {
-                               if (cqr->irb.esw.esw0.erw.cons &&
-                                   test_bit(DASD_CQR_FLAGS_USE_ERP,
-                                            &cqr->flags)) {
-                                       erp_fn = device->discipline->
-                                               erp_action(cqr);
-                                       erp_fn(cqr);
-                               } else
-                                       dasd_default_erp_action(cqr);
-                       }
-                       goto restart;
-               }
-
-               /* First of all call extended error reporting. */
-               if (dasd_eer_enabled(device) &&
-                   cqr->status == DASD_CQR_FAILED) {
-                       dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
-
-                       /* restart request  */
-                       cqr->status = DASD_CQR_QUEUED;
-                       cqr->retries = 255;
-                       device->stopped |= DASD_STOPPED_QUIESCE;
-                       goto restart;
+                       __dasd_device_recovery(device, cqr);
                }
-
-               /* Process finished ERP request. */
-               if (cqr->refers) {
-                       __dasd_process_erp(device, cqr);
-                       goto restart;
-               }
-
                /* Rechain finished requests to final queue */
-               cqr->endclk = get_clock();
-               list_move_tail(&cqr->list, final_queue);
+               list_move_tail(&cqr->devlist, final_queue);
        }
 }
 
-static void
-dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
-{
-       struct request *req;
-       struct dasd_device *device;
-       int status;
-
-       req = (struct request *) data;
-       device = cqr->device;
-       dasd_profile_end(device, cqr, req);
-       status = cqr->device->discipline->free_cp(cqr,req);
-       spin_lock_irq(&device->request_queue_lock);
-       dasd_end_request(req, status);
-       spin_unlock_irq(&device->request_queue_lock);
-}
-
-
 /*
- * Fetch requests from the block device queue.
+ * the cqrs from the final queue are returned to the upper layer
+ * by setting a dasd_block state and calling the callback function
  */
-static void
-__dasd_process_blk_queue(struct dasd_device * device)
+static void __dasd_device_process_final_queue(struct dasd_device *device,
+                                             struct list_head *final_queue)
 {
-       struct request_queue *queue;
-       struct request *req;
+       struct list_head *l, *n;
        struct dasd_ccw_req *cqr;
-       int nr_queued;
-
-       queue = device->request_queue;
-       /* No queue ? Then there is nothing to do. */
-       if (queue == NULL)
-               return;
-
-       /*
-        * We requeue request from the block device queue to the ccw
-        * queue only in two states. In state DASD_STATE_READY the
-        * partition detection is done and we need to requeue requests
-        * for that. State DASD_STATE_ONLINE is normal block device
-        * operation.
-        */
-       if (device->state != DASD_STATE_READY &&
-           device->state != DASD_STATE_ONLINE)
-               return;
-       nr_queued = 0;
-       /* Now we try to fetch requests from the request queue */
-       list_for_each_entry(cqr, &device->ccw_queue, list)
-               if (cqr->status == DASD_CQR_QUEUED)
-                       nr_queued++;
-       while (!blk_queue_plugged(queue) &&
-              elv_next_request(queue) &&
-               nr_queued < DASD_CHANQ_MAX_SIZE) {
-               req = elv_next_request(queue);
 
-               if (device->features & DASD_FEATURE_READONLY &&
-                   rq_data_dir(req) == WRITE) {
-                       DBF_DEV_EVENT(DBF_ERR, device,
-                                     "Rejecting write request %p",
-                                     req);
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, 0);
-                       continue;
-               }
-               if (device->stopped & DASD_STOPPED_DC_EIO) {
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, 0);
-                       continue;
-               }
-               cqr = device->discipline->build_cp(device, req);
-               if (IS_ERR(cqr)) {
-                       if (PTR_ERR(cqr) == -ENOMEM)
-                               break;  /* terminate request queue loop */
-                       if (PTR_ERR(cqr) == -EAGAIN) {
-                               /*
-                                * The current request cannot be build right
-                                * now, we have to try later. If this request
-                                * is the head-of-queue we stop the device
-                                * for 1/2 second.
-                                */
-                               if (!list_empty(&device->ccw_queue))
-                                       break;
-                               device->stopped |= DASD_STOPPED_PENDING;
-                               dasd_set_timer(device, HZ/2);
-                               break;
-                       }
-                       DBF_DEV_EVENT(DBF_ERR, device,
-                                     "CCW creation failed (rc=%ld) "
-                                     "on request %p",
-                                     PTR_ERR(cqr), req);
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, 0);
-                       continue;
+       list_for_each_safe(l, n, final_queue) {
+               cqr = list_entry(l, struct dasd_ccw_req, devlist);
+               list_del_init(&cqr->devlist);
+               if (cqr->block)
+                       spin_lock_bh(&cqr->block->queue_lock);
+               switch (cqr->status) {
+               case DASD_CQR_SUCCESS:
+                       cqr->status = DASD_CQR_DONE;
+                       break;
+               case DASD_CQR_ERROR:
+                       cqr->status = DASD_CQR_NEED_ERP;
+                       break;
+               case DASD_CQR_CLEARED:
+                       cqr->status = DASD_CQR_TERMINATED;
+                       break;
+               default:
+                       DEV_MESSAGE(KERN_ERR, device,
+                                   "wrong cqr status in __dasd_process_final_queue "
+                                   "for cqr %p, status %x",
+                                   cqr, cqr->status);
+                       BUG();
                }
-               cqr->callback = dasd_end_request_cb;
-               cqr->callback_data = (void *) req;
-               cqr->status = DASD_CQR_QUEUED;
-               blkdev_dequeue_request(req);
-               list_add_tail(&cqr->list, &device->ccw_queue);
-               dasd_profile_start(device, cqr, req);
-               nr_queued++;
+               if (cqr->block)
+                       spin_unlock_bh(&cqr->block->queue_lock);
+               if (cqr->callback != NULL)
+                       (cqr->callback)(cqr, cqr->callback_data);
        }
 }
 
+
+
 /*
  * Take a look at the first request on the ccw queue and check
  * if it reached its expire time. If so, terminate the IO.
  */
-static void
-__dasd_check_expire(struct dasd_device * device)
+static void __dasd_device_check_expire(struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
 
        if (list_empty(&device->ccw_queue))
                return;
-       cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+       cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
        if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) &&
            (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
                if (device->discipline->term_IO(cqr) != 0) {
                        /* Hmpf, try again in 5 sec */
-                       dasd_set_timer(device, 5*HZ);
                        DEV_MESSAGE(KERN_ERR, device,
                                    "internal error - timeout (%is) expired "
                                    "for cqr %p, termination failed, "
                                    "retrying in 5s",
                                    (cqr->expires/HZ), cqr);
+                       cqr->expires += 5*HZ;
+                       dasd_device_set_timer(device, 5*HZ);
                } else {
                        DEV_MESSAGE(KERN_ERR, device,
                                    "internal error - timeout (%is) expired "
@@ -1301,77 +1217,53 @@ __dasd_check_expire(struct dasd_device * device)
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
  */
-static void
-__dasd_start_head(struct dasd_device * device)
+static void __dasd_device_start_head(struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
        int rc;
 
        if (list_empty(&device->ccw_queue))
                return;
-       cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+       cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
        if (cqr->status != DASD_CQR_QUEUED)
                return;
-       /* Non-temporary stop condition will trigger fail fast */
-       if (device->stopped & ~DASD_STOPPED_PENDING &&
-           test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
-           (!dasd_eer_enabled(device))) {
-               cqr->status = DASD_CQR_FAILED;
-               dasd_schedule_bh(device);
+       /* when device is stopped, return request to previous layer */
+       if (device->stopped) {
+               cqr->status = DASD_CQR_CLEARED;
+               dasd_schedule_device_bh(device);
                return;
        }
-       /* Don't try to start requests if device is stopped */
-       if (device->stopped)
-               return;
 
        rc = device->discipline->start_IO(cqr);
        if (rc == 0)
-               dasd_set_timer(device, cqr->expires);
+               dasd_device_set_timer(device, cqr->expires);
        else if (rc == -EACCES) {
-               dasd_schedule_bh(device);
+               dasd_schedule_device_bh(device);
        } else
                /* Hmpf, try again in 1/2 sec */
-               dasd_set_timer(device, 50);
-}
-
-static inline int
-_wait_for_clear(struct dasd_ccw_req *cqr)
-{
-       return (cqr->status == DASD_CQR_QUEUED);
+               dasd_device_set_timer(device, 50);
 }
 
 /*
- * Remove all requests from the ccw queue (all = '1') or only block device
- * requests in case all = '0'.
- * Take care of the erp-chain (chained via cqr->refers) and remove either
- * the whole erp-chain or none of the erp-requests.
- * If a request is currently running, term_IO is called and the request
- * is re-queued. Prior to removing the terminated request we need to wait
- * for the clear-interrupt.
- * In case termination is not possible we stop processing and just finishing
- * the already moved requests.
+ * Go through all request on the dasd_device request queue,
+ * terminate them on the cdev if necessary, and return them to the
+ * submitting layer via callback.
+ * Note:
+ * Make sure that all 'submitting layers' still exist when
+ * this function is called!. In other words, when 'device' is a base
+ * device then all block layer requests must have been removed before
+ * via dasd_flush_block_queue.
  */
-static int
-dasd_flush_ccw_queue(struct dasd_device * device, int all)
+int dasd_flush_device_queue(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr, *orig, *n;
-       int rc, i;
-
+       struct dasd_ccw_req *cqr, *n;
+       int rc;
        struct list_head flush_queue;
 
        INIT_LIST_HEAD(&flush_queue);
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = 0;
-restart:
-       list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) {
-               /* get original request of erp request-chain */
-               for (orig = cqr; orig->refers != NULL; orig = orig->refers);
-
-               /* Flush all request or only block device requests? */
-               if (all == 0 && cqr->callback != dasd_end_request_cb &&
-                   orig->callback != dasd_end_request_cb) {
-                       continue;
-               }
+       list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
                /* Check status and move request to flush_queue */
                switch (cqr->status) {
                case DASD_CQR_IN_IO:
@@ -1387,90 +1279,60 @@ restart:
                        }
                        break;
                case DASD_CQR_QUEUED:
-               case DASD_CQR_ERROR:
-                       /* set request to FAILED */
                        cqr->stopclk = get_clock();
-                       cqr->status = DASD_CQR_FAILED;
+                       cqr->status = DASD_CQR_CLEARED;
                        break;
-               default: /* do not touch the others */
+               default: /* no need to modify the others */
                        break;
                }
-               /* Rechain request (including erp chain) */
-               for (i = 0; cqr != NULL; cqr = cqr->refers, i++) {
-                       cqr->endclk = get_clock();
-                       list_move_tail(&cqr->list, &flush_queue);
-               }
-               if (i > 1)
-                       /* moved more than one request - need to restart */
-                       goto restart;
+               list_move_tail(&cqr->devlist, &flush_queue);
        }
-
 finished:
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
-       /* Now call the callback function of flushed requests */
-restart_cb:
-       list_for_each_entry_safe(cqr, n, &flush_queue, list) {
-               if (cqr->status == DASD_CQR_CLEAR) {
-                       /* wait for clear interrupt! */
-                       wait_event(dasd_flush_wq, _wait_for_clear(cqr));
-                       cqr->status = DASD_CQR_FAILED;
-               }
-               /* Process finished ERP request. */
-               if (cqr->refers) {
-                       __dasd_process_erp(device, cqr);
-                       /* restart list_for_xx loop since dasd_process_erp
-                        * might remove multiple elements */
-                       goto restart_cb;
-               }
-               /* call the callback function */
-               cqr->endclk = get_clock();
-               if (cqr->callback != NULL)
-                       (cqr->callback)(cqr, cqr->callback_data);
-       }
+       /*
+        * After this point all requests must be in state CLEAR_PENDING,
+        * CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become
+        * one of the others.
+        */
+       list_for_each_entry_safe(cqr, n, &flush_queue, devlist)
+               wait_event(dasd_flush_wq,
+                          (cqr->status != DASD_CQR_CLEAR_PENDING));
+       /*
+        * Now set each request back to TERMINATED, DONE or NEED_ERP
+        * and call the callback function of flushed requests
+        */
+       __dasd_device_process_final_queue(device, &flush_queue);
        return rc;
 }
 
 /*
  * Acquire the device lock and process queues for the device.
  */
-static void
-dasd_tasklet(struct dasd_device * device)
+static void dasd_device_tasklet(struct dasd_device *device)
 {
        struct list_head final_queue;
-       struct list_head *l, *n;
-       struct dasd_ccw_req *cqr;
 
        atomic_set (&device->tasklet_scheduled, 0);
        INIT_LIST_HEAD(&final_queue);
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        /* Check expire time of first request on the ccw queue. */
-       __dasd_check_expire(device);
-       /* Finish off requests on ccw queue */
-       __dasd_process_ccw_queue(device, &final_queue);
+       __dasd_device_check_expire(device);
+       /* find final requests on ccw queue */
+       __dasd_device_process_ccw_queue(device, &final_queue);
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
        /* Now call the callback function of requests with final status */
-       list_for_each_safe(l, n, &final_queue) {
-               cqr = list_entry(l, struct dasd_ccw_req, list);
-               list_del_init(&cqr->list);
-               if (cqr->callback != NULL)
-                       (cqr->callback)(cqr, cqr->callback_data);
-       }
-       spin_lock_irq(&device->request_queue_lock);
-       spin_lock(get_ccwdev_lock(device->cdev));
-       /* Get new request from the block device request queue */
-       __dasd_process_blk_queue(device);
+       __dasd_device_process_final_queue(device, &final_queue);
+       spin_lock_irq(get_ccwdev_lock(device->cdev));
        /* Now check if the head of the ccw queue needs to be started. */
-       __dasd_start_head(device);
-       spin_unlock(get_ccwdev_lock(device->cdev));
-       spin_unlock_irq(&device->request_queue_lock);
+       __dasd_device_start_head(device);
+       spin_unlock_irq(get_ccwdev_lock(device->cdev));
        dasd_put_device(device);
 }
 
 /*
  * Schedules a call to dasd_tasklet over the device tasklet.
  */
-void
-dasd_schedule_bh(struct dasd_device * device)
+void dasd_schedule_device_bh(struct dasd_device *device)
 {
        /* Protect against rescheduling. */
        if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0)
@@ -1480,160 +1342,109 @@ dasd_schedule_bh(struct dasd_device * device)
 }
 
 /*
- * Queue a request to the head of the ccw_queue. Start the I/O if
- * possible.
+ * Queue a request to the head of the device ccw_queue.
+ * Start the I/O if possible.
  */
-void
-dasd_add_request_head(struct dasd_ccw_req *req)
+void dasd_add_request_head(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        unsigned long flags;
 
-       device = req->device;
+       device = cqr->startdev;
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-       req->status = DASD_CQR_QUEUED;
-       req->device = device;
-       list_add(&req->list, &device->ccw_queue);
+       cqr->status = DASD_CQR_QUEUED;
+       list_add(&cqr->devlist, &device->ccw_queue);
        /* let the bh start the request to keep them in order */
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
 /*
- * Queue a request to the tail of the ccw_queue. Start the I/O if
- * possible.
+ * Queue a request to the tail of the device ccw_queue.
+ * Start the I/O if possible.
  */
-void
-dasd_add_request_tail(struct dasd_ccw_req *req)
+void dasd_add_request_tail(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        unsigned long flags;
 
-       device = req->device;
+       device = cqr->startdev;
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-       req->status = DASD_CQR_QUEUED;
-       req->device = device;
-       list_add_tail(&req->list, &device->ccw_queue);
+       cqr->status = DASD_CQR_QUEUED;
+       list_add_tail(&cqr->devlist, &device->ccw_queue);
        /* let the bh start the request to keep them in order */
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
 /*
- * Wakeup callback.
+ * Wakeup helper for the 'sleep_on' functions.
  */
-static void
-dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
+static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
 {
        wake_up((wait_queue_head_t *) data);
 }
 
-static inline int
-_wait_for_wakeup(struct dasd_ccw_req *cqr)
+static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int rc;
 
-       device = cqr->device;
+       device = cqr->startdev;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = ((cqr->status == DASD_CQR_DONE ||
-              cqr->status == DASD_CQR_FAILED) &&
-             list_empty(&cqr->list));
+              cqr->status == DASD_CQR_NEED_ERP ||
+              cqr->status == DASD_CQR_TERMINATED) &&
+             list_empty(&cqr->devlist));
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
        return rc;
 }
 
 /*
- * Attempts to start a special ccw queue and waits for its completion.
+ * Queue a request to the tail of the device ccw_queue and wait for
+ * it's completion.
  */
-int
-dasd_sleep_on(struct dasd_ccw_req * cqr)
+int dasd_sleep_on(struct dasd_ccw_req *cqr)
 {
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
 
-       device = cqr->device;
-       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       device = cqr->startdev;
 
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
-       cqr->status = DASD_CQR_QUEUED;
-       list_add_tail(&cqr->list, &device->ccw_queue);
-
-       /* let the bh start the request to keep them in order */
-       dasd_schedule_bh(device);
-
-       spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
+       dasd_add_request_tail(cqr);
        wait_event(wait_q, _wait_for_wakeup(cqr));
 
        /* Request status is either done or failed. */
-       rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
        return rc;
 }
 
 /*
- * Attempts to start a special ccw queue and wait interruptible
- * for its completion.
+ * Queue a request to the tail of the device ccw_queue and wait
+ * interruptible for it's completion.
  */
-int
-dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
+int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
 {
        wait_queue_head_t wait_q;
        struct dasd_device *device;
-       int rc, finished;
-
-       device = cqr->device;
-       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       int rc;
 
+       device = cqr->startdev;
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
-       cqr->status = DASD_CQR_QUEUED;
-       list_add_tail(&cqr->list, &device->ccw_queue);
-
-       /* let the bh start the request to keep them in order */
-       dasd_schedule_bh(device);
-       spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
-       finished = 0;
-       while (!finished) {
-               rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
-               if (rc != -ERESTARTSYS) {
-                       /* Request is final (done or failed) */
-                       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
-                       break;
-               }
-               spin_lock_irq(get_ccwdev_lock(device->cdev));
-               switch (cqr->status) {
-               case DASD_CQR_IN_IO:
-                        /* terminate runnig cqr */
-                       if (device->discipline->term_IO) {
-                               cqr->retries = -1;
-                               device->discipline->term_IO(cqr);
-                               /* wait (non-interruptible) for final status
-                                * because signal ist still pending */
-                               spin_unlock_irq(get_ccwdev_lock(device->cdev));
-                               wait_event(wait_q, _wait_for_wakeup(cqr));
-                               spin_lock_irq(get_ccwdev_lock(device->cdev));
-                               rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
-                               finished = 1;
-                       }
-                       break;
-               case DASD_CQR_QUEUED:
-                       /* request  */
-                       list_del_init(&cqr->list);
-                       rc = -EIO;
-                       finished = 1;
-                       break;
-               default:
-                       /* cqr with 'non-interruptable' status - just wait */
-                       break;
-               }
-               spin_unlock_irq(get_ccwdev_lock(device->cdev));
+       dasd_add_request_tail(cqr);
+       rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+       if (rc == -ERESTARTSYS) {
+               dasd_cancel_req(cqr);
+               /* wait (non-interruptible) for final status */
+               wait_event(wait_q, _wait_for_wakeup(cqr));
        }
+       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
        return rc;
 }
 
@@ -1643,25 +1454,23 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
  * and be put back to status queued, before the special request is added
  * to the head of the queue. Then the special request is waited on normally.
  */
-static inline int
-_dasd_term_running_cqr(struct dasd_device *device)
+static inline int _dasd_term_running_cqr(struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
 
        if (list_empty(&device->ccw_queue))
                return 0;
-       cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+       cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
        return device->discipline->term_IO(cqr);
 }
 
-int
-dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
+int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
 {
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
 
-       device = cqr->device;
+       device = cqr->startdev;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = _dasd_term_running_cqr(device);
        if (rc) {
@@ -1673,17 +1482,17 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
-       list_add(&cqr->list, &device->ccw_queue);
+       list_add(&cqr->devlist, &device->ccw_queue);
 
        /* let the bh start the request to keep them in order */
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
 
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
 
        /* Request status is either done or failed. */
-       rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
        return rc;
 }
 
@@ -1692,11 +1501,14 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
  * This is useful to timeout requests. The request will be
  * terminated if it is currently in i/o.
  * Returns 1 if the request has been terminated.
+ *        0 if there was no need to terminate the request (not started yet)
+ *        negative error code if termination failed
+ * Cancellation of a request is an asynchronous operation! The calling
+ * function has to wait until the request is properly returned via callback.
  */
-int
-dasd_cancel_req(struct dasd_ccw_req *cqr)
+int dasd_cancel_req(struct dasd_ccw_req *cqr)
 {
-       struct dasd_device *device = cqr->device;
+       struct dasd_device *device = cqr->startdev;
        unsigned long flags;
        int rc;
 
@@ -1704,74 +1516,453 @@ dasd_cancel_req(struct dasd_ccw_req *cqr)
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        switch (cqr->status) {
        case DASD_CQR_QUEUED:
-               /* request was not started - just set to failed */
-               cqr->status = DASD_CQR_FAILED;
+               /* request was not started - just set to cleared */
+               cqr->status = DASD_CQR_CLEARED;
                break;
        case DASD_CQR_IN_IO:
                /* request in IO - terminate IO and release again */
-               if (device->discipline->term_IO(cqr) != 0)
-                       /* what to do if unable to terminate ??????
-                          e.g. not _IN_IO */
-                       cqr->status = DASD_CQR_FAILED;
-               cqr->stopclk = get_clock();
-               rc = 1;
+               rc = device->discipline->term_IO(cqr);
+               if (rc) {
+                       DEV_MESSAGE(KERN_ERR, device,
+                                   "dasd_cancel_req is unable "
+                                   " to terminate request %p, rc = %d",
+                                   cqr, rc);
+               } else {
+                       cqr->stopclk = get_clock();
+                       rc = 1;
+               }
                break;
-       case DASD_CQR_DONE:
-       case DASD_CQR_FAILED:
-               /* already finished - do nothing */
+       default: /* already finished or clear pending - do nothing */
                break;
-       default:
-               DEV_MESSAGE(KERN_ALERT, device,
-                           "invalid status %02x in request",
-                           cqr->status);
+       }
+       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       dasd_schedule_device_bh(device);
+       return rc;
+}
+
+
+/*
+ * SECTION: Operations of the dasd_block layer.
+ */
+
+/*
+ * Timeout function for dasd_block. This is used when the block layer
+ * is waiting for something that may not come reliably, (e.g. a state
+ * change interrupt)
+ */
+static void dasd_block_timeout(unsigned long ptr)
+{
+       unsigned long flags;
+       struct dasd_block *block;
+
+       block = (struct dasd_block *) ptr;
+       spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
+       /* re-activate request queue */
+       block->base->stopped &= ~DASD_STOPPED_PENDING;
+       spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
+       dasd_schedule_block_bh(block);
+}
+
+/*
+ * Setup timeout for a dasd_block in jiffies.
+ */
+void dasd_block_set_timer(struct dasd_block *block, int expires)
+{
+       if (expires == 0) {
+               if (timer_pending(&block->timer))
+                       del_timer(&block->timer);
+               return;
+       }
+       if (timer_pending(&block->timer)) {
+               if (mod_timer(&block->timer, jiffies + expires))
+                       return;
+       }
+       block->timer.function = dasd_block_timeout;
+       block->timer.data = (unsigned long) block;
+       block->timer.expires = jiffies + expires;
+       add_timer(&block->timer);
+}
+
+/*
+ * Clear timeout for a dasd_block.
+ */
+void dasd_block_clear_timer(struct dasd_block *block)
+{
+       if (timer_pending(&block->timer))
+               del_timer(&block->timer);
+}
+
+/*
+ * posts the buffer_cache about a finalized request
+ */
+static inline void dasd_end_request(struct request *req, int uptodate)
+{
+       if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
                BUG();
+       add_disk_randomness(req->rq_disk);
+       end_that_request_last(req, uptodate);
+}
+
+/*
+ * Process finished error recovery ccw.
+ */
+static inline void __dasd_block_process_erp(struct dasd_block *block,
+                                           struct dasd_ccw_req *cqr)
+{
+       dasd_erp_fn_t erp_fn;
+       struct dasd_device *device = block->base;
+
+       if (cqr->status == DASD_CQR_DONE)
+               DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
+       else
+               DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
+       erp_fn = device->discipline->erp_postaction(cqr);
+       erp_fn(cqr);
+}
 
+/*
+ * Fetch requests from the block device queue.
+ */
+static void __dasd_process_request_queue(struct dasd_block *block)
+{
+       struct request_queue *queue;
+       struct request *req;
+       struct dasd_ccw_req *cqr;
+       struct dasd_device *basedev;
+       unsigned long flags;
+       queue = block->request_queue;
+       basedev = block->base;
+       /* No queue ? Then there is nothing to do. */
+       if (queue == NULL)
+               return;
+
+       /*
+        * We requeue request from the block device queue to the ccw
+        * queue only in two states. In state DASD_STATE_READY the
+        * partition detection is done and we need to requeue requests
+        * for that. State DASD_STATE_ONLINE is normal block device
+        * operation.
+        */
+       if (basedev->state < DASD_STATE_READY)
+               return;
+       /* Now we try to fetch requests from the request queue */
+       while (!blk_queue_plugged(queue) &&
+              elv_next_request(queue)) {
+
+               req = elv_next_request(queue);
+
+               if (basedev->features & DASD_FEATURE_READONLY &&
+                   rq_data_dir(req) == WRITE) {
+                       DBF_DEV_EVENT(DBF_ERR, basedev,
+                                     "Rejecting write request %p",
+                                     req);
+                       blkdev_dequeue_request(req);
+                       dasd_end_request(req, 0);
+                       continue;
+               }
+               cqr = basedev->discipline->build_cp(basedev, block, req);
+               if (IS_ERR(cqr)) {
+                       if (PTR_ERR(cqr) == -EBUSY)
+                               break;  /* normal end condition */
+                       if (PTR_ERR(cqr) == -ENOMEM)
+                               break;  /* terminate request queue loop */
+                       if (PTR_ERR(cqr) == -EAGAIN) {
+                               /*
+                                * The current request cannot be build right
+                                * now, we have to try later. If this request
+                                * is the head-of-queue we stop the device
+                                * for 1/2 second.
+                                */
+                               if (!list_empty(&block->ccw_queue))
+                                       break;
+                               spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
+                               basedev->stopped |= DASD_STOPPED_PENDING;
+                               spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
+                               dasd_block_set_timer(block, HZ/2);
+                               break;
+                       }
+                       DBF_DEV_EVENT(DBF_ERR, basedev,
+                                     "CCW creation failed (rc=%ld) "
+                                     "on request %p",
+                                     PTR_ERR(cqr), req);
+                       blkdev_dequeue_request(req);
+                       dasd_end_request(req, 0);
+                       continue;
+               }
+               /*
+                *  Note: callback is set to dasd_return_cqr_cb in
+                * __dasd_block_start_head to cover erp requests as well
+                */
+               cqr->callback_data = (void *) req;
+               cqr->status = DASD_CQR_FILLED;
+               blkdev_dequeue_request(req);
+               list_add_tail(&cqr->blocklist, &block->ccw_queue);
+               dasd_profile_start(block, cqr, req);
+       }
+}
+
+static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
+{
+       struct request *req;
+       int status;
+
+       req = (struct request *) cqr->callback_data;
+       dasd_profile_end(cqr->block, cqr, req);
+       status = cqr->memdev->discipline->free_cp(cqr, req);
+       dasd_end_request(req, status);
+}
+
+/*
+ * Process ccw request queue.
+ */
+static void __dasd_process_block_ccw_queue(struct dasd_block *block,
+                                          struct list_head *final_queue)
+{
+       struct list_head *l, *n;
+       struct dasd_ccw_req *cqr;
+       dasd_erp_fn_t erp_fn;
+       unsigned long flags;
+       struct dasd_device *base = block->base;
+
+restart:
+       /* Process request with final status. */
+       list_for_each_safe(l, n, &block->ccw_queue) {
+               cqr = list_entry(l, struct dasd_ccw_req, blocklist);
+               if (cqr->status != DASD_CQR_DONE &&
+                   cqr->status != DASD_CQR_FAILED &&
+                   cqr->status != DASD_CQR_NEED_ERP &&
+                   cqr->status != DASD_CQR_TERMINATED)
+                       continue;
+
+               if (cqr->status == DASD_CQR_TERMINATED) {
+                       base->discipline->handle_terminated_request(cqr);
+                       goto restart;
+               }
+
+               /*  Process requests that may be recovered */
+               if (cqr->status == DASD_CQR_NEED_ERP) {
+                       if (cqr->irb.esw.esw0.erw.cons &&
+                           test_bit(DASD_CQR_FLAGS_USE_ERP,
+                                    &cqr->flags)) {
+                               erp_fn = base->discipline->erp_action(cqr);
+                               erp_fn(cqr);
+                       }
+                       goto restart;
+               }
+
+               /* First of all call extended error reporting. */
+               if (dasd_eer_enabled(base) &&
+                   cqr->status == DASD_CQR_FAILED) {
+                       dasd_eer_write(base, cqr, DASD_EER_FATALERROR);
+
+                       /* restart request  */
+                       cqr->status = DASD_CQR_FILLED;
+                       cqr->retries = 255;
+                       spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+                       base->stopped |= DASD_STOPPED_QUIESCE;
+                       spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
+                                              flags);
+                       goto restart;
+               }
+
+               /* Process finished ERP request. */
+               if (cqr->refers) {
+                       __dasd_block_process_erp(block, cqr);
+                       goto restart;
+               }
+
+               /* Rechain finished requests to final queue */
+               cqr->endclk = get_clock();
+               list_move_tail(&cqr->blocklist, final_queue);
+       }
+}
+
+static void dasd_return_cqr_cb(struct dasd_ccw_req *cqr, void *data)
+{
+       dasd_schedule_block_bh(cqr->block);
+}
+
+static void __dasd_block_start_head(struct dasd_block *block)
+{
+       struct dasd_ccw_req *cqr;
+
+       if (list_empty(&block->ccw_queue))
+               return;
+       /* We allways begin with the first requests on the queue, as some
+        * of previously started requests have to be enqueued on a
+        * dasd_device again for error recovery.
+        */
+       list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
+               if (cqr->status != DASD_CQR_FILLED)
+                       continue;
+               /* Non-temporary stop condition will trigger fail fast */
+               if (block->base->stopped & ~DASD_STOPPED_PENDING &&
+                   test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+                   (!dasd_eer_enabled(block->base))) {
+                       cqr->status = DASD_CQR_FAILED;
+                       dasd_schedule_block_bh(block);
+                       continue;
+               }
+               /* Don't try to start requests if device is stopped */
+               if (block->base->stopped)
+                       return;
+
+               /* just a fail safe check, should not happen */
+               if (!cqr->startdev)
+                       cqr->startdev = block->base;
+
+               /* make sure that the requests we submit find their way back */
+               cqr->callback = dasd_return_cqr_cb;
+
+               dasd_add_request_tail(cqr);
+       }
+}
+
+/*
+ * Central dasd_block layer routine. Takes requests from the generic
+ * block layer request queue, creates ccw requests, enqueues them on
+ * a dasd_device and processes ccw requests that have been returned.
+ */
+static void dasd_block_tasklet(struct dasd_block *block)
+{
+       struct list_head final_queue;
+       struct list_head *l, *n;
+       struct dasd_ccw_req *cqr;
+
+       atomic_set(&block->tasklet_scheduled, 0);
+       INIT_LIST_HEAD(&final_queue);
+       spin_lock(&block->queue_lock);
+       /* Finish off requests on ccw queue */
+       __dasd_process_block_ccw_queue(block, &final_queue);
+       spin_unlock(&block->queue_lock);
+       /* Now call the callback function of requests with final status */
+       spin_lock_irq(&block->request_queue_lock);
+       list_for_each_safe(l, n, &final_queue) {
+               cqr = list_entry(l, struct dasd_ccw_req, blocklist);
+               list_del_init(&cqr->blocklist);
+               __dasd_cleanup_cqr(cqr);
+       }
+       spin_lock(&block->queue_lock);
+       /* Get new request from the block device request queue */
+       __dasd_process_request_queue(block);
+       /* Now check if the head of the ccw queue needs to be started. */
+       __dasd_block_start_head(block);
+       spin_unlock(&block->queue_lock);
+       spin_unlock_irq(&block->request_queue_lock);
+       dasd_put_device(block->base);
+}
+
+static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
+{
+       wake_up(&dasd_flush_wq);
+}
+
+/*
+ * Go through all request on the dasd_block request queue, cancel them
+ * on the respective dasd_device, and return them to the generic
+ * block layer.
+ */
+static int dasd_flush_block_queue(struct dasd_block *block)
+{
+       struct dasd_ccw_req *cqr, *n;
+       int rc, i;
+       struct list_head flush_queue;
+
+       INIT_LIST_HEAD(&flush_queue);
+       spin_lock_bh(&block->queue_lock);
+       rc = 0;
+restart:
+       list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
+               /* if this request currently owned by a dasd_device cancel it */
+               if (cqr->status >= DASD_CQR_QUEUED)
+                       rc = dasd_cancel_req(cqr);
+               if (rc < 0)
+                       break;
+               /* Rechain request (including erp chain) so it won't be
+                * touched by the dasd_block_tasklet anymore.
+                * Replace the callback so we notice when the request
+                * is returned from the dasd_device layer.
+                */
+               cqr->callback = _dasd_wake_block_flush_cb;
+               for (i = 0; cqr != NULL; cqr = cqr->refers, i++)
+                       list_move_tail(&cqr->blocklist, &flush_queue);
+               if (i > 1)
+                       /* moved more than one request - need to restart */
+                       goto restart;
+       }
+       spin_unlock_bh(&block->queue_lock);
+       /* Now call the callback function of flushed requests */
+restart_cb:
+       list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) {
+               wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
+               /* Process finished ERP request. */
+               if (cqr->refers) {
+                       __dasd_block_process_erp(block, cqr);
+                       /* restart list_for_xx loop since dasd_process_erp
+                        * might remove multiple elements */
+                       goto restart_cb;
+               }
+               /* call the callback function */
+               cqr->endclk = get_clock();
+               list_del_init(&cqr->blocklist);
+               __dasd_cleanup_cqr(cqr);
        }
-       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-       dasd_schedule_bh(device);
        return rc;
 }
 
 /*
- * SECTION: Block device operations (request queue, partitions, open, release).
+ * Schedules a call to dasd_tasklet over the device tasklet.
+ */
+void dasd_schedule_block_bh(struct dasd_block *block)
+{
+       /* Protect against rescheduling. */
+       if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0)
+               return;
+       /* life cycle of block is bound to it's base device */
+       dasd_get_device(block->base);
+       tasklet_hi_schedule(&block->tasklet);
+}
+
+
+/*
+ * SECTION: external block device operations
+ * (request queue handling, open, release, etc.)
  */
 
 /*
  * Dasd request queue function. Called from ll_rw_blk.c
  */
-static void
-do_dasd_request(struct request_queue * queue)
+static void do_dasd_request(struct request_queue *queue)
 {
-       struct dasd_device *device;
+       struct dasd_block *block;
 
-       device = (struct dasd_device *) queue->queuedata;
-       spin_lock(get_ccwdev_lock(device->cdev));
+       block = queue->queuedata;
+       spin_lock(&block->queue_lock);
        /* Get new request from the block device request queue */
-       __dasd_process_blk_queue(device);
+       __dasd_process_request_queue(block);
        /* Now check if the head of the ccw queue needs to be started. */
-       __dasd_start_head(device);
-       spin_unlock(get_ccwdev_lock(device->cdev));
+       __dasd_block_start_head(block);
+       spin_unlock(&block->queue_lock);
 }
 
 /*
  * Allocate and initialize request queue and default I/O scheduler.
  */
-static int
-dasd_alloc_queue(struct dasd_device * device)
+static int dasd_alloc_queue(struct dasd_block *block)
 {
        int rc;
 
-       device->request_queue = blk_init_queue(do_dasd_request,
-                                              &device->request_queue_lock);
-       if (device->request_queue == NULL)
+       block->request_queue = blk_init_queue(do_dasd_request,
+                                              &block->request_queue_lock);
+       if (block->request_queue == NULL)
                return -ENOMEM;
 
-       device->request_queue->queuedata = device;
+       block->request_queue->queuedata = block;
 
-       elevator_exit(device->request_queue->elevator);
-       rc = elevator_init(device->request_queue, "deadline");
+       elevator_exit(block->request_queue->elevator);
+       rc = elevator_init(block->request_queue, "deadline");
        if (rc) {
-               blk_cleanup_queue(device->request_queue);
+               blk_cleanup_queue(block->request_queue);
                return rc;
        }
        return 0;
@@ -1780,79 +1971,76 @@ dasd_alloc_queue(struct dasd_device * device)
 /*
  * Allocate and initialize request queue.
  */
-static void
-dasd_setup_queue(struct dasd_device * device)
+static void dasd_setup_queue(struct dasd_block *block)
 {
        int max;
 
-       blk_queue_hardsect_size(device->request_queue, device->bp_block);
-       max = device->discipline->max_blocks << device->s2b_shift;
-       blk_queue_max_sectors(device->request_queue, max);
-       blk_queue_max_phys_segments(device->request_queue, -1L);
-       blk_queue_max_hw_segments(device->request_queue, -1L);
-       blk_queue_max_segment_size(device->request_queue, -1L);
-       blk_queue_segment_boundary(device->request_queue, -1L);
-       blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
+       blk_queue_hardsect_size(block->request_queue, block->bp_block);
+       max = block->base->discipline->max_blocks << block->s2b_shift;
+       blk_queue_max_sectors(block->request_queue, max);
+       blk_queue_max_phys_segments(block->request_queue, -1L);
+       blk_queue_max_hw_segments(block->request_queue, -1L);
+       blk_queue_max_segment_size(block->request_queue, -1L);
+       blk_queue_segment_boundary(block->request_queue, -1L);
+       blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
 }
 
 /*
  * Deactivate and free request queue.
  */
-static void
-dasd_free_queue(struct dasd_device * device)
+static void dasd_free_queue(struct dasd_block *block)
 {
-       if (device->request_queue) {
-               blk_cleanup_queue(device->request_queue);
-               device->request_queue = NULL;
+       if (block->request_queue) {
+               blk_cleanup_queue(block->request_queue);
+               block->request_queue = NULL;
        }
 }
 
 /*
  * Flush request on the request queue.
  */
-static void
-dasd_flush_request_queue(struct dasd_device * device)
+static void dasd_flush_request_queue(struct dasd_block *block)
 {
        struct request *req;
 
-       if (!device->request_queue)
+       if (!block->request_queue)
                return;
 
-       spin_lock_irq(&device->request_queue_lock);
-       while ((req = elv_next_request(device->request_queue))) {
+       spin_lock_irq(&block->request_queue_lock);
+       while ((req = elv_next_request(block->request_queue))) {
                blkdev_dequeue_request(req);
                dasd_end_request(req, 0);
        }
-       spin_unlock_irq(&device->request_queue_lock);
+       spin_unlock_irq(&block->request_queue_lock);
 }
 
-static int
-dasd_open(struct inode *inp, struct file *filp)
+static int dasd_open(struct inode *inp, struct file *filp)
 {
        struct gendisk *disk = inp->i_bdev->bd_disk;
-       struct dasd_device *device = disk->private_data;
+       struct dasd_block *block = disk->private_data;
+       struct dasd_device *base = block->base;
        int rc;
 
-        atomic_inc(&device->open_count);
-       if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+       atomic_inc(&block->open_count);
+       if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
                rc = -ENODEV;
                goto unlock;
        }
 
-       if (!try_module_get(device->discipline->owner)) {
+       if (!try_module_get(base->discipline->owner)) {
                rc = -EINVAL;
                goto unlock;
        }
 
        if (dasd_probeonly) {
-               DEV_MESSAGE(KERN_INFO, device, "%s",
+               DEV_MESSAGE(KERN_INFO, base, "%s",
                            "No access to device due to probeonly mode");
                rc = -EPERM;
                goto out;
        }
 
-       if (device->state <= DASD_STATE_BASIC) {
-               DBF_DEV_EVENT(DBF_ERR, device, " %s",
+       if (base->state <= DASD_STATE_BASIC) {
+               DBF_DEV_EVENT(DBF_ERR, base, " %s",
                              " Cannot open unrecognized device");
                rc = -ENODEV;
                goto out;
@@ -1861,41 +2049,41 @@ dasd_open(struct inode *inp, struct file *filp)
        return 0;
 
 out:
-       module_put(device->discipline->owner);
+       module_put(base->discipline->owner);
 unlock:
-       atomic_dec(&device->open_count);
+       atomic_dec(&block->open_count);
        return rc;
 }
 
-static int
-dasd_release(struct inode *inp, struct file *filp)
+static int dasd_release(struct inode *inp, struct file *filp)
 {
        struct gendisk *disk = inp->i_bdev->bd_disk;
-       struct dasd_device *device = disk->private_data;
+       struct dasd_block *block = disk->private_data;
 
-       atomic_dec(&device->open_count);
-       module_put(device->discipline->owner);
+       atomic_dec(&block->open_count);
+       module_put(block->base->discipline->owner);
        return 0;
 }
 
 /*
  * Return disk geometry.
  */
-static int
-dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct dasd_device *device;
+       struct dasd_block *block;
+       struct dasd_device *base;
 
-       device = bdev->bd_disk->private_data;
-       if (!device)
+       block = bdev->bd_disk->private_data;
+       base = block->base;
+       if (!block)
                return -ENODEV;
 
-       if (!device->discipline ||
-           !device->discipline->fill_geometry)
+       if (!base->discipline ||
+           !base->discipline->fill_geometry)
                return -EINVAL;
 
-       device->discipline->fill_geometry(device, geo);
-       geo->start = get_start_sect(bdev) >> device->s2b_shift;
+       base->discipline->fill_geometry(block, geo);
+       geo->start = get_start_sect(bdev) >> block->s2b_shift;
        return 0;
 }
 
@@ -1909,6 +2097,9 @@ dasd_device_operations = {
        .getgeo         = dasd_getgeo,
 };
 
+/*******************************************************************************
+ * end of block device operations
+ */
 
 static void
 dasd_exit(void)
@@ -1937,9 +2128,8 @@ dasd_exit(void)
  * Initial attempt at a probe function. this can be simplified once
  * the other detection code is gone.
  */
-int
-dasd_generic_probe (struct ccw_device *cdev,
-                   struct dasd_discipline *discipline)
+int dasd_generic_probe(struct ccw_device *cdev,
+                      struct dasd_discipline *discipline)
 {
        int ret;
 
@@ -1969,19 +2159,20 @@ dasd_generic_probe (struct ccw_device *cdev,
                ret = ccw_device_set_online(cdev);
        if (ret)
                printk(KERN_WARNING
-                      "dasd_generic_probe: could not initially online "
-                      "ccw-device %s\n", cdev->dev.bus_id);
-       return ret;
+                      "dasd_generic_probe: could not initially "
+                      "online ccw-device %s; return code: %d\n",
+                      cdev->dev.bus_id, ret);
+       return 0;
 }
 
 /*
  * This will one day be called from a global not_oper handler.
  * It is also used by driver_unregister during module unload.
  */
-void
-dasd_generic_remove (struct ccw_device *cdev)
+void dasd_generic_remove(struct ccw_device *cdev)
 {
        struct dasd_device *device;
+       struct dasd_block *block;
 
        cdev->handler = NULL;
 
@@ -2001,7 +2192,15 @@ dasd_generic_remove (struct ccw_device *cdev)
         */
        dasd_set_target_state(device, DASD_STATE_NEW);
        /* dasd_delete_device destroys the device reference. */
+       block = device->block;
+       device->block = NULL;
        dasd_delete_device(device);
+       /*
+        * life cycle of block is bound to device, so delete it after
+        * device was safely removed
+        */
+       if (block)
+               dasd_free_block(block);
 }
 
 /*
@@ -2009,10 +2208,8 @@ dasd_generic_remove (struct ccw_device *cdev)
  * the device is detected for the first time and is supposed to be used
  * or the user has started activation through sysfs.
  */
-int
-dasd_generic_set_online (struct ccw_device *cdev,
-                        struct dasd_discipline *base_discipline)
-
+int dasd_generic_set_online(struct ccw_device *cdev,
+                           struct dasd_discipline *base_discipline)
 {
        struct dasd_discipline *discipline;
        struct dasd_device *device;
@@ -2048,6 +2245,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
        device->base_discipline = base_discipline;
        device->discipline = discipline;
 
+       /* check_device will allocate block device if necessary */
        rc = discipline->check_device(device);
        if (rc) {
                printk (KERN_WARNING
@@ -2067,6 +2265,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
                        cdev->dev.bus_id);
                rc = -ENODEV;
                dasd_set_target_state(device, DASD_STATE_NEW);
+               if (device->block)
+                       dasd_free_block(device->block);
                dasd_delete_device(device);
        } else
                pr_debug("dasd_generic device %s found\n",
@@ -2081,10 +2281,10 @@ dasd_generic_set_online (struct ccw_device *cdev,
        return rc;
 }
 
-int
-dasd_generic_set_offline (struct ccw_device *cdev)
+int dasd_generic_set_offline(struct ccw_device *cdev)
 {
        struct dasd_device *device;
+       struct dasd_block *block;
        int max_count, open_count;
 
        device = dasd_device_from_cdev(cdev);
@@ -2101,30 +2301,39 @@ dasd_generic_set_offline (struct ccw_device *cdev)
         * the blkdev_get in dasd_scan_partitions. We are only interested
         * in the other openers.
         */
-       max_count = device->bdev ? 0 : -1;
-       open_count = (int) atomic_read(&device->open_count);
-       if (open_count > max_count) {
-               if (open_count > 0)
-                       printk (KERN_WARNING "Can't offline dasd device with "
-                               "open count = %i.\n",
-                               open_count);
-               else
-                       printk (KERN_WARNING "%s",
-                               "Can't offline dasd device due to internal "
-                               "use\n");
-               clear_bit(DASD_FLAG_OFFLINE, &device->flags);
-               dasd_put_device(device);
-               return -EBUSY;
+       if (device->block) {
+               struct dasd_block *block = device->block;
+               max_count = block->bdev ? 0 : -1;
+               open_count = (int) atomic_read(&block->open_count);
+               if (open_count > max_count) {
+                       if (open_count > 0)
+                               printk(KERN_WARNING "Can't offline dasd "
+                                      "device with open count = %i.\n",
+                                      open_count);
+                       else
+                               printk(KERN_WARNING "%s",
+                                      "Can't offline dasd device due "
+                                      "to internal use\n");
+                       clear_bit(DASD_FLAG_OFFLINE, &device->flags);
+                       dasd_put_device(device);
+                       return -EBUSY;
+               }
        }
        dasd_set_target_state(device, DASD_STATE_NEW);
        /* dasd_delete_device destroys the device reference. */
+       block = device->block;
+       device->block = NULL;
        dasd_delete_device(device);
-
+       /*
+        * life cycle of block is bound to device, so delete it after
+        * device was safely removed
+        */
+       if (block)
+               dasd_free_block(block);
        return 0;
 }
 
-int
-dasd_generic_notify(struct ccw_device *cdev, int event)
+int dasd_generic_notify(struct ccw_device *cdev, int event)
 {
        struct dasd_device *device;
        struct dasd_ccw_req *cqr;
@@ -2145,27 +2354,22 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
                if (device->state < DASD_STATE_BASIC)
                        break;
                /* Device is active. We want to keep it. */
-               if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) {
-                       list_for_each_entry(cqr, &device->ccw_queue, list)
-                               if (cqr->status == DASD_CQR_IN_IO)
-                                       cqr->status = DASD_CQR_FAILED;
-                       device->stopped |= DASD_STOPPED_DC_EIO;
-               } else {
-                       list_for_each_entry(cqr, &device->ccw_queue, list)
-                               if (cqr->status == DASD_CQR_IN_IO) {
-                                       cqr->status = DASD_CQR_QUEUED;
-                                       cqr->retries++;
-                               }
-                       device->stopped |= DASD_STOPPED_DC_WAIT;
-                       dasd_set_timer(device, 0);
-               }
-               dasd_schedule_bh(device);
+               list_for_each_entry(cqr, &device->ccw_queue, devlist)
+                       if (cqr->status == DASD_CQR_IN_IO) {
+                               cqr->status = DASD_CQR_QUEUED;
+                               cqr->retries++;
+                       }
+               device->stopped |= DASD_STOPPED_DC_WAIT;
+               dasd_device_clear_timer(device);
+               dasd_schedule_device_bh(device);
                ret = 1;
                break;
        case CIO_OPER:
                /* FIXME: add a sanity check. */
-               device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO);
-               dasd_schedule_bh(device);
+               device->stopped &= ~DASD_STOPPED_DC_WAIT;
+               dasd_schedule_device_bh(device);
+               if (device->block)
+                       dasd_schedule_block_bh(device->block);
                ret = 1;
                break;
        }
@@ -2195,7 +2399,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
        ccw->cda = (__u32)(addr_t)rdc_buffer;
        ccw->count = rdc_buffer_size;
 
-       cqr->device = device;
+       cqr->startdev = device;
+       cqr->memdev = device;
        cqr->expires = 10*HZ;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        cqr->retries = 2;
@@ -2217,13 +2422,12 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
                return PTR_ERR(cqr);
 
        ret = dasd_sleep_on(cqr);
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return ret;
 }
 EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
 
-static int __init
-dasd_init(void)
+static int __init dasd_init(void)
 {
        int rc;
 
@@ -2231,7 +2435,7 @@ dasd_init(void)
        init_waitqueue_head(&dasd_flush_wq);
 
        /* register 'common' DASD debug area, used for all DBF_XXX calls */
-       dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
+       dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
        if (dasd_debug_area == NULL) {
                rc = -ENOMEM;
                goto failed;
@@ -2277,15 +2481,18 @@ EXPORT_SYMBOL(dasd_diag_discipline_pointer);
 EXPORT_SYMBOL(dasd_add_request_head);
 EXPORT_SYMBOL(dasd_add_request_tail);
 EXPORT_SYMBOL(dasd_cancel_req);
-EXPORT_SYMBOL(dasd_clear_timer);
+EXPORT_SYMBOL(dasd_device_clear_timer);
+EXPORT_SYMBOL(dasd_block_clear_timer);
 EXPORT_SYMBOL(dasd_enable_device);
 EXPORT_SYMBOL(dasd_int_handler);
 EXPORT_SYMBOL(dasd_kfree_request);
 EXPORT_SYMBOL(dasd_kick_device);
 EXPORT_SYMBOL(dasd_kmalloc_request);
-EXPORT_SYMBOL(dasd_schedule_bh);
+EXPORT_SYMBOL(dasd_schedule_device_bh);
+EXPORT_SYMBOL(dasd_schedule_block_bh);
 EXPORT_SYMBOL(dasd_set_target_state);
-EXPORT_SYMBOL(dasd_set_timer);
+EXPORT_SYMBOL(dasd_device_set_timer);
+EXPORT_SYMBOL(dasd_block_set_timer);
 EXPORT_SYMBOL(dasd_sfree_request);
 EXPORT_SYMBOL(dasd_sleep_on);
 EXPORT_SYMBOL(dasd_sleep_on_immediatly);
@@ -2299,4 +2506,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
 EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-
+EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change);
+EXPORT_SYMBOL_GPL(dasd_flush_device_queue);
+EXPORT_SYMBOL_GPL(dasd_alloc_block);
+EXPORT_SYMBOL_GPL(dasd_free_block);
diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
deleted file mode 100644 (file)
index 1ddab89..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_3370_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(3370)"
-
-#include "dasd_int.h"
-
-
-/*
- * DASD_3370_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
- *   'Chapter 7. 3370 Sense Data'.
- *
- * RETURN VALUES
- *   dasd_era_none     no error
- *   dasd_era_fatal    for all fatal (unrecoverable errors)
- *   dasd_era_recover  for all others.
- */
-dasd_era_t
-dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-       char *sense = irb->ecw;
-
-       /* check for successful execution first */
-       if (irb->scsw.cstat == 0x00 &&
-           irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-       if (sense[0] & 0x80) {  /* CMD reject */
-               return dasd_era_fatal;
-       }
-       if (sense[0] & 0x40) {  /* Drive offline */
-               return dasd_era_recover;
-       }
-       if (sense[0] & 0x20) {  /* Bus out parity */
-               return dasd_era_recover;
-       }
-       if (sense[0] & 0x10) {  /* equipment check */
-               if (sense[1] & 0x80) {
-                       return dasd_era_fatal;
-               }
-               return dasd_era_recover;
-       }
-       if (sense[0] & 0x08) {  /* data check */
-               if (sense[1] & 0x80) {
-                       return dasd_era_fatal;
-               }
-               return dasd_era_recover;
-       }
-       if (sense[0] & 0x04) {  /* overrun */
-               if (sense[1] & 0x80) {
-                       return dasd_era_fatal;
-               }
-               return dasd_era_recover;
-       }
-       if (sense[1] & 0x40) {  /* invalid blocksize */
-               return dasd_era_fatal;
-       }
-       if (sense[1] & 0x04) {  /* file protected */
-               return dasd_era_recover;
-       }
-       if (sense[1] & 0x01) {  /* operation incomplete */
-               return dasd_era_recover;
-       }
-       if (sense[2] & 0x80) {  /* check data erroor */
-               return dasd_era_recover;
-       }
-       if (sense[2] & 0x10) {  /* Env. data present */
-               return dasd_era_recover;
-       }
-       /* examine the 24 byte sense data */
-       return dasd_era_recover;
-
-}                              /* END dasd_3370_erp_examine */
index 5b7385e430ea6b64c6970ec4bf275a89a8bb3285..c361ab69ec0023c3eae201d50b4d10a2acb6b595 100644 (file)
@@ -24,158 +24,6 @@ struct DCTL_data {
        unsigned short res;        /* reserved */
 } __attribute__ ((packed));
 
-/*
- *****************************************************************************
- * SECTION ERP EXAMINATION
- *****************************************************************************
- */
-
-/*
- * DASD_3990_ERP_EXAMINE_24
- *
- * DESCRIPTION
- *   Checks only for fatal (unrecoverable) error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   Each bit configuration leading to an action code 2 (Exit with
- *   programming error or unusual condition indication)
- *   are handled as fatal errors.
- *
- *   All other configurations are handled as recoverable errors.
- *
- * RETURN VALUES
- *   dasd_era_fatal    for all fatal (unrecoverable errors)
- *   dasd_era_recover  for all others.
- */
-static dasd_era_t
-dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
-{
-
-       struct dasd_device *device = cqr->device;
-
-       /* check for 'Command Reject' */
-       if ((sense[0] & SNS0_CMD_REJECT) &&
-           (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
-
-               DEV_MESSAGE(KERN_ERR, device, "%s",
-                           "EXAMINE 24: Command Reject detected - "
-                           "fatal error");
-
-               return dasd_era_fatal;
-       }
-
-       /* check for 'Invalid Track Format' */
-       if ((sense[1] & SNS1_INV_TRACK_FORMAT) &&
-           (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
-
-               DEV_MESSAGE(KERN_ERR, device, "%s",
-                           "EXAMINE 24: Invalid Track Format detected "
-                           "- fatal error");
-
-               return dasd_era_fatal;
-       }
-
-       /* check for 'No Record Found' */
-       if (sense[1] & SNS1_NO_REC_FOUND) {
-
-                /* FIXME: fatal error ?!? */
-               DEV_MESSAGE(KERN_ERR, device,
-                           "EXAMINE 24: No Record Found detected %s",
-                            device->state <= DASD_STATE_BASIC ?
-                           " " : "- fatal error");
-
-               return dasd_era_fatal;
-       }
-
-       /* return recoverable for all others */
-       return dasd_era_recover;
-}                              /* END dasd_3990_erp_examine_24 */
-
-/*
- * DASD_3990_ERP_EXAMINE_32
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recoverable error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- * RETURN VALUES
- *   dasd_era_none     no error
- *   dasd_era_fatal    for all fatal (unrecoverable errors)
- *   dasd_era_recover  for recoverable others.
- */
-static dasd_era_t
-dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
-{
-
-       struct dasd_device *device = cqr->device;
-
-       switch (sense[25]) {
-       case 0x00:
-               return dasd_era_none;
-
-       case 0x01:
-               DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error");
-
-               return dasd_era_fatal;
-
-       default:
-
-               return dasd_era_recover;
-       }
-
-}                              /* end dasd_3990_erp_examine_32 */
-
-/*
- * DASD_3990_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3990 Storage Control  Reference' manual
- *   'Chapter 7. Error Recovery Procedures'.
- *
- * RETURN VALUES
- *   dasd_era_none     no error
- *   dasd_era_fatal    for all fatal (unrecoverable errors)
- *   dasd_era_recover  for all others.
- */
-dasd_era_t
-dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-
-       char *sense = irb->ecw;
-       dasd_era_t era = dasd_era_recover;
-       struct dasd_device *device = cqr->device;
-
-       /* check for successful execution first */
-       if (irb->scsw.cstat == 0x00 &&
-           irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-
-       /* distinguish between 24 and 32 byte sense data */
-       if (sense[27] & DASD_SENSE_BIT_0) {
-
-               era = dasd_3990_erp_examine_24(cqr, sense);
-
-       } else {
-
-               era = dasd_3990_erp_examine_32(cqr, sense);
-
-       }
-
-       /* log the erp chain if fatal error occurred */
-       if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
-               dasd_log_sense(cqr, irb);
-       }
-
-       return era;
-
-}                              /* END dasd_3990_erp_examine */
-
 /*
  *****************************************************************************
  * SECTION ERP HANDLING
@@ -206,7 +54,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
 {
        struct dasd_ccw_req *cqr = erp->refers;
 
-       dasd_free_erp_request(erp, erp->device);
+       dasd_free_erp_request(erp, erp->memdev);
        cqr->status = final_status;
        return cqr;
 
@@ -224,15 +72,17 @@ static void
 dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
+       unsigned long flags;
 
        DEV_MESSAGE(KERN_INFO, device,
                    "blocking request queue for %is", expires/HZ);
 
+       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        device->stopped |= DASD_STOPPED_PENDING;
-       erp->status = DASD_CQR_QUEUED;
-
-       dasd_set_timer(device, expires);
+       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       erp->status = DASD_CQR_FILLED;
+       dasd_block_set_timer(device->block, expires);
 }
 
 /*
@@ -251,7 +101,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        /* first time set initial retry counter and erp_function */
        /* and retry once without blocking queue                 */
@@ -292,11 +142,14 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 static void
 dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
 {
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
        __u8 opm;
+       unsigned long flags;
 
        /* try alternate valid path */
+       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        opm = ccw_device_get_path_mask(device->cdev);
+       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
        //FIXME: start with get_opm ?
        if (erp->lpm == 0)
                erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum);
@@ -309,9 +162,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
                            "try alternate lpm=%x (lpum=%x / opm=%x)",
                            erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm);
 
-               /* reset status to queued to handle the request again... */
-               if (erp->status > DASD_CQR_QUEUED)
-                       erp->status = DASD_CQR_QUEUED;
+               /* reset status to submit the request again... */
+               erp->status = DASD_CQR_FILLED;
                erp->retries = 1;
        } else {
                DEV_MESSAGE(KERN_ERR, device,
@@ -320,8 +172,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
                            erp->irb.esw.esw0.sublog.lpum, opm);
 
                /* post request with permanent error */
-               if (erp->status > DASD_CQR_QUEUED)
-                       erp->status = DASD_CQR_FAILED;
+               erp->status = DASD_CQR_FAILED;
        }
 }                              /* end dasd_3990_erp_alternate_path */
 
@@ -344,14 +195,14 @@ static struct dasd_ccw_req *
 dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
        struct DCTL_data *DCTL_data;
        struct ccw1 *ccw;
        struct dasd_ccw_req *dctl_cqr;
 
        dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
-                                         sizeof (struct DCTL_data),
-                                         erp->device);
+                                         sizeof(struct DCTL_data),
+                                         device);
        if (IS_ERR(dctl_cqr)) {
                DEV_MESSAGE(KERN_ERR, device, "%s",
                            "Unable to allocate DCTL-CQR");
@@ -365,13 +216,14 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
        DCTL_data->modifier = modifier;
 
        ccw = dctl_cqr->cpaddr;
-       memset(ccw, 0, sizeof (struct ccw1));
+       memset(ccw, 0, sizeof(struct ccw1));
        ccw->cmd_code = CCW_CMD_DCTL;
        ccw->count = 4;
        ccw->cda = (__u32)(addr_t) DCTL_data;
        dctl_cqr->function = dasd_3990_erp_DCTL;
        dctl_cqr->refers = erp;
-       dctl_cqr->device = erp->device;
+       dctl_cqr->startdev = device;
+       dctl_cqr->memdev = device;
        dctl_cqr->magic = erp->magic;
        dctl_cqr->expires = 5 * 60 * HZ;
        dctl_cqr->retries = 2;
@@ -435,7 +287,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        /* first time set initial retry counter and erp_function    */
        /* and retry once without waiting for state change pending  */
@@ -472,7 +324,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
                                     "redriving request immediately, "
                                     "%d retries left",
                                     erp->retries);
-                       erp->status = DASD_CQR_QUEUED;
+                       erp->status = DASD_CQR_FILLED;
                }
        }
 
@@ -530,7 +382,7 @@ static void
 dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
        char msg_format = (sense[7] & 0xF0);
        char msg_no = (sense[7] & 0x0F);
 
@@ -1157,7 +1009,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_com_rej;
 
@@ -1198,7 +1050,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        /* first time set initial retry counter and erp_function */
        /* and retry once without blocking queue                 */
@@ -1237,7 +1089,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_equip_check;
 
@@ -1279,7 +1131,6 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
 
                erp = dasd_3990_erp_action_5(erp);
        }
-
        return erp;
 
 }                              /* end dasd_3990_erp_equip_check */
@@ -1299,7 +1150,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_data_check;
 
@@ -1358,7 +1209,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_overrun;
 
@@ -1387,7 +1238,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_inv_format;
 
@@ -1403,8 +1254,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
 
        } else {
                DEV_MESSAGE(KERN_ERR, device, "%s",
-                           "Invalid Track Format - Fatal error should have "
-                           "been handled within the interrupt handler");
+                           "Invalid Track Format - Fatal error");
 
                erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
        }
@@ -1428,7 +1278,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-       struct dasd_device *device = default_erp->device;
+       struct dasd_device *device = default_erp->startdev;
 
        DEV_MESSAGE(KERN_ERR, device, "%s",
                    "End-of-Cylinder - must never happen");
@@ -1453,7 +1303,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_env_data;
 
@@ -1463,11 +1313,9 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
 
        /* don't retry on disabled interface */
        if (sense[7] != 0x0F) {
-
                erp = dasd_3990_erp_action_4(erp, sense);
        } else {
-
-               erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO);
+               erp->status = DASD_CQR_FILLED;
        }
 
        return erp;
@@ -1490,11 +1338,10 @@ static struct dasd_ccw_req *
 dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-       struct dasd_device *device = default_erp->device;
+       struct dasd_device *device = default_erp->startdev;
 
        DEV_MESSAGE(KERN_ERR, device, "%s",
-                   "No Record Found - Fatal error should "
-                   "have been handled within the interrupt handler");
+                   "No Record Found - Fatal error ");
 
        return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
 
@@ -1517,7 +1364,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected");
 
@@ -1525,6 +1372,43 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 
 }                              /* end dasd_3990_erp_file_prot */
 
+/*
+ * DASD_3990_ERP_INSPECT_ALIAS
+ *
+ * DESCRIPTION
+ *   Checks if the original request was started on an alias device.
+ *   If yes, it modifies the original and the erp request so that
+ *   the erp request can be started on a base device.
+ *
+ * PARAMETER
+ *   erp               pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp               pointer to the modified ERP, or NULL
+ */
+
+static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
+                                               struct dasd_ccw_req *erp)
+{
+       struct dasd_ccw_req *cqr = erp->refers;
+
+       if (cqr->block &&
+           (cqr->block->base != cqr->startdev)) {
+               if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
+                       DEV_MESSAGE(KERN_ERR, cqr->startdev,
+                                   "ERP on alias device for request %p,"
+                                   " recover on base device %s", cqr,
+                                   cqr->block->base->cdev->dev.bus_id);
+               }
+               dasd_eckd_reset_ccw_to_base_io(cqr);
+               erp->startdev = cqr->block->base;
+               erp->function = dasd_3990_erp_inspect_alias;
+               return erp;
+       } else
+               return NULL;
+}
+
+
 /*
  * DASD_3990_ERP_INSPECT_24
  *
@@ -1623,7 +1507,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->retries = 256;
        erp->function = dasd_3990_erp_action_10_32;
@@ -1657,13 +1541,14 @@ static struct dasd_ccw_req *
 dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-       struct dasd_device *device = default_erp->device;
+       struct dasd_device *device = default_erp->startdev;
        __u32 cpa = 0;
        struct dasd_ccw_req *cqr;
        struct dasd_ccw_req *erp;
        struct DE_eckd_data *DE_data;
+       struct PFX_eckd_data *PFX_data;
        char *LO_data;          /* LO_eckd_data_t */
-       struct ccw1 *ccw;
+       struct ccw1 *ccw, *oldccw;
 
        DEV_MESSAGE(KERN_DEBUG, device, "%s",
                    "Write not finished because of unexpected condition");
@@ -1702,8 +1587,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
        /* Build new ERP request including DE/LO */
        erp = dasd_alloc_erp_request((char *) &cqr->magic,
                                     2 + 1,/* DE/LO + TIC */
-                                    sizeof (struct DE_eckd_data) +
-                                    sizeof (struct LO_eckd_data), device);
+                                    sizeof(struct DE_eckd_data) +
+                                    sizeof(struct LO_eckd_data), device);
 
        if (IS_ERR(erp)) {
                DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP");
@@ -1712,10 +1597,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
        /* use original DE */
        DE_data = erp->data;
-       memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data));
+       oldccw = cqr->cpaddr;
+       if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {
+               PFX_data = cqr->data;
+               memcpy(DE_data, &PFX_data->define_extend,
+                      sizeof(struct DE_eckd_data));
+       } else
+               memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data));
 
        /* create LO */
-       LO_data = erp->data + sizeof (struct DE_eckd_data);
+       LO_data = erp->data + sizeof(struct DE_eckd_data);
 
        if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
 
@@ -1748,7 +1639,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
        /* create DE ccw */
        ccw = erp->cpaddr;
-       memset(ccw, 0, sizeof (struct ccw1));
+       memset(ccw, 0, sizeof(struct ccw1));
        ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 16;
@@ -1756,7 +1647,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
        /* create LO ccw */
        ccw++;
-       memset(ccw, 0, sizeof (struct ccw1));
+       memset(ccw, 0, sizeof(struct ccw1));
        ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 16;
@@ -1770,7 +1661,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
        /* fill erp related fields */
        erp->function = dasd_3990_erp_action_1B_32;
        erp->refers = default_erp->refers;
-       erp->device = device;
+       erp->startdev = device;
+       erp->memdev = device;
        erp->magic = default_erp->magic;
        erp->expires = 0;
        erp->retries = 256;
@@ -1803,7 +1695,7 @@ static struct dasd_ccw_req *
 dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 {
 
-       struct dasd_device *device = previous_erp->device;
+       struct dasd_device *device = previous_erp->startdev;
        __u32 cpa = 0;
        struct dasd_ccw_req *cqr;
        struct dasd_ccw_req *erp;
@@ -1827,7 +1719,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
                DEV_MESSAGE(KERN_DEBUG, device, "%s",
                            "Imprecise ending is set - just retry");
 
-               previous_erp->status = DASD_CQR_QUEUED;
+               previous_erp->status = DASD_CQR_FILLED;
 
                return previous_erp;
        }
@@ -1850,7 +1742,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
        erp = previous_erp;
 
        /* update the LO with the new returned sense data  */
-       LO_data = erp->data + sizeof (struct DE_eckd_data);
+       LO_data = erp->data + sizeof(struct DE_eckd_data);
 
        if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
 
@@ -1889,7 +1781,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
        ccw++;                  /* addr of TIC ccw */
        ccw->cda = cpa;
 
-       erp->status = DASD_CQR_QUEUED;
+       erp->status = DASD_CQR_FILLED;
 
        return erp;
 
@@ -1968,9 +1860,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
                         * try further actions. */
 
                        erp->lpm = 0;
-
-                       erp->status = DASD_CQR_ERROR;
-
+                       erp->status = DASD_CQR_NEED_ERP;
                }
        }
 
@@ -2047,7 +1937,7 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
        if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
 
                /* set to suspended duplex state then restart */
-               struct dasd_device *device = erp->device;
+               struct dasd_device *device = erp->startdev;
 
                DEV_MESSAGE(KERN_ERR, device, "%s",
                            "Set device to suspended duplex state should be "
@@ -2081,28 +1971,26 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
 {
 
        if ((erp->function == dasd_3990_erp_compound_retry) &&
-           (erp->status == DASD_CQR_ERROR)) {
+           (erp->status == DASD_CQR_NEED_ERP)) {
 
                dasd_3990_erp_compound_path(erp, sense);
        }
 
        if ((erp->function == dasd_3990_erp_compound_path) &&
-           (erp->status == DASD_CQR_ERROR)) {
+           (erp->status == DASD_CQR_NEED_ERP)) {
 
                erp = dasd_3990_erp_compound_code(erp, sense);
        }
 
        if ((erp->function == dasd_3990_erp_compound_code) &&
-           (erp->status == DASD_CQR_ERROR)) {
+           (erp->status == DASD_CQR_NEED_ERP)) {
 
                dasd_3990_erp_compound_config(erp, sense);
        }
 
        /* if no compound action ERP specified, the request failed */
-       if (erp->status == DASD_CQR_ERROR) {
-
+       if (erp->status == DASD_CQR_NEED_ERP)
                erp->status = DASD_CQR_FAILED;
-       }
 
        return erp;
 
@@ -2127,7 +2015,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
 
        erp->function = dasd_3990_erp_inspect_32;
 
@@ -2149,8 +2037,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 
                case 0x01:      /* fatal error */
                        DEV_MESSAGE(KERN_ERR, device, "%s",
-                                   "Fatal error should have been "
-                                   "handled within the interrupt handler");
+                                   "Retry not recommended - Fatal error");
 
                        erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
                        break;
@@ -2253,6 +2140,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
        /* already set up new ERP !                           */
        char *sense = erp->refers->irb.ecw;
 
+       /* if this problem occured on an alias retry on base */
+       erp_new = dasd_3990_erp_inspect_alias(erp);
+       if (erp_new)
+               return erp_new;
+
        /* distinguish between 24 and 32 byte sense data */
        if (sense[27] & DASD_SENSE_BIT_0) {
 
@@ -2287,13 +2179,13 @@ static struct dasd_ccw_req *
 dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 {
 
-       struct dasd_device *device = cqr->device;
+       struct dasd_device *device = cqr->startdev;
        struct ccw1 *ccw;
 
        /* allocate additional request block */
        struct dasd_ccw_req *erp;
 
-       erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device);
+       erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device);
        if (IS_ERR(erp)) {
                 if (cqr->retries <= 0) {
                        DEV_MESSAGE(KERN_ERR, device, "%s",
@@ -2305,7 +2197,7 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
                                      "Unable to allocate ERP request "
                                     "(%i retries left)",
                                      cqr->retries);
-                       dasd_set_timer(device, (HZ << 3));
+                       dasd_block_set_timer(device->block, (HZ << 3));
                 }
                return cqr;
        }
@@ -2319,7 +2211,9 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
        ccw->cda      = (long)(cqr->cpaddr);
        erp->function = dasd_3990_erp_add_erp;
        erp->refers   = cqr;
-       erp->device   = cqr->device;
+       erp->startdev = device;
+       erp->memdev   = device;
+       erp->block    = cqr->block;
        erp->magic    = cqr->magic;
        erp->expires  = 0;
        erp->retries  = 256;
@@ -2466,7 +2360,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 {
 
-       struct dasd_device *device = erp->device;
+       struct dasd_device *device = erp->startdev;
        char *sense = erp->irb.ecw;
 
        /* check for 24 byte sense ERP */
@@ -2557,7 +2451,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
                               struct dasd_ccw_req *erp)
 {
 
-       struct dasd_device *device = erp_head->device;
+       struct dasd_device *device = erp_head->startdev;
        struct dasd_ccw_req *erp_done = erp_head;       /* finished req */
        struct dasd_ccw_req *erp_free = NULL;   /* req to be freed */
 
@@ -2569,13 +2463,13 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
                              "original request was lost\n");
 
                /* remove the request from the device queue */
-               list_del(&erp_done->list);
+               list_del(&erp_done->blocklist);
 
                erp_free = erp_done;
                erp_done = erp_done->refers;
 
                /* free the finished erp request */
-               dasd_free_erp_request(erp_free, erp_free->device);
+               dasd_free_erp_request(erp_free, erp_free->memdev);
 
        }                       /* end while */
 
@@ -2603,7 +2497,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
                                    erp->retries, erp);
 
                        /* handle the request again... */
-                       erp->status = DASD_CQR_QUEUED;
+                       erp->status = DASD_CQR_FILLED;
                }
 
        } else {
@@ -2620,7 +2514,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
  * DASD_3990_ERP_ACTION
  *
  * DESCRIPTION
- *   controll routine for 3990 erp actions.
+ *   control routine for 3990 erp actions.
  *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
  *
  * PARAMETER
@@ -2636,9 +2530,8 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
 struct dasd_ccw_req *
 dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 {
-
        struct dasd_ccw_req *erp = NULL;
-       struct dasd_device *device = cqr->device;
+       struct dasd_device *device = cqr->startdev;
        struct dasd_ccw_req *temp_erp = NULL;
 
        if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2704,10 +2597,11 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
                }
        }
 
-       /* enqueue added ERP request */
-       if (erp->status == DASD_CQR_FILLED) {
-               erp->status = DASD_CQR_QUEUED;
-               list_add(&erp->list, &device->ccw_queue);
+       /* enqueue ERP request if it's a new one */
+       if (list_empty(&erp->blocklist)) {
+               cqr->status = DASD_CQR_IN_ERP;
+               /* add erp request before the cqr */
+               list_add_tail(&erp->blocklist, &cqr->blocklist);
        }
 
        return erp;
diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
deleted file mode 100644 (file)
index 6e08268..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_9336_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(9336)"
-
-#include "dasd_int.h"
-
-
-/*
- * DASD_9336_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
- *   'Chapter 7. 9336 Sense Data'.
- *
- * RETURN VALUES
- *   dasd_era_none     no error
- *   dasd_era_fatal    for all fatal (unrecoverable errors)
- *   dasd_era_recover  for all others.
- */
-dasd_era_t
-dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-       /* check for successful execution first */
-       if (irb->scsw.cstat == 0x00 &&
-           irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-
-       /* examine the 24 byte sense data */
-       return dasd_era_recover;
-
-}                              /* END dasd_9336_erp_examine */
diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
deleted file mode 100644 (file)
index ddecb98..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_9345_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(9343)"
-
-#include "dasd_int.h"
-
-dasd_era_t
-dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-       if (irb->scsw.cstat == 0x00 &&
-           irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-
-       return dasd_era_recover;
-}
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
new file mode 100644 (file)
index 0000000..3a40bee
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+ * PAV alias management for the DASD ECKD discipline
+ *
+ * Copyright IBM Corporation, 2007
+ * Author(s): Stefan Weinhuber <wein@de.ibm.com>
+ */
+
+#include <linux/list.h>
+#include <asm/ebcdic.h>
+#include "dasd_int.h"
+#include "dasd_eckd.h"
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif                         /* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eckd):"
+
+
+/*
+ * General concept of alias management:
+ * - PAV and DASD alias management is specific to the eckd discipline.
+ * - A device is connected to an lcu as long as the device exists.
+ *   dasd_alias_make_device_known_to_lcu will be called wenn the
+ *   device is checked by the eckd discipline and
+ *   dasd_alias_disconnect_device_from_lcu will be called
+ *   before the device is deleted.
+ * - The dasd_alias_add_device / dasd_alias_remove_device
+ *   functions mark the point when a device is 'ready for service'.
+ * - A summary unit check is a rare occasion, but it is mandatory to
+ *   support it. It requires some complex recovery actions before the
+ *   devices can be used again (see dasd_alias_handle_summary_unit_check).
+ * - dasd_alias_get_start_dev will find an alias device that can be used
+ *   instead of the base device and does some (very simple) load balancing.
+ *   This is the function that gets called for each I/O, so when improving
+ *   something, this function should get faster or better, the rest has just
+ *   to be correct.
+ */
+
+
+static void summary_unit_check_handling_work(struct work_struct *);
+static void lcu_update_work(struct work_struct *);
+static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *);
+
+static struct alias_root aliastree = {
+       .serverlist = LIST_HEAD_INIT(aliastree.serverlist),
+       .lock = __SPIN_LOCK_UNLOCKED(aliastree.lock),
+};
+
+static struct alias_server *_find_server(struct dasd_uid *uid)
+{
+       struct alias_server *pos;
+       list_for_each_entry(pos, &aliastree.serverlist, server) {
+               if (!strncmp(pos->uid.vendor, uid->vendor,
+                            sizeof(uid->vendor))
+                   && !strncmp(pos->uid.serial, uid->serial,
+                               sizeof(uid->serial)))
+                       return pos;
+       };
+       return NULL;
+}
+
+static struct alias_lcu *_find_lcu(struct alias_server *server,
+                                  struct dasd_uid *uid)
+{
+       struct alias_lcu *pos;
+       list_for_each_entry(pos, &server->lculist, lcu) {
+               if (pos->uid.ssid == uid->ssid)
+                       return pos;
+       };
+       return NULL;
+}
+
+static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
+                                          struct dasd_uid *uid)
+{
+       struct alias_pav_group *pos;
+       __u8 search_unit_addr;
+
+       /* for hyper pav there is only one group */
+       if (lcu->pav == HYPER_PAV) {
+               if (list_empty(&lcu->grouplist))
+                       return NULL;
+               else
+                       return list_first_entry(&lcu->grouplist,
+                                               struct alias_pav_group, group);
+       }
+
+       /* for base pav we have to find the group that matches the base */
+       if (uid->type == UA_BASE_DEVICE)
+               search_unit_addr = uid->real_unit_addr;
+       else
+               search_unit_addr = uid->base_unit_addr;
+       list_for_each_entry(pos, &lcu->grouplist, group) {
+               if (pos->uid.base_unit_addr == search_unit_addr)
+                       return pos;
+       };
+       return NULL;
+}
+
+static struct alias_server *_allocate_server(struct dasd_uid *uid)
+{
+       struct alias_server *server;
+
+       server = kzalloc(sizeof(*server), GFP_KERNEL);
+       if (!server)
+               return ERR_PTR(-ENOMEM);
+       memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor));
+       memcpy(server->uid.serial, uid->serial, sizeof(uid->serial));
+       INIT_LIST_HEAD(&server->server);
+       INIT_LIST_HEAD(&server->lculist);
+       return server;
+}
+
+static void _free_server(struct alias_server *server)
+{
+       kfree(server);
+}
+
+static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)
+{
+       struct alias_lcu *lcu;
+
+       lcu = kzalloc(sizeof(*lcu), GFP_KERNEL);
+       if (!lcu)
+               return ERR_PTR(-ENOMEM);
+       lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA);
+       if (!lcu->uac)
+               goto out_err1;
+       lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA);
+       if (!lcu->rsu_cqr)
+               goto out_err2;
+       lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1),
+                                      GFP_KERNEL | GFP_DMA);
+       if (!lcu->rsu_cqr->cpaddr)
+               goto out_err3;
+       lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA);
+       if (!lcu->rsu_cqr->data)
+               goto out_err4;
+
+       memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor));
+       memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial));
+       lcu->uid.ssid = uid->ssid;
+       lcu->pav = NO_PAV;
+       lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING;
+       INIT_LIST_HEAD(&lcu->lcu);
+       INIT_LIST_HEAD(&lcu->inactive_devices);
+       INIT_LIST_HEAD(&lcu->active_devices);
+       INIT_LIST_HEAD(&lcu->grouplist);
+       INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);
+       INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);
+       spin_lock_init(&lcu->lock);
+       return lcu;
+
+out_err4:
+       kfree(lcu->rsu_cqr->cpaddr);
+out_err3:
+       kfree(lcu->rsu_cqr);
+out_err2:
+       kfree(lcu->uac);
+out_err1:
+       kfree(lcu);
+       return ERR_PTR(-ENOMEM);
+}
+
+static void _free_lcu(struct alias_lcu *lcu)
+{
+       kfree(lcu->rsu_cqr->data);
+       kfree(lcu->rsu_cqr->cpaddr);
+       kfree(lcu->rsu_cqr);
+       kfree(lcu->uac);
+       kfree(lcu);
+}
+
+/*
+ * This is the function that will allocate all the server and lcu data,
+ * so this function must be called first for a new device.
+ * If the return value is 1, the lcu was already known before, if it
+ * is 0, this is a new lcu.
+ * Negative return code indicates that something went wrong (e.g. -ENOMEM)
+ */
+int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       unsigned long flags;
+       struct alias_server *server, *newserver;
+       struct alias_lcu *lcu, *newlcu;
+       int is_lcu_known;
+       struct dasd_uid *uid;
+
+       private = (struct dasd_eckd_private *) device->private;
+       uid = &private->uid;
+       spin_lock_irqsave(&aliastree.lock, flags);
+       is_lcu_known = 1;
+       server = _find_server(uid);
+       if (!server) {
+               spin_unlock_irqrestore(&aliastree.lock, flags);
+               newserver = _allocate_server(uid);
+               if (IS_ERR(newserver))
+                       return PTR_ERR(newserver);
+               spin_lock_irqsave(&aliastree.lock, flags);
+               server = _find_server(uid);
+               if (!server) {
+                       list_add(&newserver->server, &aliastree.serverlist);
+                       server = newserver;
+                       is_lcu_known = 0;
+               } else {
+                       /* someone was faster */
+                       _free_server(newserver);
+               }
+       }
+
+       lcu = _find_lcu(server, uid);
+       if (!lcu) {
+               spin_unlock_irqrestore(&aliastree.lock, flags);
+               newlcu = _allocate_lcu(uid);
+               if (IS_ERR(newlcu))
+                       return PTR_ERR(lcu);
+               spin_lock_irqsave(&aliastree.lock, flags);
+               lcu = _find_lcu(server, uid);
+               if (!lcu) {
+                       list_add(&newlcu->lcu, &server->lculist);
+                       lcu = newlcu;
+                       is_lcu_known = 0;
+               } else {
+                       /* someone was faster */
+                       _free_lcu(newlcu);
+               }
+               is_lcu_known = 0;
+       }
+       spin_lock(&lcu->lock);
+       list_add(&device->alias_list, &lcu->inactive_devices);
+       private->lcu = lcu;
+       spin_unlock(&lcu->lock);
+       spin_unlock_irqrestore(&aliastree.lock, flags);
+
+       return is_lcu_known;
+}
+
+/*
+ * This function removes a device from the scope of alias management.
+ * The complicated part is to make sure that it is not in use by
+ * any of the workers. If necessary cancel the work.
+ */
+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       unsigned long flags;
+       struct alias_lcu *lcu;
+       struct alias_server *server;
+       int was_pending;
+
+       private = (struct dasd_eckd_private *) device->private;
+       lcu = private->lcu;
+       spin_lock_irqsave(&lcu->lock, flags);
+       list_del_init(&device->alias_list);
+       /* make sure that the workers don't use this device */
+       if (device == lcu->suc_data.device) {
+               spin_unlock_irqrestore(&lcu->lock, flags);
+               cancel_work_sync(&lcu->suc_data.worker);
+               spin_lock_irqsave(&lcu->lock, flags);
+               if (device == lcu->suc_data.device)
+                       lcu->suc_data.device = NULL;
+       }
+       was_pending = 0;
+       if (device == lcu->ruac_data.device) {
+               spin_unlock_irqrestore(&lcu->lock, flags);
+               was_pending = 1;
+               cancel_delayed_work_sync(&lcu->ruac_data.dwork);
+               spin_lock_irqsave(&lcu->lock, flags);
+               if (device == lcu->ruac_data.device)
+                       lcu->ruac_data.device = NULL;
+       }
+       private->lcu = NULL;
+       spin_unlock_irqrestore(&lcu->lock, flags);
+
+       spin_lock_irqsave(&aliastree.lock, flags);
+       spin_lock(&lcu->lock);
+       if (list_empty(&lcu->grouplist) &&
+           list_empty(&lcu->active_devices) &&
+           list_empty(&lcu->inactive_devices)) {
+               list_del(&lcu->lcu);
+               spin_unlock(&lcu->lock);
+               _free_lcu(lcu);
+               lcu = NULL;
+       } else {
+               if (was_pending)
+                       _schedule_lcu_update(lcu, NULL);
+               spin_unlock(&lcu->lock);
+       }
+       server = _find_server(&private->uid);
+       if (server && list_empty(&server->lculist)) {
+               list_del(&server->server);
+               _free_server(server);
+       }
+       spin_unlock_irqrestore(&aliastree.lock, flags);
+}
+
+/*
+ * This function assumes that the unit address configuration stored
+ * in the lcu is up to date and will update the device uid before
+ * adding it to a pav group.
+ */
+static int _add_device_to_lcu(struct alias_lcu *lcu,
+                             struct dasd_device *device)
+{
+
+       struct dasd_eckd_private *private;
+       struct alias_pav_group *group;
+       struct dasd_uid *uid;
+
+       private = (struct dasd_eckd_private *) device->private;
+       uid = &private->uid;
+       uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type;
+       uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua;
+       dasd_set_uid(device->cdev, &private->uid);
+
+       /* if we have no PAV anyway, we don't need to bother with PAV groups */
+       if (lcu->pav == NO_PAV) {
+               list_move(&device->alias_list, &lcu->active_devices);
+               return 0;
+       }
+
+       group = _find_group(lcu, uid);
+       if (!group) {
+               group = kzalloc(sizeof(*group), GFP_ATOMIC);
+               if (!group)
+                       return -ENOMEM;
+               memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor));
+               memcpy(group->uid.serial, uid->serial, sizeof(uid->serial));
+               group->uid.ssid = uid->ssid;
+               if (uid->type == UA_BASE_DEVICE)
+                       group->uid.base_unit_addr = uid->real_unit_addr;
+               else
+                       group->uid.base_unit_addr = uid->base_unit_addr;
+               INIT_LIST_HEAD(&group->group);
+               INIT_LIST_HEAD(&group->baselist);
+               INIT_LIST_HEAD(&group->aliaslist);
+               list_add(&group->group, &lcu->grouplist);
+       }
+       if (uid->type == UA_BASE_DEVICE)
+               list_move(&device->alias_list, &group->baselist);
+       else
+               list_move(&device->alias_list, &group->aliaslist);
+       private->pavgroup = group;
+       return 0;
+};
+
+static void _remove_device_from_lcu(struct alias_lcu *lcu,
+                                   struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       struct alias_pav_group *group;
+
+       private = (struct dasd_eckd_private *) device->private;
+       list_move(&device->alias_list, &lcu->inactive_devices);
+       group = private->pavgroup;
+       if (!group)
+               return;
+       private->pavgroup = NULL;
+       if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) {
+               list_del(&group->group);
+               kfree(group);
+               return;
+       }
+       if (group->next == device)
+               group->next = NULL;
+};
+
+static int read_unit_address_configuration(struct dasd_device *device,
+                                          struct alias_lcu *lcu)
+{
+       struct dasd_psf_prssd_data *prssdp;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int rc;
+       unsigned long flags;
+
+       cqr = dasd_kmalloc_request("ECKD",
+                                  1 /* PSF */  + 1 /* RSSD */ ,
+                                  (sizeof(struct dasd_psf_prssd_data)),
+                                  device);
+       if (IS_ERR(cqr))
+               return PTR_ERR(cqr);
+       cqr->startdev = device;
+       cqr->memdev = device;
+       clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+       cqr->retries = 10;
+       cqr->expires = 20 * HZ;
+
+       /* Prepare for Read Subsystem Data */
+       prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+       memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+       prssdp->order = PSF_ORDER_PRSSD;
+       prssdp->suborder = 0x0e;        /* Read unit address configuration */
+       /* all other bytes of prssdp must be zero */
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->count = sizeof(struct dasd_psf_prssd_data);
+       ccw->flags |= CCW_FLAG_CC;
+       ccw->cda = (__u32)(addr_t) prssdp;
+
+       /* Read Subsystem Data - feature codes */
+       memset(lcu->uac, 0, sizeof(*(lcu->uac)));
+
+       ccw++;
+       ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+       ccw->count = sizeof(*(lcu->uac));
+       ccw->cda = (__u32)(addr_t) lcu->uac;
+
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+
+       /* need to unset flag here to detect race with summary unit check */
+       spin_lock_irqsave(&lcu->lock, flags);
+       lcu->flags &= ~NEED_UAC_UPDATE;
+       spin_unlock_irqrestore(&lcu->lock, flags);
+
+       do {
+               rc = dasd_sleep_on(cqr);
+       } while (rc && (cqr->retries > 0));
+       if (rc) {
+               spin_lock_irqsave(&lcu->lock, flags);
+               lcu->flags |= NEED_UAC_UPDATE;
+               spin_unlock_irqrestore(&lcu->lock, flags);
+       }
+       dasd_kfree_request(cqr, cqr->memdev);
+       return rc;
+}
+
+static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
+{
+       unsigned long flags;
+       struct alias_pav_group *pavgroup, *tempgroup;
+       struct dasd_device *device, *tempdev;
+       int i, rc;
+       struct dasd_eckd_private *private;
+
+       spin_lock_irqsave(&lcu->lock, flags);
+       list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) {
+               list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,
+                                        alias_list) {
+                       list_move(&device->alias_list, &lcu->active_devices);
+                       private = (struct dasd_eckd_private *) device->private;
+                       private->pavgroup = NULL;
+               }
+               list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,
+                                        alias_list) {
+                       list_move(&device->alias_list, &lcu->active_devices);
+                       private = (struct dasd_eckd_private *) device->private;
+                       private->pavgroup = NULL;
+               }
+               list_del(&pavgroup->group);
+               kfree(pavgroup);
+       }
+       spin_unlock_irqrestore(&lcu->lock, flags);
+
+       rc = read_unit_address_configuration(refdev, lcu);
+       if (rc)
+               return rc;
+
+       spin_lock_irqsave(&lcu->lock, flags);
+       lcu->pav = NO_PAV;
+       for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
+               switch (lcu->uac->unit[i].ua_type) {
+               case UA_BASE_PAV_ALIAS:
+                       lcu->pav = BASE_PAV;
+                       break;
+               case UA_HYPER_PAV_ALIAS:
+                       lcu->pav = HYPER_PAV;
+                       break;
+               }
+               if (lcu->pav != NO_PAV)
+                       break;
+       }
+
+       list_for_each_entry_safe(device, tempdev, &lcu->active_devices,
+                                alias_list) {
+               _add_device_to_lcu(lcu, device);
+       }
+       spin_unlock_irqrestore(&lcu->lock, flags);
+       return 0;
+}
+
+static void lcu_update_work(struct work_struct *work)
+{
+       struct alias_lcu *lcu;
+       struct read_uac_work_data *ruac_data;
+       struct dasd_device *device;
+       unsigned long flags;
+       int rc;
+
+       ruac_data = container_of(work, struct read_uac_work_data, dwork.work);
+       lcu = container_of(ruac_data, struct alias_lcu, ruac_data);
+       device = ruac_data->device;
+       rc = _lcu_update(device, lcu);
+       /*
+        * Need to check flags again, as there could have been another
+        * prepare_update or a new device a new device while we were still
+        * processing the data
+        */
+       spin_lock_irqsave(&lcu->lock, flags);
+       if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
+               DEV_MESSAGE(KERN_WARNING, device, "could not update"
+                           " alias data in lcu (rc = %d), retry later", rc);
+               schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+       } else {
+               lcu->ruac_data.device = NULL;
+               lcu->flags &= ~UPDATE_PENDING;
+       }
+       spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+static int _schedule_lcu_update(struct alias_lcu *lcu,
+                               struct dasd_device *device)
+{
+       struct dasd_device *usedev = NULL;
+       struct alias_pav_group *group;
+
+       lcu->flags |= NEED_UAC_UPDATE;
+       if (lcu->ruac_data.device) {
+               /* already scheduled or running */
+               return 0;
+       }
+       if (device && !list_empty(&device->alias_list))
+               usedev = device;
+
+       if (!usedev && !list_empty(&lcu->grouplist)) {
+               group = list_first_entry(&lcu->grouplist,
+                                        struct alias_pav_group, group);
+               if (!list_empty(&group->baselist))
+                       usedev = list_first_entry(&group->baselist,
+                                                 struct dasd_device,
+                                                 alias_list);
+               else if (!list_empty(&group->aliaslist))
+                       usedev = list_first_entry(&group->aliaslist,
+                                                 struct dasd_device,
+                                                 alias_list);
+       }
+       if (!usedev && !list_empty(&lcu->active_devices)) {
+               usedev = list_first_entry(&lcu->active_devices,
+                                         struct dasd_device, alias_list);
+       }
+       /*
+        * if we haven't found a proper device yet, give up for now, the next
+        * device that will be set active will trigger an lcu update
+        */
+       if (!usedev)
+               return -EINVAL;
+       lcu->ruac_data.device = usedev;
+       schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+       return 0;
+}
+
+int dasd_alias_add_device(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       struct alias_lcu *lcu;
+       unsigned long flags;
+       int rc;
+
+       private = (struct dasd_eckd_private *) device->private;
+       lcu = private->lcu;
+       rc = 0;
+       spin_lock_irqsave(&lcu->lock, flags);
+       if (!(lcu->flags & UPDATE_PENDING)) {
+               rc = _add_device_to_lcu(lcu, device);
+               if (rc)
+                       lcu->flags |= UPDATE_PENDING;
+       }
+       if (lcu->flags & UPDATE_PENDING) {
+               list_move(&device->alias_list, &lcu->active_devices);
+               _schedule_lcu_update(lcu, device);
+       }
+       spin_unlock_irqrestore(&lcu->lock, flags);
+       return rc;
+}
+
+int dasd_alias_remove_device(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       struct alias_lcu *lcu;
+       unsigned long flags;
+
+       private = (struct dasd_eckd_private *) device->private;
+       lcu = private->lcu;
+       spin_lock_irqsave(&lcu->lock, flags);
+       _remove_device_from_lcu(lcu, device);
+       spin_unlock_irqrestore(&lcu->lock, flags);
+       return 0;
+}
+
+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
+{
+
+       struct dasd_device *alias_device;
+       struct alias_pav_group *group;
+       struct alias_lcu *lcu;
+       struct dasd_eckd_private *private, *alias_priv;
+       unsigned long flags;
+
+       private = (struct dasd_eckd_private *) base_device->private;
+       group = private->pavgroup;
+       lcu = private->lcu;
+       if (!group || !lcu)
+               return NULL;
+       if (lcu->pav == NO_PAV ||
+           lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
+               return NULL;
+
+       spin_lock_irqsave(&lcu->lock, flags);
+       alias_device = group->next;
+       if (!alias_device) {
+               if (list_empty(&group->aliaslist)) {
+                       spin_unlock_irqrestore(&lcu->lock, flags);
+                       return NULL;
+               } else {
+                       alias_device = list_first_entry(&group->aliaslist,
+                                                       struct dasd_device,
+                                                       alias_list);
+               }
+       }
+       if (list_is_last(&alias_device->alias_list, &group->aliaslist))
+               group->next = list_first_entry(&group->aliaslist,
+                                              struct dasd_device, alias_list);
+       else
+               group->next = list_first_entry(&alias_device->alias_list,
+                                              struct dasd_device, alias_list);
+       spin_unlock_irqrestore(&lcu->lock, flags);
+       alias_priv = (struct dasd_eckd_private *) alias_device->private;
+       if ((alias_priv->count < private->count) && !alias_device->stopped)
+               return alias_device;
+       else
+               return NULL;
+}
+
+/*
+ * Summary unit check handling depends on the way alias devices
+ * are handled so it is done here rather then in dasd_eckd.c
+ */
+static int reset_summary_unit_check(struct alias_lcu *lcu,
+                                   struct dasd_device *device,
+                                   char reason)
+{
+       struct dasd_ccw_req *cqr;
+       int rc = 0;
+
+       cqr = lcu->rsu_cqr;
+       strncpy((char *) &cqr->magic, "ECKD", 4);
+       ASCEBC((char *) &cqr->magic, 4);
+       cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK;
+       cqr->cpaddr->flags = 0 ;
+       cqr->cpaddr->count = 16;
+       cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
+       ((char *)cqr->data)[0] = reason;
+
+       clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+       cqr->retries = 255;     /* set retry counter to enable basic ERP */
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       cqr->expires = 5 * HZ;
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+
+       rc = dasd_sleep_on_immediatly(cqr);
+       return rc;
+}
+
+static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
+{
+       struct alias_pav_group *pavgroup;
+       struct dasd_device *device;
+       struct dasd_eckd_private *private;
+
+       /* active and inactive list can contain alias as well as base devices */
+       list_for_each_entry(device, &lcu->active_devices, alias_list) {
+               private = (struct dasd_eckd_private *) device->private;
+               if (private->uid.type != UA_BASE_DEVICE)
+                       continue;
+               dasd_schedule_block_bh(device->block);
+               dasd_schedule_device_bh(device);
+       }
+       list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+               private = (struct dasd_eckd_private *) device->private;
+               if (private->uid.type != UA_BASE_DEVICE)
+                       continue;
+               dasd_schedule_block_bh(device->block);
+               dasd_schedule_device_bh(device);
+       }
+       list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+               list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+                       dasd_schedule_block_bh(device->block);
+                       dasd_schedule_device_bh(device);
+               }
+       }
+}
+
+static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
+{
+       struct alias_pav_group *pavgroup;
+       struct dasd_device *device, *temp;
+       struct dasd_eckd_private *private;
+       int rc;
+       unsigned long flags;
+       LIST_HEAD(active);
+
+       /*
+        * Problem here ist that dasd_flush_device_queue may wait
+        * for termination of a request to complete. We can't keep
+        * the lcu lock during that time, so we must assume that
+        * the lists may have changed.
+        * Idea: first gather all active alias devices in a separate list,
+        * then flush the first element of this list unlocked, and afterwards
+        * check if it is still on the list before moving it to the
+        * active_devices list.
+        */
+
+       spin_lock_irqsave(&lcu->lock, flags);
+       list_for_each_entry_safe(device, temp, &lcu->active_devices,
+                                alias_list) {
+               private = (struct dasd_eckd_private *) device->private;
+               if (private->uid.type == UA_BASE_DEVICE)
+                       continue;
+               list_move(&device->alias_list, &active);
+       }
+
+       list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+               list_splice_init(&pavgroup->aliaslist, &active);
+       }
+       while (!list_empty(&active)) {
+               device = list_first_entry(&active, struct dasd_device,
+                                         alias_list);
+               spin_unlock_irqrestore(&lcu->lock, flags);
+               rc = dasd_flush_device_queue(device);
+               spin_lock_irqsave(&lcu->lock, flags);
+               /*
+                * only move device around if it wasn't moved away while we
+                * were waiting for the flush
+                */
+               if (device == list_first_entry(&active,
+                                              struct dasd_device, alias_list))
+                       list_move(&device->alias_list, &lcu->active_devices);
+       }
+       spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+/*
+ * This function is called in interrupt context, so the
+ * cdev lock for device is already locked!
+ */
+static void _stop_all_devices_on_lcu(struct alias_lcu *lcu,
+                                    struct dasd_device *device)
+{
+       struct alias_pav_group *pavgroup;
+       struct dasd_device *pos;
+
+       list_for_each_entry(pos, &lcu->active_devices, alias_list) {
+               if (pos != device)
+                       spin_lock(get_ccwdev_lock(pos->cdev));
+               pos->stopped |= DASD_STOPPED_SU;
+               if (pos != device)
+                       spin_unlock(get_ccwdev_lock(pos->cdev));
+       }
+       list_for_each_entry(pos, &lcu->inactive_devices, alias_list) {
+               if (pos != device)
+                       spin_lock(get_ccwdev_lock(pos->cdev));
+               pos->stopped |= DASD_STOPPED_SU;
+               if (pos != device)
+                       spin_unlock(get_ccwdev_lock(pos->cdev));
+       }
+       list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+               list_for_each_entry(pos, &pavgroup->baselist, alias_list) {
+                       if (pos != device)
+                               spin_lock(get_ccwdev_lock(pos->cdev));
+                       pos->stopped |= DASD_STOPPED_SU;
+                       if (pos != device)
+                               spin_unlock(get_ccwdev_lock(pos->cdev));
+               }
+               list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) {
+                       if (pos != device)
+                               spin_lock(get_ccwdev_lock(pos->cdev));
+                       pos->stopped |= DASD_STOPPED_SU;
+                       if (pos != device)
+                               spin_unlock(get_ccwdev_lock(pos->cdev));
+               }
+       }
+}
+
+static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
+{
+       struct alias_pav_group *pavgroup;
+       struct dasd_device *device;
+       unsigned long flags;
+
+       list_for_each_entry(device, &lcu->active_devices, alias_list) {
+               spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+               device->stopped &= ~DASD_STOPPED_SU;
+               spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       }
+
+       list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+               spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+               device->stopped &= ~DASD_STOPPED_SU;
+               spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       }
+
+       list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+               list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+                       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+                       device->stopped &= ~DASD_STOPPED_SU;
+                       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+                                              flags);
+               }
+               list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+                       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+                       device->stopped &= ~DASD_STOPPED_SU;
+                       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+                                              flags);
+               }
+       }
+}
+
+static void summary_unit_check_handling_work(struct work_struct *work)
+{
+       struct alias_lcu *lcu;
+       struct summary_unit_check_work_data *suc_data;
+       unsigned long flags;
+       struct dasd_device *device;
+
+       suc_data = container_of(work, struct summary_unit_check_work_data,
+                               worker);
+       lcu = container_of(suc_data, struct alias_lcu, suc_data);
+       device = suc_data->device;
+
+       /* 1. flush alias devices */
+       flush_all_alias_devices_on_lcu(lcu);
+
+       /* 2. reset summary unit check */
+       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+       device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
+       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       reset_summary_unit_check(lcu, device, suc_data->reason);
+
+       spin_lock_irqsave(&lcu->lock, flags);
+       _unstop_all_devices_on_lcu(lcu);
+       _restart_all_base_devices_on_lcu(lcu);
+       /* 3. read new alias configuration */
+       _schedule_lcu_update(lcu, device);
+       lcu->suc_data.device = NULL;
+       spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+/*
+ * note: this will be called from int handler context (cdev locked)
+ */
+void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
+                                         struct irb *irb)
+{
+       struct alias_lcu *lcu;
+       char reason;
+       struct dasd_eckd_private *private;
+
+       private = (struct dasd_eckd_private *) device->private;
+
+       reason = irb->ecw[8];
+       DEV_MESSAGE(KERN_WARNING, device, "%s %x",
+                   "eckd handle summary unit check: reason", reason);
+
+       lcu = private->lcu;
+       if (!lcu) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                           "device not ready to handle summary"
+                           " unit check (no lcu structure)");
+               return;
+       }
+       spin_lock(&lcu->lock);
+       _stop_all_devices_on_lcu(lcu, device);
+       /* prepare for lcu_update */
+       private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
+       /* If this device is about to be removed just return and wait for
+        * the next interrupt on a different device
+        */
+       if (list_empty(&device->alias_list)) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                           "device is in offline processing,"
+                           " don't do summary unit check handling");
+               spin_unlock(&lcu->lock);
+               return;
+       }
+       if (lcu->suc_data.device) {
+               /* already scheduled or running */
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                           "previous instance of summary unit check worker"
+                           " still pending");
+               spin_unlock(&lcu->lock);
+               return ;
+       }
+       lcu->suc_data.reason = reason;
+       lcu->suc_data.device = device;
+       spin_unlock(&lcu->lock);
+       schedule_work(&lcu->suc_data.worker);
+};
index 0c67258fb9ec07cb6351edb1a4ee307848f4db67..f4fb40257348e3bd3e42b59b1061332233e1eed0 100644 (file)
@@ -48,22 +48,6 @@ struct dasd_devmap {
        struct dasd_uid uid;
 };
 
-/*
- * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
- * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
- * the DASD device driver.
- */
-struct dasd_server_ssid_map {
-       struct list_head list;
-       struct system_id {
-               char vendor[4];
-               char serial[15];
-               __u16 ssid;
-       } sid;
-};
-
-static struct list_head dasd_server_ssid_list;
-
 /*
  * Parameter parsing functions for dasd= parameter. The syntax is:
  *   <devno>           : (0x)?[0-9a-fA-F]+
@@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
                devmap->features &= ~DASD_FEATURE_READONLY;
        if (devmap->device)
                devmap->device->features = devmap->features;
-       if (devmap->device && devmap->device->gdp)
-               set_disk_ro(devmap->device->gdp, val);
+       if (devmap->device && devmap->device->block
+           && devmap->device->block->gdp)
+               set_disk_ro(devmap->device->block->gdp, val);
        spin_unlock(&dasd_devmap_lock);
        return count;
 }
@@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
 
        devmap = dasd_find_busid(dev->bus_id);
        spin_lock(&dasd_devmap_lock);
-       if (!IS_ERR(devmap))
-               alias = devmap->uid.alias;
+       if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
+               spin_unlock(&dasd_devmap_lock);
+               return sprintf(buf, "0\n");
+       }
+       if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
+           devmap->uid.type == UA_HYPER_PAV_ALIAS)
+               alias = 1;
        else
                alias = 0;
        spin_unlock(&dasd_devmap_lock);
-
        return sprintf(buf, alias ? "1\n" : "0\n");
 }
 
@@ -930,19 +919,36 @@ static ssize_t
 dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct dasd_devmap *devmap;
-       char uid[UID_STRLEN];
+       char uid_string[UID_STRLEN];
+       char ua_string[3];
+       struct dasd_uid *uid;
 
        devmap = dasd_find_busid(dev->bus_id);
        spin_lock(&dasd_devmap_lock);
-       if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
-               snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
-                        devmap->uid.vendor, devmap->uid.serial,
-                        devmap->uid.ssid, devmap->uid.unit_addr);
-       else
-               uid[0] = 0;
+       if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
+               spin_unlock(&dasd_devmap_lock);
+               return sprintf(buf, "\n");
+       }
+       uid = &devmap->uid;
+       switch (uid->type) {
+       case UA_BASE_DEVICE:
+               sprintf(ua_string, "%02x", uid->real_unit_addr);
+               break;
+       case UA_BASE_PAV_ALIAS:
+               sprintf(ua_string, "%02x", uid->base_unit_addr);
+               break;
+       case UA_HYPER_PAV_ALIAS:
+               sprintf(ua_string, "xx");
+               break;
+       default:
+               /* should not happen, treat like base device */
+               sprintf(ua_string, "%02x", uid->real_unit_addr);
+               break;
+       }
+       snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
+                uid->vendor, uid->serial, uid->ssid, ua_string);
        spin_unlock(&dasd_devmap_lock);
-
-       return snprintf(buf, PAGE_SIZE, "%s\n", uid);
+       return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
 }
 
 static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
@@ -1040,39 +1046,16 @@ int
 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 {
        struct dasd_devmap *devmap;
-       struct dasd_server_ssid_map *srv, *tmp;
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
                return PTR_ERR(devmap);
 
-       /* generate entry for server_ssid_map */
-       srv = (struct dasd_server_ssid_map *)
-               kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
-       if (!srv)
-               return -ENOMEM;
-       strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
-       strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
-       srv->sid.ssid = uid->ssid;
-
-       /* server is already contained ? */
        spin_lock(&dasd_devmap_lock);
        devmap->uid = *uid;
-       list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
-               if (!memcmp(&srv->sid, &tmp->sid,
-                           sizeof(struct system_id))) {
-                       kfree(srv);
-                       srv = NULL;
-                       break;
-               }
-       }
-
-       /* add servermap to serverlist */
-       if (srv)
-               list_add(&srv->list, &dasd_server_ssid_list);
        spin_unlock(&dasd_devmap_lock);
 
-       return (srv ? 1 : 0);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(dasd_set_uid);
 
@@ -1138,9 +1121,6 @@ dasd_devmap_init(void)
        dasd_max_devindex = 0;
        for (i = 0; i < 256; i++)
                INIT_LIST_HEAD(&dasd_hashlists[i]);
-
-       /* Initialize servermap structure. */
-       INIT_LIST_HEAD(&dasd_server_ssid_list);
        return 0;
 }
 
index 571320ab9e1ace333ac4c9f78c98a59379b9cc03..d91df38ee4f7cb4ed418a043e689fc95126e8c7e 100644 (file)
@@ -142,7 +142,7 @@ dasd_diag_erp(struct dasd_device *device)
        int rc;
 
        mdsk_term_io(device);
-       rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+       rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
        if (rc)
                DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
                            "rc=%d", rc);
@@ -158,11 +158,11 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
        struct dasd_diag_req *dreq;
        int rc;
 
-       device = cqr->device;
+       device = cqr->startdev;
        if (cqr->retries < 0) {
                DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
                            "- no retry left)", cqr);
-               cqr->status = DASD_CQR_FAILED;
+               cqr->status = DASD_CQR_ERROR;
                return -EIO;
        }
        private = (struct dasd_diag_private *) device->private;
@@ -184,7 +184,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
        switch (rc) {
        case 0: /* Synchronous I/O finished successfully */
                cqr->stopclk = get_clock();
-               cqr->status = DASD_CQR_DONE;
+               cqr->status = DASD_CQR_SUCCESS;
                /* Indicate to calling function that only a dasd_schedule_bh()
                   and no timer is needed */
                 rc = -EACCES;
@@ -209,12 +209,12 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
 {
        struct dasd_device *device;
 
-       device = cqr->device;
+       device = cqr->startdev;
        mdsk_term_io(device);
-       mdsk_init_io(device, device->bp_block, 0, NULL);
-       cqr->status = DASD_CQR_CLEAR;
+       mdsk_init_io(device, device->block->bp_block, 0, NULL);
+       cqr->status = DASD_CQR_CLEAR_PENDING;
        cqr->stopclk = get_clock();
-       dasd_schedule_bh(device);
+       dasd_schedule_device_bh(device);
        return 0;
 }
 
@@ -247,7 +247,7 @@ dasd_ext_handler(__u16 code)
                return;
        }
        cqr = (struct dasd_ccw_req *) ip;
-       device = (struct dasd_device *) cqr->device;
+       device = (struct dasd_device *) cqr->startdev;
        if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
                DEV_MESSAGE(KERN_WARNING, device,
                            " magic number of dasd_ccw_req 0x%08X doesn't"
@@ -260,10 +260,10 @@ dasd_ext_handler(__u16 code)
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 
        /* Check for a pending clear operation */
-       if (cqr->status == DASD_CQR_CLEAR) {
-               cqr->status = DASD_CQR_QUEUED;
-               dasd_clear_timer(device);
-               dasd_schedule_bh(device);
+       if (cqr->status == DASD_CQR_CLEAR_PENDING) {
+               cqr->status = DASD_CQR_CLEARED;
+               dasd_device_clear_timer(device);
+               dasd_schedule_device_bh(device);
                spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
                return;
        }
@@ -272,11 +272,11 @@ dasd_ext_handler(__u16 code)
 
        expires = 0;
        if (status == 0) {
-               cqr->status = DASD_CQR_DONE;
+               cqr->status = DASD_CQR_SUCCESS;
                /* Start first request on queue if possible -> fast_io. */
                if (!list_empty(&device->ccw_queue)) {
                        next = list_entry(device->ccw_queue.next,
-                                         struct dasd_ccw_req, list);
+                                         struct dasd_ccw_req, devlist);
                        if (next->status == DASD_CQR_QUEUED) {
                                rc = dasd_start_diag(next);
                                if (rc == 0)
@@ -296,10 +296,10 @@ dasd_ext_handler(__u16 code)
        }
 
        if (expires != 0)
-               dasd_set_timer(device, expires);
+               dasd_device_set_timer(device, expires);
        else
-               dasd_clear_timer(device);
-       dasd_schedule_bh(device);
+               dasd_device_clear_timer(device);
+       dasd_schedule_device_bh(device);
 
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
@@ -309,6 +309,7 @@ dasd_ext_handler(__u16 code)
 static int
 dasd_diag_check_device(struct dasd_device *device)
 {
+       struct dasd_block *block;
        struct dasd_diag_private *private;
        struct dasd_diag_characteristics *rdc_data;
        struct dasd_diag_bio bio;
@@ -328,6 +329,16 @@ dasd_diag_check_device(struct dasd_device *device)
                ccw_device_get_id(device->cdev, &private->dev_id);
                device->private = (void *) private;
        }
+       block = dasd_alloc_block();
+       if (IS_ERR(block)) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                           "could not allocate dasd block structure");
+               kfree(device->private);
+               return PTR_ERR(block);
+       }
+       device->block = block;
+       block->base = device;
+
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
        rdc_data->dev_nr = private->dev_id.devno;
@@ -409,14 +420,14 @@ dasd_diag_check_device(struct dasd_device *device)
                  sizeof(DASD_DIAG_CMS1)) == 0) {
                /* get formatted blocksize from label block */
                bsize = (unsigned int) label->block_size;
-               device->blocks = (unsigned long) label->block_count;
+               block->blocks = (unsigned long) label->block_count;
        } else
-               device->blocks = end_block;
-       device->bp_block = bsize;
-       device->s2b_shift = 0;  /* bits to shift 512 to get a block */
+               block->blocks = end_block;
+       block->bp_block = bsize;
+       block->s2b_shift = 0;   /* bits to shift 512 to get a block */
        for (sb = 512; sb < bsize; sb = sb << 1)
-               device->s2b_shift++;
-       rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+               block->s2b_shift++;
+       rc = mdsk_init_io(device, block->bp_block, 0, NULL);
        if (rc) {
                DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
                        "failed (rc=%d)", rc);
@@ -424,9 +435,9 @@ dasd_diag_check_device(struct dasd_device *device)
        } else {
                DEV_MESSAGE(KERN_INFO, device,
                            "(%ld B/blk): %ldkB",
-                           (unsigned long) device->bp_block,
-                           (unsigned long) (device->blocks <<
-                               device->s2b_shift) >> 1);
+                           (unsigned long) block->bp_block,
+                           (unsigned long) (block->blocks <<
+                               block->s2b_shift) >> 1);
        }
 out:
        free_page((long) label);
@@ -436,22 +447,16 @@ out:
 /* Fill in virtual disk geometry for device. Return zero on success, non-zero
  * otherwise. */
 static int
-dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 {
-       if (dasd_check_blocksize(device->bp_block) != 0)
+       if (dasd_check_blocksize(block->bp_block) != 0)
                return -EINVAL;
-       geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
+       geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
        geo->heads = 16;
-       geo->sectors = 128 >> device->s2b_shift;
+       geo->sectors = 128 >> block->s2b_shift;
        return 0;
 }
 
-static dasd_era_t
-dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat)
-{
-       return dasd_era_fatal;
-}
-
 static dasd_erp_fn_t
 dasd_diag_erp_action(struct dasd_ccw_req * cqr)
 {
@@ -466,8 +471,9 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
 
 /* Create DASD request from block device request. Return pointer to new
  * request on success, ERR_PTR otherwise. */
-static struct dasd_ccw_req *
-dasd_diag_build_cp(struct dasd_device * device, struct request *req)
+static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
+                                              struct dasd_block *block,
+                                              struct request *req)
 {
        struct dasd_ccw_req *cqr;
        struct dasd_diag_req *dreq;
@@ -486,17 +492,17 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
                rw_cmd = MDSK_WRITE_REQ;
        else
                return ERR_PTR(-EINVAL);
-       blksize = device->bp_block;
+       blksize = block->bp_block;
        /* Calculate record id of first and last block. */
-       first_rec = req->sector >> device->s2b_shift;
-       last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+       first_rec = req->sector >> block->s2b_shift;
+       last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
        /* Check struct bio and count the number of blocks for the request. */
        count = 0;
        rq_for_each_segment(bv, req, iter) {
                if (bv->bv_len & (blksize - 1))
                        /* Fba can only do full blocks. */
                        return ERR_PTR(-EINVAL);
-               count += bv->bv_len >> (device->s2b_shift + 9);
+               count += bv->bv_len >> (block->s2b_shift + 9);
        }
        /* Paranoia. */
        if (count != last_rec - first_rec + 1)
@@ -505,7 +511,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
        datasize = sizeof(struct dasd_diag_req) +
                count*sizeof(struct dasd_diag_bio);
        cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
-                                  datasize, device);
+                                  datasize, memdev);
        if (IS_ERR(cqr))
                return cqr;
 
@@ -529,7 +535,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
        cqr->buildclk = get_clock();
        if (req->cmd_flags & REQ_FAILFAST)
                set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-       cqr->device = device;
+       cqr->startdev = memdev;
+       cqr->memdev = memdev;
+       cqr->block = block;
        cqr->expires = DIAG_TIMEOUT;
        cqr->status = DASD_CQR_FILLED;
        return cqr;
@@ -543,10 +551,15 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        int status;
 
        status = cqr->status == DASD_CQR_DONE;
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return status;
 }
 
+static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
+{
+       cqr->status = DASD_CQR_FILLED;
+};
+
 /* Fill in IOCTL data for device. */
 static int
 dasd_diag_fill_info(struct dasd_device * device,
@@ -583,7 +596,7 @@ static struct dasd_discipline dasd_diag_discipline = {
        .fill_geometry = dasd_diag_fill_geometry,
        .start_IO = dasd_start_diag,
        .term_IO = dasd_diag_term_IO,
-       .examine_error = dasd_diag_examine_error,
+       .handle_terminated_request = dasd_diag_handle_terminated_request,
        .erp_action = dasd_diag_erp_action,
        .erp_postaction = dasd_diag_erp_postaction,
        .build_cp = dasd_diag_build_cp,
index 44adf8496bda6e238f3ca106a5bf804f96f64ecc..61f16937c1e0d8d8756186b76abfa57ab4aa2324 100644 (file)
@@ -52,16 +52,6 @@ MODULE_LICENSE("GPL");
 
 static struct dasd_discipline dasd_eckd_discipline;
 
-struct dasd_eckd_private {
-       struct dasd_eckd_characteristics rdc_data;
-       struct dasd_eckd_confdata conf_data;
-       struct dasd_eckd_path path_data;
-       struct eckd_count count_area[5];
-       int init_cqr_status;
-       int uses_cdl;
-       struct attrib_data_t attrib;    /* e.g. cache operations */
-};
-
 /* The ccw bus type uses this table to find devices that it sends to
  * dasd_eckd_probe */
 static struct ccw_device_id dasd_eckd_ids[] = {
@@ -188,7 +178,7 @@ check_XRC (struct ccw1         *de_ccw,
        if (rc == -ENOSYS || rc == -EACCES)
                rc = 0;
 
-       de_ccw->count = sizeof (struct DE_eckd_data);
+       de_ccw->count = sizeof(struct DE_eckd_data);
        de_ccw->flags |= CCW_FLAG_SLI;
        return rc;
 }
@@ -208,7 +198,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        ccw->count = 16;
        ccw->cda = (__u32) __pa(data);
 
-       memset(data, 0, sizeof (struct DE_eckd_data));
+       memset(data, 0, sizeof(struct DE_eckd_data));
        switch (cmd) {
        case DASD_ECKD_CCW_READ_HOME_ADDRESS:
        case DASD_ECKD_CCW_READ_RECORD_ZERO:
@@ -280,6 +270,132 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        return rc;
 }
 
+static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
+                              struct dasd_device  *device)
+{
+       struct dasd_eckd_private *private;
+       int rc;
+
+       private = (struct dasd_eckd_private *) device->private;
+       if (!private->rdc_data.facilities.XRC_supported)
+               return 0;
+
+       /* switch on System Time Stamp - needed for XRC Support */
+       pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid'   */
+       pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */
+       pfxdata->validity.time_stamp = 1;           /* 'Time Stamp Valid'   */
+
+       rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time);
+       /* Ignore return code if sync clock is switched off. */
+       if (rc == -ENOSYS || rc == -EACCES)
+               rc = 0;
+       return rc;
+}
+
+static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
+                 int totrk, int cmd, struct dasd_device *basedev,
+                 struct dasd_device *startdev)
+{
+       struct dasd_eckd_private *basepriv, *startpriv;
+       struct DE_eckd_data *data;
+       struct ch_t geo, beg, end;
+       int rc = 0;
+
+       basepriv = (struct dasd_eckd_private *) basedev->private;
+       startpriv = (struct dasd_eckd_private *) startdev->private;
+       data = &pfxdata->define_extend;
+
+       ccw->cmd_code = DASD_ECKD_CCW_PFX;
+       ccw->flags = 0;
+       ccw->count = sizeof(*pfxdata);
+       ccw->cda = (__u32) __pa(pfxdata);
+
+       memset(pfxdata, 0, sizeof(*pfxdata));
+       /* prefix data */
+       pfxdata->format = 0;
+       pfxdata->base_address = basepriv->conf_data.ned1.unit_addr;
+       pfxdata->base_lss = basepriv->conf_data.ned1.ID;
+       pfxdata->validity.define_extend = 1;
+
+       /* private uid is kept up to date, conf_data may be outdated */
+       if (startpriv->uid.type != UA_BASE_DEVICE) {
+               pfxdata->validity.verify_base = 1;
+               if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
+                       pfxdata->validity.hyper_pav = 1;
+       }
+
+       /* define extend data (mostly)*/
+       switch (cmd) {
+       case DASD_ECKD_CCW_READ_HOME_ADDRESS:
+       case DASD_ECKD_CCW_READ_RECORD_ZERO:
+       case DASD_ECKD_CCW_READ:
+       case DASD_ECKD_CCW_READ_MT:
+       case DASD_ECKD_CCW_READ_CKD:
+       case DASD_ECKD_CCW_READ_CKD_MT:
+       case DASD_ECKD_CCW_READ_KD:
+       case DASD_ECKD_CCW_READ_KD_MT:
+       case DASD_ECKD_CCW_READ_COUNT:
+               data->mask.perm = 0x1;
+               data->attributes.operation = basepriv->attrib.operation;
+               break;
+       case DASD_ECKD_CCW_WRITE:
+       case DASD_ECKD_CCW_WRITE_MT:
+       case DASD_ECKD_CCW_WRITE_KD:
+       case DASD_ECKD_CCW_WRITE_KD_MT:
+               data->mask.perm = 0x02;
+               data->attributes.operation = basepriv->attrib.operation;
+               rc = check_XRC_on_prefix(pfxdata, basedev);
+               break;
+       case DASD_ECKD_CCW_WRITE_CKD:
+       case DASD_ECKD_CCW_WRITE_CKD_MT:
+               data->attributes.operation = DASD_BYPASS_CACHE;
+               rc = check_XRC_on_prefix(pfxdata, basedev);
+               break;
+       case DASD_ECKD_CCW_ERASE:
+       case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
+       case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
+               data->mask.perm = 0x3;
+               data->mask.auth = 0x1;
+               data->attributes.operation = DASD_BYPASS_CACHE;
+               rc = check_XRC_on_prefix(pfxdata, basedev);
+               break;
+       default:
+               DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd);
+               break;
+       }
+
+       data->attributes.mode = 0x3;    /* ECKD */
+
+       if ((basepriv->rdc_data.cu_type == 0x2105 ||
+            basepriv->rdc_data.cu_type == 0x2107 ||
+            basepriv->rdc_data.cu_type == 0x1750)
+           && !(basepriv->uses_cdl && trk < 2))
+               data->ga_extended |= 0x40; /* Regular Data Format Mode */
+
+       geo.cyl = basepriv->rdc_data.no_cyl;
+       geo.head = basepriv->rdc_data.trk_per_cyl;
+       beg.cyl = trk / geo.head;
+       beg.head = trk % geo.head;
+       end.cyl = totrk / geo.head;
+       end.head = totrk % geo.head;
+
+       /* check for sequential prestage - enhance cylinder range */
+       if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
+           data->attributes.operation == DASD_SEQ_ACCESS) {
+
+               if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl)
+                       end.cyl += basepriv->attrib.nr_cyl;
+               else
+                       end.cyl = (geo.cyl - 1);
+       }
+
+       data->beg_ext.cyl = beg.cyl;
+       data->beg_ext.head = beg.head;
+       data->end_ext.cyl = end.cyl;
+       data->end_ext.head = end.head;
+       return rc;
+}
+
 static void
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
              int rec_on_trk, int no_rec, int cmd,
@@ -300,7 +416,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
        ccw->count = 16;
        ccw->cda = (__u32) __pa(data);
 
-       memset(data, 0, sizeof (struct LO_eckd_data));
+       memset(data, 0, sizeof(struct LO_eckd_data));
        sector = 0;
        if (rec_on_trk) {
                switch (private->rdc_data.dev_type) {
@@ -441,12 +557,15 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
               sizeof(uid->serial) - 1);
        EBCASC(uid->serial, sizeof(uid->serial) - 1);
        uid->ssid = confdata->neq.subsystemID;
-       if (confdata->ned2.sneq.flags == 0x40) {
-               uid->alias = 1;
-               uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
-       } else
-               uid->unit_addr = confdata->ned1.unit_addr;
-
+       uid->real_unit_addr = confdata->ned1.unit_addr;
+       if (confdata->ned2.sneq.flags == 0x40 &&
+           confdata->ned2.sneq.format == 0x0001) {
+               uid->type = confdata->ned2.sneq.sua_flags;
+               if (uid->type == UA_BASE_PAV_ALIAS)
+                       uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr;
+       } else {
+               uid->type = UA_BASE_DEVICE;
+       }
        return 0;
 }
 
@@ -470,7 +589,9 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
        ccw->cda = (__u32)(addr_t)rcd_buffer;
        ccw->count = ciw->count;
 
-       cqr->device = device;
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
        cqr->expires = 10*HZ;
        cqr->lpm = lpm;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -511,7 +632,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
        /*
         * on success we update the user input parms
         */
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        if (ret)
                goto out_error;
 
@@ -557,19 +678,19 @@ dasd_eckd_read_conf(struct dasd_device *device)
                                        "data retrieved");
                                continue;       /* no error */
                        }
-                       if (conf_len != sizeof (struct dasd_eckd_confdata)) {
+                       if (conf_len != sizeof(struct dasd_eckd_confdata)) {
                                MESSAGE(KERN_WARNING,
                                        "sizes of configuration data mismatch"
                                        "%d (read) vs %ld (expected)",
                                        conf_len,
-                                       sizeof (struct dasd_eckd_confdata));
+                                       sizeof(struct dasd_eckd_confdata));
                                kfree(conf_data);
                                continue;       /* no error */
                        }
                        /* save first valid configuration data */
                        if (!conf_data_saved){
                                memcpy(&private->conf_data, conf_data,
-                                      sizeof (struct dasd_eckd_confdata));
+                                      sizeof(struct dasd_eckd_confdata));
                                conf_data_saved++;
                        }
                        switch (((char *)conf_data)[242] & 0x07){
@@ -586,39 +707,104 @@ dasd_eckd_read_conf(struct dasd_device *device)
        return 0;
 }
 
+static int dasd_eckd_read_features(struct dasd_device *device)
+{
+       struct dasd_psf_prssd_data *prssdp;
+       struct dasd_rssd_features *features;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int rc;
+       struct dasd_eckd_private *private;
+
+       private = (struct dasd_eckd_private *) device->private;
+       cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+                                  1 /* PSF */  + 1 /* RSSD */ ,
+                                  (sizeof(struct dasd_psf_prssd_data) +
+                                   sizeof(struct dasd_rssd_features)),
+                                  device);
+       if (IS_ERR(cqr)) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                           "Could not allocate initialization request");
+               return PTR_ERR(cqr);
+       }
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+       cqr->retries = 5;
+       cqr->expires = 10 * HZ;
+
+       /* Prepare for Read Subsystem Data */
+       prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+       memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+       prssdp->order = PSF_ORDER_PRSSD;
+       prssdp->suborder = 0x41;        /* Read Feature Codes */
+       /* all other bytes of prssdp must be zero */
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->count = sizeof(struct dasd_psf_prssd_data);
+       ccw->flags |= CCW_FLAG_CC;
+       ccw->cda = (__u32)(addr_t) prssdp;
+
+       /* Read Subsystem Data - feature codes */
+       features = (struct dasd_rssd_features *) (prssdp + 1);
+       memset(features, 0, sizeof(struct dasd_rssd_features));
+
+       ccw++;
+       ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+       ccw->count = sizeof(struct dasd_rssd_features);
+       ccw->cda = (__u32)(addr_t) features;
+
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+       rc = dasd_sleep_on(cqr);
+       if (rc == 0) {
+               prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+               features = (struct dasd_rssd_features *) (prssdp + 1);
+               memcpy(&private->features, features,
+                      sizeof(struct dasd_rssd_features));
+       }
+       dasd_sfree_request(cqr, cqr->memdev);
+       return rc;
+}
+
+
 /*
  * Build CP for Perform Subsystem Function - SSC.
  */
-static struct dasd_ccw_req *
-dasd_eckd_build_psf_ssc(struct dasd_device *device)
+static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       struct dasd_psf_ssc_data *psf_ssc_data;
-       struct ccw1 *ccw;
+       struct dasd_ccw_req *cqr;
+       struct dasd_psf_ssc_data *psf_ssc_data;
+       struct ccw1 *ccw;
 
-       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
                                  sizeof(struct dasd_psf_ssc_data),
                                  device);
 
-       if (IS_ERR(cqr)) {
-              DEV_MESSAGE(KERN_WARNING, device, "%s",
+       if (IS_ERR(cqr)) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
                           "Could not allocate PSF-SSC request");
-              return cqr;
-       }
-       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
-       psf_ssc_data->order = PSF_ORDER_SSC;
-       psf_ssc_data->suborder = 0x08;
-
-       ccw = cqr->cpaddr;
-       ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->cda = (__u32)(addr_t)psf_ssc_data;
-       ccw->count = 66;
-
-       cqr->device = device;
-       cqr->expires = 10*HZ;
-       cqr->buildclk = get_clock();
-       cqr->status = DASD_CQR_FILLED;
-       return cqr;
+               return cqr;
+       }
+       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+       psf_ssc_data->order = PSF_ORDER_SSC;
+       psf_ssc_data->suborder = 0x88;
+       psf_ssc_data->reserved[0] = 0x88;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->cda = (__u32)(addr_t)psf_ssc_data;
+       ccw->count = 66;
+
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       cqr->expires = 10*HZ;
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+       return cqr;
 }
 
 /*
@@ -629,28 +815,28 @@ dasd_eckd_build_psf_ssc(struct dasd_device *device)
 static int
 dasd_eckd_psf_ssc(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       int rc;
-
-       cqr = dasd_eckd_build_psf_ssc(device);
-       if (IS_ERR(cqr))
-              return PTR_ERR(cqr);
-
-       rc = dasd_sleep_on(cqr);
-       if (!rc)
-              /* trigger CIO to reprobe devices */
-              css_schedule_reprobe();
-       dasd_sfree_request(cqr, cqr->device);
-       return rc;
+       struct dasd_ccw_req *cqr;
+       int rc;
+
+       cqr = dasd_eckd_build_psf_ssc(device);
+       if (IS_ERR(cqr))
+               return PTR_ERR(cqr);
+
+       rc = dasd_sleep_on(cqr);
+       if (!rc)
+               /* trigger CIO to reprobe devices */
+               css_schedule_reprobe();
+       dasd_sfree_request(cqr, cqr->memdev);
+       return rc;
 }
 
 /*
  * Valide storage server of current device.
  */
-static int
-dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
+static int dasd_eckd_validate_server(struct dasd_device *device)
 {
        int rc;
+       struct dasd_eckd_private *private;
 
        /* Currently PAV is the only reason to 'validate' server on LPAR */
        if (dasd_nopav || MACHINE_IS_VM)
@@ -659,9 +845,11 @@ dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
        rc = dasd_eckd_psf_ssc(device);
        /* may be requested feature is not available on server,
         * therefore just report error and go ahead */
+       private = (struct dasd_eckd_private *) device->private;
        DEV_MESSAGE(KERN_INFO, device,
                    "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
-                   uid->vendor, uid->serial, uid->ssid, rc);
+                   private->uid.vendor, private->uid.serial,
+                   private->uid.ssid, rc);
        /* RE-Read Configuration Data */
        return dasd_eckd_read_conf(device);
 }
@@ -674,9 +862,9 @@ static int
 dasd_eckd_check_characteristics(struct dasd_device *device)
 {
        struct dasd_eckd_private *private;
-       struct dasd_uid uid;
+       struct dasd_block *block;
        void *rdc_data;
-       int rc;
+       int is_known, rc;
 
        private = (struct dasd_eckd_private *) device->private;
        if (private == NULL) {
@@ -699,27 +887,54 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        /* Read Configuration Data */
        rc = dasd_eckd_read_conf(device);
        if (rc)
-               return rc;
+               goto out_err1;
 
        /* Generate device unique id and register in devmap */
-       rc = dasd_eckd_generate_uid(device, &uid);
+       rc = dasd_eckd_generate_uid(device, &private->uid);
        if (rc)
-               return rc;
-       rc = dasd_set_uid(device->cdev, &uid);
-       if (rc == 1)    /* new server found */
-               rc = dasd_eckd_validate_server(device, &uid);
+               goto out_err1;
+       dasd_set_uid(device->cdev, &private->uid);
+
+       if (private->uid.type == UA_BASE_DEVICE) {
+               block = dasd_alloc_block();
+               if (IS_ERR(block)) {
+                       DEV_MESSAGE(KERN_WARNING, device, "%s",
+                                   "could not allocate dasd block structure");
+                       rc = PTR_ERR(block);
+                       goto out_err1;
+               }
+               device->block = block;
+               block->base = device;
+       }
+
+       /* register lcu with alias handling, enable PAV if this is a new lcu */
+       is_known = dasd_alias_make_device_known_to_lcu(device);
+       if (is_known < 0) {
+               rc = is_known;
+               goto out_err2;
+       }
+       if (!is_known) {
+               /* new lcu found */
+               rc = dasd_eckd_validate_server(device); /* will switch pav on */
+               if (rc)
+                       goto out_err3;
+       }
+
+       /* Read Feature Codes */
+       rc = dasd_eckd_read_features(device);
        if (rc)
-               return rc;
+               goto out_err3;
 
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
        memset(rdc_data, 0, sizeof(rdc_data));
        rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
-       if (rc)
+       if (rc) {
                DEV_MESSAGE(KERN_WARNING, device,
                            "Read device characteristics returned "
                            "rc=%d", rc);
-
+               goto out_err3;
+       }
        DEV_MESSAGE(KERN_INFO, device,
                    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
                    private->rdc_data.dev_type,
@@ -729,9 +944,24 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                    private->rdc_data.no_cyl,
                    private->rdc_data.trk_per_cyl,
                    private->rdc_data.sec_per_trk);
+       return 0;
+
+out_err3:
+       dasd_alias_disconnect_device_from_lcu(device);
+out_err2:
+       dasd_free_block(device->block);
+       device->block = NULL;
+out_err1:
+       kfree(device->private);
+       device->private = NULL;
        return rc;
 }
 
+static void dasd_eckd_uncheck_device(struct dasd_device *device)
+{
+       dasd_alias_disconnect_device_from_lcu(device);
+}
+
 static struct dasd_ccw_req *
 dasd_eckd_analysis_ccw(struct dasd_device *device)
 {
@@ -755,7 +985,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
        /* Define extent for the first 3 tracks. */
        define_extent(ccw++, cqr->data, 0, 2,
                      DASD_ECKD_CCW_READ_COUNT, device);
-       LO_data = cqr->data + sizeof (struct DE_eckd_data);
+       LO_data = cqr->data + sizeof(struct DE_eckd_data);
        /* Locate record for the first 4 records on track 0. */
        ccw[-1].flags |= CCW_FLAG_CC;
        locate_record(ccw++, LO_data++, 0, 0, 4,
@@ -783,7 +1013,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
        ccw->count = 8;
        ccw->cda = (__u32)(addr_t) count_data;
 
-       cqr->device = device;
+       cqr->block = NULL;
+       cqr->startdev = device;
+       cqr->memdev = device;
        cqr->retries = 0;
        cqr->buildclk = get_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -803,7 +1035,7 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
        struct dasd_eckd_private *private;
        struct dasd_device *device;
 
-       device = init_cqr->device;
+       device = init_cqr->startdev;
        private = (struct dasd_eckd_private *) device->private;
        private->init_cqr_status = init_cqr->status;
        dasd_sfree_request(init_cqr, device);
@@ -811,13 +1043,13 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
 }
 
 static int
-dasd_eckd_start_analysis(struct dasd_device *device)
+dasd_eckd_start_analysis(struct dasd_block *block)
 {
        struct dasd_eckd_private *private;
        struct dasd_ccw_req *init_cqr;
 
-       private = (struct dasd_eckd_private *) device->private;
-       init_cqr = dasd_eckd_analysis_ccw(device);
+       private = (struct dasd_eckd_private *) block->base->private;
+       init_cqr = dasd_eckd_analysis_ccw(block->base);
        if (IS_ERR(init_cqr))
                return PTR_ERR(init_cqr);
        init_cqr->callback = dasd_eckd_analysis_callback;
@@ -828,13 +1060,15 @@ dasd_eckd_start_analysis(struct dasd_device *device)
 }
 
 static int
-dasd_eckd_end_analysis(struct dasd_device *device)
+dasd_eckd_end_analysis(struct dasd_block *block)
 {
+       struct dasd_device *device;
        struct dasd_eckd_private *private;
        struct eckd_count *count_area;
        unsigned int sb, blk_per_trk;
        int status, i;
 
+       device = block->base;
        private = (struct dasd_eckd_private *) device->private;
        status = private->init_cqr_status;
        private->init_cqr_status = -1;
@@ -846,7 +1080,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
 
        private->uses_cdl = 1;
        /* Calculate number of blocks/records per track. */
-       blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
+       blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
        /* Check Track 0 for Compatible Disk Layout */
        count_area = NULL;
        for (i = 0; i < 3; i++) {
@@ -876,56 +1110,65 @@ dasd_eckd_end_analysis(struct dasd_device *device)
        if (count_area != NULL && count_area->kl == 0) {
                /* we found notthing violating our disk layout */
                if (dasd_check_blocksize(count_area->dl) == 0)
-                       device->bp_block = count_area->dl;
+                       block->bp_block = count_area->dl;
        }
-       if (device->bp_block == 0) {
+       if (block->bp_block == 0) {
                DEV_MESSAGE(KERN_WARNING, device, "%s",
                            "Volume has incompatible disk layout");
                return -EMEDIUMTYPE;
        }
-       device->s2b_shift = 0;  /* bits to shift 512 to get a block */
-       for (sb = 512; sb < device->bp_block; sb = sb << 1)
-               device->s2b_shift++;
+       block->s2b_shift = 0;   /* bits to shift 512 to get a block */
+       for (sb = 512; sb < block->bp_block; sb = sb << 1)
+               block->s2b_shift++;
 
-       blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
-       device->blocks = (private->rdc_data.no_cyl *
+       blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
+       block->blocks = (private->rdc_data.no_cyl *
                          private->rdc_data.trk_per_cyl *
                          blk_per_trk);
 
        DEV_MESSAGE(KERN_INFO, device,
                    "(%dkB blks): %dkB at %dkB/trk %s",
-                   (device->bp_block >> 10),
+                   (block->bp_block >> 10),
                    ((private->rdc_data.no_cyl *
                      private->rdc_data.trk_per_cyl *
-                     blk_per_trk * (device->bp_block >> 9)) >> 1),
-                   ((blk_per_trk * device->bp_block) >> 10),
+                     blk_per_trk * (block->bp_block >> 9)) >> 1),
+                   ((blk_per_trk * block->bp_block) >> 10),
                    private->uses_cdl ?
                    "compatible disk layout" : "linux disk layout");
 
        return 0;
 }
 
-static int
-dasd_eckd_do_analysis(struct dasd_device *device)
+static int dasd_eckd_do_analysis(struct dasd_block *block)
 {
        struct dasd_eckd_private *private;
 
-       private = (struct dasd_eckd_private *) device->private;
+       private = (struct dasd_eckd_private *) block->base->private;
        if (private->init_cqr_status < 0)
-               return dasd_eckd_start_analysis(device);
+               return dasd_eckd_start_analysis(block);
        else
-               return dasd_eckd_end_analysis(device);
+               return dasd_eckd_end_analysis(block);
 }
 
+static int dasd_eckd_ready_to_online(struct dasd_device *device)
+{
+       return dasd_alias_add_device(device);
+};
+
+static int dasd_eckd_online_to_ready(struct dasd_device *device)
+{
+       return dasd_alias_remove_device(device);
+};
+
 static int
-dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 {
        struct dasd_eckd_private *private;
 
-       private = (struct dasd_eckd_private *) device->private;
-       if (dasd_check_blocksize(device->bp_block) == 0) {
+       private = (struct dasd_eckd_private *) block->base->private;
+       if (dasd_check_blocksize(block->bp_block) == 0) {
                geo->sectors = recs_per_track(&private->rdc_data,
-                                             0, device->bp_block);
+                                             0, block->bp_block);
        }
        geo->cylinders = private->rdc_data.no_cyl;
        geo->heads = private->rdc_data.trk_per_cyl;
@@ -1037,7 +1280,7 @@ dasd_eckd_format_device(struct dasd_device * device,
                locate_record(ccw++, (struct LO_eckd_data *) data,
                              fdata->start_unit, 0, rpt + 1,
                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
-                             device->bp_block);
+                             device->block->bp_block);
                data += sizeof(struct LO_eckd_data);
                break;
        case 0x04: /* Invalidate track. */
@@ -1110,43 +1353,28 @@ dasd_eckd_format_device(struct dasd_device * device,
                        ccw++;
                }
        }
-       fcp->device = device;
-       fcp->retries = 2;       /* set retry counter to enable ERP */
+       fcp->startdev = device;
+       fcp->memdev = device;
+       clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
+       fcp->retries = 5;       /* set retry counter to enable default ERP */
        fcp->buildclk = get_clock();
        fcp->status = DASD_CQR_FILLED;
        return fcp;
 }
 
-static dasd_era_t
-dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
+static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
-       struct dasd_device *device = (struct dasd_device *) cqr->device;
-       struct ccw_device *cdev = device->cdev;
-
-       if (irb->scsw.cstat == 0x00 &&
-           irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-
-       switch (cdev->id.cu_type) {
-       case 0x3990:
-       case 0x2105:
-       case 0x2107:
-       case 0x1750:
-               return dasd_3990_erp_examine(cqr, irb);
-       case 0x9343:
-               return dasd_9343_erp_examine(cqr, irb);
-       case 0x3880:
-       default:
-               DEV_MESSAGE(KERN_WARNING, device, "%s",
-                           "default (unknown CU type) - RECOVERABLE return");
-               return dasd_era_recover;
+       cqr->status = DASD_CQR_FILLED;
+       if (cqr->block && (cqr->startdev != cqr->block->base)) {
+               dasd_eckd_reset_ccw_to_base_io(cqr);
+               cqr->startdev = cqr->block->base;
        }
-}
+};
 
 static dasd_erp_fn_t
 dasd_eckd_erp_action(struct dasd_ccw_req * cqr)
 {
-       struct dasd_device *device = (struct dasd_device *) cqr->device;
+       struct dasd_device *device = (struct dasd_device *) cqr->startdev;
        struct ccw_device *cdev = device->cdev;
 
        switch (cdev->id.cu_type) {
@@ -1168,8 +1396,37 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr)
        return dasd_default_erp_postaction;
 }
 
-static struct dasd_ccw_req *
-dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+
+static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
+                                                  struct irb *irb)
+{
+       char mask;
+
+       /* first of all check for state change pending interrupt */
+       mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+       if ((irb->scsw.dstat & mask) == mask) {
+               dasd_generic_handle_state_change(device);
+               return;
+       }
+
+       /* summary unit check */
+       if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) {
+               dasd_alias_handle_summary_unit_check(device, irb);
+               return;
+       }
+
+       /* just report other unsolicited interrupts */
+       DEV_MESSAGE(KERN_DEBUG, device, "%s",
+                   "unsolicited interrupt received");
+       device->discipline->dump_sense(device, NULL, irb);
+       dasd_schedule_device_bh(device);
+
+       return;
+};
+
+static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
+                                              struct dasd_block *block,
+                                              struct request *req)
 {
        struct dasd_eckd_private *private;
        unsigned long *idaws;
@@ -1185,8 +1442,11 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
        sector_t first_trk, last_trk;
        unsigned int first_offs, last_offs;
        unsigned char cmd, rcmd;
+       int use_prefix;
+       struct dasd_device *basedev;
 
-       private = (struct dasd_eckd_private *) device->private;
+       basedev = block->base;
+       private = (struct dasd_eckd_private *) basedev->private;
        if (rq_data_dir(req) == READ)
                cmd = DASD_ECKD_CCW_READ_MT;
        else if (rq_data_dir(req) == WRITE)
@@ -1194,13 +1454,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
        else
                return ERR_PTR(-EINVAL);
        /* Calculate number of blocks/records per track. */
-       blksize = device->bp_block;
+       blksize = block->bp_block;
        blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
        /* Calculate record id of first and last block. */
-       first_rec = first_trk = req->sector >> device->s2b_shift;
+       first_rec = first_trk = req->sector >> block->s2b_shift;
        first_offs = sector_div(first_trk, blk_per_trk);
        last_rec = last_trk =
-               (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+               (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
        last_offs = sector_div(last_trk, blk_per_trk);
        /* Check struct bio and count the number of blocks for the request. */
        count = 0;
@@ -1209,20 +1469,33 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
                if (bv->bv_len & (blksize - 1))
                        /* Eckd can only do full blocks. */
                        return ERR_PTR(-EINVAL);
-               count += bv->bv_len >> (device->s2b_shift + 9);
+               count += bv->bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
                if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
-                       cidaw += bv->bv_len >> (device->s2b_shift + 9);
+                       cidaw += bv->bv_len >> (block->s2b_shift + 9);
 #endif
        }
        /* Paranoia. */
        if (count != last_rec - first_rec + 1)
                return ERR_PTR(-EINVAL);
-       /* 1x define extent + 1x locate record + number of blocks */
-       cplength = 2 + count;
-       /* 1x define extent + 1x locate record + cidaws*sizeof(long) */
-       datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) +
-               cidaw * sizeof(unsigned long);
+
+       /* use the prefix command if available */
+       use_prefix = private->features.feature[8] & 0x01;
+       if (use_prefix) {
+               /* 1x prefix + number of blocks */
+               cplength = 2 + count;
+               /* 1x prefix + cidaws*sizeof(long) */
+               datasize = sizeof(struct PFX_eckd_data) +
+                       sizeof(struct LO_eckd_data) +
+                       cidaw * sizeof(unsigned long);
+       } else {
+               /* 1x define extent + 1x locate record + number of blocks */
+               cplength = 2 + count;
+               /* 1x define extent + 1x locate record + cidaws*sizeof(long) */
+               datasize = sizeof(struct DE_eckd_data) +
+                       sizeof(struct LO_eckd_data) +
+                       cidaw * sizeof(unsigned long);
+       }
        /* Find out the number of additional locate record ccws for cdl. */
        if (private->uses_cdl && first_rec < 2*blk_per_trk) {
                if (last_rec >= 2*blk_per_trk)
@@ -1232,26 +1505,42 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
        }
        /* Allocate the ccw request. */
        cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
-                                  cplength, datasize, device);
+                                  cplength, datasize, startdev);
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
-       /* First ccw is define extent. */
-       if (define_extent(ccw++, cqr->data, first_trk,
-                         last_trk, cmd, device) == -EAGAIN) {
-               /* Clock not in sync and XRC is enabled. Try again later. */
-               dasd_sfree_request(cqr, device);
-               return ERR_PTR(-EAGAIN);
+       /* First ccw is define extent or prefix. */
+       if (use_prefix) {
+               if (prefix(ccw++, cqr->data, first_trk,
+                          last_trk, cmd, basedev, startdev) == -EAGAIN) {
+                       /* Clock not in sync and XRC is enabled.
+                        * Try again later.
+                        */
+                       dasd_sfree_request(cqr, startdev);
+                       return ERR_PTR(-EAGAIN);
+               }
+               idaws = (unsigned long *) (cqr->data +
+                                          sizeof(struct PFX_eckd_data));
+       } else {
+               if (define_extent(ccw++, cqr->data, first_trk,
+                                 last_trk, cmd, startdev) == -EAGAIN) {
+                       /* Clock not in sync and XRC is enabled.
+                        * Try again later.
+                        */
+                       dasd_sfree_request(cqr, startdev);
+                       return ERR_PTR(-EAGAIN);
+               }
+               idaws = (unsigned long *) (cqr->data +
+                                          sizeof(struct DE_eckd_data));
        }
        /* Build locate_record+read/write/ccws. */
-       idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
        LO_data = (struct LO_eckd_data *) (idaws + cidaw);
        recid = first_rec;
        if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
                /* Only standard blocks so there is just one locate record. */
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
-                             last_rec - recid + 1, cmd, device, blksize);
+                             last_rec - recid + 1, cmd, basedev, blksize);
        }
        rq_for_each_segment(bv, req, iter) {
                dst = page_address(bv->bv_page) + bv->bv_offset;
@@ -1281,7 +1570,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
                                ccw[-1].flags |= CCW_FLAG_CC;
                                locate_record(ccw++, LO_data++,
                                              trkid, recoffs + 1,
-                                             1, rcmd, device, count);
+                                             1, rcmd, basedev, count);
                        }
                        /* Locate record for standard blocks ? */
                        if (private->uses_cdl && recid == 2*blk_per_trk) {
@@ -1289,7 +1578,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
                                locate_record(ccw++, LO_data++,
                                              trkid, recoffs + 1,
                                              last_rec - recid + 1,
-                                             cmd, device, count);
+                                             cmd, basedev, count);
                        }
                        /* Read/write ccw. */
                        ccw[-1].flags |= CCW_FLAG_CC;
@@ -1310,7 +1599,9 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
        }
        if (req->cmd_flags & REQ_FAILFAST)
                set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-       cqr->device = device;
+       cqr->startdev = startdev;
+       cqr->memdev = startdev;
+       cqr->block = block;
        cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
        cqr->lpm = private->path_data.ppm;
        cqr->retries = 256;
@@ -1333,10 +1624,10 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 
        if (!dasd_page_cache)
                goto out;
-       private = (struct dasd_eckd_private *) cqr->device->private;
-       blksize = cqr->device->bp_block;
+       private = (struct dasd_eckd_private *) cqr->block->base->private;
+       blksize = cqr->block->bp_block;
        blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
-       recid = req->sector >> cqr->device->s2b_shift;
+       recid = req->sector >> cqr->block->s2b_shift;
        ccw = cqr->cpaddr;
        /* Skip over define extent & locate record. */
        ccw++;
@@ -1367,10 +1658,71 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        }
 out:
        status = cqr->status == DASD_CQR_DONE;
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return status;
 }
 
+/*
+ * Modify ccw chain in cqr so it can be started on a base device.
+ *
+ * Note that this is not enough to restart the cqr!
+ * Either reset cqr->startdev as well (summary unit check handling)
+ * or restart via separate cqr (as in ERP handling).
+ */
+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr)
+{
+       struct ccw1 *ccw;
+       struct PFX_eckd_data *pfxdata;
+
+       ccw = cqr->cpaddr;
+       pfxdata = cqr->data;
+
+       if (ccw->cmd_code == DASD_ECKD_CCW_PFX) {
+               pfxdata->validity.verify_base = 0;
+               pfxdata->validity.hyper_pav = 0;
+       }
+}
+
+#define DASD_ECKD_CHANQ_MAX_SIZE 4
+
+static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
+                                                    struct dasd_block *block,
+                                                    struct request *req)
+{
+       struct dasd_eckd_private *private;
+       struct dasd_device *startdev;
+       unsigned long flags;
+       struct dasd_ccw_req *cqr;
+
+       startdev = dasd_alias_get_start_dev(base);
+       if (!startdev)
+               startdev = base;
+       private = (struct dasd_eckd_private *) startdev->private;
+       if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE)
+               return ERR_PTR(-EBUSY);
+
+       spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
+       private->count++;
+       cqr = dasd_eckd_build_cp(startdev, block, req);
+       if (IS_ERR(cqr))
+               private->count--;
+       spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags);
+       return cqr;
+}
+
+static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr,
+                                  struct request *req)
+{
+       struct dasd_eckd_private *private;
+       unsigned long flags;
+
+       spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags);
+       private = (struct dasd_eckd_private *) cqr->memdev->private;
+       private->count--;
+       spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags);
+       return dasd_eckd_free_cp(cqr, req);
+}
+
 static int
 dasd_eckd_fill_info(struct dasd_device * device,
                    struct dasd_information2_t * info)
@@ -1384,9 +1736,9 @@ dasd_eckd_fill_info(struct dasd_device * device,
        info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
        memcpy(info->characteristics, &private->rdc_data,
               sizeof(struct dasd_eckd_characteristics));
-       info->confdata_size = sizeof (struct dasd_eckd_confdata);
+       info->confdata_size = sizeof(struct dasd_eckd_confdata);
        memcpy(info->configuration_data, &private->conf_data,
-              sizeof (struct dasd_eckd_confdata));
+              sizeof(struct dasd_eckd_confdata));
        return 0;
 }
 
@@ -1419,7 +1771,8 @@ dasd_eckd_release(struct dasd_device *device)
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
        cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-       cqr->device = device;
+       cqr->startdev = device;
+       cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
        cqr->retries = 2;       /* set retry counter to enable basic ERP */
@@ -1429,7 +1782,7 @@ dasd_eckd_release(struct dasd_device *device)
 
        rc = dasd_sleep_on_immediatly(cqr);
 
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return rc;
 }
 
@@ -1459,7 +1812,8 @@ dasd_eckd_reserve(struct dasd_device *device)
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
        cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-       cqr->device = device;
+       cqr->startdev = device;
+       cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
        cqr->retries = 2;       /* set retry counter to enable basic ERP */
@@ -1469,7 +1823,7 @@ dasd_eckd_reserve(struct dasd_device *device)
 
        rc = dasd_sleep_on_immediatly(cqr);
 
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return rc;
 }
 
@@ -1498,7 +1852,8 @@ dasd_eckd_steal_lock(struct dasd_device *device)
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
        cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-       cqr->device = device;
+       cqr->startdev = device;
+       cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
        cqr->retries = 2;       /* set retry counter to enable basic ERP */
@@ -1508,7 +1863,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
 
        rc = dasd_sleep_on_immediatly(cqr);
 
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return rc;
 }
 
@@ -1526,52 +1881,52 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
 
        cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
                                   1 /* PSF */  + 1 /* RSSD */ ,
-                                  (sizeof (struct dasd_psf_prssd_data) +
-                                   sizeof (struct dasd_rssd_perf_stats_t)),
+                                  (sizeof(struct dasd_psf_prssd_data) +
+                                   sizeof(struct dasd_rssd_perf_stats_t)),
                                   device);
        if (IS_ERR(cqr)) {
                DEV_MESSAGE(KERN_WARNING, device, "%s",
                            "Could not allocate initialization request");
                return PTR_ERR(cqr);
        }
-       cqr->device = device;
+       cqr->startdev = device;
+       cqr->memdev = device;
        cqr->retries = 0;
        cqr->expires = 10 * HZ;
 
        /* Prepare for Read Subsystem Data */
        prssdp = (struct dasd_psf_prssd_data *) cqr->data;
-       memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data));
+       memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
        prssdp->order = PSF_ORDER_PRSSD;
-       prssdp->suborder = 0x01;        /* Perfomance Statistics */
+       prssdp->suborder = 0x01;        /* Performance Statistics */
        prssdp->varies[1] = 0x01;       /* Perf Statistics for the Subsystem */
 
        ccw = cqr->cpaddr;
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->count = sizeof (struct dasd_psf_prssd_data);
+       ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
        ccw->cda = (__u32)(addr_t) prssdp;
 
        /* Read Subsystem Data - Performance Statistics */
        stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
-       memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));
+       memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t));
 
        ccw++;
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
-       ccw->count = sizeof (struct dasd_rssd_perf_stats_t);
+       ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
        ccw->cda = (__u32)(addr_t) stats;
 
        cqr->buildclk = get_clock();
        cqr->status = DASD_CQR_FILLED;
        rc = dasd_sleep_on(cqr);
        if (rc == 0) {
-               /* Prepare for Read Subsystem Data */
                prssdp = (struct dasd_psf_prssd_data *) cqr->data;
                stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
                if (copy_to_user(argp, stats,
                                 sizeof(struct dasd_rssd_perf_stats_t)))
                        rc = -EFAULT;
        }
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return rc;
 }
 
@@ -1594,7 +1949,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
 
        rc = 0;
        if (copy_to_user(argp, (long *) &attrib,
-                        sizeof (struct attrib_data_t)))
+                        sizeof(struct attrib_data_t)))
                rc = -EFAULT;
 
        return rc;
@@ -1627,8 +1982,10 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
 }
 
 static int
-dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
+dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
 {
+       struct dasd_device *device = block->base;
+
        switch (cmd) {
        case BIODASDGATTR:
                return dasd_eckd_get_attrib(device, argp);
@@ -1685,9 +2042,8 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
  */
-static void
-dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
-                    struct irb *irb)
+static void dasd_eckd_dump_sense(struct dasd_device *device,
+                                struct dasd_ccw_req *req, struct irb *irb)
 {
        char *page;
        struct ccw1 *first, *last, *fail, *from, *to;
@@ -1743,37 +2099,40 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
        }
        printk("%s", page);
 
-       /* dump the Channel Program (max 140 Bytes per line) */
-       /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
-       first = req->cpaddr;
-       for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-       to = min(first + 6, last);
-       len = sprintf(page,  KERN_ERR PRINTK_HEADER
-                     " Related CP in req: %p\n", req);
-       dasd_eckd_dump_ccw_range(first, to, page + len);
-       printk("%s", page);
+       if (req) {
+               /* req == NULL for unsolicited interrupts */
+               /* dump the Channel Program (max 140 Bytes per line) */
+               /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+               first = req->cpaddr;
+               for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+               to = min(first + 6, last);
+               len = sprintf(page,  KERN_ERR PRINTK_HEADER
+                             " Related CP in req: %p\n", req);
+               dasd_eckd_dump_ccw_range(first, to, page + len);
+               printk("%s", page);
 
-       /* print failing CCW area (maximum 4) */
-       /* scsw->cda is either valid or zero  */
-       len = 0;
-       from = ++to;
-       fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
-       if (from <  fail - 2) {
-               from = fail - 2;     /* there is a gap - print header */
-               len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
-       }
-       to = min(fail + 1, last);
-       len += dasd_eckd_dump_ccw_range(from, to, page + len);
-
-       /* print last CCWs (maximum 2) */
-       from = max(from, ++to);
-       if (from < last - 1) {
-               from = last - 1;     /* there is a gap - print header */
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
+               /* print failing CCW area (maximum 4) */
+               /* scsw->cda is either valid or zero  */
+               len = 0;
+               from = ++to;
+               fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+               if (from <  fail - 2) {
+                       from = fail - 2;     /* there is a gap - print header */
+                       len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
+               }
+               to = min(fail + 1, last);
+               len += dasd_eckd_dump_ccw_range(from, to, page + len);
+
+               /* print last CCWs (maximum 2) */
+               from = max(from, ++to);
+               if (from < last - 1) {
+                       from = last - 1;     /* there is a gap - print header */
+                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
+               }
+               len += dasd_eckd_dump_ccw_range(from, last, page + len);
+               if (len > 0)
+                       printk("%s", page);
        }
-       len += dasd_eckd_dump_ccw_range(from, last, page + len);
-       if (len > 0)
-               printk("%s", page);
        free_page((unsigned long) page);
 }
 
@@ -1796,16 +2155,20 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .ebcname = "ECKD",
        .max_blocks = 240,
        .check_device = dasd_eckd_check_characteristics,
+       .uncheck_device = dasd_eckd_uncheck_device,
        .do_analysis = dasd_eckd_do_analysis,
+       .ready_to_online = dasd_eckd_ready_to_online,
+       .online_to_ready = dasd_eckd_online_to_ready,
        .fill_geometry = dasd_eckd_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
+       .handle_terminated_request = dasd_eckd_handle_terminated_request,
        .format_device = dasd_eckd_format_device,
-       .examine_error = dasd_eckd_examine_error,
        .erp_action = dasd_eckd_erp_action,
        .erp_postaction = dasd_eckd_erp_postaction,
-       .build_cp = dasd_eckd_build_cp,
-       .free_cp = dasd_eckd_free_cp,
+       .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
+       .build_cp = dasd_eckd_build_alias_cp,
+       .free_cp = dasd_eckd_free_alias_cp,
        .dump_sense = dasd_eckd_dump_sense,
        .fill_info = dasd_eckd_fill_info,
        .ioctl = dasd_eckd_ioctl,
index 712ff1650134c5e1b60953758c922440231bd66d..fc2509c939bc4ef3d7a00cc4a200fcd647e06c0a 100644 (file)
@@ -39,6 +39,8 @@
 #define DASD_ECKD_CCW_READ_CKD_MT       0x9e
 #define DASD_ECKD_CCW_WRITE_CKD_MT      0x9d
 #define DASD_ECKD_CCW_RESERVE           0xB4
+#define DASD_ECKD_CCW_PFX               0xE7
+#define DASD_ECKD_CCW_RSCK              0xF9
 
 /*
  * Perform Subsystem Function / Sub-Orders
@@ -137,6 +139,25 @@ struct LO_eckd_data {
        __u16 length;
 } __attribute__ ((packed));
 
+/* Prefix data for format 0x00 and 0x01 */
+struct PFX_eckd_data {
+       unsigned char format;
+       struct {
+               unsigned char define_extend:1;
+               unsigned char time_stamp:1;
+               unsigned char verify_base:1;
+               unsigned char hyper_pav:1;
+               unsigned char reserved:4;
+       } __attribute__ ((packed)) validity;
+       __u8 base_address;
+       __u8 aux;
+       __u8 base_lss;
+       __u8 reserved[7];
+       struct DE_eckd_data define_extend;
+       struct LO_eckd_data locate_record;
+       __u8 LO_extended_data[4];
+} __attribute__ ((packed));
+
 struct dasd_eckd_characteristics {
        __u16 cu_type;
        struct {
@@ -254,7 +275,9 @@ struct dasd_eckd_confdata {
                } __attribute__ ((packed)) ned;
                struct {
                        unsigned char flags;            /* byte  0    */
-                       unsigned char res2[7];          /* byte  1- 7 */
+                       unsigned char res1;             /* byte  1    */
+                       __u16 format;                   /* byte  2-3  */
+                       unsigned char res2[4];          /* byte  4-7  */
                        unsigned char sua_flags;        /* byte  8    */
                        __u8 base_unit_addr;            /* byte  9    */
                        unsigned char res3[22];         /* byte 10-31 */
@@ -343,6 +366,11 @@ struct dasd_eckd_path {
        __u8 npm;
 };
 
+struct dasd_rssd_features {
+       char feature[256];
+} __attribute__((packed));
+
+
 /*
  * Perform Subsystem Function - Prepare for Read Subsystem Data
  */
@@ -365,4 +393,99 @@ struct dasd_psf_ssc_data {
        unsigned char reserved[59];
 } __attribute__((packed));
 
+
+/*
+ * some structures and definitions for alias handling
+ */
+struct dasd_unit_address_configuration {
+       struct {
+               char ua_type;
+               char base_ua;
+       } unit[256];
+} __attribute__((packed));
+
+
+#define MAX_DEVICES_PER_LCU 256
+
+/* flags on the LCU  */
+#define NEED_UAC_UPDATE  0x01
+#define UPDATE_PENDING 0x02
+
+enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV};
+
+
+struct alias_root {
+       struct list_head serverlist;
+       spinlock_t lock;
+};
+
+struct alias_server {
+       struct list_head server;
+       struct dasd_uid uid;
+       struct list_head lculist;
+};
+
+struct summary_unit_check_work_data {
+       char reason;
+       struct dasd_device *device;
+       struct work_struct worker;
+};
+
+struct read_uac_work_data {
+       struct dasd_device *device;
+       struct delayed_work dwork;
+};
+
+struct alias_lcu {
+       struct list_head lcu;
+       struct dasd_uid uid;
+       enum pavtype pav;
+       char flags;
+       spinlock_t lock;
+       struct list_head grouplist;
+       struct list_head active_devices;
+       struct list_head inactive_devices;
+       struct dasd_unit_address_configuration *uac;
+       struct summary_unit_check_work_data suc_data;
+       struct read_uac_work_data ruac_data;
+       struct dasd_ccw_req *rsu_cqr;
+};
+
+struct alias_pav_group {
+       struct list_head group;
+       struct dasd_uid uid;
+       struct alias_lcu *lcu;
+       struct list_head baselist;
+       struct list_head aliaslist;
+       struct dasd_device *next;
+};
+
+
+struct dasd_eckd_private {
+       struct dasd_eckd_characteristics rdc_data;
+       struct dasd_eckd_confdata conf_data;
+       struct dasd_eckd_path path_data;
+       struct eckd_count count_area[5];
+       int init_cqr_status;
+       int uses_cdl;
+       struct attrib_data_t attrib;    /* e.g. cache operations */
+       struct dasd_rssd_features features;
+
+       /* alias managemnet */
+       struct dasd_uid uid;
+       struct alias_pav_group *pavgroup;
+       struct alias_lcu *lcu;
+       int count;
+};
+
+
+
+int dasd_alias_make_device_known_to_lcu(struct dasd_device *);
+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
+int dasd_alias_add_device(struct dasd_device *);
+int dasd_alias_remove_device(struct dasd_device *);
+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
+void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
+
 #endif                         /* DASD_ECKD_H */
index 0c081a664ee8561d84048c50065c0fa654d91cb4..6e53ab606e9720f531ba8ad218fb0a7524cf212a 100644 (file)
@@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
        unsigned long flags;
        struct eerbuffer *eerb;
 
-       snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+       snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
        if (snss_rc)
                data_size = 0;
        else
@@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *device)
                set_bit(DASD_FLAG_EER_SNSS, &device->flags);
                return;
        }
+       /* cdev is already locked, can't use dasd_add_request_head */
        clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
        cqr->status = DASD_CQR_QUEUED;
-       list_add(&cqr->list, &device->ccw_queue);
-       dasd_schedule_bh(device);
+       list_add(&cqr->devlist, &device->ccw_queue);
+       dasd_schedule_device_bh(device);
 }
 
 /*
@@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *device)
  */
 static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
 {
-        struct dasd_device *device = cqr->device;
+       struct dasd_device *device = cqr->startdev;
        unsigned long flags;
 
        dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
@@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *device)
        if (!cqr)
                return -ENOMEM;
 
-       cqr->device = device;
+       cqr->startdev = device;
        cqr->retries = 255;
        cqr->expires = 10 * HZ;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
index caa5d91420f827a20a5f6c2c69706ffac091c346..8f10000851a3acc603e941ff7741d6a16097dffa 100644 (file)
@@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
        if (cqr == NULL)
                return ERR_PTR(-ENOMEM);
        memset(cqr, 0, sizeof(struct dasd_ccw_req));
+       INIT_LIST_HEAD(&cqr->devlist);
+       INIT_LIST_HEAD(&cqr->blocklist);
        data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
        cqr->cpaddr = NULL;
        if (cplength > 0) {
@@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
 }
 
 void
-dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
 {
        unsigned long flags;
 
@@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
  * dasd_default_erp_action just retries the current cqr
  */
 struct dasd_ccw_req *
-dasd_default_erp_action(struct dasd_ccw_req * cqr)
+dasd_default_erp_action(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
 
-       device = cqr->device;
+       device = cqr->startdev;
 
         /* just retry - there is nothing to save ... I got no sense data.... */
         if (cqr->retries > 0) {
@@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
                              "default ERP called (%i retries left)",
                              cqr->retries);
                cqr->lpm    = LPM_ANYPATH;
-               cqr->status = DASD_CQR_QUEUED;
+               cqr->status = DASD_CQR_FILLED;
         } else {
                 DEV_MESSAGE (KERN_WARNING, device, "%s",
                             "default ERP called (NO retry left)");
                cqr->status = DASD_CQR_FAILED;
-               cqr->stopclk = get_clock ();
+               cqr->stopclk = get_clock();
         }
         return cqr;
 }                              /* end dasd_default_erp_action */
@@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
  * RETURN VALUES
  *   cqr               pointer to the original CQR
  */
-struct dasd_ccw_req *
-dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
+struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
 {
-       struct dasd_device *device;
        int success;
 
        BUG_ON(cqr->refers == NULL || cqr->function == NULL);
 
-       device = cqr->device;
        success = cqr->status == DASD_CQR_DONE;
 
        /* free all ERPs - but NOT the original cqr */
@@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
                struct dasd_ccw_req *refers;
 
                refers = cqr->refers;
-               /* remove the request from the device queue */
-               list_del(&cqr->list);
+               /* remove the request from the block queue */
+               list_del(&cqr->blocklist);
                /* free the finished erp request */
-               dasd_free_erp_request(cqr, device);
+               dasd_free_erp_request(cqr, cqr->memdev);
                cqr = refers;
        }
 
@@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 {
        struct dasd_device *device;
 
-       device = cqr->device;
+       device = cqr->startdev;
        /* dump sense data */
        if (device->discipline && device->discipline->dump_sense)
                device->discipline->dump_sense(device, cqr, irb);
index 1d95822e0b8e0934125d28f80815ce6ade9d76f7..d13ea05089a7c3e2e291034258e072675bef0464 100644 (file)
@@ -117,6 +117,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
 static int
 dasd_fba_check_characteristics(struct dasd_device *device)
 {
+       struct dasd_block *block;
        struct dasd_fba_private *private;
        struct ccw_device *cdev = device->cdev;
        void *rdc_data;
@@ -133,6 +134,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)
                }
                device->private = (void *) private;
        }
+       block = dasd_alloc_block();
+       if (IS_ERR(block)) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                           "could not allocate dasd block structure");
+               kfree(device->private);
+               return PTR_ERR(block);
+       }
+       device->block = block;
+       block->base = device;
+
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
        rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
@@ -155,60 +166,37 @@ dasd_fba_check_characteristics(struct dasd_device *device)
        return 0;
 }
 
-static int
-dasd_fba_do_analysis(struct dasd_device *device)
+static int dasd_fba_do_analysis(struct dasd_block *block)
 {
        struct dasd_fba_private *private;
        int sb, rc;
 
-       private = (struct dasd_fba_private *) device->private;
+       private = (struct dasd_fba_private *) block->base->private;
        rc = dasd_check_blocksize(private->rdc_data.blk_size);
        if (rc) {
-               DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
+               DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
                            private->rdc_data.blk_size);
                return rc;
        }
-       device->blocks = private->rdc_data.blk_bdsa;
-       device->bp_block = private->rdc_data.blk_size;
-       device->s2b_shift = 0;  /* bits to shift 512 to get a block */
+       block->blocks = private->rdc_data.blk_bdsa;
+       block->bp_block = private->rdc_data.blk_size;
+       block->s2b_shift = 0;   /* bits to shift 512 to get a block */
        for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
-               device->s2b_shift++;
+               block->s2b_shift++;
        return 0;
 }
 
-static int
-dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+static int dasd_fba_fill_geometry(struct dasd_block *block,
+                                 struct hd_geometry *geo)
 {
-       if (dasd_check_blocksize(device->bp_block) != 0)
+       if (dasd_check_blocksize(block->bp_block) != 0)
                return -EINVAL;
-       geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
+       geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
        geo->heads = 16;
-       geo->sectors = 128 >> device->s2b_shift;
+       geo->sectors = 128 >> block->s2b_shift;
        return 0;
 }
 
-static dasd_era_t
-dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-       struct dasd_device *device;
-       struct ccw_device *cdev;
-
-       device = (struct dasd_device *) cqr->device;
-       if (irb->scsw.cstat == 0x00 &&
-           irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-
-       cdev = device->cdev;
-       switch (cdev->id.dev_type) {
-       case 0x3370:
-               return dasd_3370_erp_examine(cqr, irb);
-       case 0x9336:
-               return dasd_9336_erp_examine(cqr, irb);
-       default:
-               return dasd_era_recover;
-       }
-}
-
 static dasd_erp_fn_t
 dasd_fba_erp_action(struct dasd_ccw_req * cqr)
 {
@@ -221,13 +209,34 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
        if (cqr->function == dasd_default_erp_action)
                return dasd_default_erp_postaction;
 
-       DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p",
+       DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
                    cqr->function);
        return NULL;
 }
 
-static struct dasd_ccw_req *
-dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
+                                                  struct irb *irb)
+{
+       char mask;
+
+       /* first of all check for state change pending interrupt */
+       mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+       if ((irb->scsw.dstat & mask) == mask) {
+               dasd_generic_handle_state_change(device);
+               return;
+       }
+
+       /* check for unsolicited interrupts */
+       DEV_MESSAGE(KERN_DEBUG, device, "%s",
+                   "unsolicited interrupt received");
+       device->discipline->dump_sense(device, NULL, irb);
+       dasd_schedule_device_bh(device);
+       return;
+};
+
+static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
+                                             struct dasd_block *block,
+                                             struct request *req)
 {
        struct dasd_fba_private *private;
        unsigned long *idaws;
@@ -242,17 +251,17 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
        unsigned int blksize, off;
        unsigned char cmd;
 
-       private = (struct dasd_fba_private *) device->private;
+       private = (struct dasd_fba_private *) block->base->private;
        if (rq_data_dir(req) == READ) {
                cmd = DASD_FBA_CCW_READ;
        } else if (rq_data_dir(req) == WRITE) {
                cmd = DASD_FBA_CCW_WRITE;
        } else
                return ERR_PTR(-EINVAL);
-       blksize = device->bp_block;
+       blksize = block->bp_block;
        /* Calculate record id of first and last block. */
-       first_rec = req->sector >> device->s2b_shift;
-       last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+       first_rec = req->sector >> block->s2b_shift;
+       last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
        /* Check struct bio and count the number of blocks for the request. */
        count = 0;
        cidaw = 0;
@@ -260,7 +269,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
                if (bv->bv_len & (blksize - 1))
                        /* Fba can only do full blocks. */
                        return ERR_PTR(-EINVAL);
-               count += bv->bv_len >> (device->s2b_shift + 9);
+               count += bv->bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
                if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
                        cidaw += bv->bv_len / blksize;
@@ -284,13 +293,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
        }
        /* Allocate the ccw request. */
        cqr = dasd_smalloc_request(dasd_fba_discipline.name,
-                                  cplength, datasize, device);
+                                  cplength, datasize, memdev);
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
        /* First ccw is define extent. */
        define_extent(ccw++, cqr->data, rq_data_dir(req),
-                     device->bp_block, req->sector, req->nr_sectors);
+                     block->bp_block, req->sector, req->nr_sectors);
        /* Build locate_record + read/write ccws. */
        idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
        LO_data = (struct LO_fba_data *) (idaws + cidaw);
@@ -326,7 +335,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
                                        ccw[-1].flags |= CCW_FLAG_CC;
                        }
                        ccw->cmd_code = cmd;
-                       ccw->count = device->bp_block;
+                       ccw->count = block->bp_block;
                        if (idal_is_needed(dst, blksize)) {
                                ccw->cda = (__u32)(addr_t) idaws;
                                ccw->flags = CCW_FLAG_IDA;
@@ -342,7 +351,9 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
        }
        if (req->cmd_flags & REQ_FAILFAST)
                set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-       cqr->device = device;
+       cqr->startdev = memdev;
+       cqr->memdev = memdev;
+       cqr->block = block;
        cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
        cqr->retries = 32;
        cqr->buildclk = get_clock();
@@ -363,8 +374,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 
        if (!dasd_page_cache)
                goto out;
-       private = (struct dasd_fba_private *) cqr->device->private;
-       blksize = cqr->device->bp_block;
+       private = (struct dasd_fba_private *) cqr->block->base->private;
+       blksize = cqr->block->bp_block;
        ccw = cqr->cpaddr;
        /* Skip over define extent & locate record. */
        ccw++;
@@ -394,10 +405,15 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        }
 out:
        status = cqr->status == DASD_CQR_DONE;
-       dasd_sfree_request(cqr, cqr->device);
+       dasd_sfree_request(cqr, cqr->memdev);
        return status;
 }
 
+static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
+{
+       cqr->status = DASD_CQR_FILLED;
+};
+
 static int
 dasd_fba_fill_info(struct dasd_device * device,
                   struct dasd_information2_t * info)
@@ -546,9 +562,10 @@ static struct dasd_discipline dasd_fba_discipline = {
        .fill_geometry = dasd_fba_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
-       .examine_error = dasd_fba_examine_error,
+       .handle_terminated_request = dasd_fba_handle_terminated_request,
        .erp_action = dasd_fba_erp_action,
        .erp_postaction = dasd_fba_erp_postaction,
+       .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
        .build_cp = dasd_fba_build_cp,
        .free_cp = dasd_fba_free_cp,
        .dump_sense = dasd_fba_dump_sense,
index 47ba4462708de9583cadef43f4cd0995567e7878..aee6565aaf983fda86bfaaf483d2aaeb9ddfac9a 100644 (file)
 /*
  * Allocate and register gendisk structure for device.
  */
-int
-dasd_gendisk_alloc(struct dasd_device *device)
+int dasd_gendisk_alloc(struct dasd_block *block)
 {
        struct gendisk *gdp;
+       struct dasd_device *base;
        int len;
 
        /* Make sure the minor for this device exists. */
-       if (device->devindex >= DASD_PER_MAJOR)
+       base = block->base;
+       if (base->devindex >= DASD_PER_MAJOR)
                return -EBUSY;
 
        gdp = alloc_disk(1 << DASD_PARTN_BITS);
@@ -41,9 +42,9 @@ dasd_gendisk_alloc(struct dasd_device *device)
 
        /* Initialize gendisk structure. */
        gdp->major = DASD_MAJOR;
-       gdp->first_minor = device->devindex << DASD_PARTN_BITS;
+       gdp->first_minor = base->devindex << DASD_PARTN_BITS;
        gdp->fops = &dasd_device_operations;
-       gdp->driverfs_dev = &device->cdev->dev;
+       gdp->driverfs_dev = &base->cdev->dev;
 
        /*
         * Set device name.
@@ -53,53 +54,51 @@ dasd_gendisk_alloc(struct dasd_device *device)
         *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
         */
        len = sprintf(gdp->disk_name, "dasd");
-       if (device->devindex > 25) {
-               if (device->devindex > 701) {
-                       if (device->devindex > 18277)
+       if (base->devindex > 25) {
+               if (base->devindex > 701) {
+                       if (base->devindex > 18277)
                                len += sprintf(gdp->disk_name + len, "%c",
-                                              'a'+(((device->devindex-18278)
+                                              'a'+(((base->devindex-18278)
                                                     /17576)%26));
                        len += sprintf(gdp->disk_name + len, "%c",
-                                      'a'+(((device->devindex-702)/676)%26));
+                                      'a'+(((base->devindex-702)/676)%26));
                }
                len += sprintf(gdp->disk_name + len, "%c",
-                              'a'+(((device->devindex-26)/26)%26));
+                              'a'+(((base->devindex-26)/26)%26));
        }
-       len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
+       len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
 
-       if (device->features & DASD_FEATURE_READONLY)
+       if (block->base->features & DASD_FEATURE_READONLY)
                set_disk_ro(gdp, 1);
-       gdp->private_data = device;
-       gdp->queue = device->request_queue;
-       device->gdp = gdp;
-       set_capacity(device->gdp, 0);
-       add_disk(device->gdp);
+       gdp->private_data = block;
+       gdp->queue = block->request_queue;
+       block->gdp = gdp;
+       set_capacity(block->gdp, 0);
+       add_disk(block->gdp);
        return 0;
 }
 
 /*
  * Unregister and free gendisk structure for device.
  */
-void
-dasd_gendisk_free(struct dasd_device *device)
+void dasd_gendisk_free(struct dasd_block *block)
 {
-       if (device->gdp) {
-               del_gendisk(device->gdp);
-               device->gdp->queue = NULL;
-               put_disk(device->gdp);
-               device->gdp = NULL;
+       if (block->gdp) {
+               del_gendisk(block->gdp);
+               block->gdp->queue = NULL;
+               put_disk(block->gdp);
+               block->gdp = NULL;
        }
 }
 
 /*
  * Trigger a partition detection.
  */
-int
-dasd_scan_partitions(struct dasd_device * device)
+int dasd_scan_partitions(struct dasd_block *block)
 {
        struct block_device *bdev;
 
-       bdev = bdget_disk(device->gdp, 0);
+       bdev = bdget_disk(block->gdp, 0);
        if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
                return -ENODEV;
        /*
@@ -117,7 +116,7 @@ dasd_scan_partitions(struct dasd_device * device)
         * is why the assignment to device->bdev is done AFTER
         * the BLKRRPART ioctl.
         */
-       device->bdev = bdev;
+       block->bdev = bdev;
        return 0;
 }
 
@@ -125,8 +124,7 @@ dasd_scan_partitions(struct dasd_device * device)
  * Remove all inodes in the system for a device, delete the
  * partitions and make device unusable by setting its size to zero.
  */
-void
-dasd_destroy_partitions(struct dasd_device * device)
+void dasd_destroy_partitions(struct dasd_block *block)
 {
        /* The two structs have 168/176 byte on 31/64 bit. */
        struct blkpg_partition bpart;
@@ -137,8 +135,8 @@ dasd_destroy_partitions(struct dasd_device * device)
         * Get the bdev pointer from the device structure and clear
         * device->bdev to lower the offline open_count limit again.
         */
-       bdev = device->bdev;
-       device->bdev = NULL;
+       bdev = block->bdev;
+       block->bdev = NULL;
 
        /*
         * See fs/partition/check.c:delete_partition
@@ -149,17 +147,16 @@ dasd_destroy_partitions(struct dasd_device * device)
        memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
        barg.data = (void __force __user *) &bpart;
        barg.op = BLKPG_DEL_PARTITION;
-       for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
+       for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
                ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
 
-       invalidate_partition(device->gdp, 0);
+       invalidate_partition(block->gdp, 0);
        /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
        blkdev_put(bdev);
-       set_capacity(device->gdp, 0);
+       set_capacity(block->gdp, 0);
 }
 
-int
-dasd_gendisk_init(void)
+int dasd_gendisk_init(void)
 {
        int rc;
 
@@ -174,8 +171,7 @@ dasd_gendisk_init(void)
        return 0;
 }
 
-void
-dasd_gendisk_exit(void)
+void dasd_gendisk_exit(void)
 {
        unregister_blkdev(DASD_MAJOR, "dasd");
 }
index d427daeef511bd1bfaddf153b9c1c363da4e9cf3..44b2984dfbee32aa4021379665fef8de58dd588c 100644 (file)
  * SECTION: Type definitions
  */
 struct dasd_device;
-
-typedef enum {
-       dasd_era_fatal = -1,    /* no chance to recover              */
-       dasd_era_none = 0,      /* don't recover, everything alright */
-       dasd_era_msg = 1,       /* don't recover, just report...     */
-       dasd_era_recover = 2    /* recovery action recommended       */
-} dasd_era_t;
+struct dasd_block;
 
 /* BIT DEFINITIONS FOR SENSE DATA */
 #define DASD_SENSE_BIT_0 0x80
@@ -151,19 +145,22 @@ do { \
 
 struct dasd_ccw_req {
        unsigned int magic;             /* Eye catcher */
-        struct list_head list;         /* list_head for request queueing. */
+       struct list_head devlist;       /* for dasd_device request queue */
+       struct list_head blocklist;     /* for dasd_block request queue */
 
        /* Where to execute what... */
-       struct dasd_device *device;     /* device the request is for */
+       struct dasd_block *block;       /* the originating block device */
+       struct dasd_device *memdev;     /* the device used to allocate this */
+       struct dasd_device *startdev;   /* device the request is started on */
        struct ccw1 *cpaddr;            /* address of channel program */
-       char status;                    /* status of this request */
+       char status;                    /* status of this request */
        short retries;                  /* A retry counter */
        unsigned long flags;            /* flags of this request */
 
        /* ... and how */
        unsigned long starttime;        /* jiffies time of request start */
        int expires;                    /* expiration period in jiffies */
-       char lpm;                       /* logical path mask */
+       char lpm;                       /* logical path mask */
        void *data;                     /* pointer to data area */
 
        /* these are important for recovering erroneous requests          */
@@ -178,20 +175,27 @@ struct dasd_ccw_req {
        unsigned long long endclk;      /* TOD-clock of request termination */
 
         /* Callback that is called after reaching final status. */
-        void (*callback)(struct dasd_ccw_req *, void *data);
-        void *callback_data;
+       void (*callback)(struct dasd_ccw_req *, void *data);
+       void *callback_data;
 };
 
 /*
  * dasd_ccw_req -> status can be:
  */
-#define DASD_CQR_FILLED   0x00 /* request is ready to be processed */
-#define DASD_CQR_QUEUED   0x01 /* request is queued to be processed */
-#define DASD_CQR_IN_IO    0x02 /* request is currently in IO */
-#define DASD_CQR_DONE     0x03 /* request is completed successfully */
-#define DASD_CQR_ERROR    0x04 /* request is completed with error */
-#define DASD_CQR_FAILED   0x05 /* request is finally failed */
-#define DASD_CQR_CLEAR    0x06 /* request is clear pending */
+#define DASD_CQR_FILLED        0x00    /* request is ready to be processed */
+#define DASD_CQR_DONE          0x01    /* request is completed successfully */
+#define DASD_CQR_NEED_ERP      0x02    /* request needs recovery action */
+#define DASD_CQR_IN_ERP        0x03    /* request is in recovery */
+#define DASD_CQR_FAILED        0x04    /* request is finally failed */
+#define DASD_CQR_TERMINATED    0x05    /* request was stopped by driver */
+
+#define DASD_CQR_QUEUED        0x80    /* request is queued to be processed */
+#define DASD_CQR_IN_IO         0x81    /* request is currently in IO */
+#define DASD_CQR_ERROR         0x82    /* request is completed with error */
+#define DASD_CQR_CLEAR_PENDING 0x83    /* request is clear pending */
+#define DASD_CQR_CLEARED       0x84    /* request was cleared */
+#define DASD_CQR_SUCCESS       0x85    /* request was successfull */
+
 
 /* per dasd_ccw_req flags */
 #define DASD_CQR_FLAGS_USE_ERP   0     /* use ERP for this request */
@@ -214,52 +218,71 @@ struct dasd_discipline {
 
        struct list_head list;  /* used for list of disciplines */
 
-        /*
-         * Device recognition functions. check_device is used to verify
-         * the sense data and the information returned by read device
-         * characteristics. It returns 0 if the discipline can be used
-         * for the device in question.
-         * do_analysis is used in the step from device state "basic" to
-         * state "accept". It returns 0 if the device can be made ready,
-         * it returns -EMEDIUMTYPE if the device can't be made ready or
-         * -EAGAIN if do_analysis started a ccw that needs to complete
-         * before the analysis may be repeated.
-         */
-        int (*check_device)(struct dasd_device *);
-       int (*do_analysis) (struct dasd_device *);
-
-        /*
-         * Device operation functions. build_cp creates a ccw chain for
-         * a block device request, start_io starts the request and
-         * term_IO cancels it (e.g. in case of a timeout). format_device
-         * returns a ccw chain to be used to format the device.
-         */
+       /*
+        * Device recognition functions. check_device is used to verify
+        * the sense data and the information returned by read device
+        * characteristics. It returns 0 if the discipline can be used
+        * for the device in question. uncheck_device is called during
+        * device shutdown to deregister a device from its discipline.
+        */
+       int (*check_device) (struct dasd_device *);
+       void (*uncheck_device) (struct dasd_device *);
+
+       /*
+        * do_analysis is used in the step from device state "basic" to
+        * state "accept". It returns 0 if the device can be made ready,
+        * it returns -EMEDIUMTYPE if the device can't be made ready or
+        * -EAGAIN if do_analysis started a ccw that needs to complete
+        * before the analysis may be repeated.
+        */
+       int (*do_analysis) (struct dasd_block *);
+
+       /*
+        * Last things to do when a device is set online, and first things
+        * when it is set offline.
+        */
+       int (*ready_to_online) (struct dasd_device *);
+       int (*online_to_ready) (struct dasd_device *);
+
+       /*
+        * Device operation functions. build_cp creates a ccw chain for
+        * a block device request, start_io starts the request and
+        * term_IO cancels it (e.g. in case of a timeout). format_device
+        * returns a ccw chain to be used to format the device.
+        * handle_terminated_request allows to examine a cqr and prepare
+        * it for retry.
+        */
        struct dasd_ccw_req *(*build_cp) (struct dasd_device *,
+                                         struct dasd_block *,
                                          struct request *);
        int (*start_IO) (struct dasd_ccw_req *);
        int (*term_IO) (struct dasd_ccw_req *);
+       void (*handle_terminated_request) (struct dasd_ccw_req *);
        struct dasd_ccw_req *(*format_device) (struct dasd_device *,
                                               struct format_data_t *);
        int (*free_cp) (struct dasd_ccw_req *, struct request *);
-        /*
-         * Error recovery functions. examine_error() returns a value that
-         * indicates what to do for an error condition. If examine_error()
+
+       /*
+        * Error recovery functions. examine_error() returns a value that
+        * indicates what to do for an error condition. If examine_error()
         * returns 'dasd_era_recover' erp_action() is called to create a
-         * special error recovery ccw. erp_postaction() is called after
-         * an error recovery ccw has finished its execution. dump_sense
-         * is called for every error condition to print the sense data
-         * to the console.
-         */
-       dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *);
+        * special error recovery ccw. erp_postaction() is called after
+        * an error recovery ccw has finished its execution. dump_sense
+        * is called for every error condition to print the sense data
+        * to the console.
+        */
        dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *);
        dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
        void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
                            struct irb *);
 
+       void (*handle_unsolicited_interrupt) (struct dasd_device *,
+                                             struct irb *);
+
         /* i/o control functions. */
-       int (*fill_geometry) (struct dasd_device *, struct hd_geometry *);
+       int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
        int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
-       int (*ioctl) (struct dasd_device *, unsigned int, void __user *);
+       int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -267,12 +290,18 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
 /*
  * Unique identifier for dasd device.
  */
+#define UA_NOT_CONFIGURED  0x00
+#define UA_BASE_DEVICE    0x01
+#define UA_BASE_PAV_ALIAS  0x02
+#define UA_HYPER_PAV_ALIAS 0x03
+
 struct dasd_uid {
-       __u8 alias;
+       __u8 type;
        char vendor[4];
        char serial[15];
        __u16 ssid;
-       __u8 unit_addr;
+       __u8 real_unit_addr;
+       __u8 base_unit_addr;
 };
 
 /*
@@ -293,14 +322,9 @@ struct dasd_uid {
 
 struct dasd_device {
        /* Block device stuff. */
-       struct gendisk *gdp;
-       struct request_queue *request_queue;
-       spinlock_t request_queue_lock;
-       struct block_device *bdev;
+       struct dasd_block *block;
+
         unsigned int devindex;
-       unsigned long blocks;      /* size of volume in blocks */
-       unsigned int bp_block;     /* bytes per block */
-       unsigned int s2b_shift;    /* log2 (bp_block/512) */
        unsigned long flags;       /* per device flags */
        unsigned short features;   /* copy of devmap-features (read-only!) */
 
@@ -316,9 +340,8 @@ struct dasd_device {
        int state, target;
        int stopped;            /* device (ccw_device_start) was stopped */
 
-       /* Open and reference count. */
+       /* reference count. */
         atomic_t ref_count;
-       atomic_t open_count;
 
        /* ccw queue and memory for static ccw/erp buffers. */
        struct list_head ccw_queue;
@@ -337,20 +360,45 @@ struct dasd_device {
 
        struct ccw_device *cdev;
 
+       /* hook for alias management */
+       struct list_head alias_list;
+};
+
+struct dasd_block {
+       /* Block device stuff. */
+       struct gendisk *gdp;
+       struct request_queue *request_queue;
+       spinlock_t request_queue_lock;
+       struct block_device *bdev;
+       atomic_t open_count;
+
+       unsigned long blocks;      /* size of volume in blocks */
+       unsigned int bp_block;     /* bytes per block */
+       unsigned int s2b_shift;    /* log2 (bp_block/512) */
+
+       struct dasd_device *base;
+       struct list_head ccw_queue;
+       spinlock_t queue_lock;
+
+       atomic_t tasklet_scheduled;
+       struct tasklet_struct tasklet;
+       struct timer_list timer;
+
 #ifdef CONFIG_DASD_PROFILE
        struct dasd_profile_info_t profile;
 #endif
 };
 
+
+
 /* reasons why device (ccw_device_start) was stopped */
 #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
 #define DASD_STOPPED_QUIESCE 2         /* Quiesced */
 #define DASD_STOPPED_PENDING 4         /* long busy */
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
-#define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
+#define DASD_STOPPED_SU      16        /* summary unit check handling */
 
 /* per device flags */
-#define DASD_FLAG_DSC_ERROR    2       /* return -EIO when disconnected */
 #define DASD_FLAG_OFFLINE      3       /* device is in offline processing */
 #define DASD_FLAG_EER_SNSS     4       /* A SNSS is required */
 #define DASD_FLAG_EER_IN_USE   5       /* A SNSS request is running */
@@ -489,6 +537,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device)
 struct dasd_device *dasd_alloc_device(void);
 void dasd_free_device(struct dasd_device *);
 
+struct dasd_block *dasd_alloc_block(void);
+void dasd_free_block(struct dasd_block *);
+
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
 void dasd_kick_device(struct dasd_device *);
@@ -497,18 +548,23 @@ void dasd_add_request_head(struct dasd_ccw_req *);
 void dasd_add_request_tail(struct dasd_ccw_req *);
 int  dasd_start_IO(struct dasd_ccw_req *);
 int  dasd_term_IO(struct dasd_ccw_req *);
-void dasd_schedule_bh(struct dasd_device *);
+void dasd_schedule_device_bh(struct dasd_device *);
+void dasd_schedule_block_bh(struct dasd_block *);
 int  dasd_sleep_on(struct dasd_ccw_req *);
 int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
 int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
-void dasd_set_timer(struct dasd_device *, int);
-void dasd_clear_timer(struct dasd_device *);
+void dasd_device_set_timer(struct dasd_device *, int);
+void dasd_device_clear_timer(struct dasd_device *);
+void dasd_block_set_timer(struct dasd_block *, int);
+void dasd_block_clear_timer(struct dasd_block *);
 int  dasd_cancel_req(struct dasd_ccw_req *);
+int dasd_flush_device_queue(struct dasd_device *);
 int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
 void dasd_generic_remove (struct ccw_device *cdev);
 int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
+void dasd_generic_handle_state_change(struct dasd_device *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
 
@@ -542,10 +598,10 @@ int dasd_busid_known(char *);
 /* externals in dasd_gendisk.c */
 int  dasd_gendisk_init(void);
 void dasd_gendisk_exit(void);
-int dasd_gendisk_alloc(struct dasd_device *);
-void dasd_gendisk_free(struct dasd_device *);
-int dasd_scan_partitions(struct dasd_device *);
-void dasd_destroy_partitions(struct dasd_device *);
+int dasd_gendisk_alloc(struct dasd_block *);
+void dasd_gendisk_free(struct dasd_block *);
+int dasd_scan_partitions(struct dasd_block *);
+void dasd_destroy_partitions(struct dasd_block *);
 
 /* externals in dasd_ioctl.c */
 int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
@@ -563,20 +619,9 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
 
-/* externals in dasd_3370_erp.c */
-dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
-
 /* externals in dasd_3990_erp.c */
-dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *);
 struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
 
-/* externals in dasd_9336_erp.c */
-dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *);
-
-/* externals in dasd_9336_erp.c */
-dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *);
-struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *);
-
 /* externals in dasd_eer.c */
 #ifdef CONFIG_DASD_EER
 int dasd_eer_init(void);
index 672eb0a3dd0bd4e5e48a71ce33456ee0ce668dc6..91a64630cb0f4095f9fa9933189df9a520bd77ab 100644 (file)
@@ -38,15 +38,15 @@ dasd_ioctl_api_version(void __user *argp)
 static int
 dasd_ioctl_enable(struct block_device *bdev)
 {
-       struct dasd_device *device = bdev->bd_disk->private_data;
+       struct dasd_block *block = bdev->bd_disk->private_data;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       dasd_enable_device(device);
+       dasd_enable_device(block->base);
        /* Formatting the dasd device can change the capacity. */
        mutex_lock(&bdev->bd_mutex);
-       i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
+       i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
        mutex_unlock(&bdev->bd_mutex);
        return 0;
 }
@@ -58,7 +58,7 @@ dasd_ioctl_enable(struct block_device *bdev)
 static int
 dasd_ioctl_disable(struct block_device *bdev)
 {
-       struct dasd_device *device = bdev->bd_disk->private_data;
+       struct dasd_block *block = bdev->bd_disk->private_data;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -71,7 +71,7 @@ dasd_ioctl_disable(struct block_device *bdev)
         * using the BIODASDFMT ioctl. Therefore the correct state for the
         * device is DASD_STATE_BASIC that allows to do basic i/o.
         */
-       dasd_set_target_state(device, DASD_STATE_BASIC);
+       dasd_set_target_state(block->base, DASD_STATE_BASIC);
        /*
         * Set i_size to zero, since read, write, etc. check against this
         * value.
@@ -85,19 +85,19 @@ dasd_ioctl_disable(struct block_device *bdev)
 /*
  * Quiesce device.
  */
-static int
-dasd_ioctl_quiesce(struct dasd_device *device)
+static int dasd_ioctl_quiesce(struct dasd_block *block)
 {
        unsigned long flags;
+       struct dasd_device *base;
 
+       base = block->base;
        if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
 
-       DEV_MESSAGE (KERN_DEBUG, device, "%s",
-                    "Quiesce IO on device");
-       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-       device->stopped |= DASD_STOPPED_QUIESCE;
-       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
+       spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+       base->stopped |= DASD_STOPPED_QUIESCE;
+       spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
        return 0;
 }
 
@@ -105,22 +105,21 @@ dasd_ioctl_quiesce(struct dasd_device *device)
 /*
  * Quiesce device.
  */
-static int
-dasd_ioctl_resume(struct dasd_device *device)
+static int dasd_ioctl_resume(struct dasd_block *block)
 {
        unsigned long flags;
+       struct dasd_device *base;
 
+       base = block->base;
        if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
 
-       DEV_MESSAGE (KERN_DEBUG, device, "%s",
-                    "resume IO on device");
-
-       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-       device->stopped &= ~DASD_STOPPED_QUIESCE;
-       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
+       spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+       base->stopped &= ~DASD_STOPPED_QUIESCE;
+       spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 
-       dasd_schedule_bh (device);
+       dasd_schedule_block_bh(block);
        return 0;
 }
 
@@ -130,22 +129,23 @@ dasd_ioctl_resume(struct dasd_device *device)
  * commands to format a single unit of the device. In terms of the ECKD
  * devices this means CCWs are generated to format a single track.
  */
-static int
-dasd_format(struct dasd_device * device, struct format_data_t * fdata)
+static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
 {
        struct dasd_ccw_req *cqr;
+       struct dasd_device *base;
        int rc;
 
-       if (device->discipline->format_device == NULL)
+       base = block->base;
+       if (base->discipline->format_device == NULL)
                return -EPERM;
 
-       if (device->state != DASD_STATE_BASIC) {
-               DEV_MESSAGE(KERN_WARNING, device, "%s",
+       if (base->state != DASD_STATE_BASIC) {
+               DEV_MESSAGE(KERN_WARNING, base, "%s",
                            "dasd_format: device is not disabled! ");
                return -EBUSY;
        }
 
-       DBF_DEV_EVENT(DBF_NOTICE, device,
+       DBF_DEV_EVENT(DBF_NOTICE, base,
                      "formatting units %d to %d (%d B blocks) flags %d",
                      fdata->start_unit,
                      fdata->stop_unit, fdata->blksize, fdata->intensity);
@@ -156,20 +156,20 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
         * enabling the device later.
         */
        if (fdata->start_unit == 0) {
-               struct block_device *bdev = bdget_disk(device->gdp, 0);
+               struct block_device *bdev = bdget_disk(block->gdp, 0);
                bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
                bdput(bdev);
        }
 
        while (fdata->start_unit <= fdata->stop_unit) {
-               cqr = device->discipline->format_device(device, fdata);
+               cqr = base->discipline->format_device(base, fdata);
                if (IS_ERR(cqr))
                        return PTR_ERR(cqr);
                rc = dasd_sleep_on_interruptible(cqr);
-               dasd_sfree_request(cqr, cqr->device);
+               dasd_sfree_request(cqr, cqr->memdev);
                if (rc) {
                        if (rc != -ERESTARTSYS)
-                               DEV_MESSAGE(KERN_ERR, device,
+                               DEV_MESSAGE(KERN_ERR, base,
                                            " Formatting of unit %d failed "
                                            "with rc = %d",
                                            fdata->start_unit, rc);
@@ -186,7 +186,7 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
 static int
 dasd_ioctl_format(struct block_device *bdev, void __user *argp)
 {
-       struct dasd_device *device = bdev->bd_disk->private_data;
+       struct dasd_block *block = bdev->bd_disk->private_data;
        struct format_data_t fdata;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -194,51 +194,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
        if (!argp)
                return -EINVAL;
 
-       if (device->features & DASD_FEATURE_READONLY)
+       if (block->base->features & DASD_FEATURE_READONLY)
                return -EROFS;
        if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
                return -EFAULT;
        if (bdev != bdev->bd_contains) {
-               DEV_MESSAGE(KERN_WARNING, device, "%s",
+               DEV_MESSAGE(KERN_WARNING, block->base, "%s",
                            "Cannot low-level format a partition");
                return -EINVAL;
        }
-       return dasd_format(device, &fdata);
+       return dasd_format(block, &fdata);
 }
 
 #ifdef CONFIG_DASD_PROFILE
 /*
  * Reset device profile information
  */
-static int
-dasd_ioctl_reset_profile(struct dasd_device *device)
+static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
-       memset(&device->profile, 0, sizeof (struct dasd_profile_info_t));
+       memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
        return 0;
 }
 
 /*
  * Return device profile information
  */
-static int
-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
        if (dasd_profile_level == DASD_PROFILE_OFF)
                return -EIO;
-       if (copy_to_user(argp, &device->profile,
-                        sizeof (struct dasd_profile_info_t)))
+       if (copy_to_user(argp, &block->profile,
+                        sizeof(struct dasd_profile_info_t)))
                return -EFAULT;
        return 0;
 }
 #else
-static int
-dasd_ioctl_reset_profile(struct dasd_device *device)
+static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
        return -ENOSYS;
 }
 
-static int
-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
        return -ENOSYS;
 }
@@ -247,87 +243,88 @@ dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
 /*
  * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
  */
-static int
-dasd_ioctl_information(struct dasd_device *device,
-               unsigned int cmd, void __user *argp)
+static int dasd_ioctl_information(struct dasd_block *block,
+                                 unsigned int cmd, void __user *argp)
 {
        struct dasd_information2_t *dasd_info;
        unsigned long flags;
        int rc;
+       struct dasd_device *base;
        struct ccw_device *cdev;
        struct ccw_dev_id dev_id;
 
-       if (!device->discipline->fill_info)
+       base = block->base;
+       if (!base->discipline->fill_info)
                return -EINVAL;
 
        dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
        if (dasd_info == NULL)
                return -ENOMEM;
 
-       rc = device->discipline->fill_info(device, dasd_info);
+       rc = base->discipline->fill_info(base, dasd_info);
        if (rc) {
                kfree(dasd_info);
                return rc;
        }
 
-       cdev = device->cdev;
+       cdev = base->cdev;
        ccw_device_get_id(cdev, &dev_id);
 
        dasd_info->devno = dev_id.devno;
-       dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
+       dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
        dasd_info->cu_type = cdev->id.cu_type;
        dasd_info->cu_model = cdev->id.cu_model;
        dasd_info->dev_type = cdev->id.dev_type;
        dasd_info->dev_model = cdev->id.dev_model;
-       dasd_info->status = device->state;
+       dasd_info->status = base->state;
        /*
         * The open_count is increased for every opener, that includes
         * the blkdev_get in dasd_scan_partitions.
         * This must be hidden from user-space.
         */
-       dasd_info->open_count = atomic_read(&device->open_count);
-       if (!device->bdev)
+       dasd_info->open_count = atomic_read(&block->open_count);
+       if (!block->bdev)
                dasd_info->open_count++;
 
        /*
         * check if device is really formatted
         * LDL / CDL was returned by 'fill_info'
         */
-       if ((device->state < DASD_STATE_READY) ||
-           (dasd_check_blocksize(device->bp_block)))
+       if ((base->state < DASD_STATE_READY) ||
+           (dasd_check_blocksize(block->bp_block)))
                dasd_info->format = DASD_FORMAT_NONE;
 
        dasd_info->features |=
-               ((device->features & DASD_FEATURE_READONLY) != 0);
+               ((base->features & DASD_FEATURE_READONLY) != 0);
 
-       if (device->discipline)
-               memcpy(dasd_info->type, device->discipline->name, 4);
+       if (base->discipline)
+               memcpy(dasd_info->type, base->discipline->name, 4);
        else
                memcpy(dasd_info->type, "none", 4);
 
-       if (device->request_queue->request_fn) {
+       if (block->request_queue->request_fn) {
                struct list_head *l;
 #ifdef DASD_EXTENDED_PROFILING
                {
                        struct list_head *l;
-                       spin_lock_irqsave(&device->lock, flags);
-                       list_for_each(l, &device->request_queue->queue_head)
+                       spin_lock_irqsave(&block->lock, flags);
+                       list_for_each(l, &block->request_queue->queue_head)
                                dasd_info->req_queue_len++;
-                       spin_unlock_irqrestore(&device->lock, flags);
+                       spin_unlock_irqrestore(&block->lock, flags);
                }
 #endif                         /* DASD_EXTENDED_PROFILING */
-               spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-               list_for_each(l, &device->ccw_queue)
+               spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+               list_for_each(l, &base->ccw_queue)
                        dasd_info->chanq_len++;
-               spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+               spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
                                       flags);
        }
 
        rc = 0;
        if (copy_to_user(argp, dasd_info,
                         ((cmd == (unsigned int) BIODASDINFO2) ?
-                         sizeof (struct dasd_information2_t) :
-                         sizeof (struct dasd_information_t))))
+                         sizeof(struct dasd_information2_t) :
+                         sizeof(struct dasd_information_t))))
                rc = -EFAULT;
        kfree(dasd_info);
        return rc;
@@ -339,7 +336,7 @@ dasd_ioctl_information(struct dasd_device *device,
 static int
 dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
 {
-       struct dasd_device *device =  bdev->bd_disk->private_data;
+       struct dasd_block *block =  bdev->bd_disk->private_data;
        int intval;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -351,11 +348,10 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
                return -EFAULT;
 
        set_disk_ro(bdev->bd_disk, intval);
-       return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
+       return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
 }
 
-static int
-dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
+static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
                unsigned long arg)
 {
        struct cmbdata __user *argp = (void __user *) arg;
@@ -363,7 +359,7 @@ dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
        struct cmbdata data;
        int ret;
 
-       ret = cmf_readall(device->cdev, &data);
+       ret = cmf_readall(block->base->cdev, &data);
        if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
                return -EFAULT;
        return ret;
@@ -374,10 +370,10 @@ dasd_ioctl(struct inode *inode, struct file *file,
           unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
-       struct dasd_device *device = bdev->bd_disk->private_data;
+       struct dasd_block *block = bdev->bd_disk->private_data;
        void __user *argp = (void __user *)arg;
 
-       if (!device)
+       if (!block)
                 return -ENODEV;
 
        if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
@@ -391,33 +387,33 @@ dasd_ioctl(struct inode *inode, struct file *file,
        case BIODASDENABLE:
                return dasd_ioctl_enable(bdev);
        case BIODASDQUIESCE:
-               return dasd_ioctl_quiesce(device);
+               return dasd_ioctl_quiesce(block);
        case BIODASDRESUME:
-               return dasd_ioctl_resume(device);
+               return dasd_ioctl_resume(block);
        case BIODASDFMT:
                return dasd_ioctl_format(bdev, argp);
        case BIODASDINFO:
-               return dasd_ioctl_information(device, cmd, argp);
+               return dasd_ioctl_information(block, cmd, argp);
        case BIODASDINFO2:
-               return dasd_ioctl_information(device, cmd, argp);
+               return dasd_ioctl_information(block, cmd, argp);
        case BIODASDPRRD:
-               return dasd_ioctl_read_profile(device, argp);
+               return dasd_ioctl_read_profile(block, argp);
        case BIODASDPRRST:
-               return dasd_ioctl_reset_profile(device);
+               return dasd_ioctl_reset_profile(block);
        case BLKROSET:
                return dasd_ioctl_set_ro(bdev, argp);
        case DASDAPIVER:
                return dasd_ioctl_api_version(argp);
        case BIODASDCMFENABLE:
-               return enable_cmf(device->cdev);
+               return enable_cmf(block->base->cdev);
        case BIODASDCMFDISABLE:
-               return disable_cmf(device->cdev);
+               return disable_cmf(block->base->cdev);
        case BIODASDREADALLCMB:
-               return dasd_ioctl_readall_cmb(device, cmd, arg);
+               return dasd_ioctl_readall_cmb(block, cmd, arg);
        default:
                /* if the discipline has an ioctl method try it. */
-               if (device->discipline->ioctl) {
-                       int rval = device->discipline->ioctl(device, cmd, argp);
+               if (block->base->discipline->ioctl) {
+                       int rval = block->base->discipline->ioctl(block, cmd, argp);
                        if (rval != -ENOIOCTLCMD)
                                return rval;
                }
index ac7e8ef504cb98f5ae6d0c0d40efa3ac54059f75..28a86f070048b4a3a25719fb100546df9cd8ebd8 100644 (file)
@@ -54,11 +54,16 @@ static int
 dasd_devices_show(struct seq_file *m, void *v)
 {
        struct dasd_device *device;
+       struct dasd_block *block;
        char *substr;
 
        device = dasd_device_from_devindex((unsigned long) v - 1);
        if (IS_ERR(device))
                return 0;
+       if (device->block)
+               block = device->block;
+       else
+               return 0;
        /* Print device number. */
        seq_printf(m, "%s", device->cdev->dev.bus_id);
        /* Print discipline string. */
@@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, void *v)
        else
                seq_printf(m, "(none)");
        /* Print kdev. */
-       if (device->gdp)
+       if (block->gdp)
                seq_printf(m, " at (%3d:%6d)",
-                          device->gdp->major, device->gdp->first_minor);
+                          block->gdp->major, block->gdp->first_minor);
        else
                seq_printf(m, "  at (???:??????)");
        /* Print device name. */
-       if (device->gdp)
-               seq_printf(m, " is %-8s", device->gdp->disk_name);
+       if (block->gdp)
+               seq_printf(m, " is %-8s", block->gdp->disk_name);
        else
                seq_printf(m, " is ????????");
        /* Print devices features. */
@@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, void *v)
        case DASD_STATE_READY:
        case DASD_STATE_ONLINE:
                seq_printf(m, "active ");
-               if (dasd_check_blocksize(device->bp_block))
+               if (dasd_check_blocksize(block->bp_block))
                        seq_printf(m, "n/f       ");
                else
                        seq_printf(m,
                                   "at blocksize: %d, %ld blocks, %ld MB",
-                                  device->bp_block, device->blocks,
-                                  ((device->bp_block >> 9) *
-                                   device->blocks) >> 11);
+                                  block->bp_block, block->blocks,
+                                  ((block->bp_block >> 9) *
+                                   block->blocks) >> 11);
                break;
        default:
                seq_printf(m, "no stat");
@@ -137,7 +142,7 @@ static void dasd_devices_stop(struct seq_file *m, void *v)
 {
 }
 
-static struct seq_operations dasd_devices_seq_ops = {
+static const struct seq_operations dasd_devices_seq_ops = {
        .start          = dasd_devices_start,
        .next           = dasd_devices_next,
        .stop           = dasd_devices_stop,
index 15a5789b773425ba35a0ee0e6f43b8bf18866872..7779bfce1c3181518f2f11debd7a70081be40753 100644 (file)
@@ -82,7 +82,7 @@ struct dcssblk_dev_info {
        struct request_queue *dcssblk_queue;
 };
 
-static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices);
+static LIST_HEAD(dcssblk_devices);
 static struct rw_semaphore dcssblk_devices_sem;
 
 /*
index 130de19916f27b305deae4c2866dd29bfbda84c1..7e73e39a174122462cc917f953e8b2406278e4f9 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-        sclp_info.o sclp_config.o sclp_chp.o
+        sclp_cmd.o sclp_config.o sclp_cpi_sys.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
index 20442fbf93465087b266f21d6790a71f9df8fa83..a86c0534cd49f337dbceb8ef2dab3ac2e0115688 100644 (file)
@@ -295,7 +295,7 @@ module_init(mon_init);
 module_exit(mon_exit);
 
 module_param_named(max_bufs, mon_max_bufs, int, 0644);
-MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
+MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
                 "that can be active at one time");
 
 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
index 8d1c64a24deccd7921c9ecb2e49b68cd9bcce6fb..0d98f1ff2edd5db5ae4f79815de723f81d0241be 100644 (file)
@@ -66,7 +66,7 @@ struct raw3270 {
 static DEFINE_MUTEX(raw3270_mutex);
 
 /* List of 3270 devices. */
-static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
+static LIST_HEAD(raw3270_devices);
 
 /*
  * Flag to indicate if the driver has been registered. Some operations
@@ -1210,7 +1210,7 @@ struct raw3270_notifier {
        void (*notifier)(int, int);
 };
 
-static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier);
+static LIST_HEAD(raw3270_notifier);
 
 int raw3270_register_notifier(void (*notifier)(int, int))
 {
index c7318a125852e37c94f0359ba2ce0d7e7d4d8912..aa8186d18aee8c957a074d845507b74ac985cf1e 100644 (file)
@@ -56,8 +56,6 @@ typedef unsigned int sclp_cmdw_t;
 #define SCLP_CMDW_READ_EVENT_DATA      0x00770005
 #define SCLP_CMDW_WRITE_EVENT_DATA     0x00760005
 #define SCLP_CMDW_WRITE_EVENT_MASK     0x00780005
-#define SCLP_CMDW_READ_SCP_INFO                0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
 
 #define GDS_ID_MDSMU           0x1310
 #define GDS_ID_MDSROUTEINFO    0x1311
@@ -83,6 +81,8 @@ extern u64 sclp_facilities;
 
 #define SCLP_HAS_CHP_INFO      (sclp_facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG  (sclp_facilities & 0x2000000000000000ULL)
+#define SCLP_HAS_CPU_INFO      (sclp_facilities & 0x0800000000000000ULL)
+#define SCLP_HAS_CPU_RECONFIG  (sclp_facilities & 0x0400000000000000ULL)
 
 struct gds_subvector {
        u8      length;
diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c
deleted file mode 100644 (file)
index c68f5e7..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- *  drivers/s390/char/sclp_chp.c
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
- */
-
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/errno.h>
-#include <linux/completion.h>
-#include <asm/sclp.h>
-#include <asm/chpid.h>
-
-#include "sclp.h"
-
-#define TAG    "sclp_chp: "
-
-#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH       0x000f0001
-#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH     0x000e0001
-#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION        0x00030001
-
-static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
-{
-       return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
-}
-
-static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
-{
-       return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
-}
-
-static void chp_callback(struct sclp_req *req, void *data)
-{
-       struct completion *completion = data;
-
-       complete(completion);
-}
-
-struct chp_cfg_sccb {
-       struct sccb_header header;
-       u8 ccm;
-       u8 reserved[6];
-       u8 cssid;
-} __attribute__((packed));
-
-struct chp_cfg_data {
-       struct chp_cfg_sccb sccb;
-       struct sclp_req req;
-       struct completion completion;
-} __attribute__((packed));
-
-static int do_configure(sclp_cmdw_t cmd)
-{
-       struct chp_cfg_data *data;
-       int rc;
-
-       if (!SCLP_HAS_CHP_RECONFIG)
-               return -EOPNOTSUPP;
-       /* Prepare sccb. */
-       data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!data)
-               return -ENOMEM;
-       data->sccb.header.length = sizeof(struct chp_cfg_sccb);
-       data->req.command = cmd;
-       data->req.sccb = &(data->sccb);
-       data->req.status = SCLP_REQ_FILLED;
-       data->req.callback = chp_callback;
-       data->req.callback_data = &(data->completion);
-       init_completion(&data->completion);
-
-       /* Perform sclp request. */
-       rc = sclp_add_request(&(data->req));
-       if (rc)
-               goto out;
-       wait_for_completion(&data->completion);
-
-       /* Check response .*/
-       if (data->req.status != SCLP_REQ_DONE) {
-               printk(KERN_WARNING TAG "configure channel-path request failed "
-                      "(status=0x%02x)\n", data->req.status);
-               rc = -EIO;
-               goto out;
-       }
-       switch (data->sccb.header.response_code) {
-       case 0x0020:
-       case 0x0120:
-       case 0x0440:
-       case 0x0450:
-               break;
-       default:
-               printk(KERN_WARNING TAG "configure channel-path failed "
-                      "(cmd=0x%08x, response=0x%04x)\n", cmd,
-                      data->sccb.header.response_code);
-               rc = -EIO;
-               break;
-       }
-out:
-       free_page((unsigned long) data);
-
-       return rc;
-}
-
-/**
- * sclp_chp_configure - perform configure channel-path sclp command
- * @chpid: channel-path ID
- *
- * Perform configure channel-path command sclp command for specified chpid.
- * Return 0 after command successfully finished, non-zero otherwise.
- */
-int sclp_chp_configure(struct chp_id chpid)
-{
-       return do_configure(get_configure_cmdw(chpid));
-}
-
-/**
- * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
- * @chpid: channel-path ID
- *
- * Perform deconfigure channel-path command sclp command for specified chpid
- * and wait for completion. On success return 0. Return non-zero otherwise.
- */
-int sclp_chp_deconfigure(struct chp_id chpid)
-{
-       return do_configure(get_deconfigure_cmdw(chpid));
-}
-
-struct chp_info_sccb {
-       struct sccb_header header;
-       u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
-       u8 standby[SCLP_CHP_INFO_MASK_SIZE];
-       u8 configured[SCLP_CHP_INFO_MASK_SIZE];
-       u8 ccm;
-       u8 reserved[6];
-       u8 cssid;
-} __attribute__((packed));
-
-struct chp_info_data {
-       struct chp_info_sccb sccb;
-       struct sclp_req req;
-       struct completion completion;
-} __attribute__((packed));
-
-/**
- * sclp_chp_read_info - perform read channel-path information sclp command
- * @info: resulting channel-path information data
- *
- * Perform read channel-path information sclp command and wait for completion.
- * On success, store channel-path information in @info and return 0. Return
- * non-zero otherwise.
- */
-int sclp_chp_read_info(struct sclp_chp_info *info)
-{
-       struct chp_info_data *data;
-       int rc;
-
-       if (!SCLP_HAS_CHP_INFO)
-               return -EOPNOTSUPP;
-       /* Prepare sccb. */
-       data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!data)
-               return -ENOMEM;
-       data->sccb.header.length = sizeof(struct chp_info_sccb);
-       data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
-       data->req.sccb = &(data->sccb);
-       data->req.status = SCLP_REQ_FILLED;
-       data->req.callback = chp_callback;
-       data->req.callback_data = &(data->completion);
-       init_completion(&data->completion);
-
-       /* Perform sclp request. */
-       rc = sclp_add_request(&(data->req));
-       if (rc)
-               goto out;
-       wait_for_completion(&data->completion);
-
-       /* Check response .*/
-       if (data->req.status != SCLP_REQ_DONE) {
-               printk(KERN_WARNING TAG "read channel-path info request failed "
-                      "(status=0x%02x)\n", data->req.status);
-               rc = -EIO;
-               goto out;
-       }
-       if (data->sccb.header.response_code != 0x0010) {
-               printk(KERN_WARNING TAG "read channel-path info failed "
-                      "(response=0x%04x)\n", data->sccb.header.response_code);
-               rc = -EIO;
-               goto out;
-       }
-       memcpy(info->recognized, data->sccb.recognized,
-              SCLP_CHP_INFO_MASK_SIZE);
-       memcpy(info->standby, data->sccb.standby,
-              SCLP_CHP_INFO_MASK_SIZE);
-       memcpy(info->configured, data->sccb.configured,
-              SCLP_CHP_INFO_MASK_SIZE);
-out:
-       free_page((unsigned long) data);
-
-       return rc;
-}
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
new file mode 100644 (file)
index 0000000..b5c2339
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ *  drivers/s390/char/sclp_cmd.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *              Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/chpid.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+#define TAG    "sclp_cmd: "
+
+#define SCLP_CMDW_READ_SCP_INFO                0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
+
+struct read_info_sccb {
+       struct  sccb_header header;     /* 0-7 */
+       u16     rnmax;                  /* 8-9 */
+       u8      rnsize;                 /* 10 */
+       u8      _reserved0[24 - 11];    /* 11-15 */
+       u8      loadparm[8];            /* 24-31 */
+       u8      _reserved1[48 - 32];    /* 32-47 */
+       u64     facilities;             /* 48-55 */
+       u8      _reserved2[84 - 56];    /* 56-83 */
+       u8      fac84;                  /* 84 */
+       u8      _reserved3[91 - 85];    /* 85-90 */
+       u8      flags;                  /* 91 */
+       u8      _reserved4[100 - 92];   /* 92-99 */
+       u32     rnsize2;                /* 100-103 */
+       u64     rnmax2;                 /* 104-111 */
+       u8      _reserved5[4096 - 112]; /* 112-4095 */
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static struct read_info_sccb __initdata early_read_info_sccb;
+static int __initdata early_read_info_sccb_valid;
+
+u64 sclp_facilities;
+static u8 sclp_fac84;
+
+static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
+{
+       int rc;
+
+       __ctl_set_bit(0, 9);
+       rc = sclp_service_call(cmd, sccb);
+       if (rc)
+               goto out;
+       __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+                       PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+       local_irq_disable();
+out:
+       /* Contents of the sccb might have changed. */
+       barrier();
+       __ctl_clear_bit(0, 9);
+       return rc;
+}
+
+void __init sclp_read_info_early(void)
+{
+       int rc;
+       int i;
+       struct read_info_sccb *sccb;
+       sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+                                 SCLP_CMDW_READ_SCP_INFO};
+
+       sccb = &early_read_info_sccb;
+       for (i = 0; i < ARRAY_SIZE(commands); i++) {
+               do {
+                       memset(sccb, 0, sizeof(*sccb));
+                       sccb->header.length = sizeof(*sccb);
+                       sccb->header.control_mask[2] = 0x80;
+                       rc = sclp_cmd_sync_early(commands[i], sccb);
+               } while (rc == -EBUSY);
+
+               if (rc)
+                       break;
+               if (sccb->header.response_code == 0x10) {
+                       early_read_info_sccb_valid = 1;
+                       break;
+               }
+               if (sccb->header.response_code != 0x1f0)
+                       break;
+       }
+}
+
+void __init sclp_facilities_detect(void)
+{
+       if (!early_read_info_sccb_valid)
+               return;
+       sclp_facilities = early_read_info_sccb.facilities;
+       sclp_fac84 = early_read_info_sccb.fac84;
+}
+
+unsigned long long __init sclp_memory_detect(void)
+{
+       unsigned long long memsize;
+       struct read_info_sccb *sccb;
+
+       if (!early_read_info_sccb_valid)
+               return 0;
+       sccb = &early_read_info_sccb;
+       if (sccb->rnsize)
+               memsize = sccb->rnsize << 20;
+       else
+               memsize = sccb->rnsize2 << 20;
+       if (sccb->rnmax)
+               memsize *= sccb->rnmax;
+       else
+               memsize *= sccb->rnmax2;
+       return memsize;
+}
+
+/*
+ * This function will be called after sclp_memory_detect(), which gets called
+ * early from early.c code. Therefore the sccb should have valid contents.
+ */
+void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
+{
+       struct read_info_sccb *sccb;
+
+       if (!early_read_info_sccb_valid)
+               return;
+       sccb = &early_read_info_sccb;
+       info->is_valid = 1;
+       if (sccb->flags & 0x2)
+               info->has_dump = 1;
+       memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
+}
+
+static void sclp_sync_callback(struct sclp_req *req, void *data)
+{
+       struct completion *completion = data;
+
+       complete(completion);
+}
+
+static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
+{
+       struct completion completion;
+       struct sclp_req *request;
+       int rc;
+
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+       request->command = cmd;
+       request->sccb = sccb;
+       request->status = SCLP_REQ_FILLED;
+       request->callback = sclp_sync_callback;
+       request->callback_data = &completion;
+       init_completion(&completion);
+
+       /* Perform sclp request. */
+       rc = sclp_add_request(request);
+       if (rc)
+               goto out;
+       wait_for_completion(&completion);
+
+       /* Check response. */
+       if (request->status != SCLP_REQ_DONE) {
+               printk(KERN_WARNING TAG "sync request failed "
+                      "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
+               rc = -EIO;
+       }
+out:
+       kfree(request);
+       return rc;
+}
+
+/*
+ * CPU configuration related functions.
+ */
+
+#define SCLP_CMDW_READ_CPU_INFO                0x00010001
+#define SCLP_CMDW_CONFIGURE_CPU                0x00110001
+#define SCLP_CMDW_DECONFIGURE_CPU      0x00100001
+
+struct read_cpu_info_sccb {
+       struct  sccb_header header;
+       u16     nr_configured;
+       u16     offset_configured;
+       u16     nr_standby;
+       u16     offset_standby;
+       u8      reserved[4096 - 16];
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
+                              struct read_cpu_info_sccb *sccb)
+{
+       char *page = (char *) sccb;
+
+       memset(info, 0, sizeof(*info));
+       info->configured = sccb->nr_configured;
+       info->standby = sccb->nr_standby;
+       info->combined = sccb->nr_configured + sccb->nr_standby;
+       info->has_cpu_type = sclp_fac84 & 0x1;
+       memcpy(&info->cpu, page + sccb->offset_configured,
+              info->combined * sizeof(struct sclp_cpu_entry));
+}
+
+int sclp_get_cpu_info(struct sclp_cpu_info *info)
+{
+       int rc;
+       struct read_cpu_info_sccb *sccb;
+
+       if (!SCLP_HAS_CPU_INFO)
+               return -EOPNOTSUPP;
+       sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       sccb->header.length = sizeof(*sccb);
+       rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
+       if (rc)
+               goto out;
+       if (sccb->header.response_code != 0x0010) {
+               printk(KERN_WARNING TAG "readcpuinfo failed "
+                      "(response=0x%04x)\n", sccb->header.response_code);
+               rc = -EIO;
+               goto out;
+       }
+       sclp_fill_cpu_info(info, sccb);
+out:
+       free_page((unsigned long) sccb);
+       return rc;
+}
+
+struct cpu_configure_sccb {
+       struct sccb_header header;
+} __attribute__((packed, aligned(8)));
+
+static int do_cpu_configure(sclp_cmdw_t cmd)
+{
+       struct cpu_configure_sccb *sccb;
+       int rc;
+
+       if (!SCLP_HAS_CPU_RECONFIG)
+               return -EOPNOTSUPP;
+       /*
+        * This is not going to cross a page boundary since we force
+        * kmalloc to have a minimum alignment of 8 bytes on s390.
+        */
+       sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       sccb->header.length = sizeof(*sccb);
+       rc = do_sync_request(cmd, sccb);
+       if (rc)
+               goto out;
+       switch (sccb->header.response_code) {
+       case 0x0020:
+       case 0x0120:
+               break;
+       default:
+               printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
+                      "response=0x%04x)\n", cmd, sccb->header.response_code);
+               rc = -EIO;
+               break;
+       }
+out:
+       kfree(sccb);
+       return rc;
+}
+
+int sclp_cpu_configure(u8 cpu)
+{
+       return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
+}
+
+int sclp_cpu_deconfigure(u8 cpu)
+{
+       return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
+}
+
+/*
+ * Channel path configuration related functions.
+ */
+
+#define SCLP_CMDW_CONFIGURE_CHPATH             0x000f0001
+#define SCLP_CMDW_DECONFIGURE_CHPATH           0x000e0001
+#define SCLP_CMDW_READ_CHPATH_INFORMATION      0x00030001
+
+struct chp_cfg_sccb {
+       struct sccb_header header;
+       u8 ccm;
+       u8 reserved[6];
+       u8 cssid;
+} __attribute__((packed));
+
+static int do_chp_configure(sclp_cmdw_t cmd)
+{
+       struct chp_cfg_sccb *sccb;
+       int rc;
+
+       if (!SCLP_HAS_CHP_RECONFIG)
+               return -EOPNOTSUPP;
+       /* Prepare sccb. */
+       sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       sccb->header.length = sizeof(*sccb);
+       rc = do_sync_request(cmd, sccb);
+       if (rc)
+               goto out;
+       switch (sccb->header.response_code) {
+       case 0x0020:
+       case 0x0120:
+       case 0x0440:
+       case 0x0450:
+               break;
+       default:
+               printk(KERN_WARNING TAG "configure channel-path failed "
+                      "(cmd=0x%08x, response=0x%04x)\n", cmd,
+                      sccb->header.response_code);
+               rc = -EIO;
+               break;
+       }
+out:
+       free_page((unsigned long) sccb);
+       return rc;
+}
+
+/**
+ * sclp_chp_configure - perform configure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform configure channel-path command sclp command for specified chpid.
+ * Return 0 after command successfully finished, non-zero otherwise.
+ */
+int sclp_chp_configure(struct chp_id chpid)
+{
+       return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
+}
+
+/**
+ * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform deconfigure channel-path command sclp command for specified chpid
+ * and wait for completion. On success return 0. Return non-zero otherwise.
+ */
+int sclp_chp_deconfigure(struct chp_id chpid)
+{
+       return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
+}
+
+struct chp_info_sccb {
+       struct sccb_header header;
+       u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
+       u8 standby[SCLP_CHP_INFO_MASK_SIZE];
+       u8 configured[SCLP_CHP_INFO_MASK_SIZE];
+       u8 ccm;
+       u8 reserved[6];
+       u8 cssid;
+} __attribute__((packed));
+
+/**
+ * sclp_chp_read_info - perform read channel-path information sclp command
+ * @info: resulting channel-path information data
+ *
+ * Perform read channel-path information sclp command and wait for completion.
+ * On success, store channel-path information in @info and return 0. Return
+ * non-zero otherwise.
+ */
+int sclp_chp_read_info(struct sclp_chp_info *info)
+{
+       struct chp_info_sccb *sccb;
+       int rc;
+
+       if (!SCLP_HAS_CHP_INFO)
+               return -EOPNOTSUPP;
+       /* Prepare sccb. */
+       sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       sccb->header.length = sizeof(*sccb);
+       rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
+       if (rc)
+               goto out;
+       if (sccb->header.response_code != 0x0010) {
+               printk(KERN_WARNING TAG "read channel-path info failed "
+                      "(response=0x%04x)\n", sccb->header.response_code);
+               rc = -EIO;
+               goto out;
+       }
+       memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
+       memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
+       memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
+out:
+       free_page((unsigned long) sccb);
+       return rc;
+}
index 5322e5e54a988e8d06522f532bbbe04c5e67abd4..9dc77f14fa52042978de137751e74168972b3a42 100644 (file)
@@ -29,12 +29,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
        struct sys_device *sysdev;
 
        printk(KERN_WARNING TAG "cpu capability changed.\n");
-       lock_cpu_hotplug();
+       get_online_cpus();
        for_each_online_cpu(cpu) {
                sysdev = get_cpu_sysdev(cpu);
                kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
        }
-       unlock_cpu_hotplug();
+       put_online_cpus();
 }
 
 static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
index 82a13d9fdfe44d6091b4e63724c72161d7d20aa6..5716487b8c9d378cf0c7b37645abd985d894a687 100644 (file)
 /*
- * Author: Martin Peschke <mpeschke@de.ibm.com>
- * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ *  drivers/s390/char/sclp_cpi.c
+ *    SCLP control programm identification
  *
- * SCLP Control-Program Identification.
+ *    Copyright IBM Corp. 2001, 2007
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *              Michael Ernst <mernst@de.ibm.com>
  */
 
-#include <linux/version.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <asm/ebcdic.h>
-#include <asm/semaphore.h>
-
-#include "sclp.h"
-#include "sclp_rw.h"
-
-#define CPI_LENGTH_SYSTEM_TYPE 8
-#define CPI_LENGTH_SYSTEM_NAME 8
-#define CPI_LENGTH_SYSPLEX_NAME        8
-
-struct cpi_evbuf {
-       struct evbuf_header header;
-       u8      id_format;
-       u8      reserved0;
-       u8      system_type[CPI_LENGTH_SYSTEM_TYPE];
-       u64     reserved1;
-       u8      system_name[CPI_LENGTH_SYSTEM_NAME];
-       u64     reserved2;
-       u64     system_level;
-       u64     reserved3;
-       u8      sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
-       u8      reserved4[16];
-} __attribute__((packed));
-
-struct cpi_sccb {
-       struct sccb_header header;
-       struct cpi_evbuf cpi_evbuf;
-} __attribute__((packed));
-
-/* Event type structure for write message and write priority message */
-static struct sclp_register sclp_cpi_event =
-{
-       .send_mask = EVTYP_CTLPROGIDENT_MASK
-};
+#include <linux/version.h>
+#include "sclp_cpi_sys.h"
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Identify this operating system instance "
+                  "to the System z hardware");
+MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, "
+             "Michael Ernst <mernst@de.ibm.com>");
 
-MODULE_AUTHOR(
-       "Martin Peschke, IBM Deutschland Entwicklung GmbH "
-       "<mpeschke@de.ibm.com>");
-
-MODULE_DESCRIPTION(
-       "identify this operating system instance to the S/390 "
-       "or zSeries hardware");
+static char *system_name = "";
+static char *sysplex_name = "";
 
-static char *system_name = NULL;
 module_param(system_name, charp, 0);
 MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
-
-static char *sysplex_name = NULL;
-#ifdef ALLOW_SYSPLEX_NAME
 module_param(sysplex_name, charp, 0);
 MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
-#endif
-
-/* use default value for this field (as well as for system level) */
-static char *system_type = "LINUX";
 
-static int
-cpi_check_parms(void)
+static int __init cpi_module_init(void)
 {
-       /* reject if no system type specified */
-       if (!system_type) {
-               printk("cpi: bug: no system type specified\n");
-               return -EINVAL;
-       }
-
-       /* reject if system type larger than 8 characters */
-       if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) {
-               printk("cpi: bug: system type has length of %li characters - "
-                      "only %i characters supported\n",
-                      strlen(system_type), CPI_LENGTH_SYSTEM_TYPE);
-               return -EINVAL;
-       }
-
-       /* reject if no system name specified */
-       if (!system_name) {
-               printk("cpi: no system name specified\n");
-               return -EINVAL;
-       }
-
-       /* reject if system name larger than 8 characters */
-       if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) {
-               printk("cpi: system name has length of %li characters - "
-                      "only %i characters supported\n",
-                      strlen(system_name), CPI_LENGTH_SYSTEM_NAME);
-               return -EINVAL;
-       }
-
-       /* reject if specified sysplex name larger than 8 characters */
-       if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) {
-               printk("cpi: sysplex name has length of %li characters"
-                      " - only %i characters supported\n",
-                      strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME);
-               return -EINVAL;
-       }
-       return 0;
+       return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
+                                LINUX_VERSION_CODE);
 }
 
-static void
-cpi_callback(struct sclp_req *req, void *data)
-{
-       struct semaphore *sem;
-
-       sem = (struct semaphore *) data;
-       up(sem);
-}
-
-static struct sclp_req *
-cpi_prepare_req(void)
-{
-       struct sclp_req *req;
-       struct cpi_sccb *sccb;
-       struct cpi_evbuf *evb;
-
-       req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
-       if (req == NULL)
-               return ERR_PTR(-ENOMEM);
-       sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
-       if (sccb == NULL) {
-               kfree(req);
-               return ERR_PTR(-ENOMEM);
-       }
-       memset(sccb, 0, sizeof(struct cpi_sccb));
-
-       /* setup SCCB for Control-Program Identification */
-       sccb->header.length = sizeof(struct cpi_sccb);
-       sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
-       sccb->cpi_evbuf.header.type = 0x0B;
-       evb = &sccb->cpi_evbuf;
-
-       /* set system type */
-       memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
-       memcpy(evb->system_type, system_type, strlen(system_type));
-       sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-       EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-
-       /* set system name */
-       memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
-       memcpy(evb->system_name, system_name, strlen(system_name));
-       sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-       EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-
-       /* set system level */
-       evb->system_level = LINUX_VERSION_CODE;
-
-       /* set sysplex name */
-       if (sysplex_name) {
-               memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
-               memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name));
-               sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-               EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-       }
-
-       /* prepare request data structure presented to SCLP driver */
-       req->command = SCLP_CMDW_WRITE_EVENT_DATA;
-       req->sccb = sccb;
-       req->status = SCLP_REQ_FILLED;
-       req->callback = cpi_callback;
-       return req;
-}
-
-static void
-cpi_free_req(struct sclp_req *req)
-{
-       free_page((unsigned long) req->sccb);
-       kfree(req);
-}
-
-static int __init
-cpi_module_init(void)
-{
-       struct semaphore sem;
-       struct sclp_req *req;
-       int rc;
-
-       rc = cpi_check_parms();
-       if (rc)
-               return rc;
-
-       rc = sclp_register(&sclp_cpi_event);
-       if (rc) {
-               /* could not register sclp event. Die. */
-               printk(KERN_WARNING "cpi: could not register to hardware "
-                      "console.\n");
-               return -EINVAL;
-       }
-       if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
-               printk(KERN_WARNING "cpi: no control program identification "
-                      "support\n");
-               sclp_unregister(&sclp_cpi_event);
-               return -EOPNOTSUPP;
-       }
-
-       req = cpi_prepare_req();
-       if (IS_ERR(req)) {
-               printk(KERN_WARNING "cpi: couldn't allocate request\n");
-               sclp_unregister(&sclp_cpi_event);
-               return PTR_ERR(req);
-       }
-
-       /* Prepare semaphore */
-       sema_init(&sem, 0);
-       req->callback_data = &sem;
-       /* Add request to sclp queue */
-       rc = sclp_add_request(req);
-       if (rc) {
-               printk(KERN_WARNING "cpi: could not start request\n");
-               cpi_free_req(req);
-               sclp_unregister(&sclp_cpi_event);
-               return rc;
-       }
-       /* make "insmod" sleep until callback arrives */
-       down(&sem);
-
-       rc = ((struct cpi_sccb *) req->sccb)->header.response_code;
-       if (rc != 0x0020) {
-               printk(KERN_WARNING "cpi: failed with response code 0x%x\n",
-                      rc);
-               rc = -ECOMM;
-       } else
-               rc = 0;
-
-       cpi_free_req(req);
-       sclp_unregister(&sclp_cpi_event);
-
-       return rc;
-}
-
-
 static void __exit cpi_module_exit(void)
 {
 }
 
-
-/* declare driver module init/cleanup functions */
 module_init(cpi_module_init);
 module_exit(cpi_module_exit);
-
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
new file mode 100644 (file)
index 0000000..4161703
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.c
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2001, 2007
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *              Michael Ernst <mernst@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/ebcdic.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+#include "sclp_rw.h"
+#include "sclp_cpi_sys.h"
+
+#define CPI_LENGTH_NAME 8
+#define CPI_LENGTH_LEVEL 16
+
+struct cpi_evbuf {
+       struct evbuf_header header;
+       u8      id_format;
+       u8      reserved0;
+       u8      system_type[CPI_LENGTH_NAME];
+       u64     reserved1;
+       u8      system_name[CPI_LENGTH_NAME];
+       u64     reserved2;
+       u64     system_level;
+       u64     reserved3;
+       u8      sysplex_name[CPI_LENGTH_NAME];
+       u8      reserved4[16];
+} __attribute__((packed));
+
+struct cpi_sccb {
+       struct sccb_header header;
+       struct cpi_evbuf cpi_evbuf;
+} __attribute__((packed));
+
+static struct sclp_register sclp_cpi_event = {
+       .send_mask = EVTYP_CTLPROGIDENT_MASK,
+};
+
+static char system_name[CPI_LENGTH_NAME + 1];
+static char sysplex_name[CPI_LENGTH_NAME + 1];
+static char system_type[CPI_LENGTH_NAME + 1];
+static u64 system_level;
+
+static void set_data(char *field, char *data)
+{
+       memset(field, ' ', CPI_LENGTH_NAME);
+       memcpy(field, data, strlen(data));
+       sclp_ascebc_str(field, CPI_LENGTH_NAME);
+}
+
+static void cpi_callback(struct sclp_req *req, void *data)
+{
+       struct completion *completion = data;
+
+       complete(completion);
+}
+
+static struct sclp_req *cpi_prepare_req(void)
+{
+       struct sclp_req *req;
+       struct cpi_sccb *sccb;
+       struct cpi_evbuf *evb;
+
+       req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+       sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb) {
+               kfree(req);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* setup SCCB for Control-Program Identification */
+       sccb->header.length = sizeof(struct cpi_sccb);
+       sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
+       sccb->cpi_evbuf.header.type = 0x0b;
+       evb = &sccb->cpi_evbuf;
+
+       /* set system type */
+       set_data(evb->system_type, system_type);
+
+       /* set system name */
+       set_data(evb->system_name, system_name);
+
+       /* set sytem level */
+       evb->system_level = system_level;
+
+       /* set sysplex name */
+       set_data(evb->sysplex_name, sysplex_name);
+
+       /* prepare request data structure presented to SCLP driver */
+       req->command = SCLP_CMDW_WRITE_EVENT_DATA;
+       req->sccb = sccb;
+       req->status = SCLP_REQ_FILLED;
+       req->callback = cpi_callback;
+       return req;
+}
+
+static void cpi_free_req(struct sclp_req *req)
+{
+       free_page((unsigned long) req->sccb);
+       kfree(req);
+}
+
+static int cpi_req(void)
+{
+       struct completion completion;
+       struct sclp_req *req;
+       int rc;
+       int response;
+
+       rc = sclp_register(&sclp_cpi_event);
+       if (rc) {
+               printk(KERN_WARNING "cpi: could not register "
+                       "to hardware console.\n");
+               goto out;
+       }
+       if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
+               printk(KERN_WARNING "cpi: no control program "
+                       "identification support\n");
+               rc = -EOPNOTSUPP;
+               goto out_unregister;
+       }
+
+       req = cpi_prepare_req();
+       if (IS_ERR(req)) {
+               printk(KERN_WARNING "cpi: could not allocate request\n");
+               rc = PTR_ERR(req);
+               goto out_unregister;
+       }
+
+       init_completion(&completion);
+       req->callback_data = &completion;
+
+       /* Add request to sclp queue */
+       rc = sclp_add_request(req);
+       if (rc) {
+               printk(KERN_WARNING "cpi: could not start request\n");
+               goto out_free_req;
+       }
+
+       wait_for_completion(&completion);
+
+       if (req->status != SCLP_REQ_DONE) {
+               printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n",
+                       req->status);
+               rc = -EIO;
+               goto out_free_req;
+       }
+
+       response = ((struct cpi_sccb *) req->sccb)->header.response_code;
+       if (response != 0x0020) {
+               printk(KERN_WARNING "cpi: failed with "
+                       "response code 0x%x\n", response);
+               rc = -EIO;
+       }
+
+out_free_req:
+       cpi_free_req(req);
+
+out_unregister:
+       sclp_unregister(&sclp_cpi_event);
+
+out:
+       return rc;
+}
+
+static int check_string(const char *attr, const char *str)
+{
+       size_t len;
+       size_t i;
+
+       len = strlen(str);
+
+       if ((len > 0) && (str[len - 1] == '\n'))
+               len--;
+
+       if (len > CPI_LENGTH_NAME)
+               return -EINVAL;
+
+       for (i = 0; i < len ; i++) {
+               if (isalpha(str[i]) || isdigit(str[i]) ||
+                   strchr("$@# ", str[i]))
+                       continue;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void set_string(char *attr, const char *value)
+{
+       size_t len;
+       size_t i;
+
+       len = strlen(value);
+
+       if ((len > 0) && (value[len - 1] == '\n'))
+               len--;
+
+       for (i = 0; i < CPI_LENGTH_NAME; i++) {
+               if (i < len)
+                       attr[i] = toupper(value[i]);
+               else
+                       attr[i] = ' ';
+       }
+}
+
+static ssize_t system_name_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%s\n", system_name);
+}
+
+static ssize_t system_name_store(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf,
+       size_t len)
+{
+       int rc;
+
+       rc = check_string("system_name", buf);
+       if (rc)
+               return rc;
+
+       set_string(system_name, buf);
+
+       return len;
+}
+
+static struct kobj_attribute system_name_attr =
+       __ATTR(system_name, 0644, system_name_show, system_name_store);
+
+static ssize_t sysplex_name_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
+}
+
+static ssize_t sysplex_name_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buf,
+       size_t len)
+{
+       int rc;
+
+       rc = check_string("sysplex_name", buf);
+       if (rc)
+               return rc;
+
+       set_string(sysplex_name, buf);
+
+       return len;
+}
+
+static struct kobj_attribute sysplex_name_attr =
+       __ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
+
+static ssize_t system_type_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%s\n", system_type);
+}
+
+static ssize_t system_type_store(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf,
+       size_t len)
+{
+       int rc;
+
+       rc = check_string("system_type", buf);
+       if (rc)
+               return rc;
+
+       set_string(system_type, buf);
+
+       return len;
+}
+
+static struct kobj_attribute system_type_attr =
+       __ATTR(system_type, 0644, system_type_show, system_type_store);
+
+static ssize_t system_level_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *page)
+{
+       unsigned long long level = system_level;
+
+       return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
+}
+
+static ssize_t system_level_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buf,
+       size_t len)
+{
+       unsigned long long level;
+       char *endp;
+
+       level = simple_strtoull(buf, &endp, 16);
+
+       if (endp == buf)
+               return -EINVAL;
+       if (*endp == '\n')
+               endp++;
+       if (*endp)
+               return -EINVAL;
+
+       system_level = level;
+
+       return len;
+}
+
+static struct kobj_attribute system_level_attr =
+       __ATTR(system_level, 0644, system_level_show, system_level_store);
+
+static ssize_t set_store(struct kobject *kobj,
+                        struct kobj_attribute *attr,
+                        const char *buf, size_t len)
+{
+       int rc;
+
+       rc = cpi_req();
+       if (rc)
+               return rc;
+
+       return len;
+}
+
+static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
+
+static struct attribute *cpi_attrs[] = {
+       &system_name_attr.attr,
+       &sysplex_name_attr.attr,
+       &system_type_attr.attr,
+       &system_level_attr.attr,
+       &set_attr.attr,
+       NULL,
+};
+
+static struct attribute_group cpi_attr_group = {
+       .attrs = cpi_attrs,
+};
+
+static struct kset *cpi_kset;
+
+int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
+                     const u64 level)
+{
+       int rc;
+
+       rc = check_string("system_name", system);
+       if (rc)
+               return rc;
+       rc = check_string("sysplex_name", sysplex);
+       if (rc)
+               return rc;
+       rc = check_string("system_type", type);
+       if (rc)
+               return rc;
+
+       set_string(system_name, system);
+       set_string(sysplex_name, sysplex);
+       set_string(system_type, type);
+       system_level = level;
+
+       return cpi_req();
+}
+EXPORT_SYMBOL(sclp_cpi_set_data);
+
+static int __init cpi_init(void)
+{
+       int rc;
+
+       cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
+       if (!cpi_kset)
+               return -ENOMEM;
+
+       rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
+       if (rc)
+               kset_unregister(cpi_kset);
+
+       return rc;
+}
+
+__initcall(cpi_init);
diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h
new file mode 100644 (file)
index 0000000..deef3e6
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.h
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Michael Ernst <mernst@de.ibm.com>
+ */
+
+#ifndef __SCLP_CPI_SYS_H__
+#define __SCLP_CPI_SYS_H__
+
+int sclp_cpi_set_data(const char *system, const char *sysplex,
+                     const char *type, u64 level);
+
+#endif  /* __SCLP_CPI_SYS_H__ */
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
deleted file mode 100644 (file)
index a1136e0..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *  drivers/s390/char/sclp_info.c
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <asm/sclp.h>
-#include "sclp.h"
-
-struct sclp_readinfo_sccb {
-       struct  sccb_header header;     /* 0-7 */
-       u16     rnmax;                  /* 8-9 */
-       u8      rnsize;                 /* 10 */
-       u8      _reserved0[24 - 11];    /* 11-23 */
-       u8      loadparm[8];            /* 24-31 */
-       u8      _reserved1[48 - 32];    /* 32-47 */
-       u64     facilities;             /* 48-55 */
-       u8      _reserved2[91 - 56];    /* 56-90 */
-       u8      flags;                  /* 91 */
-       u8      _reserved3[100 - 92];   /* 92-99 */
-       u32     rnsize2;                /* 100-103 */
-       u64     rnmax2;                 /* 104-111 */
-       u8      _reserved4[4096 - 112]; /* 112-4095 */
-} __attribute__((packed, aligned(4096)));
-
-static struct sclp_readinfo_sccb __initdata early_readinfo_sccb;
-static int __initdata early_readinfo_sccb_valid;
-
-u64 sclp_facilities;
-
-void __init sclp_readinfo_early(void)
-{
-       int ret;
-       int i;
-       struct sclp_readinfo_sccb *sccb;
-       sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
-                                 SCLP_CMDW_READ_SCP_INFO};
-
-       /* Enable service signal subclass mask. */
-       __ctl_set_bit(0, 9);
-       sccb = &early_readinfo_sccb;
-       for (i = 0; i < ARRAY_SIZE(commands); i++) {
-               do {
-                       memset(sccb, 0, sizeof(*sccb));
-                       sccb->header.length = sizeof(*sccb);
-                       sccb->header.control_mask[2] = 0x80;
-                       ret = sclp_service_call(commands[i], sccb);
-               } while (ret == -EBUSY);
-
-               if (ret)
-                       break;
-               __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
-                               PSW_MASK_WAIT | PSW_DEFAULT_KEY);
-               local_irq_disable();
-               /*
-                * Contents of the sccb might have changed
-                * therefore a barrier is needed.
-                */
-               barrier();
-               if (sccb->header.response_code == 0x10) {
-                       early_readinfo_sccb_valid = 1;
-                       break;
-               }
-               if (sccb->header.response_code != 0x1f0)
-                       break;
-       }
-       /* Disable service signal subclass mask again. */
-       __ctl_clear_bit(0, 9);
-}
-
-void __init sclp_facilities_detect(void)
-{
-       if (!early_readinfo_sccb_valid)
-               return;
-       sclp_facilities = early_readinfo_sccb.facilities;
-}
-
-unsigned long long __init sclp_memory_detect(void)
-{
-       unsigned long long memsize;
-       struct sclp_readinfo_sccb *sccb;
-
-       if (!early_readinfo_sccb_valid)
-               return 0;
-       sccb = &early_readinfo_sccb;
-       if (sccb->rnsize)
-               memsize = sccb->rnsize << 20;
-       else
-               memsize = sccb->rnsize2 << 20;
-       if (sccb->rnmax)
-               memsize *= sccb->rnmax;
-       else
-               memsize *= sccb->rnmax2;
-       return memsize;
-}
-
-/*
- * This function will be called after sclp_memory_detect(), which gets called
- * early from early.c code. Therefore the sccb should have valid contents.
- */
-void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
-{
-       struct sclp_readinfo_sccb *sccb;
-
-       if (!early_readinfo_sccb_valid)
-               return;
-       sccb = &early_readinfo_sccb;
-       info->is_valid = 1;
-       if (sccb->flags & 0x2)
-               info->has_dump = 1;
-       memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
-}
index d6b06ab81188884a1a63729653366a7ab4ee7b8d..ad7195d3de0cfaf5613df7b75b8c6cb3d0865d52 100644 (file)
@@ -76,7 +76,7 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
 }
 
 /*
- * Return a pointer to the orignal page that has been used to create
+ * Return a pointer to the original page that has been used to create
  * the buffer.
  */
 void *
index da25f8e24152b7da94a52c79eff4903fabe17eae..8246ef3ab09583da05e33519bcf8e738e55b5a5a 100644 (file)
@@ -1495,7 +1495,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
                           device->cdev->dev.bus_id);
                return tape_3590_erp_basic(device, request, irb, -EPERM);
        case 0x8013:
-               PRINT_WARN("(%s): Another host has priviliged access to the "
+               PRINT_WARN("(%s): Another host has privileged access to the "
                           "tape device\n", device->cdev->dev.bus_id);
                PRINT_WARN("(%s): To solve the problem unload the current "
                           "cartridge!\n", device->cdev->dev.bus_id);
index 2fae6338ee1c146fd09e9c2824129cfaa1e9d9d8..7ad8cf157641a22dd000831de72173f76aa2e5e6 100644 (file)
@@ -37,7 +37,7 @@ static void tape_long_busy_timeout(unsigned long data);
  * we can assign the devices to minor numbers of the same major
  * The list is protected by the rwlock
  */
-static struct list_head tape_device_list = LIST_HEAD_INIT(tape_device_list);
+static LIST_HEAD(tape_device_list);
 static DEFINE_RWLOCK(tape_device_lock);
 
 /*
index cea49f001f89cbea1fadc0c541e0f08b2d888491..c9b96d51b28f25d36ab9fa85fbc34e60648fc3e0 100644 (file)
@@ -97,7 +97,7 @@ static void tape_proc_stop(struct seq_file *m, void *v)
 {
 }
 
-static struct seq_operations tape_proc_seq = {
+static const struct seq_operations tape_proc_seq = {
        .start          = tape_proc_start,
        .next           = tape_proc_next,
        .stop           = tape_proc_stop,
index e0c4c508e12181b813b51a3926396be5a46e85c9..d364e0bfae12eb1ff999439aee0a94fa7c99087d 100644 (file)
@@ -683,7 +683,7 @@ static int vmlogrdr_register_driver(void)
        /* Register with iucv driver */
        ret = iucv_register(&vmlogrdr_iucv_handler, 1);
        if (ret) {
-               printk (KERN_ERR "vmlogrdr: failed to register with"
+               printk (KERN_ERR "vmlogrdr: failed to register with "
                        "iucv driver\n");
                goto out;
        }
index d70a6e65bf14fdf314dae599450d55c85e815b23..7689b500a1046ffbddfd0426c7229847959bc0f0 100644 (file)
@@ -759,7 +759,7 @@ static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
        return newpos;
 }
 
-static struct file_operations ur_fops = {
+static const struct file_operations ur_fops = {
        .owner   = THIS_MODULE,
        .open    = ur_open,
        .release = ur_release,
index 7073daf77981005e7edfe0c6f59c08b2a3251212..f523501e6e6c60bb25bbf80077847f87edcfc23a 100644 (file)
@@ -470,7 +470,7 @@ static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
        return rc;
 }
 
-static struct file_operations zcore_fops = {
+static const struct file_operations zcore_fops = {
        .owner          = THIS_MODULE,
        .llseek         = zcore_lseek,
        .read           = zcore_read,
index 5287631fbfc8439d92c921c6664998bf1eea5caa..b7a07a866291624a30a3ba13fab6bce3eb6034f7 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/airq.c
- *   S/390 common I/O routines -- support for adapter interruptions
+ *    Support for adapter interruptions
  *
- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
- *                           IBM Corporation
- *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *              Cornelia Huck (cornelia.huck@de.ibm.com)
- *              Arnd Bergmann (arndb@de.ibm.com)
+ *    Copyright IBM Corp. 1999,2007
+ *    Author(s): Ingo Adlung <adlung@de.ibm.com>
+ *              Cornelia Huck <cornelia.huck@de.ibm.com>
+ *              Arnd Bergmann <arndb@de.ibm.com>
+ *              Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
 
+#include <asm/airq.h>
+
+#include "cio.h"
 #include "cio_debug.h"
-#include "airq.h"
 
-static adapter_int_handler_t adapter_handler;
+#define NR_AIRQS               32
+#define NR_AIRQS_PER_WORD      sizeof(unsigned long)
+#define NR_AIRQ_WORDS          (NR_AIRQS / NR_AIRQS_PER_WORD)
 
-/*
- * register for adapter interrupts
- *
- * With HiperSockets the zSeries architecture provides for
- *  means of adapter interrups, pseudo I/O interrupts that are
- *  not tied to an I/O subchannel, but to an adapter. However,
- *  it doesn't disclose the info how to enable/disable them, but
- *  to recognize them only. Perhaps we should consider them
- *  being shared interrupts, and thus build a linked list
- *  of adapter handlers ... to be evaluated ...
- */
-int
-s390_register_adapter_interrupt (adapter_int_handler_t handler)
-{
-       int ret;
-       char dbf_txt[15];
+union indicator_t {
+       unsigned long word[NR_AIRQ_WORDS];
+       unsigned char byte[NR_AIRQS];
+} __attribute__((packed));
 
-       CIO_TRACE_EVENT (4, "rgaint");
+struct airq_t {
+       adapter_int_handler_t handler;
+       void *drv_data;
+};
 
-       if (handler == NULL)
-               ret = -EINVAL;
-       else
-               ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
-       if (!ret)
-               synchronize_sched();  /* Allow interrupts to complete. */
+static union indicator_t indicators;
+static struct airq_t *airqs[NR_AIRQS];
 
-       sprintf (dbf_txt, "ret:%d", ret);
-       CIO_TRACE_EVENT (4, dbf_txt);
+static int register_airq(struct airq_t *airq)
+{
+       int i;
 
-       return ret;
+       for (i = 0; i < NR_AIRQS; i++)
+               if (!cmpxchg(&airqs[i], NULL, airq))
+                       return i;
+       return -ENOMEM;
 }
 
-int
-s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
+/**
+ * s390_register_adapter_interrupt() - register adapter interrupt handler
+ * @handler: adapter handler to be registered
+ * @drv_data: driver data passed with each call to the handler
+ *
+ * Returns:
+ *  Pointer to the indicator to be used on success
+ *  ERR_PTR() if registration failed
+ */
+void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
+                                     void *drv_data)
 {
+       struct airq_t *airq;
+       char dbf_txt[16];
        int ret;
-       char dbf_txt[15];
 
-       CIO_TRACE_EVENT (4, "urgaint");
-
-       if (handler == NULL)
-               ret = -EINVAL;
-       else {
-               adapter_handler = NULL;
-               synchronize_sched();  /* Allow interrupts to complete. */
-               ret = 0;
+       airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
+       if (!airq) {
+               ret = -ENOMEM;
+               goto out;
        }
-       sprintf (dbf_txt, "ret:%d", ret);
-       CIO_TRACE_EVENT (4, dbf_txt);
-
-       return ret;
+       airq->handler = handler;
+       airq->drv_data = drv_data;
+       ret = register_airq(airq);
+       if (ret < 0)
+               kfree(airq);
+out:
+       snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
+       CIO_TRACE_EVENT(4, dbf_txt);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       else
+               return &indicators.byte[ret];
 }
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
 
-void
-do_adapter_IO (void)
+/**
+ * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
+ * @ind: indicator for which the handler is to be unregistered
+ */
+void s390_unregister_adapter_interrupt(void *ind)
 {
-       CIO_TRACE_EVENT (6, "doaio");
+       struct airq_t *airq;
+       char dbf_txt[16];
+       int i;
 
-       if (adapter_handler)
-               (*adapter_handler) ();
+       i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
+       snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
+       CIO_TRACE_EVENT(4, dbf_txt);
+       indicators.byte[i] = 0;
+       airq = xchg(&airqs[i], NULL);
+       /*
+        * Allow interrupts to complete. This will ensure that the airq handle
+        * is no longer referenced by any interrupt handler.
+        */
+       synchronize_sched();
+       kfree(airq);
 }
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
+
+#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
 
-EXPORT_SYMBOL (s390_register_adapter_interrupt);
-EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
+void do_adapter_IO(void)
+{
+       int w;
+       int i;
+       unsigned long word;
+       struct airq_t *airq;
+
+       /*
+        * Access indicator array in word-sized chunks to minimize storage
+        * fetch operations.
+        */
+       for (w = 0; w < NR_AIRQ_WORDS; w++) {
+               word = indicators.word[w];
+               i = w * NR_AIRQS_PER_WORD;
+               /*
+                * Check bytes within word for active indicators.
+                */
+               while (word) {
+                       if (word & INDICATOR_MASK) {
+                               airq = airqs[i];
+                               if (likely(airq))
+                                       airq->handler(&indicators.byte[i],
+                                                     airq->drv_data);
+                               else
+                                       /*
+                                        * Reset ill-behaved indicator.
+                                        */
+                                       indicators.byte[i] = 0;
+                       }
+                       word <<= 8;
+                       i++;
+               }
+       }
+}
diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h
deleted file mode 100644 (file)
index 7d6be3f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef S390_AINTERRUPT_H
-#define S390_AINTERRUPT_H
-
-typedef        int (*adapter_int_handler_t)(void);
-
-extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
-extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
-extern void do_adapter_IO (void);
-
-#endif
index bd5f16f80bf8f316e8d52937771100cf0f914d7f..e8597ec92247b2eb9127f32448b24c47b12a50e1 100644 (file)
@@ -348,7 +348,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
        return user_len;
 }
 
-static struct seq_operations cio_ignore_proc_seq_ops = {
+static const struct seq_operations cio_ignore_proc_seq_ops = {
        .start = cio_ignore_proc_seq_start,
        .stop  = cio_ignore_proc_seq_stop,
        .next  = cio_ignore_proc_seq_next,
index 5baa517c3b6625665f98dadada2679ec7da4e641..3964056a9a4745f05b607c86a1a837eaa961c0eb 100644 (file)
@@ -35,8 +35,8 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
        struct ccwgroup_device *gdev;
        struct ccwgroup_driver *gdrv;
 
-       gdev = container_of(dev, struct ccwgroup_device, dev);
-       gdrv = container_of(drv, struct ccwgroup_driver, driver);
+       gdev = to_ccwgroupdev(dev);
+       gdrv = to_ccwgroupdrv(drv);
 
        if (gdev->creator_id == gdrv->driver_id)
                return 1;
@@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev)
        struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
 
        mutex_lock(&gdev->reg_mutex);
-       __ccwgroup_remove_symlinks(gdev);
-       device_unregister(dev);
+       if (device_is_registered(&gdev->dev)) {
+               __ccwgroup_remove_symlinks(gdev);
+               device_unregister(dev);
+       }
        mutex_unlock(&gdev->reg_mutex);
 }
 
@@ -111,7 +113,7 @@ ccwgroup_release (struct device *dev)
        gdev = to_ccwgroupdev(dev);
 
        for (i = 0; i < gdev->count; i++) {
-               gdev->cdev[i]->dev.driver_data = NULL;
+               dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
                put_device(&gdev->cdev[i]->dev);
        }
        kfree(gdev);
@@ -196,11 +198,11 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
                        goto error;
                }
                /* Don't allow a device to belong to more than one group. */
-               if (gdev->cdev[i]->dev.driver_data) {
+               if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
                        rc = -EINVAL;
                        goto error;
                }
-               gdev->cdev[i]->dev.driver_data = gdev;
+               dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
        }
 
        gdev->creator_id = creator_id;
@@ -234,8 +236,8 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
 error:
        for (i = 0; i < argc; i++)
                if (gdev->cdev[i]) {
-                       if (gdev->cdev[i]->dev.driver_data == gdev)
-                               gdev->cdev[i]->dev.driver_data = NULL;
+                       if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
+                               dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
                        put_device(&gdev->cdev[i]->dev);
                }
        mutex_unlock(&gdev->reg_mutex);
@@ -408,6 +410,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
        /* register our new driver with the core */
        cdriver->driver.bus = &ccwgroup_bus_type;
        cdriver->driver.name = cdriver->name;
+       cdriver->driver.owner = cdriver->owner;
 
        return driver_register(&cdriver->driver);
 }
@@ -463,8 +466,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
 {
        struct ccwgroup_device *gdev;
 
-       if (cdev->dev.driver_data) {
-               gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
+       gdev = dev_get_drvdata(&cdev->dev);
+       if (gdev) {
                if (get_device(&gdev->dev)) {
                        mutex_lock(&gdev->reg_mutex);
                        if (device_is_registered(&gdev->dev))
index 597c0c76a2adcaf12cc228465b6f363a8a528626..e7ba16a74ef7bf49cb4b19c5cb91b9b5a8cc12d5 100644 (file)
@@ -89,7 +89,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
        /* Copy data */
        ret = 0;
        memset(ssd, 0, sizeof(struct chsc_ssd_info));
-       if ((ssd_area->st != 0) && (ssd_area->st != 2))
+       if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
+           (ssd_area->st != SUBCHANNEL_TYPE_MSG))
                goto out_free;
        ssd->path_mask = ssd_area->path_mask;
        ssd->fla_valid_mask = ssd_area->fla_valid_mask;
@@ -132,20 +133,16 @@ static void terminate_internal_io(struct subchannel *sch)
        device_set_intretry(sch);
        /* Call handler. */
        if (sch->driver && sch->driver->termination)
-               sch->driver->termination(&sch->dev);
+               sch->driver->termination(sch);
 }
 
-static int
-s390_subchannel_remove_chpid(struct device *dev, void *data)
+static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
 {
        int j;
        int mask;
-       struct subchannel *sch;
-       struct chp_id *chpid;
+       struct chp_id *chpid = data;
        struct schib schib;
 
-       sch = to_subchannel(dev);
-       chpid = data;
        for (j = 0; j < 8; j++) {
                mask = 0x80 >> j;
                if ((sch->schib.pmcw.pim & mask) &&
@@ -158,7 +155,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
        spin_lock_irq(sch->lock);
 
        stsch(sch->schid, &schib);
-       if (!schib.pmcw.dnv)
+       if (!css_sch_is_valid(&schib))
                goto out_unreg;
        memcpy(&sch->schib, &schib, sizeof(struct schib));
        /* Check for single path devices. */
@@ -172,12 +169,12 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
                        terminate_internal_io(sch);
                        /* Re-start path verification. */
                        if (sch->driver && sch->driver->verify)
-                               sch->driver->verify(&sch->dev);
+                               sch->driver->verify(sch);
                }
        } else {
                /* trigger path verification. */
                if (sch->driver && sch->driver->verify)
-                       sch->driver->verify(&sch->dev);
+                       sch->driver->verify(sch);
                else if (sch->lpm == mask)
                        goto out_unreg;
        }
@@ -201,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpid)
 
        if (chp_get_status(chpid) <= 0)
                return;
-       bus_for_each_dev(&css_bus_type, NULL, &chpid,
-                        s390_subchannel_remove_chpid);
+       for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
 }
 
-static int
-s390_process_res_acc_new_sch(struct subchannel_id schid)
+static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
 {
        struct schib schib;
        /*
@@ -252,18 +247,10 @@ static int get_res_chpid_mask(struct chsc_ssd_info *ssd,
        return 0;
 }
 
-static int
-__s390_process_res_acc(struct subchannel_id schid, void *data)
+static int __s390_process_res_acc(struct subchannel *sch, void *data)
 {
        int chp_mask, old_lpm;
-       struct res_acc_data *res_data;
-       struct subchannel *sch;
-
-       res_data = data;
-       sch = get_subchannel_by_schid(schid);
-       if (!sch)
-               /* Check if a subchannel is newly available. */
-               return s390_process_res_acc_new_sch(schid);
+       struct res_acc_data *res_data = data;
 
        spin_lock_irq(sch->lock);
        chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
@@ -279,10 +266,10 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
        if (!old_lpm && sch->lpm)
                device_trigger_reprobe(sch);
        else if (sch->driver && sch->driver->verify)
-               sch->driver->verify(&sch->dev);
+               sch->driver->verify(sch);
 out:
        spin_unlock_irq(sch->lock);
-       put_device(&sch->dev);
+
        return 0;
 }
 
@@ -305,7 +292,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data)
         * The more information we have (info), the less scanning
         * will we have to do.
         */
-       for_each_subchannel(__s390_process_res_acc, res_data);
+       for_each_subchannel_staged(__s390_process_res_acc,
+                                  s390_process_res_acc_new_sch, res_data);
 }
 
 static int
@@ -499,8 +487,7 @@ void chsc_process_crw(void)
        } while (sei_area->flags & 0x80);
 }
 
-static int
-__chp_add_new_sch(struct subchannel_id schid)
+static int __chp_add_new_sch(struct subchannel_id schid, void *data)
 {
        struct schib schib;
 
@@ -514,45 +501,37 @@ __chp_add_new_sch(struct subchannel_id schid)
 }
 
 
-static int
-__chp_add(struct subchannel_id schid, void *data)
+static int __chp_add(struct subchannel *sch, void *data)
 {
        int i, mask;
-       struct chp_id *chpid;
-       struct subchannel *sch;
-
-       chpid = data;
-       sch = get_subchannel_by_schid(schid);
-       if (!sch)
-               /* Check if the subchannel is now available. */
-               return __chp_add_new_sch(schid);
+       struct chp_id *chpid = data;
+
        spin_lock_irq(sch->lock);
        for (i=0; i<8; i++) {
                mask = 0x80 >> i;
                if ((sch->schib.pmcw.pim & mask) &&
-                   (sch->schib.pmcw.chpid[i] == chpid->id)) {
-                       if (stsch(sch->schid, &sch->schib) != 0) {
-                               /* Endgame. */
-                               spin_unlock_irq(sch->lock);
-                               return -ENXIO;
-                       }
+                   (sch->schib.pmcw.chpid[i] == chpid->id))
                        break;
-               }
        }
        if (i==8) {
                spin_unlock_irq(sch->lock);
                return 0;
        }
+       if (stsch(sch->schid, &sch->schib)) {
+               spin_unlock_irq(sch->lock);
+               css_schedule_eval(sch->schid);
+               return 0;
+       }
        sch->lpm = ((sch->schib.pmcw.pim &
                     sch->schib.pmcw.pam &
                     sch->schib.pmcw.pom)
                    | mask) & sch->opm;
 
        if (sch->driver && sch->driver->verify)
-               sch->driver->verify(&sch->dev);
+               sch->driver->verify(sch);
 
        spin_unlock_irq(sch->lock);
-       put_device(&sch->dev);
+
        return 0;
 }
 
@@ -564,7 +543,8 @@ void chsc_chp_online(struct chp_id chpid)
        CIO_TRACE_EVENT(2, dbf_txt);
 
        if (chp_get_status(chpid) != 0)
-               for_each_subchannel(__chp_add, &chpid);
+               for_each_subchannel_staged(__chp_add, __chp_add_new_sch,
+                                          &chpid);
 }
 
 static void __s390_subchannel_vary_chpid(struct subchannel *sch,
@@ -589,7 +569,7 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
                        if (!old_lpm)
                                device_trigger_reprobe(sch);
                        else if (sch->driver && sch->driver->verify)
-                               sch->driver->verify(&sch->dev);
+                               sch->driver->verify(sch);
                        break;
                }
                sch->opm &= ~mask;
@@ -603,37 +583,29 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
                                terminate_internal_io(sch);
                                /* Re-start path verification. */
                                if (sch->driver && sch->driver->verify)
-                                       sch->driver->verify(&sch->dev);
+                                       sch->driver->verify(sch);
                        }
                } else if (!sch->lpm) {
                        if (device_trigger_verify(sch) != 0)
                                css_schedule_eval(sch->schid);
                } else if (sch->driver && sch->driver->verify)
-                       sch->driver->verify(&sch->dev);
+                       sch->driver->verify(sch);
                break;
        }
        spin_unlock_irqrestore(sch->lock, flags);
 }
 
-static int s390_subchannel_vary_chpid_off(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
 {
-       struct subchannel *sch;
-       struct chp_id *chpid;
-
-       sch = to_subchannel(dev);
-       chpid = data;
+       struct chp_id *chpid = data;
 
        __s390_subchannel_vary_chpid(sch, *chpid, 0);
        return 0;
 }
 
-static int s390_subchannel_vary_chpid_on(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
 {
-       struct subchannel *sch;
-       struct chp_id *chpid;
-
-       sch = to_subchannel(dev);
-       chpid = data;
+       struct chp_id *chpid = data;
 
        __s390_subchannel_vary_chpid(sch, *chpid, 1);
        return 0;
@@ -643,13 +615,7 @@ static int
 __s390_vary_chpid_on(struct subchannel_id schid, void *data)
 {
        struct schib schib;
-       struct subchannel *sch;
 
-       sch = get_subchannel_by_schid(schid);
-       if (sch) {
-               put_device(&sch->dev);
-               return 0;
-       }
        if (stsch_err(schid, &schib))
                /* We're through */
                return -ENXIO;
@@ -669,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, int on)
         * Redo PathVerification on the devices the chpid connects to
         */
 
-       bus_for_each_dev(&css_bus_type, NULL, &chpid, on ?
-                        s390_subchannel_vary_chpid_on :
-                        s390_subchannel_vary_chpid_off);
        if (on)
-               /* Scan for new devices on varied on path. */
-               for_each_subchannel(__s390_vary_chpid_on, NULL);
+               for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
+                                          __s390_vary_chpid_on, &chpid);
+       else
+               for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
+                                          NULL, &chpid);
+
        return 0;
 }
 
@@ -1075,7 +1042,7 @@ chsc_determine_css_characteristics(void)
 
        scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scsc_area) {
-               CIO_MSG_EVENT(0, "Was not able to determine available"
+               CIO_MSG_EVENT(0, "Was not able to determine available "
                              "CHSCs due to no memory.\n");
                return -ENOMEM;
        }
index 46905345159e6705036d7d20030de558a534b60d..60590a12d5299ce43e2626f045fdd488589d40cc 100644 (file)
 #include <asm/reset.h>
 #include <asm/ipl.h>
 #include <asm/chpid.h>
-#include "airq.h"
+#include <asm/airq.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
 #include "ioasm.h"
+#include "io_sch.h"
 #include "blacklist.h"
 #include "cio_debug.h"
 #include "chp.h"
@@ -56,39 +57,37 @@ __setup ("cio_msg=", cio_setup);
 
 /*
  * Function: cio_debug_init
- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * Initializes three debug logs for common I/O:
+ * - cio_msg logs generic cio messages
  * - cio_trace logs the calling of different functions
- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ * - cio_crw logs machine check related cio messages
  */
-static int __init
-cio_debug_init (void)
+static int __init cio_debug_init(void)
 {
-       cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
+       cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
        if (!cio_debug_msg_id)
                goto out_unregister;
-       debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
-       debug_set_level (cio_debug_msg_id, 2);
-       cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
+       debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+       debug_set_level(cio_debug_msg_id, 2);
+       cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
        if (!cio_debug_trace_id)
                goto out_unregister;
-       debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
-       debug_set_level (cio_debug_trace_id, 2);
-       cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
+       debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+       debug_set_level(cio_debug_trace_id, 2);
+       cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
        if (!cio_debug_crw_id)
                goto out_unregister;
-       debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
-       debug_set_level (cio_debug_crw_id, 2);
+       debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+       debug_set_level(cio_debug_crw_id, 4);
        return 0;
 
 out_unregister:
        if (cio_debug_msg_id)
-               debug_unregister (cio_debug_msg_id);
+               debug_unregister(cio_debug_msg_id);
        if (cio_debug_trace_id)
-               debug_unregister (cio_debug_trace_id);
+               debug_unregister(cio_debug_trace_id);
        if (cio_debug_crw_id)
-               debug_unregister (cio_debug_crw_id);
+               debug_unregister(cio_debug_crw_id);
        printk(KERN_WARNING"cio: could not initialize debugging\n");
        return -1;
 }
@@ -147,7 +146,7 @@ cio_tpi(void)
        spin_lock(sch->lock);
        memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
        if (sch->driver && sch->driver->irq)
-               sch->driver->irq(&sch->dev);
+               sch->driver->irq(sch);
        spin_unlock(sch->lock);
        irq_exit ();
        _local_bh_enable();
@@ -184,33 +183,35 @@ cio_start_key (struct subchannel *sch,    /* subchannel structure */
 {
        char dbf_txt[15];
        int ccode;
+       struct orb *orb;
 
-       CIO_TRACE_EVENT (4, "stIO");
-       CIO_TRACE_EVENT (4, sch->dev.bus_id);
+       CIO_TRACE_EVENT(4, "stIO");
+       CIO_TRACE_EVENT(4, sch->dev.bus_id);
 
+       orb = &to_io_private(sch)->orb;
        /* sch is always under 2G. */
-       sch->orb.intparm = (__u32)(unsigned long)sch;
-       sch->orb.fmt = 1;
+       orb->intparm = (u32)(addr_t)sch;
+       orb->fmt = 1;
 
-       sch->orb.pfch = sch->options.prefetch == 0;
-       sch->orb.spnd = sch->options.suspend;
-       sch->orb.ssic = sch->options.suspend && sch->options.inter;
-       sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
+       orb->pfch = sch->options.prefetch == 0;
+       orb->spnd = sch->options.suspend;
+       orb->ssic = sch->options.suspend && sch->options.inter;
+       orb->lpm = (lpm != 0) ? lpm : sch->lpm;
 #ifdef CONFIG_64BIT
        /*
         * for 64 bit we always support 64 bit IDAWs with 4k page size only
         */
-       sch->orb.c64 = 1;
-       sch->orb.i2k = 0;
+       orb->c64 = 1;
+       orb->i2k = 0;
 #endif
-       sch->orb.key = key >> 4;
+       orb->key = key >> 4;
        /* issue "Start Subchannel" */
-       sch->orb.cpa = (__u32) __pa (cpa);
-       ccode = ssch (sch->schid, &sch->orb);
+       orb->cpa = (__u32) __pa(cpa);
+       ccode = ssch(sch->schid, orb);
 
        /* process condition code */
-       sprintf (dbf_txt, "ccode:%d", ccode);
-       CIO_TRACE_EVENT (4, dbf_txt);
+       sprintf(dbf_txt, "ccode:%d", ccode);
+       CIO_TRACE_EVENT(4, dbf_txt);
 
        switch (ccode) {
        case 0:
@@ -405,8 +406,8 @@ cio_modify (struct subchannel *sch)
 /*
  * Enable subchannel.
  */
-int
-cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
+int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
+                         u32 intparm)
 {
        char dbf_txt[15];
        int ccode;
@@ -425,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
        for (retry = 5, ret = 0; retry > 0; retry--) {
                sch->schib.pmcw.ena = 1;
                sch->schib.pmcw.isc = isc;
-               sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+               sch->schib.pmcw.intparm = intparm;
                ret = cio_modify(sch);
                if (ret == -ENODEV)
                        break;
@@ -567,7 +568,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
         */
        if (sch->st != 0) {
                CIO_DEBUG(KERN_INFO, 0,
-                         "cio: Subchannel 0.%x.%04x reports "
+                         "Subchannel 0.%x.%04x reports "
                          "non-I/O subchannel type %04X\n",
                          sch->schid.ssid, sch->schid.sch_no, sch->st);
                /* We stop here for non-io subchannels. */
@@ -576,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        }
 
        /* Initialization for io subchannels. */
-       if (!sch->schib.pmcw.dnv) {
-               /* io subchannel but device number is invalid. */
+       if (!css_sch_is_valid(&sch->schib)) {
                err = -ENODEV;
                goto out;
        }
+
        /* Devno is valid. */
        if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
                /*
@@ -600,7 +601,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        sch->lpm = sch->schib.pmcw.pam & sch->opm;
 
        CIO_DEBUG(KERN_INFO, 0,
-                 "cio: Detected device %04x on subchannel 0.%x.%04X"
+                 "Detected device %04x on subchannel 0.%x.%04X"
                  " - PIM = %02X, PAM = %02X, POM = %02X\n",
                  sch->schib.pmcw.dev, sch->schid.ssid,
                  sch->schid.sch_no, sch->schib.pmcw.pim,
@@ -680,7 +681,7 @@ do_IRQ (struct pt_regs *regs)
                                sizeof (irb->scsw));
                        /* Call interrupt handler if there is one. */
                        if (sch->driver && sch->driver->irq)
-                               sch->driver->irq(&sch->dev);
+                               sch->driver->irq(sch);
                }
                if (sch)
                        spin_unlock(sch->lock);
@@ -698,8 +699,14 @@ do_IRQ (struct pt_regs *regs)
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct subchannel console_subchannel;
+static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
+void *cio_get_console_priv(void)
+{
+       return &console_priv;
+}
+
 /*
  * busy wait for the next interrupt on the console
  */
@@ -738,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data)
 {
        if (stsch_err(schid, &console_subchannel.schib) != 0)
                return -ENXIO;
-       if (console_subchannel.schib.pmcw.dnv &&
-           console_subchannel.schib.pmcw.dev ==
-           console_devno) {
+       if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
+           console_subchannel.schib.pmcw.dnv &&
+           (console_subchannel.schib.pmcw.dev == console_devno)) {
                console_irq = schid.sch_no;
                return 1; /* found */
        }
@@ -758,6 +765,7 @@ cio_get_console_sch_no(void)
                /* VM provided us with the irq number of the console. */
                schid.sch_no = console_irq;
                if (stsch(schid, &console_subchannel.schib) != 0 ||
+                   (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
                    !console_subchannel.schib.pmcw.dnv)
                        return -1;
                console_devno = console_subchannel.schib.pmcw.dev;
@@ -804,7 +812,7 @@ cio_probe_console(void)
        ctl_set_bit(6, 24);
        console_subchannel.schib.pmcw.isc = 7;
        console_subchannel.schib.pmcw.intparm =
-               (__u32)(unsigned long)&console_subchannel;
+               (u32)(addr_t)&console_subchannel;
        ret = cio_modify(&console_subchannel);
        if (ret) {
                console_subchannel_in_use = 0;
@@ -1022,7 +1030,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
 
        if (stsch_reset(schid, &schib))
                return -ENXIO;
-       if (schib.pmcw.dnv &&
+       if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
            (schib.pmcw.dev == match_id->devid.devno) &&
            (schid.ssid == match_id->devid.ssid)) {
                match_id->schid = schid;
@@ -1068,6 +1076,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
                return -ENODEV;
        if (stsch(schid, &schib))
                return -ENODEV;
+       if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
+               return -ENODEV;
        if (!schib.pmcw.dnv)
                return -ENODEV;
        iplinfo->devno = schib.pmcw.dev;
index 7446c39951a716c88ad5c1f8cf4fc699aff9d050..52afa4c784dece8d646a2aa210e67410a096a7d4 100644 (file)
  * path management control word
  */
 struct pmcw {
-       __u32 intparm;          /* interruption parameter */
-       __u32 qf   : 1;         /* qdio facility */
-       __u32 res0 : 1;         /* reserved zeros */
-       __u32 isc  : 3;         /* interruption sublass */
-       __u32 res5 : 3;         /* reserved zeros */
-       __u32 ena  : 1;         /* enabled */
-       __u32 lm   : 2;         /* limit mode */
-       __u32 mme  : 2;         /* measurement-mode enable */
-       __u32 mp   : 1;         /* multipath mode */
-       __u32 tf   : 1;         /* timing facility */
-       __u32 dnv  : 1;         /* device number valid */
-       __u32 dev  : 16;        /* device number */
-       __u8  lpm;              /* logical path mask */
-       __u8  pnom;             /* path not operational mask */
-       __u8  lpum;             /* last path used mask */
-       __u8  pim;              /* path installed mask */
-       __u16 mbi;              /* measurement-block index */
-       __u8  pom;              /* path operational mask */
-       __u8  pam;              /* path available mask */
-       __u8  chpid[8];         /* CHPID 0-7 (if available) */
-       __u32 unused1 : 8;      /* reserved zeros */
-       __u32 st      : 3;      /* subchannel type */
-       __u32 unused2 : 18;     /* reserved zeros */
-       __u32 mbfc    : 1;      /* measurement block format control */
-       __u32 xmwme   : 1;      /* extended measurement word mode enable */
-       __u32 csense  : 1;      /* concurrent sense; can be enabled ...*/
+       u32 intparm;            /* interruption parameter */
+       u32 qf   : 1;           /* qdio facility */
+       u32 res0 : 1;           /* reserved zeros */
+       u32 isc  : 3;           /* interruption sublass */
+       u32 res5 : 3;           /* reserved zeros */
+       u32 ena  : 1;           /* enabled */
+       u32 lm   : 2;           /* limit mode */
+       u32 mme  : 2;           /* measurement-mode enable */
+       u32 mp   : 1;           /* multipath mode */
+       u32 tf   : 1;           /* timing facility */
+       u32 dnv  : 1;           /* device number valid */
+       u32 dev  : 16;          /* device number */
+       u8  lpm;                /* logical path mask */
+       u8  pnom;               /* path not operational mask */
+       u8  lpum;               /* last path used mask */
+       u8  pim;                /* path installed mask */
+       u16 mbi;                /* measurement-block index */
+       u8  pom;                /* path operational mask */
+       u8  pam;                /* path available mask */
+       u8  chpid[8];           /* CHPID 0-7 (if available) */
+       u32 unused1 : 8;        /* reserved zeros */
+       u32 st      : 3;        /* subchannel type */
+       u32 unused2 : 18;       /* reserved zeros */
+       u32 mbfc    : 1;        /* measurement block format control */
+       u32 xmwme   : 1;        /* extended measurement word mode enable */
+       u32 csense  : 1;        /* concurrent sense; can be enabled ...*/
                                /*  ... per MSCH, however, if facility */
                                /*  ... is not installed, this results */
                                /*  ... in an operand exception.       */
@@ -52,31 +52,6 @@ struct schib {
        __u8 mda[4];             /* model dependent area */
 } __attribute__ ((packed,aligned(4)));
 
-/*
- * operation request block
- */
-struct orb {
-       __u32 intparm;          /* interruption parameter */
-       __u32 key  : 4;         /* flags, like key, suspend control, etc. */
-       __u32 spnd : 1;         /* suspend control */
-       __u32 res1 : 1;         /* reserved */
-       __u32 mod  : 1;         /* modification control */
-       __u32 sync : 1;         /* synchronize control */
-       __u32 fmt  : 1;         /* format control */
-       __u32 pfch : 1;         /* prefetch control */
-       __u32 isic : 1;         /* initial-status-interruption control */
-       __u32 alcc : 1;         /* address-limit-checking control */
-       __u32 ssic : 1;         /* suppress-suspended-interr. control */
-       __u32 res2 : 1;         /* reserved */
-       __u32 c64  : 1;         /* IDAW/QDIO 64 bit control  */
-       __u32 i2k  : 1;         /* IDAW 2/4kB block size control */
-       __u32 lpm  : 8;         /* logical path mask */
-       __u32 ils  : 1;         /* incorrect length */
-       __u32 zero : 6;         /* reserved zeros */
-       __u32 orbx : 1;         /* ORB extension control */
-       __u32 cpa;              /* channel program address */
-}  __attribute__ ((packed,aligned(4)));
-
 /* subchannel data structure used by I/O subroutines */
 struct subchannel {
        struct subchannel_id schid;
@@ -85,7 +60,7 @@ struct subchannel {
        enum {
                SUBCHANNEL_TYPE_IO = 0,
                SUBCHANNEL_TYPE_CHSC = 1,
-               SUBCHANNEL_TYPE_MESSAGE = 2,
+               SUBCHANNEL_TYPE_MSG = 2,
                SUBCHANNEL_TYPE_ADM = 3,
        } st;                   /* subchannel type */
 
@@ -99,11 +74,10 @@ struct subchannel {
        __u8 lpm;               /* logical path mask */
        __u8 opm;               /* operational path mask */
        struct schib schib;     /* subchannel information block */
-       struct orb orb;         /* operation request block */
-       struct ccw1 sense_ccw;  /* static ccw for sense command */
        struct chsc_ssd_info ssd_info;  /* subchannel description */
        struct device dev;      /* entry in device tree */
        struct css_driver *driver;
+       void *private; /* private per subchannel type data */
 } __attribute__ ((aligned(8)));
 
 #define IO_INTERRUPT_TYPE         0 /* I/O interrupt type */
@@ -111,7 +85,7 @@ struct subchannel {
 #define to_subchannel(n) container_of(n, struct subchannel, dev)
 
 extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
-extern int cio_enable_subchannel (struct subchannel *, unsigned int);
+extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
 extern int cio_disable_subchannel (struct subchannel *);
 extern int cio_cancel (struct subchannel *);
 extern int cio_clear (struct subchannel *);
@@ -125,6 +99,7 @@ extern int cio_get_options (struct subchannel *);
 extern int cio_modify (struct subchannel *);
 
 int cio_create_sch_lock(struct subchannel *);
+void do_adapter_IO(void);
 
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
@@ -133,10 +108,12 @@ extern void cio_release_console(void);
 extern int cio_is_console(struct subchannel_id);
 extern struct subchannel *cio_get_console_subchannel(void);
 extern spinlock_t * cio_get_console_lock(void);
+extern void *cio_get_console_priv(void);
 #else
 #define cio_is_console(schid) 0
 #define cio_get_console_subchannel() NULL
-#define cio_get_console_lock() NULL;
+#define cio_get_console_lock() NULL
+#define cio_get_console_priv() NULL
 #endif
 
 extern int cio_show_msg;
index c9bf8989930ff9d3c4fa1b08b1c95513997cf906..d7429ef6c666c1c56a4fa8b2ab05e04cc69901cf 100644 (file)
@@ -8,20 +8,19 @@ extern debug_info_t *cio_debug_msg_id;
 extern debug_info_t *cio_debug_trace_id;
 extern debug_info_t *cio_debug_crw_id;
 
-#define CIO_TRACE_EVENT(imp, txt) do { \
+#define CIO_TRACE_EVENT(imp, txt) do {                         \
                debug_text_event(cio_debug_trace_id, imp, txt); \
        } while (0)
 
-#define CIO_MSG_EVENT(imp, args...) do { \
-               debug_sprintf_event(cio_debug_msg_id, imp , ##args); \
+#define CIO_MSG_EVENT(imp, args...) do {                               \
+               debug_sprintf_event(cio_debug_msg_id, imp , ##args);    \
        } while (0)
 
-#define CIO_CRW_EVENT(imp, args...) do { \
-               debug_sprintf_event(cio_debug_crw_id, imp , ##args); \
+#define CIO_CRW_EVENT(imp, args...) do {                               \
+               debug_sprintf_event(cio_debug_crw_id, imp , ##args);    \
        } while (0)
 
-static inline void
-CIO_HEX_EVENT(int level, void *data, int length)
+static inline void CIO_HEX_EVENT(int level, void *data, int length)
 {
        if (unlikely(!cio_debug_trace_id))
                return;
@@ -32,9 +31,10 @@ CIO_HEX_EVENT(int level, void *data, int length)
        }
 }
 
-#define CIO_DEBUG(printk_level,event_level,msg...) ({ \
-       if (cio_show_msg) printk(printk_level msg); \
-       CIO_MSG_EVENT (event_level, msg); \
-})
+#define CIO_DEBUG(printk_level, event_level, msg...) do {      \
+               if (cio_show_msg)                               \
+                       printk(printk_level "cio: " msg);       \
+               CIO_MSG_EVENT(event_level, msg);                \
+       } while (0)
 
 #endif
index c3df2cd009a4f1b113615e728d3a15e0d2593c4f..3b45bbe6cce0c80a10b9450d06b590d70b4f06cc 100644 (file)
@@ -51,6 +51,62 @@ for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
        return ret;
 }
 
+struct cb_data {
+       void *data;
+       struct idset *set;
+       int (*fn_known_sch)(struct subchannel *, void *);
+       int (*fn_unknown_sch)(struct subchannel_id, void *);
+};
+
+static int call_fn_known_sch(struct device *dev, void *data)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct cb_data *cb = data;
+       int rc = 0;
+
+       idset_sch_del(cb->set, sch->schid);
+       if (cb->fn_known_sch)
+               rc = cb->fn_known_sch(sch, cb->data);
+       return rc;
+}
+
+static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
+{
+       struct cb_data *cb = data;
+       int rc = 0;
+
+       if (idset_sch_contains(cb->set, schid))
+               rc = cb->fn_unknown_sch(schid, cb->data);
+       return rc;
+}
+
+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
+                              int (*fn_unknown)(struct subchannel_id,
+                              void *), void *data)
+{
+       struct cb_data cb;
+       int rc;
+
+       cb.set = idset_sch_new();
+       if (!cb.set)
+               return -ENOMEM;
+       idset_fill(cb.set);
+       cb.data = data;
+       cb.fn_known_sch = fn_known;
+       cb.fn_unknown_sch = fn_unknown;
+       /* Process registered subchannels. */
+       rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
+       if (rc)
+               goto out;
+       /* Process unregistered subchannels. */
+       if (fn_unknown)
+               rc = for_each_subchannel(call_fn_unknown_sch, &cb);
+out:
+       idset_free(cb.set);
+
+       return rc;
+}
+
 static struct subchannel *
 css_alloc_subchannel(struct subchannel_id schid)
 {
@@ -77,7 +133,7 @@ css_alloc_subchannel(struct subchannel_id schid)
         * This is fine even on 64bit since the subchannel is always located
         * under 2G.
         */
-       sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+       sch->schib.pmcw.intparm = (u32)(addr_t)sch;
        ret = cio_modify(sch);
        if (ret) {
                kfree(sch->lock);
@@ -237,11 +293,25 @@ get_subchannel_by_schid(struct subchannel_id schid)
        return dev ? to_subchannel(dev) : NULL;
 }
 
+/**
+ * css_sch_is_valid() - check if a subchannel is valid
+ * @schib: subchannel information block for the subchannel
+ */
+int css_sch_is_valid(struct schib *schib)
+{
+       if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
+               return 0;
+       return 1;
+}
+EXPORT_SYMBOL_GPL(css_sch_is_valid);
+
 static int css_get_subchannel_status(struct subchannel *sch)
 {
        struct schib schib;
 
-       if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
+       if (stsch(sch->schid, &schib))
+               return CIO_GONE;
+       if (!css_sch_is_valid(&schib))
                return CIO_GONE;
        if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
                return CIO_REVALIDATE;
@@ -293,7 +363,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
                action = UNREGISTER;
                if (sch->driver && sch->driver->notify) {
                        spin_unlock_irqrestore(sch->lock, flags);
-                       ret = sch->driver->notify(&sch->dev, event);
+                       ret = sch->driver->notify(sch, event);
                        spin_lock_irqsave(sch->lock, flags);
                        if (ret)
                                action = NONE;
@@ -349,7 +419,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
                /* Will be done on the slow path. */
                return -EAGAIN;
        }
-       if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
+       if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) {
                /* Unusable - ignore. */
                return 0;
        }
@@ -388,20 +458,56 @@ static int __init slow_subchannel_init(void)
        return 0;
 }
 
-static void css_slow_path_func(struct work_struct *unused)
+static int slow_eval_known_fn(struct subchannel *sch, void *data)
 {
-       struct subchannel_id schid;
+       int eval;
+       int rc;
 
-       CIO_TRACE_EVENT(4, "slowpath");
        spin_lock_irq(&slow_subchannel_lock);
-       init_subchannel_id(&schid);
-       while (idset_sch_get_first(slow_subchannel_set, &schid)) {
-               idset_sch_del(slow_subchannel_set, schid);
-               spin_unlock_irq(&slow_subchannel_lock);
-               css_evaluate_subchannel(schid, 1);
-               spin_lock_irq(&slow_subchannel_lock);
+       eval = idset_sch_contains(slow_subchannel_set, sch->schid);
+       idset_sch_del(slow_subchannel_set, sch->schid);
+       spin_unlock_irq(&slow_subchannel_lock);
+       if (eval) {
+               rc = css_evaluate_known_subchannel(sch, 1);
+               if (rc == -EAGAIN)
+                       css_schedule_eval(sch->schid);
        }
+       return 0;
+}
+
+static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
+{
+       int eval;
+       int rc = 0;
+
+       spin_lock_irq(&slow_subchannel_lock);
+       eval = idset_sch_contains(slow_subchannel_set, schid);
+       idset_sch_del(slow_subchannel_set, schid);
        spin_unlock_irq(&slow_subchannel_lock);
+       if (eval) {
+               rc = css_evaluate_new_subchannel(schid, 1);
+               switch (rc) {
+               case -EAGAIN:
+                       css_schedule_eval(schid);
+                       rc = 0;
+                       break;
+               case -ENXIO:
+               case -ENOMEM:
+               case -EIO:
+                       /* These should abort looping */
+                       break;
+               default:
+                       rc = 0;
+               }
+       }
+       return rc;
+}
+
+static void css_slow_path_func(struct work_struct *unused)
+{
+       CIO_TRACE_EVENT(4, "slowpath");
+       for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn,
+                                  NULL);
 }
 
 static DECLARE_WORK(slow_path_work, css_slow_path_func);
@@ -430,7 +536,6 @@ void css_schedule_eval_all(void)
 /* Reprobe subchannel if unregistered. */
 static int reprobe_subchannel(struct subchannel_id schid, void *data)
 {
-       struct subchannel *sch;
        int ret;
 
        CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
@@ -438,13 +543,6 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
        if (need_reprobe)
                return -EAGAIN;
 
-       sch = get_subchannel_by_schid(schid);
-       if (sch) {
-               /* Already known. */
-               put_device(&sch->dev);
-               return 0;
-       }
-
        ret = css_probe_device(schid);
        switch (ret) {
        case 0:
@@ -472,7 +570,7 @@ static void reprobe_all(struct work_struct *unused)
        /* Make sure initial subchannel scan is done. */
        wait_event(ccw_device_init_wq,
                   atomic_read(&ccw_device_init_count) == 0);
-       ret = for_each_subchannel(reprobe_subchannel, NULL);
+       ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
 
        CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
                      need_reprobe);
@@ -787,8 +885,8 @@ int sch_is_pseudo_sch(struct subchannel *sch)
 static int
 css_bus_match (struct device *dev, struct device_driver *drv)
 {
-       struct subchannel *sch = container_of (dev, struct subchannel, dev);
-       struct css_driver *driver = container_of (drv, struct css_driver, drv);
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *driver = to_cssdriver(drv);
 
        if (sch->st == driver->subchannel_type)
                return 1;
@@ -796,32 +894,36 @@ css_bus_match (struct device *dev, struct device_driver *drv)
        return 0;
 }
 
-static int
-css_probe (struct device *dev)
+static int css_probe(struct device *dev)
 {
        struct subchannel *sch;
+       int ret;
 
        sch = to_subchannel(dev);
-       sch->driver = container_of (dev->driver, struct css_driver, drv);
-       return (sch->driver->probe ? sch->driver->probe(sch) : 0);
+       sch->driver = to_cssdriver(dev->driver);
+       ret = sch->driver->probe ? sch->driver->probe(sch) : 0;
+       if (ret)
+               sch->driver = NULL;
+       return ret;
 }
 
-static int
-css_remove (struct device *dev)
+static int css_remove(struct device *dev)
 {
        struct subchannel *sch;
+       int ret;
 
        sch = to_subchannel(dev);
-       return (sch->driver->remove ? sch->driver->remove(sch) : 0);
+       ret = sch->driver->remove ? sch->driver->remove(sch) : 0;
+       sch->driver = NULL;
+       return ret;
 }
 
-static void
-css_shutdown (struct device *dev)
+static void css_shutdown(struct device *dev)
 {
        struct subchannel *sch;
 
        sch = to_subchannel(dev);
-       if (sch->driver->shutdown)
+       if (sch->driver && sch->driver->shutdown)
                sch->driver->shutdown(sch);
 }
 
@@ -833,6 +935,34 @@ struct bus_type css_bus_type = {
        .shutdown = css_shutdown,
 };
 
+/**
+ * css_driver_register - register a css driver
+ * @cdrv: css driver to register
+ *
+ * This is mainly a wrapper around driver_register that sets name
+ * and bus_type in the embedded struct device_driver correctly.
+ */
+int css_driver_register(struct css_driver *cdrv)
+{
+       cdrv->drv.name = cdrv->name;
+       cdrv->drv.bus = &css_bus_type;
+       cdrv->drv.owner = cdrv->owner;
+       return driver_register(&cdrv->drv);
+}
+EXPORT_SYMBOL_GPL(css_driver_register);
+
+/**
+ * css_driver_unregister - unregister a css driver
+ * @cdrv: css driver to unregister
+ *
+ * This is a wrapper around driver_unregister.
+ */
+void css_driver_unregister(struct css_driver *cdrv)
+{
+       driver_unregister(&cdrv->drv);
+}
+EXPORT_SYMBOL_GPL(css_driver_unregister);
+
 subsys_initcall(init_channel_subsystem);
 
 MODULE_LICENSE("GPL");
index 81215ef3243575bfa451218c96be4c0506772310..b70554523552a9809e90a87a3e13d20a3781d021 100644 (file)
@@ -58,64 +58,6 @@ struct pgid {
        __u32 tod_high;         /* high word TOD clock */
 } __attribute__ ((packed));
 
-#define MAX_CIWS 8
-
-/*
- * sense-id response buffer layout
- */
-struct senseid {
-       /* common part */
-       __u8  reserved;         /* always 0x'FF' */
-       __u16 cu_type;          /* control unit type */
-       __u8  cu_model;         /* control unit model */
-       __u16 dev_type;         /* device type */
-       __u8  dev_model;        /* device model */
-       __u8  unused;           /* padding byte */
-       /* extended part */
-       struct ciw ciw[MAX_CIWS];       /* variable # of CIWs */
-}  __attribute__ ((packed,aligned(4)));
-
-struct ccw_device_private {
-       struct ccw_device *cdev;
-       struct subchannel *sch;
-       int state;              /* device state */
-       atomic_t onoff;
-       unsigned long registered;
-       struct ccw_dev_id dev_id;       /* device id */
-       struct subchannel_id schid;     /* subchannel number */
-       __u8 imask;             /* lpm mask for SNID/SID/SPGID */
-       int iretry;             /* retry counter SNID/SID/SPGID */
-       struct {
-               unsigned int fast:1;    /* post with "channel end" */
-               unsigned int repall:1;  /* report every interrupt status */
-               unsigned int pgroup:1;  /* do path grouping */
-               unsigned int force:1;   /* allow forced online */
-       } __attribute__ ((packed)) options;
-       struct {
-               unsigned int pgid_single:1; /* use single path for Set PGID */
-               unsigned int esid:1;        /* Ext. SenseID supported by HW */
-               unsigned int dosense:1;     /* delayed SENSE required */
-               unsigned int doverify:1;    /* delayed path verification */
-               unsigned int donotify:1;    /* call notify function */
-               unsigned int recog_done:1;  /* dev. recog. complete */
-               unsigned int fake_irb:1;    /* deliver faked irb */
-               unsigned int intretry:1;    /* retry internal operation */
-       } __attribute__((packed)) flags;
-       unsigned long intparm;  /* user interruption parameter */
-       struct qdio_irq *qdio_data;
-       struct irb irb;         /* device status */
-       struct senseid senseid; /* SenseID info */
-       struct pgid pgid[8];    /* path group IDs per chpid*/
-       struct ccw1 iccws[2];   /* ccws for SNID/SID/SPGID commands */
-       struct work_struct kick_work;
-       wait_queue_head_t wait_q;
-       struct timer_list timer;
-       void *cmb;                      /* measurement information */
-       struct list_head cmb_list;      /* list of measured devices */
-       u64 cmb_start_time;             /* clock value of cmb reset */
-       void *cmb_wait;                 /* deferred cmb enable/disable */
-};
-
 /*
  * A css driver handles all subchannels of one type.
  * Currently, we only care about I/O subchannels (type 0), these
@@ -123,25 +65,35 @@ struct ccw_device_private {
  */
 struct subchannel;
 struct css_driver {
+       struct module *owner;
        unsigned int subchannel_type;
        struct device_driver drv;
-       void (*irq)(struct device *);
-       int (*notify)(struct device *, int);
-       void (*verify)(struct device *);
-       void (*termination)(struct device *);
+       void (*irq)(struct subchannel *);
+       int (*notify)(struct subchannel *, int);
+       void (*verify)(struct subchannel *);
+       void (*termination)(struct subchannel *);
        int (*probe)(struct subchannel *);
        int (*remove)(struct subchannel *);
        void (*shutdown)(struct subchannel *);
+       const char *name;
 };
 
+#define to_cssdriver(n) container_of(n, struct css_driver, drv)
+
 /*
  * all css_drivers have the css_bus_type
  */
 extern struct bus_type css_bus_type;
 
+extern int css_driver_register(struct css_driver *);
+extern void css_driver_unregister(struct css_driver *);
+
 extern void css_sch_device_unregister(struct subchannel *);
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
+                              int (*fn_unknown)(struct subchannel_id,
+                              void *), void *data);
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
 extern void css_process_crw(int, int);
 extern void css_reiterate_subchannels(void);
@@ -188,6 +140,8 @@ void css_schedule_eval(struct subchannel_id schid);
 void css_schedule_eval_all(void);
 
 int sch_is_pseudo_sch(struct subchannel *);
+struct schib;
+int css_sch_is_valid(struct schib *);
 
 extern struct workqueue_struct *slow_path_wq;
 
index 74f6b539974a1d0310875e3cad4298ea3cf7ba82..d35dc3f25d06ec3a392a35da8617ca85d4da70f7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <linux/timer.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
+
+static struct timer_list recovery_timer;
+static spinlock_t recovery_lock;
+static int recovery_phase;
+static const unsigned long recovery_delay[] = { 3, 30, 300 };
 
 /******************* bus type handling ***********************/
 
@@ -115,19 +122,18 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 struct bus_type ccw_bus_type;
 
-static int io_subchannel_probe (struct subchannel *);
-static int io_subchannel_remove (struct subchannel *);
-static int io_subchannel_notify(struct device *, int);
-static void io_subchannel_verify(struct device *);
-static void io_subchannel_ioterm(struct device *);
+static void io_subchannel_irq(struct subchannel *);
+static int io_subchannel_probe(struct subchannel *);
+static int io_subchannel_remove(struct subchannel *);
+static int io_subchannel_notify(struct subchannel *, int);
+static void io_subchannel_verify(struct subchannel *);
+static void io_subchannel_ioterm(struct subchannel *);
 static void io_subchannel_shutdown(struct subchannel *);
 
 static struct css_driver io_subchannel_driver = {
+       .owner = THIS_MODULE,
        .subchannel_type = SUBCHANNEL_TYPE_IO,
-       .drv = {
-               .name = "io_subchannel",
-               .bus  = &css_bus_type,
-       },
+       .name = "io_subchannel",
        .irq = io_subchannel_irq,
        .notify = io_subchannel_notify,
        .verify = io_subchannel_verify,
@@ -142,6 +148,8 @@ struct workqueue_struct *ccw_device_notify_work;
 wait_queue_head_t ccw_device_init_wq;
 atomic_t ccw_device_init_count;
 
+static void recovery_func(unsigned long data);
+
 static int __init
 init_ccw_bus_type (void)
 {
@@ -149,6 +157,7 @@ init_ccw_bus_type (void)
 
        init_waitqueue_head(&ccw_device_init_wq);
        atomic_set(&ccw_device_init_count, 0);
+       setup_timer(&recovery_timer, recovery_func, 0);
 
        ccw_device_work = create_singlethread_workqueue("cio");
        if (!ccw_device_work)
@@ -166,7 +175,8 @@ init_ccw_bus_type (void)
        if ((ret = bus_register (&ccw_bus_type)))
                goto out_err;
 
-       if ((ret = driver_register(&io_subchannel_driver.drv)))
+       ret = css_driver_register(&io_subchannel_driver);
+       if (ret)
                goto out_err;
 
        wait_event(ccw_device_init_wq,
@@ -186,7 +196,7 @@ out_err:
 static void __exit
 cleanup_ccw_bus_type (void)
 {
-       driver_unregister(&io_subchannel_driver.drv);
+       css_driver_unregister(&io_subchannel_driver);
        bus_unregister(&ccw_bus_type);
        destroy_workqueue(ccw_device_notify_work);
        destroy_workqueue(ccw_device_work);
@@ -773,7 +783,7 @@ static void sch_attach_device(struct subchannel *sch,
 {
        css_update_ssd_info(sch);
        spin_lock_irq(sch->lock);
-       sch->dev.driver_data = cdev;
+       sch_set_cdev(sch, cdev);
        cdev->private->schid = sch->schid;
        cdev->ccwlock = sch->lock;
        device_trigger_reprobe(sch);
@@ -795,7 +805,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
                put_device(&other_sch->dev);
                return;
        }
-       other_sch->dev.driver_data = NULL;
+       sch_set_cdev(other_sch, NULL);
        /* No need to keep a subchannel without ccw device around. */
        css_sch_device_unregister(other_sch);
        put_device(&other_sch->dev);
@@ -831,12 +841,12 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
                return;
        }
        spin_lock_irq(sch->lock);
-       sch->dev.driver_data = cdev;
+       sch_set_cdev(sch, cdev);
        spin_unlock_irq(sch->lock);
        /* Start recognition for the new ccw device. */
        if (io_subchannel_recog(cdev, sch)) {
                spin_lock_irq(sch->lock);
-               sch->dev.driver_data = NULL;
+               sch_set_cdev(sch, NULL);
                spin_unlock_irq(sch->lock);
                if (cdev->dev.release)
                        cdev->dev.release(&cdev->dev);
@@ -940,7 +950,7 @@ io_subchannel_register(struct work_struct *work)
                              cdev->private->dev_id.devno, ret);
                put_device(&cdev->dev);
                spin_lock_irqsave(sch->lock, flags);
-               sch->dev.driver_data = NULL;
+               sch_set_cdev(sch, NULL);
                spin_unlock_irqrestore(sch->lock, flags);
                kfree (cdev->private);
                kfree (cdev);
@@ -1022,7 +1032,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
        int rc;
        struct ccw_device_private *priv;
 
-       sch->dev.driver_data = cdev;
+       sch_set_cdev(sch, cdev);
        sch->driver = &io_subchannel_driver;
        cdev->ccwlock = sch->lock;
 
@@ -1082,7 +1092,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
        }
        if (former_parent) {
                spin_lock_irq(former_parent->lock);
-               former_parent->dev.driver_data = NULL;
+               sch_set_cdev(former_parent, NULL);
                spin_unlock_irq(former_parent->lock);
                css_sch_device_unregister(former_parent);
                /* Reset intparm to zeroes. */
@@ -1096,6 +1106,18 @@ out:
        put_device(&cdev->dev);
 }
 
+static void io_subchannel_irq(struct subchannel *sch)
+{
+       struct ccw_device *cdev;
+
+       cdev = sch_get_cdev(sch);
+
+       CIO_TRACE_EVENT(3, "IRQ");
+       CIO_TRACE_EVENT(3, sch->dev.bus_id);
+       if (cdev)
+               dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
+}
+
 static int
 io_subchannel_probe (struct subchannel *sch)
 {
@@ -1104,13 +1126,13 @@ io_subchannel_probe (struct subchannel *sch)
        unsigned long flags;
        struct ccw_dev_id dev_id;
 
-       if (sch->dev.driver_data) {
+       cdev = sch_get_cdev(sch);
+       if (cdev) {
                /*
                 * This subchannel already has an associated ccw_device.
                 * Register it and exit. This happens for all early
                 * device, e.g. the console.
                 */
-               cdev = sch->dev.driver_data;
                cdev->dev.groups = ccwdev_attr_groups;
                device_initialize(&cdev->dev);
                ccw_device_register(cdev);
@@ -1132,6 +1154,11 @@ io_subchannel_probe (struct subchannel *sch)
         */
        dev_id.devno = sch->schib.pmcw.dev;
        dev_id.ssid = sch->schid.ssid;
+       /* Allocate I/O subchannel private data. */
+       sch->private = kzalloc(sizeof(struct io_subchannel_private),
+                              GFP_KERNEL | GFP_DMA);
+       if (!sch->private)
+               return -ENOMEM;
        cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
        if (!cdev)
                cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1149,16 +1176,18 @@ io_subchannel_probe (struct subchannel *sch)
                return 0;
        }
        cdev = io_subchannel_create_ccwdev(sch);
-       if (IS_ERR(cdev))
+       if (IS_ERR(cdev)) {
+               kfree(sch->private);
                return PTR_ERR(cdev);
-
+       }
        rc = io_subchannel_recog(cdev, sch);
        if (rc) {
                spin_lock_irqsave(sch->lock, flags);
-               sch->dev.driver_data = NULL;
+               sch_set_cdev(sch, NULL);
                spin_unlock_irqrestore(sch->lock, flags);
                if (cdev->dev.release)
                        cdev->dev.release(&cdev->dev);
+               kfree(sch->private);
        }
 
        return rc;
@@ -1170,25 +1199,25 @@ io_subchannel_remove (struct subchannel *sch)
        struct ccw_device *cdev;
        unsigned long flags;
 
-       if (!sch->dev.driver_data)
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
                return 0;
-       cdev = sch->dev.driver_data;
        /* Set ccw device to not operational and drop reference. */
        spin_lock_irqsave(cdev->ccwlock, flags);
-       sch->dev.driver_data = NULL;
+       sch_set_cdev(sch, NULL);
        cdev->private->state = DEV_STATE_NOT_OPER;
        spin_unlock_irqrestore(cdev->ccwlock, flags);
        ccw_device_unregister(cdev);
        put_device(&cdev->dev);
+       kfree(sch->private);
        return 0;
 }
 
-static int
-io_subchannel_notify(struct device *dev, int event)
+static int io_subchannel_notify(struct subchannel *sch, int event)
 {
        struct ccw_device *cdev;
 
-       cdev = dev->driver_data;
+       cdev = sch_get_cdev(sch);
        if (!cdev)
                return 0;
        if (!cdev->drv)
@@ -1198,22 +1227,20 @@ io_subchannel_notify(struct device *dev, int event)
        return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
 }
 
-static void
-io_subchannel_verify(struct device *dev)
+static void io_subchannel_verify(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       cdev = dev->driver_data;
+       cdev = sch_get_cdev(sch);
        if (cdev)
                dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 }
 
-static void
-io_subchannel_ioterm(struct device *dev)
+static void io_subchannel_ioterm(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       cdev = dev->driver_data;
+       cdev = sch_get_cdev(sch);
        if (!cdev)
                return;
        /* Internal I/O will be retried by the interrupt handler. */
@@ -1231,7 +1258,7 @@ io_subchannel_shutdown(struct subchannel *sch)
        struct ccw_device *cdev;
        int ret;
 
-       cdev = sch->dev.driver_data;
+       cdev = sch_get_cdev(sch);
 
        if (cio_is_console(sch->schid))
                return;
@@ -1271,6 +1298,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
 {
        int rc;
 
+       /* Attach subchannel private data. */
+       sch->private = cio_get_console_priv();
+       memset(sch->private, 0, sizeof(struct io_subchannel_private));
        /* Initialize the ccw_device structure. */
        cdev->dev.parent= &sch->dev;
        rc = io_subchannel_recog(cdev, sch);
@@ -1456,6 +1486,7 @@ int ccw_driver_register(struct ccw_driver *cdriver)
 
        drv->bus = &ccw_bus_type;
        drv->name = cdriver->name;
+       drv->owner = cdriver->owner;
 
        return driver_register(drv);
 }
@@ -1481,6 +1512,60 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
        return sch->schid;
 }
 
+static int recovery_check(struct device *dev, void *data)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       int *redo = data;
+
+       spin_lock_irq(cdev->ccwlock);
+       switch (cdev->private->state) {
+       case DEV_STATE_DISCONNECTED:
+               CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+                             cdev->private->dev_id.ssid,
+                             cdev->private->dev_id.devno);
+               dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+               *redo = 1;
+               break;
+       case DEV_STATE_DISCONNECTED_SENSE_ID:
+               *redo = 1;
+               break;
+       }
+       spin_unlock_irq(cdev->ccwlock);
+
+       return 0;
+}
+
+static void recovery_func(unsigned long data)
+{
+       int redo = 0;
+
+       bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
+       if (redo) {
+               spin_lock_irq(&recovery_lock);
+               if (!timer_pending(&recovery_timer)) {
+                       if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
+                               recovery_phase++;
+                       mod_timer(&recovery_timer, jiffies +
+                                 recovery_delay[recovery_phase] * HZ);
+               }
+               spin_unlock_irq(&recovery_lock);
+       } else
+               CIO_MSG_EVENT(2, "recovery: end\n");
+}
+
+void ccw_device_schedule_recovery(void)
+{
+       unsigned long flags;
+
+       CIO_MSG_EVENT(2, "recovery: schedule\n");
+       spin_lock_irqsave(&recovery_lock, flags);
+       if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
+               recovery_phase = 0;
+               mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
+       }
+       spin_unlock_irqrestore(&recovery_lock, flags);
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
index 0d4089600439263c65c4ddb05479d636e8eae67b..d40a2ffaa0006234b57dbed8b69105de6fc1afe2 100644 (file)
@@ -5,6 +5,8 @@
 #include <asm/atomic.h>
 #include <linux/wait.h>
 
+#include "io_sch.h"
+
 /*
  * states of the device statemachine
  */
@@ -74,7 +76,6 @@ extern struct workqueue_struct *ccw_device_notify_work;
 extern wait_queue_head_t ccw_device_init_wq;
 extern atomic_t ccw_device_init_count;
 
-void io_subchannel_irq (struct device *pdev);
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -87,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
 
+void ccw_device_schedule_recovery(void);
+
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
 void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
index bfad421cda66a6bd82a253486d38450703eb6590..4b92c84fb438440874eeb9ea4cb42b5f72965739 100644 (file)
 #include "ioasm.h"
 #include "chp.h"
 
+static int timeout_log_enabled;
+
 int
 device_is_online(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       if (!sch->dev.driver_data)
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
                return 0;
-       cdev = sch->dev.driver_data;
        return (cdev->private->state == DEV_STATE_ONLINE);
 }
 
@@ -41,9 +43,9 @@ device_is_disconnected(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       if (!sch->dev.driver_data)
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
                return 0;
-       cdev = sch->dev.driver_data;
        return (cdev->private->state == DEV_STATE_DISCONNECTED ||
                cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
 }
@@ -53,19 +55,21 @@ device_set_disconnected(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       if (!sch->dev.driver_data)
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
                return;
-       cdev = sch->dev.driver_data;
        ccw_device_set_timeout(cdev, 0);
        cdev->private->flags.fake_irb = 0;
        cdev->private->state = DEV_STATE_DISCONNECTED;
+       if (cdev->online)
+               ccw_device_schedule_recovery();
 }
 
 void device_set_intretry(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       cdev = sch->dev.driver_data;
+       cdev = sch_get_cdev(sch);
        if (!cdev)
                return;
        cdev->private->flags.intretry = 1;
@@ -75,13 +79,62 @@ int device_trigger_verify(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       cdev = sch->dev.driver_data;
+       cdev = sch_get_cdev(sch);
        if (!cdev || !cdev->online)
                return -EINVAL;
        dev_fsm_event(cdev, DEV_EVENT_VERIFY);
        return 0;
 }
 
+static int __init ccw_timeout_log_setup(char *unused)
+{
+       timeout_log_enabled = 1;
+       return 1;
+}
+
+__setup("ccw_timeout_log", ccw_timeout_log_setup);
+
+static void ccw_timeout_log(struct ccw_device *cdev)
+{
+       struct schib schib;
+       struct subchannel *sch;
+       struct io_subchannel_private *private;
+       int cc;
+
+       sch = to_subchannel(cdev->dev.parent);
+       private = to_io_private(sch);
+       cc = stsch(sch->schid, &schib);
+
+       printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
+              "device information:\n", get_clock());
+       printk(KERN_WARNING "cio: orb:\n");
+       print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+                      &private->orb, sizeof(private->orb), 0);
+       printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
+       printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
+       printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
+              "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
+
+       if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
+           (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
+               printk(KERN_WARNING "cio: last channel program (intern):\n");
+       else
+               printk(KERN_WARNING "cio: last channel program:\n");
+
+       print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+                      (void *)(addr_t)private->orb.cpa,
+                      sizeof(struct ccw1), 0);
+       printk(KERN_WARNING "cio: ccw device state: %d\n",
+              cdev->private->state);
+       printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
+       printk(KERN_WARNING "cio: schib:\n");
+       print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+                      &schib, sizeof(schib), 0);
+       printk(KERN_WARNING "cio: ccw device flags:\n");
+       print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+                      &cdev->private->flags, sizeof(cdev->private->flags), 0);
+}
+
 /*
  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
  */
@@ -92,6 +145,8 @@ ccw_device_timeout(unsigned long data)
 
        cdev = (struct ccw_device *) data;
        spin_lock_irq(cdev->ccwlock);
+       if (timeout_log_enabled)
+               ccw_timeout_log(cdev);
        dev_fsm_event(cdev, DEV_EVENT_TIMEOUT);
        spin_unlock_irq(cdev->ccwlock);
 }
@@ -122,9 +177,9 @@ device_kill_pending_timer(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       if (!sch->dev.driver_data)
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
                return;
-       cdev = sch->dev.driver_data;
        ccw_device_set_timeout(cdev, 0);
 }
 
@@ -268,7 +323,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
        switch (state) {
        case DEV_STATE_NOT_OPER:
                CIO_DEBUG(KERN_WARNING, 2,
-                         "cio: SenseID : unknown device %04x on subchannel "
+                         "SenseID : unknown device %04x on subchannel "
                          "0.%x.%04x\n", cdev->private->dev_id.devno,
                          sch->schid.ssid, sch->schid.sch_no);
                break;
@@ -294,7 +349,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                }
                /* Issue device info message. */
                CIO_DEBUG(KERN_INFO, 2,
-                         "cio: SenseID : device 0.%x.%04x reports: "
+                         "SenseID : device 0.%x.%04x reports: "
                          "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
                          "%04X/%02X\n",
                          cdev->private->dev_id.ssid,
@@ -304,7 +359,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                break;
        case DEV_STATE_BOXED:
                CIO_DEBUG(KERN_WARNING, 2,
-                         "cio: SenseID : boxed device %04x on subchannel "
+                         "SenseID : boxed device %04x on subchannel "
                          "0.%x.%04x\n", cdev->private->dev_id.devno,
                          sch->schid.ssid, sch->schid.sch_no);
                break;
@@ -349,7 +404,7 @@ ccw_device_oper_notify(struct work_struct *work)
        sch = to_subchannel(cdev->dev.parent);
        if (sch->driver && sch->driver->notify) {
                spin_unlock_irqrestore(cdev->ccwlock, flags);
-               ret = sch->driver->notify(&sch->dev, CIO_OPER);
+               ret = sch->driver->notify(sch, CIO_OPER);
                spin_lock_irqsave(cdev->ccwlock, flags);
        } else
                ret = 0;
@@ -389,7 +444,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
 
        if (state == DEV_STATE_BOXED)
                CIO_DEBUG(KERN_WARNING, 2,
-                         "cio: Boxed device %04x on subchannel %04x\n",
+                         "Boxed device %04x on subchannel %04x\n",
                          cdev->private->dev_id.devno, sch->schid.sch_no);
 
        if (cdev->private->flags.donotify) {
@@ -500,7 +555,8 @@ ccw_device_recognition(struct ccw_device *cdev)
            (cdev->private->state != DEV_STATE_BOXED))
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
-       ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
+       ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+                                   (u32)(addr_t)sch);
        if (ret != 0)
                /* Couldn't enable the subchannel for i/o. Sick device. */
                return ret;
@@ -587,9 +643,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
        default:
                /* Reset oper notify indication after verify error. */
                cdev->private->flags.donotify = 0;
-               if (cdev->online)
+               if (cdev->online) {
+                       ccw_device_set_timeout(cdev, 0);
                        dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-               else
+               else
                        ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                break;
        }
@@ -610,7 +667,8 @@ ccw_device_online(struct ccw_device *cdev)
        sch = to_subchannel(cdev->dev.parent);
        if (css_init_done && !get_device(&cdev->dev))
                return -ENODEV;
-       ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
+       ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+                                   (u32)(addr_t)sch);
        if (ret != 0) {
                /* Couldn't enable the subchannel for i/o. Sick device. */
                if (ret == -ENODEV)
@@ -937,7 +995,7 @@ void device_kill_io(struct subchannel *sch)
        int ret;
        struct ccw_device *cdev;
 
-       cdev = sch->dev.driver_data;
+       cdev = sch_get_cdev(sch);
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
@@ -990,7 +1048,8 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
        struct subchannel *sch;
 
        sch = to_subchannel(cdev->dev.parent);
-       if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0)
+       if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+                                 (u32)(addr_t)sch) != 0)
                /* Couldn't enable the subchannel for i/o. Sick device. */
                return;
 
@@ -1006,9 +1065,9 @@ device_trigger_reprobe(struct subchannel *sch)
 {
        struct ccw_device *cdev;
 
-       if (!sch->dev.driver_data)
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
                return;
-       cdev = sch->dev.driver_data;
        if (cdev->private->state != DEV_STATE_DISCONNECTED)
                return;
 
@@ -1028,7 +1087,7 @@ device_trigger_reprobe(struct subchannel *sch)
        sch->schib.pmcw.ena = 0;
        if ((sch->lpm & (sch->lpm - 1)) != 0)
                sch->schib.pmcw.mp = 1;
-       sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+       sch->schib.pmcw.intparm = (u32)(addr_t)sch;
        /* We should also udate ssd info, but this has to wait. */
        /* Check if this is another device which appeared on the same sch. */
        if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
@@ -1223,21 +1282,4 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
        },
 };
 
-/*
- * io_subchannel_irq is called for "real" interrupts or for status
- * pending conditions on msch.
- */
-void
-io_subchannel_irq (struct device *pdev)
-{
-       struct ccw_device *cdev;
-
-       cdev = to_subchannel(pdev)->dev.driver_data;
-
-       CIO_TRACE_EVENT (3, "IRQ");
-       CIO_TRACE_EVENT (3, pdev->bus_id);
-       if (cdev)
-               dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
-}
-
 EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
index 156f3f9786b52e6ddfaeb765c81fec7ff0f77c73..918b8b89cf9a26c3fef86b8cd6d6f9d04a17b851 100644 (file)
@@ -24,6 +24,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Input :
@@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
                return -EAGAIN;
        }
        if (irb->scsw.cc == 3) {
-               if ((sch->orb.lpm &
-                    sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
+               u8 lpm;
+
+               lpm = to_io_private(sch)->orb.lpm;
+               if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
                        CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
                                      "on subchannel 0.%x.%04x is "
-                                     "'not operational'\n", sch->orb.lpm,
+                                     "'not operational'\n", lpm,
                                      cdev->private->dev_id.devno,
                                      sch->schid.ssid, sch->schid.sch_no);
                return -EACCES;
index 7fd2dadc32979272ad77fc16c1112e423e1e48e2..49b58eb0fab85fcca862383b551a89f3e466c86d 100644 (file)
@@ -501,7 +501,7 @@ ccw_device_stlck(struct ccw_device *cdev)
                return -ENOMEM;
        }
        spin_lock_irqsave(sch->lock, flags);
-       ret = cio_enable_subchannel(sch, 3);
+       ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
        if (ret)
                goto out_unlock;
        /*
index cb1879a96818b41b28371560b6f57173676ba14b..c52449a1f9fce93f2af14456c88cb7dc7e390d96 100644 (file)
@@ -22,6 +22,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Helper function called from interrupt context to decide whether an
@@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
                return -EAGAIN;
        }
        if (irb->scsw.cc == 3) {
+               u8 lpm;
+
+               lpm = to_io_private(sch)->orb.lpm;
                CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
                              " lpm %02X, became 'not operational'\n",
                              cdev->private->dev_id.devno, sch->schid.ssid,
-                             sch->schid.sch_no, sch->orb.lpm);
+                             sch->schid.sch_no, lpm);
                return -EACCES;
        }
        i = 8 - ffs(cdev->private->imask);
index aa96e6752592355a06b5a4fb6c97f346e4c1066d..ebe0848cfe33c14361222f33b021485cd58f67d6 100644 (file)
@@ -20,6 +20,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Check for any kind of channel or interface control check but don't
@@ -310,6 +311,7 @@ int
 ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
 {
        struct subchannel *sch;
+       struct ccw1 *sense_ccw;
 
        sch = to_subchannel(cdev->dev.parent);
 
@@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
        /*
         * We have ending status but no sense information. Do a basic sense.
         */
-       sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE;
-       sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw);
-       sch->sense_ccw.count = SENSE_MAX_COUNT;
-       sch->sense_ccw.flags = CCW_FLAG_SLI;
+       sense_ccw = &to_io_private(sch)->sense_ccw;
+       sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
+       sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
+       sense_ccw->count = SENSE_MAX_COUNT;
+       sense_ccw->flags = CCW_FLAG_SLI;
 
        /* Reset internal retry indication. */
        cdev->private->flags.intretry = 0;
 
-       return cio_start (sch, &sch->sense_ccw, 0xff);
+       return cio_start(sch, sense_ccw, 0xff);
 }
 
 /*
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
new file mode 100644 (file)
index 0000000..8c61316
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef S390_IO_SCH_H
+#define S390_IO_SCH_H
+
+#include "schid.h"
+
+/*
+ * operation request block
+ */
+struct orb {
+       u32 intparm;    /* interruption parameter */
+       u32 key  : 4;   /* flags, like key, suspend control, etc. */
+       u32 spnd : 1;   /* suspend control */
+       u32 res1 : 1;   /* reserved */
+       u32 mod  : 1;   /* modification control */
+       u32 sync : 1;   /* synchronize control */
+       u32 fmt  : 1;   /* format control */
+       u32 pfch : 1;   /* prefetch control */
+       u32 isic : 1;   /* initial-status-interruption control */
+       u32 alcc : 1;   /* address-limit-checking control */
+       u32 ssic : 1;   /* suppress-suspended-interr. control */
+       u32 res2 : 1;   /* reserved */
+       u32 c64  : 1;   /* IDAW/QDIO 64 bit control  */
+       u32 i2k  : 1;   /* IDAW 2/4kB block size control */
+       u32 lpm  : 8;   /* logical path mask */
+       u32 ils  : 1;   /* incorrect length */
+       u32 zero : 6;   /* reserved zeros */
+       u32 orbx : 1;   /* ORB extension control */
+       u32 cpa;        /* channel program address */
+}  __attribute__ ((packed, aligned(4)));
+
+struct io_subchannel_private {
+       struct orb orb;         /* operation request block */
+       struct ccw1 sense_ccw;  /* static ccw for sense command */
+} __attribute__ ((aligned(8)));
+
+#define to_io_private(n) ((struct io_subchannel_private *)n->private)
+#define sch_get_cdev(n) (dev_get_drvdata(&n->dev))
+#define sch_set_cdev(n, c) (dev_set_drvdata(&n->dev, c))
+
+#define MAX_CIWS 8
+
+/*
+ * sense-id response buffer layout
+ */
+struct senseid {
+       /* common part */
+       u8  reserved;   /* always 0x'FF' */
+       u16 cu_type;    /* control unit type */
+       u8  cu_model;   /* control unit model */
+       u16 dev_type;   /* device type */
+       u8  dev_model;  /* device model */
+       u8  unused;     /* padding byte */
+       /* extended part */
+       struct ciw ciw[MAX_CIWS];       /* variable # of CIWs */
+}  __attribute__ ((packed, aligned(4)));
+
+struct ccw_device_private {
+       struct ccw_device *cdev;
+       struct subchannel *sch;
+       int state;              /* device state */
+       atomic_t onoff;
+       unsigned long registered;
+       struct ccw_dev_id dev_id;       /* device id */
+       struct subchannel_id schid;     /* subchannel number */
+       u8 imask;               /* lpm mask for SNID/SID/SPGID */
+       int iretry;             /* retry counter SNID/SID/SPGID */
+       struct {
+               unsigned int fast:1;    /* post with "channel end" */
+               unsigned int repall:1;  /* report every interrupt status */
+               unsigned int pgroup:1;  /* do path grouping */
+               unsigned int force:1;   /* allow forced online */
+       } __attribute__ ((packed)) options;
+       struct {
+               unsigned int pgid_single:1; /* use single path for Set PGID */
+               unsigned int esid:1;        /* Ext. SenseID supported by HW */
+               unsigned int dosense:1;     /* delayed SENSE required */
+               unsigned int doverify:1;    /* delayed path verification */
+               unsigned int donotify:1;    /* call notify function */
+               unsigned int recog_done:1;  /* dev. recog. complete */
+               unsigned int fake_irb:1;    /* deliver faked irb */
+               unsigned int intretry:1;    /* retry internal operation */
+       } __attribute__((packed)) flags;
+       unsigned long intparm;  /* user interruption parameter */
+       struct qdio_irq *qdio_data;
+       struct irb irb;         /* device status */
+       struct senseid senseid; /* SenseID info */
+       struct pgid pgid[8];    /* path group IDs per chpid*/
+       struct ccw1 iccws[2];   /* ccws for SNID/SID/SPGID commands */
+       struct work_struct kick_work;
+       wait_queue_head_t wait_q;
+       struct timer_list timer;
+       void *cmb;                      /* measurement information */
+       struct list_head cmb_list;      /* list of measured devices */
+       u64 cmb_start_time;             /* clock value of cmb reset */
+       void *cmb_wait;                 /* deferred cmb enable/disable */
+};
+
+static inline int ssch(struct subchannel_id schid, volatile struct orb *addr)
+{
+       register struct subchannel_id reg1 asm("1") = schid;
+       int ccode;
+
+       asm volatile(
+               "       ssch    0(%2)\n"
+               "       ipm     %0\n"
+               "       srl     %0,28"
+               : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+       return ccode;
+}
+
+static inline int rsch(struct subchannel_id schid)
+{
+       register struct subchannel_id reg1 asm("1") = schid;
+       int ccode;
+
+       asm volatile(
+               "       rsch\n"
+               "       ipm     %0\n"
+               "       srl     %0,28"
+               : "=d" (ccode) : "d" (reg1) : "cc");
+       return ccode;
+}
+
+static inline int csch(struct subchannel_id schid)
+{
+       register struct subchannel_id reg1 asm("1") = schid;
+       int ccode;
+
+       asm volatile(
+               "       csch\n"
+               "       ipm     %0\n"
+               "       srl     %0,28"
+               : "=d" (ccode) : "d" (reg1) : "cc");
+       return ccode;
+}
+
+static inline int hsch(struct subchannel_id schid)
+{
+       register struct subchannel_id reg1 asm("1") = schid;
+       int ccode;
+
+       asm volatile(
+               "       hsch\n"
+               "       ipm     %0\n"
+               "       srl     %0,28"
+               : "=d" (ccode) : "d" (reg1) : "cc");
+       return ccode;
+}
+
+static inline int xsch(struct subchannel_id schid)
+{
+       register struct subchannel_id reg1 asm("1") = schid;
+       int ccode;
+
+       asm volatile(
+               "       .insn   rre,0xb2760000,%1,0\n"
+               "       ipm     %0\n"
+               "       srl     %0,28"
+               : "=d" (ccode) : "d" (reg1) : "cc");
+       return ccode;
+}
+
+#endif
index 7153dd959082253eb00cb182a4b53bb59b2eb72f..652ea3625f9def33d92e8c4dde4ec50373adb091 100644 (file)
@@ -109,72 +109,6 @@ static inline int tpi( volatile struct tpi_info *addr)
        return ccode;
 }
 
-static inline int ssch(struct subchannel_id schid,
-                          volatile struct orb *addr)
-{
-       register struct subchannel_id reg1 asm ("1") = schid;
-       int ccode;
-
-       asm volatile(
-               "       ssch    0(%2)\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
-       return ccode;
-}
-
-static inline int rsch(struct subchannel_id schid)
-{
-       register struct subchannel_id reg1 asm ("1") = schid;
-       int ccode;
-
-       asm volatile(
-               "       rsch\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode) : "d" (reg1) : "cc");
-       return ccode;
-}
-
-static inline int csch(struct subchannel_id schid)
-{
-       register struct subchannel_id reg1 asm ("1") = schid;
-       int ccode;
-
-       asm volatile(
-               "       csch\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode) : "d" (reg1) : "cc");
-       return ccode;
-}
-
-static inline int hsch(struct subchannel_id schid)
-{
-       register struct subchannel_id reg1 asm ("1") = schid;
-       int ccode;
-
-       asm volatile(
-               "       hsch\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode) : "d" (reg1) : "cc");
-       return ccode;
-}
-
-static inline int xsch(struct subchannel_id schid)
-{
-       register struct subchannel_id reg1 asm ("1") = schid;
-       int ccode;
-
-       asm volatile(
-               "       .insn   rre,0xb2760000,%1,0\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode) : "d" (reg1) : "cc");
-       return ccode;
-}
-
 static inline int chsc(void *chsc_area)
 {
        typedef struct { char _[4096]; } addr_type;
index 40a3208c7cf3defbc2c47429a8a4654d32290630..e2a781b6b21db091af54b3ba5b8fd691a33b0740 100644 (file)
 #include <asm/debug.h>
 #include <asm/s390_rdev.h>
 #include <asm/qdio.h>
+#include <asm/airq.h>
 
 #include "cio.h"
 #include "css.h"
 #include "device.h"
-#include "airq.h"
 #include "qdio.h"
 #include "ioasm.h"
 #include "chsc.h"
@@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in;
 static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
                                                 during a while loop */
 static DEFINE_SPINLOCK(ttiq_list_lock);
-static int register_thinint_result;
+static void *tiqdio_ind;
 static void tiqdio_tl(unsigned long);
 static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
 
@@ -399,7 +399,7 @@ qdio_get_indicator(void)
 {
        int i;
 
-       for (i=1;i<INDICATORS_PER_CACHELINE;i++)
+       for (i = 0; i < INDICATORS_PER_CACHELINE; i++)
                if (!indicator_used[i]) {
                        indicator_used[i]=1;
                        return indicators+i;
@@ -1408,8 +1408,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
        if (q->hydra_gives_outbound_pcis) {
                if (!q->siga_sync_done_on_thinints) {
                        SYNC_MEMORY_ALL;
-               } else if ((!q->siga_sync_done_on_outb_tis)&&
-                        (q->hydra_gives_outbound_pcis)) {
+               } else if (!q->siga_sync_done_on_outb_tis) {
                        SYNC_MEMORY_ALL_OUTB;
                }
        } else {
@@ -1911,8 +1910,7 @@ qdio_fill_thresholds(struct qdio_irq *irq_ptr,
        }
 }
 
-static int
-tiqdio_thinint_handler(void)
+static void tiqdio_thinint_handler(void *ind, void *drv_data)
 {
        QDIO_DBF_TEXT4(0,trace,"thin_int");
 
@@ -1925,7 +1923,6 @@ tiqdio_thinint_handler(void)
                tiqdio_clear_global_summary();
 
        tiqdio_inbound_checks();
-       return 0;
 }
 
 static void
@@ -2445,7 +2442,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
                real_addr_dev_st_chg_ind=0;
        } else {
                real_addr_local_summary_bit=
-                       virt_to_phys((volatile void *)indicators);
+                       virt_to_phys((volatile void *)tiqdio_ind);
                real_addr_dev_st_chg_ind=
                        virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
        }
@@ -3740,23 +3737,25 @@ static void
 tiqdio_register_thinints(void)
 {
        char dbf_text[20];
-       register_thinint_result=
-               s390_register_adapter_interrupt(&tiqdio_thinint_handler);
-       if (register_thinint_result) {
-               sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff));
+
+       tiqdio_ind =
+               s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL);
+       if (IS_ERR(tiqdio_ind)) {
+               sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
                QDIO_DBF_TEXT0(0,setup,dbf_text);
                QDIO_PRINT_ERR("failed to register adapter handler " \
-                              "(rc=%i).\nAdapter interrupts might " \
+                              "(rc=%li).\nAdapter interrupts might " \
                               "not work. Continuing.\n",
-                              register_thinint_result);
+                              PTR_ERR(tiqdio_ind));
+               tiqdio_ind = NULL;
        }
 }
 
 static void
 tiqdio_unregister_thinints(void)
 {
-       if (!register_thinint_result)
-               s390_unregister_adapter_interrupt(&tiqdio_thinint_handler);
+       if (tiqdio_ind)
+               s390_unregister_adapter_interrupt(tiqdio_ind);
 }
 
 static int
@@ -3768,8 +3767,8 @@ qdio_get_qdio_memory(void)
        for (i=1;i<INDICATORS_PER_CACHELINE;i++)
                indicator_used[i]=0;
        indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
-                                  GFP_KERNEL);
-               if (!indicators)
+                            GFP_KERNEL);
+       if (!indicators)
                return -ENOMEM;
        return 0;
 }
@@ -3780,7 +3779,6 @@ qdio_release_qdio_memory(void)
        kfree(indicators);
 }
 
-
 static void
 qdio_unregister_dbf_views(void)
 {
index 6d7aad18f6f0132fa24d5b10b9c5d9f88638347a..37870e4e938ed9d771d91af65f0b606b8fa61da2 100644 (file)
@@ -57,7 +57,7 @@
                                            of the queue to 0 */
 
 #define QDIO_ESTABLISH_TIMEOUT (1*HZ)
-#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
+#define QDIO_ACTIVATE_TIMEOUT (5*HZ)
 #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
 #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
 #define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
index 3561982749e36d943d927c80227215cf838285d0..c3076217871e7e25ab485a7a8f89311c2bd31679 100644 (file)
@@ -2416,7 +2416,7 @@ init_ccw_bk(struct net_device *dev)
                    privptr->p_buff_pages_perwrite);
 #endif
                    if (p_buff==NULL) {
-                        printk(KERN_INFO "%s:%s __get_free_pages"
+                       printk(KERN_INFO "%s:%s __get_free_pages "
                                "for writes buf failed : get is for %d pages\n",
                                dev->name,
                                __FUNCTION__,
index 0fd663b23d767c9a6e81777d51df467af90631e6..7bfe8d707a346573bac660270b26ac52b8d01758 100644 (file)
@@ -1115,7 +1115,7 @@ list_modified:
                        rc = lcs_send_setipm(card, ipm);
                        spin_lock_irqsave(&card->ipm_lock, flags);
                        if (rc) {
-                               PRINT_INFO("Adding multicast address failed."
+                               PRINT_INFO("Adding multicast address failed. "
                                           "Table possibly full!\n");
                                /* store ipm in failed list -> will be added
                                 * to ipm_list again, so a retry will be done
index c7ea9381db9f63050b8589ee05faa466d295120e..f3d893cfe61d4339799bb91ab9db5fb5f9698e75 100644 (file)
@@ -198,8 +198,7 @@ struct iucv_connection {
 /**
  * Linked list of all connection structs.
  */
-static struct list_head iucv_connection_list =
-       LIST_HEAD_INIT(iucv_connection_list);
+static LIST_HEAD(iucv_connection_list);
 static DEFINE_RWLOCK(iucv_connection_rwlock);
 
 /**
@@ -2089,6 +2088,11 @@ static struct attribute_group netiucv_drv_attr_group = {
        .attrs = netiucv_drv_attrs,
 };
 
+static struct attribute_group *netiucv_drv_attr_groups[] = {
+       &netiucv_drv_attr_group,
+       NULL,
+};
+
 static void netiucv_banner(void)
 {
        PRINT_INFO("NETIUCV driver initialized\n");
@@ -2113,7 +2117,6 @@ static void __exit netiucv_exit(void)
                netiucv_unregister_device(dev);
        }
 
-       sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
        driver_unregister(&netiucv_driver);
        iucv_unregister(&netiucv_handler, 1);
        iucv_unregister_dbf_views();
@@ -2133,6 +2136,7 @@ static int __init netiucv_init(void)
        if (rc)
                goto out_dbf;
        IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
+       netiucv_driver.groups = netiucv_drv_attr_groups;
        rc = driver_register(&netiucv_driver);
        if (rc) {
                PRINT_ERR("NETIUCV: failed to register driver.\n");
@@ -2140,18 +2144,9 @@ static int __init netiucv_init(void)
                goto out_iucv;
        }
 
-       rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
-       if (rc) {
-               PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
-               IUCV_DBF_TEXT_(setup, 2,
-                              "ret %d - netiucv_drv_attr_group\n", rc);
-               goto out_driver;
-       }
        netiucv_banner();
        return rc;
 
-out_driver:
-       driver_unregister(&netiucv_driver);
 out_iucv:
        iucv_unregister(&netiucv_handler, 1);
 out_dbf:
index f1ff165a5e052a3e2a180290c9de41f97b2eeba5..46ecd03a597ef2828a9ecbbd1b3077ce0aa0aefa 100644 (file)
@@ -146,7 +146,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it)
        return 0;
 }
 
-static struct seq_operations qeth_procfile_seq_ops = {
+static const struct seq_operations qeth_procfile_seq_ops = {
        .start = qeth_procfile_seq_start,
        .stop  = qeth_procfile_seq_stop,
        .next  = qeth_procfile_seq_next,
@@ -264,7 +264,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
        return 0;
 }
 
-static struct seq_operations qeth_perf_procfile_seq_ops = {
+static const struct seq_operations qeth_perf_procfile_seq_ops = {
        .start = qeth_procfile_seq_start,
        .stop  = qeth_procfile_seq_stop,
        .next  = qeth_procfile_seq_next,
index 47bb47b485814497e12201b3e4dd2f0697859504..8735a415a116feba2fc8a2b14befd0a6bae86e22 100644 (file)
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
 static struct iucv_path *smsg_path;
 
 static DEFINE_SPINLOCK(smsg_list_lock);
-static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
+static LIST_HEAD(smsg_list);
 
 static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
 static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
index 00118499018b3c94d4c2834d45e6a8eb156be6f0..874b55ed00a3473f44a71227e69c33fa70eba04e 100644 (file)
@@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
        unit->sysfs_device.release = zfcp_sysfs_unit_release;
        dev_set_drvdata(&unit->sysfs_device, unit);
 
-       init_waitqueue_head(&unit->scsi_scan_wq);
-
        /* mark unit unusable as long as sysfs registration is not complete */
        atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
 
index e01cbf152a81d3622a5d4a607b103ab472e607d0..edc5015e920d8fbc9c0f5c0fb3e457433d1e2f89 100644 (file)
@@ -52,6 +52,9 @@ static struct ccw_driver zfcp_ccw_driver = {
        .set_offline = zfcp_ccw_set_offline,
        .notify      = zfcp_ccw_notify,
        .shutdown    = zfcp_ccw_shutdown,
+       .driver = {
+               .groups = zfcp_driver_attr_groups,
+       },
 };
 
 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -120,6 +123,9 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
 
        list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) {
                list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) {
+                       if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED,
+                               &unit->status))
+                               scsi_remove_device(unit->device);
                        zfcp_unit_dequeue(unit);
                }
                zfcp_port_dequeue(port);
@@ -251,16 +257,7 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
 int __init
 zfcp_ccw_register(void)
 {
-       int retval;
-
-       retval = ccw_driver_register(&zfcp_ccw_driver);
-       if (retval)
-               goto out;
-       retval = zfcp_sysfs_driver_create_files(&zfcp_ccw_driver.driver);
-       if (retval)
-               ccw_driver_unregister(&zfcp_ccw_driver);
- out:
-       return retval;
+       return ccw_driver_register(&zfcp_ccw_driver);
 }
 
 /**
index ffa3bf756943f6aa142c8bf66bc74e70de1c3fc5..701046c9bb330ef8dc1ca6d0a76516755a5687ea 100644 (file)
@@ -161,12 +161,6 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
                   (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) {
                strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE);
                level = 4;
-       } else if ((prot_status_qual->doubleword[0] != 0) ||
-                  (prot_status_qual->doubleword[1] != 0) ||
-                  (fsf_status_qual->doubleword[0] != 0) ||
-                  (fsf_status_qual->doubleword[1] != 0)) {
-               strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE);
-               level = 3;
        } else {
                strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE);
                level = 6;
index e268f79bdbd232de9f81edb5b8d6e291998051d2..9e9f6c1e4e5d2e79441ef11c603da7ec228543a0 100644 (file)
@@ -118,7 +118,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
 
 #define ZFCP_SBAL_TIMEOUT               (5*HZ)
 
-#define ZFCP_TYPE2_RECOVERY_TIME        (8*HZ)
+#define ZFCP_TYPE2_RECOVERY_TIME        8      /* seconds */
 
 /* queue polling (values in microseconds) */
 #define ZFCP_MAX_INPUT_THRESHOLD       5000    /* FIXME: tune */
@@ -139,7 +139,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
 #define ZFCP_STATUS_READS_RECOM                        FSF_STATUS_READS_RECOM
 
 /* Do 1st retry in 1 second, then double the timeout for each following retry */
-#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP  100
+#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP  1
 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES      7
 
 /* timeout value for "default timer" for fsf requests */
@@ -983,10 +983,6 @@ struct zfcp_unit {
         struct scsi_device     *device;        /* scsi device struct pointer */
        struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
-       wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
-                                                 all scsi_scan_target
-                                                 requests have been
-                                                 completed. */
 };
 
 /* FSF request */
@@ -1127,6 +1123,20 @@ zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
        return NULL;
 }
 
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
+{
+       struct zfcp_fsf_req *request;
+       unsigned int idx;
+
+       for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) {
+               list_for_each_entry(request, &adapter->req_list[idx], list)
+                       if (request == req)
+                               return request;
+       }
+       return NULL;
+}
+
 /*
  *  functions needed for reference/usage counting
  */
index 07fa824d179f203e3f9bbbf6b099e94206140e5a..2dc8110ebf74d7a5e5e3a37bcbb6e1883e1523c6 100644 (file)
@@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter)
        debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
        while (qdio_shutdown(adapter->ccw_device,
                             QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
-               msleep(1000);
+               ssleep(1);
        debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
 
        /* cleanup used outbound sbals */
@@ -456,7 +456,7 @@ zfcp_test_link(struct zfcp_port *port)
 
        zfcp_port_get(port);
        retval = zfcp_erp_adisc(port);
-       if (retval != 0) {
+       if (retval != 0 && retval != -EBUSY) {
                zfcp_port_put(port);
                ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx "
                                "on adapter %s\n ", port->wwpn,
@@ -846,7 +846,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
        if (erp_action->fsf_req) {
                /* take lock to ensure that request is not deleted meanwhile */
                spin_lock(&adapter->req_list_lock);
-               if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
+               if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) &&
+                   erp_action->fsf_req->erp_action == erp_action) {
                        /* fsf_req still exists */
                        debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
                        debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
@@ -1285,7 +1286,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
         * note: no lock in subsequent strategy routines
         * (this allows these routine to call schedule, e.g.
         * kmalloc with such flags or qdio_initialize & friends)
-        * Note: in case of timeout, the seperate strategies will fail
+        * Note: in case of timeout, the separate strategies will fail
         * anyhow. No need for a special action. Even worse, a nameserver
         * failure would not wake up waiting ports without the call.
         */
@@ -1609,7 +1610,6 @@ static void zfcp_erp_scsi_scan(struct work_struct *work)
        scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
                         unit->scsi_lun, 0);
        atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
-       wake_up(&unit->scsi_scan_wq);
        zfcp_unit_put(unit);
        kfree(p);
 }
@@ -1900,7 +1900,7 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
                ZFCP_LOG_INFO("Waiting to allow the adapter %s "
                              "to recover itself\n",
                              zfcp_get_busid_by_adapter(adapter));
-               msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME));
+               ssleep(ZFCP_TYPE2_RECOVERY_TIME);
        }
 
        return retval;
@@ -2080,7 +2080,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
        debug_text_event(adapter->erp_dbf, 3, "qdio_down1a");
        while (qdio_shutdown(adapter->ccw_device,
                             QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
-               msleep(1000);
+               ssleep(1);
        debug_text_event(adapter->erp_dbf, 3, "qdio_down1b");
 
  failed_qdio_establish:
@@ -2165,7 +2165,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
                ZFCP_LOG_DEBUG("host connection still initialising... "
                               "waiting and retrying...\n");
                /* sleep a little bit before retry */
-               msleep(jiffies_to_msecs(sleep));
+               ssleep(sleep);
                sleep *= 2;
        }
 
index 8534cf09546c3c120a6b23d4a1a8ebd76a6b7894..06b1079b7f3d8e53dbe0961e40a02b20df2cb5ba 100644 (file)
@@ -27,8 +27,7 @@
 extern struct zfcp_data zfcp_data;
 
 /******************************** SYSFS  *************************************/
-extern int  zfcp_sysfs_driver_create_files(struct device_driver *);
-extern void zfcp_sysfs_driver_remove_files(struct device_driver *);
+extern struct attribute_group *zfcp_driver_attr_groups[];
 extern int  zfcp_sysfs_adapter_create_files(struct device *);
 extern void zfcp_sysfs_adapter_remove_files(struct device *);
 extern int  zfcp_sysfs_port_create_files(struct device *, u32);
index ff866ebd44ac1ae2771d62b346d485489c2473e5..e45f85f7c7ed815d1c4017baf16465762200235b 100644 (file)
@@ -502,7 +502,7 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
                fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                break;
        case FSF_SQ_NO_RECOM:
-               ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
+               ZFCP_LOG_NORMAL("bug: No recommendation could be given for a "
                                "problem on the adapter %s "
                                "Stopping all operations on this adapter. ",
                                zfcp_get_busid_by_adapter(fsf_req->adapter));
@@ -813,7 +813,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 
        if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
-               ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
+               ZFCP_LOG_NORMAL("bug: Reopen port indication received for "
                                "nonexisting port with d_id 0x%06x on "
                                "adapter %s. Ignored.\n",
                                status_buffer->d_id & ZFCP_DID_MASK,
@@ -1116,6 +1116,10 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
                goto out;
        }
 
+       if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+                       &unit->status)))
+               goto unit_blocked;
+
        sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1131,22 +1135,13 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
 
        zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
        retval = zfcp_fsf_req_send(fsf_req);
-       if (retval) {
-               ZFCP_LOG_INFO("error: Failed to send abort command request "
-                             "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
-                             zfcp_get_busid_by_adapter(adapter),
-                             unit->port->wwpn, unit->fcp_lun);
+       if (!retval)
+               goto out;
+
+ unit_blocked:
                zfcp_fsf_req_free(fsf_req);
                fsf_req = NULL;
-               goto out;
-       }
 
-       ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
-                      "(adapter%s, port d_id=0x%06x, "
-                      "unit x%016Lx, old_req_id=0x%lx)\n",
-                      zfcp_get_busid_by_adapter(adapter),
-                      unit->port->d_id,
-                      unit->fcp_lun, old_req_id);
  out:
        write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
        return fsf_req;
@@ -1164,8 +1159,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
 {
        int retval = -EINVAL;
        struct zfcp_unit *unit;
-       unsigned char status_qual =
-           new_fsf_req->qtcb->header.fsf_status_qual.word[0];
+       union fsf_status_qual *fsf_stat_qual =
+               &new_fsf_req->qtcb->header.fsf_status_qual;
 
        if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
                /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
@@ -1178,7 +1173,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
        switch (new_fsf_req->qtcb->header.fsf_status) {
 
        case FSF_PORT_HANDLE_NOT_VALID:
-               if (status_qual >> 4 != status_qual % 0xf) {
+               if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
                        debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
                                         "fsf_s_phand_nv0");
                        /*
@@ -1207,8 +1202,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
                break;
 
        case FSF_LUN_HANDLE_NOT_VALID:
-               if (status_qual >> 4 != status_qual % 0xf) {
-                       /* 2 */
+               if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
                        debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
                                         "fsf_s_lhand_nv0");
                        /*
@@ -1674,6 +1668,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                 goto failed_req;
        }
 
+       if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+                       &els->port->status))) {
+               ret = -EBUSY;
+               goto port_blocked;
+       }
+
        sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
         if (zfcp_use_one_sbal(els->req, els->req_count,
                               els->resp, els->resp_count)){
@@ -1755,6 +1755,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
        goto out;
 
+ port_blocked:
  failed_send:
        zfcp_fsf_req_free(fsf_req);
 
@@ -2280,7 +2281,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
                                     &lock_flags, &fsf_req);
        if (retval) {
                ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-                             "exchange port data request for"
+                             "exchange port data request for "
                              "the adapter %s.\n",
                              zfcp_get_busid_by_adapter(adapter));
                write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -2339,7 +2340,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
                                0, NULL, &lock_flags, &fsf_req);
        if (retval) {
                ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-                             "exchange port data request for"
+                             "exchange port data request for "
                              "the adapter %s.\n",
                              zfcp_get_busid_by_adapter(adapter));
                write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -3592,6 +3593,12 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
                goto failed_req_create;
        }
 
+       if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+                       &unit->status))) {
+               retval = -EBUSY;
+               goto unit_blocked;
+       }
+
        zfcp_unit_get(unit);
        fsf_req->unit = unit;
 
@@ -3732,6 +3739,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
  send_failed:
  no_fit:
  failed_scsi_cmnd:
+ unit_blocked:
        zfcp_unit_put(unit);
        zfcp_fsf_req_free(fsf_req);
        fsf_req = NULL;
@@ -3766,6 +3774,10 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
                goto out;
        }
 
+       if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+                       &unit->status)))
+               goto unit_blocked;
+
        /*
         * Used to decide on proper handler in the return path,
         * could be either zfcp_fsf_send_fcp_command_task_handler or
@@ -3799,25 +3811,13 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
 
        zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
        retval = zfcp_fsf_req_send(fsf_req);
-       if (retval) {
-               ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
-                             "management) on adapter %s, port 0x%016Lx for "
-                             "unit LUN 0x%016Lx\n",
-                             zfcp_get_busid_by_adapter(adapter),
-                             unit->port->wwpn,
-                             unit->fcp_lun);
-               zfcp_fsf_req_free(fsf_req);
-               fsf_req = NULL;
+       if (!retval)
                goto out;
-       }
 
-       ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
-                      "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
-                      "tm_flags=0x%x)\n",
-                      zfcp_get_busid_by_adapter(adapter),
-                      unit->port->wwpn,
-                      unit->fcp_lun,
-                      tm_flags);
+ unit_blocked:
+       zfcp_fsf_req_free(fsf_req);
+       fsf_req = NULL;
+
  out:
        write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
        return fsf_req;
@@ -4725,7 +4725,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
        /* allocate new FSF request */
        fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
        if (unlikely(NULL == fsf_req)) {
-               ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
+               ZFCP_LOG_DEBUG("error: Could not put an FSF request into "
                               "the outbound (send) queue.\n");
                ret = -ENOMEM;
                goto failed_fsf_req;
index 51d92b196ee716848268a79d4c8a7653b282e775..22fdc17e0d0e82aae92cbb1bdccbee6ee18f5edf 100644 (file)
@@ -529,7 +529,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
 
 
 /**
- * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
+ * zfcp_qdio_sbale_fill - set address and length in current SBALE
  *     on request_queue
  */
 static void
index abae2027f7e598c9b6c6249f6064889af140afa1..b9daf5c058628720b82c03797ed323878d541a48 100644 (file)
@@ -51,7 +51,6 @@ struct zfcp_data zfcp_data = {
                .queuecommand           = zfcp_scsi_queuecommand,
                .eh_abort_handler       = zfcp_scsi_eh_abort_handler,
                .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
-               .eh_bus_reset_handler   = zfcp_scsi_eh_host_reset_handler,
                .eh_host_reset_handler  = zfcp_scsi_eh_host_reset_handler,
                .can_queue              = 4096,
                .this_id                = -1,
@@ -181,9 +180,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 
        if (unit) {
                zfcp_erp_wait(unit->port->adapter);
-               wait_event(unit->scsi_scan_wq,
-                          atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
-                                           &unit->status) == 0);
                atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
                sdpnt->hostdata = NULL;
                unit->device = NULL;
@@ -262,8 +258,9 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
                goto out;
        }
 
-       if (unlikely(
-            !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
+       tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
+                                            ZFCP_REQ_AUTO_CLEANUP);
+       if (unlikely(tmp == -EBUSY)) {
                ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx "
                               "on port 0x%016Lx in recovery\n",
                               zfcp_get_busid_by_unit(unit),
@@ -272,9 +269,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
                goto out;
        }
 
-       tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
-                                            ZFCP_REQ_AUTO_CLEANUP);
-
        if (unlikely(tmp < 0)) {
                ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n");
                retval = SCSI_MLQUEUE_HOST_BUSY;
@@ -459,7 +453,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
                retval = SUCCESS;
                goto out;
        }
-       ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun);
+       ZFCP_LOG_NORMAL("resetting unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
+                       unit->fcp_lun, unit->port->wwpn,
+                       zfcp_get_busid_by_adapter(unit->port->adapter));
 
        /*
         * If we do not know whether the unit supports 'logical unit reset'
@@ -542,7 +538,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
 }
 
 /**
- * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
+ * zfcp_scsi_eh_host_reset_handler - handler for host reset
  */
 static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
@@ -552,8 +548,10 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
        unit = (struct zfcp_unit*) scpnt->device->hostdata;
        adapter = unit->port->adapter;
 
-       ZFCP_LOG_NORMAL("host/bus reset because of problems with "
-                       "unit 0x%016Lx\n", unit->fcp_lun);
+       ZFCP_LOG_NORMAL("host reset because of problems with "
+               "unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
+               unit->fcp_lun, unit->port->wwpn,
+               zfcp_get_busid_by_adapter(unit->port->adapter));
 
        zfcp_erp_adapter_reopen(adapter, 0);
        zfcp_erp_wait(adapter);
index 005e62f8593b66c021f28d174965f002f27a12a1..651edd58906a021fc71f6f12693998abadfd00a7 100644 (file)
@@ -98,28 +98,9 @@ static struct attribute_group zfcp_driver_attr_group = {
        .attrs = zfcp_driver_attrs,
 };
 
-/**
- * zfcp_sysfs_create_driver_files - create sysfs driver files
- * @dev: pointer to belonging device
- *
- * Create all sysfs attributes of the zfcp device driver
- */
-int
-zfcp_sysfs_driver_create_files(struct device_driver *drv)
-{
-       return sysfs_create_group(&drv->kobj, &zfcp_driver_attr_group);
-}
-
-/**
- * zfcp_sysfs_remove_driver_files - remove sysfs driver files
- * @dev: pointer to belonging device
- *
- * Remove all sysfs attributes of the zfcp device driver
- */
-void
-zfcp_sysfs_driver_remove_files(struct device_driver *drv)
-{
-       sysfs_remove_group(&drv->kobj, &zfcp_driver_attr_group);
-}
+struct attribute_group *zfcp_driver_attr_groups[] = {
+       &zfcp_driver_attr_group,
+       NULL,
+};
 
 #undef ZFCP_LOG_AREA
index b385af314356b3364f740f31a9fa6f6d9febbc47..c89ae9a043991103b84c3c19e5372f77471829b6 100644 (file)
@@ -1,3 +1 @@
 53c700_d.h
-53c7xx_d.h
-53c7xx_u.h
index afb262b4be15b8d61bfe36bb136ea20bc4f9a6fe..1c244832c6c8aa0049d560883c3b959845050b83 100644 (file)
@@ -2010,6 +2010,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
        }
 
        pci_set_master(pdev);
+       pci_try_set_mwi(pdev);
 
        if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
            || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
index 71ff3fbfce12559d161fed31be5d6d1f90101677..f4c4fe90240abdbf995d4c2f8afe0ef9b87374b4 100644 (file)
@@ -608,7 +608,8 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
                        scsi_print_sense("53c700", SCp);
 
 #endif
-                       dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+                       dma_unmap_single(hostdata->dev, slot->dma_handle,
+                                        SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
                        /* restore the old result if the request sense was
                         * successful */
                        if (result == 0)
@@ -1010,7 +1011,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
                                cmnd[1] = (SCp->device->lun & 0x7) << 5;
                                cmnd[2] = 0;
                                cmnd[3] = 0;
-                               cmnd[4] = sizeof(SCp->sense_buffer);
+                               cmnd[4] = SCSI_SENSE_BUFFERSIZE;
                                cmnd[5] = 0;
                                /* Here's a quiet hack: the
                                 * REQUEST_SENSE command is six bytes,
@@ -1024,14 +1025,14 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
                                SCp->cmd_len = 6; /* command length for
                                                   * REQUEST_SENSE */
                                slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
-                               slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
-                               slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
+                               slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+                               slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE);
                                slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
                                slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
                                slot->SG[1].pAddr = 0;
                                slot->resume_offset = hostdata->pScript;
                                dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
-                               dma_cache_sync(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+                               dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
 
                                /* queue the command for reissue */
                                slot->state = NCR_700_SLOT_QUEUED;
index 49e1ffa4b2ffbf700f2c1c22b43ebd7c59f8776a..ead47c143ce04fd9792da0d30c9a7b31f7d0db03 100644 (file)
@@ -2947,7 +2947,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
                }
        }
        memcpy(CCB->CDB, CDB, CDB_Length);
-       CCB->SenseDataLength = sizeof(Command->sense_buffer);
+       CCB->SenseDataLength = SCSI_SENSE_BUFFERSIZE;
        CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
        CCB->Command = Command;
        Command->scsi_done = CompletionRoutine;
index a6676be87843ad43d0c0fc57ff441993ac7a3985..3e161cd664637292927686aaf954e23dfc3b1a02 100644 (file)
@@ -341,7 +341,7 @@ config ISCSI_TCP
         The userspace component needed to initialize the driver, documentation,
         and sample configuration files can be found here:
 
-        http://linux-iscsi.sf.net
+        http://open-iscsi.org
 
 config SGIWD93_SCSI
        tristate "SGI WD93C93 SCSI Driver"
@@ -573,10 +573,10 @@ config SCSI_ARCMSR_AER
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 
 config SCSI_HPTIOP
-       tristate "HighPoint RocketRAID 3xxx Controller support"
+       tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
        depends on SCSI && PCI
        help
-         This option enables support for HighPoint RocketRAID 3xxx
+         This option enables support for HighPoint RocketRAID 3xxx/4xxx
          controllers.
 
          To compile this driver as a module, choose M here; the module
@@ -732,7 +732,7 @@ config SCSI_GDTH
          This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) 
          manufactured by Intel Corporation/ICP vortex GmbH. It is documented
          in the kernel source in <file:drivers/scsi/gdth.c> and
-         <file:drivers/scsi/gdth.h.>
+         <file:drivers/scsi/gdth.h>.
 
          To compile this driver as a module, choose M here: the
          module will be called gdth.
@@ -1288,17 +1288,6 @@ config SCSI_PAS16
          To compile this driver as a module, choose M here: the
          module will be called pas16.
 
-config SCSI_PSI240I
-       tristate "PSI240i support"
-       depends on ISA && SCSI
-       help
-         This is support for the PSI240i EIDE interface card which acts as a
-         SCSI host adapter.  Please read the SCSI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called psi240i.
-
 config SCSI_QLOGIC_FAS
        tristate "Qlogic FAS SCSI support"
        depends on ISA && SCSI
@@ -1359,21 +1348,6 @@ config SCSI_LPFC
           This lpfc driver supports the Emulex LightPulse
           Family of Fibre Channel PCI host adapters.
 
-config SCSI_SEAGATE
-       tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
-       depends on X86 && ISA && SCSI
-       select CHECK_SIGNATURE
-       ---help---
-         These are 8-bit SCSI controllers; the ST-01 is also supported by
-         this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
-         available from <http://www.tldp.org/docs.html#howto>.  If it
-         doesn't work out of the box, you may have to change some macros at
-         compiletime, which are described in <file:drivers/scsi/seagate.c>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called seagate.
-
-# definitely looks not 64bit safe:
 config SCSI_SIM710
        tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
        depends on (EISA || MCA) && SCSI
index 2e6129f13d38d66baf532d6b514aae10f7eb9060..93e1428d03fc54efc5adb9ca7231adfb037a03fb 100644 (file)
@@ -16,9 +16,8 @@
 
 CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
 CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
-CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
-subdir-$(CONFIG_PCMCIA)                += pcmcia
+obj-$(CONFIG_PCMCIA)           += pcmcia/
 
 obj-$(CONFIG_SCSI)             += scsi_mod.o
 obj-$(CONFIG_SCSI_TGT)         += scsi_tgt.o
@@ -59,7 +58,6 @@ obj-$(CONFIG_MVME16x_SCSI)    += 53c700.o     mvme16x_scsi.o
 obj-$(CONFIG_BVME6000_SCSI)    += 53c700.o     bvme6000_scsi.o
 obj-$(CONFIG_SCSI_SIM710)      += 53c700.o     sim710.o
 obj-$(CONFIG_SCSI_ADVANSYS)    += advansys.o
-obj-$(CONFIG_SCSI_PSI240I)     += psi240i.o
 obj-$(CONFIG_SCSI_BUSLOGIC)    += BusLogic.o
 obj-$(CONFIG_SCSI_DPT_I2O)     += dpt_i2o.o
 obj-$(CONFIG_SCSI_U14_34F)     += u14-34f.o
@@ -90,7 +88,6 @@ obj-$(CONFIG_SCSI_QLA_FC)     += qla2xxx/
 obj-$(CONFIG_SCSI_QLA_ISCSI)   += qla4xxx/
 obj-$(CONFIG_SCSI_LPFC)                += lpfc/
 obj-$(CONFIG_SCSI_PAS16)       += pas16.o
-obj-$(CONFIG_SCSI_SEAGATE)     += seagate.o
 obj-$(CONFIG_SCSI_T128)                += t128.o
 obj-$(CONFIG_SCSI_DMX3191D)    += dmx3191d.o
 obj-$(CONFIG_SCSI_DTC3280)     += dtc.o
index 2597209183d0ba7148a6757ee02730b41e01e53c..eeddbd19eba5c54af76260d1fdfea41c17ac692c 100644 (file)
@@ -295,16 +295,16 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
         * various queues are valid.
         */
 
-       if (cmd->use_sg) {
-               cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-               cmd->SCp.buffers_residual = cmd->use_sg - 1;
+       if (scsi_bufflen(cmd)) {
+               cmd->SCp.buffer = scsi_sglist(cmd);
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
                cmd->SCp.buffers_residual = 0;
-               cmd->SCp.ptr = (char *) cmd->request_buffer;
-               cmd->SCp.this_residual = cmd->request_bufflen;
+               cmd->SCp.ptr = NULL;
+               cmd->SCp.this_residual = 0;
        }
 }
 
@@ -932,7 +932,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
  *     @instance: adapter to remove
  */
 
-static void __devexit NCR5380_exit(struct Scsi_Host *instance)
+static void NCR5380_exit(struct Scsi_Host *instance)
 {
        struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 
@@ -975,14 +975,14 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
                case WRITE_6:
                case WRITE_10:
                        hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-                       hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+                       hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
                        hostdata->pendingw++;
                        break;
                case READ:
                case READ_6:
                case READ_10:
                        hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-                       hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+                       hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
                        hostdata->pendingr++;
                        break;
        }
@@ -1157,16 +1157,17 @@ static void NCR5380_main(struct work_struct *work)
  *     Locks: takes the needed instance locks
  */
 
-static irqreturn_t NCR5380_intr(int irq, void *dev_id) 
+static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
 {
        NCR5380_local_declare();
-       struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
+       struct Scsi_Host *instance = dev_id;
        struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
        int done;
        unsigned char basr;
        unsigned long flags;
 
-       dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq));
+       dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n",
+               instance->irq));
 
        do {
                done = 1;
index b7c5385e2efe2fb8c04d8892d936b46ae5570137..23f27c9c989501e3d078f6a8532240b24bafe97f 100644 (file)
@@ -73,18 +73,9 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
        }
 
        if (!dir_in) {
-           /* copy to bounce buffer for a write */
-           if (cmd->use_sg)
-#if 0
-               panic ("scsi%ddma: incomplete s/g support",
-                      instance->host_no);
-#else
+               /* copy to bounce buffer for a write */
                memcpy (HDATA(instance)->dma_bounce_buffer,
                        cmd->SCp.ptr, cmd->SCp.this_residual);
-#endif
-           else
-               memcpy (HDATA(instance)->dma_bounce_buffer,
-                       cmd->request_buffer, cmd->request_bufflen);
        }
     }
 
@@ -144,30 +135,13 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 
     /* copy from a bounce buffer, if necessary */
     if (status && HDATA(instance)->dma_bounce_buffer) {
-       if (SCpnt && SCpnt->use_sg) {
-#if 0
-           panic ("scsi%d: incomplete s/g support",
-                  instance->host_no);
-#else
-           if( HDATA(instance)->dma_dir )
+       if( HDATA(instance)->dma_dir )
                memcpy (SCpnt->SCp.ptr, 
                        HDATA(instance)->dma_bounce_buffer,
                        SCpnt->SCp.this_residual);
-           kfree (HDATA(instance)->dma_bounce_buffer);
-           HDATA(instance)->dma_bounce_buffer = NULL;
-           HDATA(instance)->dma_bounce_len = 0;
-           
-#endif
-       } else {
-           if (HDATA(instance)->dma_dir && SCpnt)
-               memcpy (SCpnt->request_buffer,
-                       HDATA(instance)->dma_bounce_buffer,
-                       SCpnt->request_bufflen);
-
-           kfree (HDATA(instance)->dma_bounce_buffer);
-           HDATA(instance)->dma_bounce_buffer = NULL;
-           HDATA(instance)->dma_bounce_len = 0;
-       }
+       kfree (HDATA(instance)->dma_bounce_buffer);
+       HDATA(instance)->dma_bounce_buffer = NULL;
+       HDATA(instance)->dma_bounce_len = 0;
     }
 }
 
index 796f1c4d772e1f5933b700c0b23826fb5f6ed43d..d7255c8bf2811a87ba866145182972e9c44d4f57 100644 (file)
@@ -70,12 +70,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 
        if (!dir_in) {
            /* copy to bounce buffer for a write */
-           if (cmd->use_sg) {
-               memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-                       cmd->SCp.ptr, cmd->SCp.this_residual);
-           } else
-               memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-                       cmd->request_buffer, cmd->request_bufflen);
+           memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+               cmd->SCp.ptr, cmd->SCp.this_residual);
        }
 
        addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
@@ -146,7 +142,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 
     /* copy from a bounce buffer, if necessary */
     if (status && HDATA(instance)->dma_bounce_buffer) {
-       if (SCpnt && SCpnt->use_sg) {
+       if (SCpnt) {
            if (HDATA(instance)->dma_dir && SCpnt)
                memcpy (SCpnt->SCp.ptr,
                        HDATA(instance)->dma_bounce_buffer,
@@ -155,11 +151,6 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
            HDATA(instance)->dma_bounce_buffer = NULL;
            HDATA(instance)->dma_bounce_len = 0;
        } else {
-           if (HDATA(instance)->dma_dir && SCpnt)
-               memcpy (SCpnt->request_buffer,
-                       HDATA(instance)->dma_bounce_buffer,
-                       SCpnt->request_bufflen);
-
            kfree (HDATA(instance)->dma_bounce_buffer);
            HDATA(instance)->dma_bounce_buffer = NULL;
            HDATA(instance)->dma_bounce_len = 0;
index a77ab8d693d416f48a53c7efd147a3508def7ec4..d7235f42cf5faa730792415727e4998dbbd1cbc2 100644 (file)
@@ -31,9 +31,9 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
+#include <linux/highmem.h> /* For flush_kernel_dcache_page */
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 /*
  *     Sense codes
  */
-#define SENCODE_NO_SENSE                        0x00
-#define SENCODE_END_OF_DATA                     0x00
-#define SENCODE_BECOMING_READY                  0x04
-#define SENCODE_INIT_CMD_REQUIRED               0x04
-#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
-#define SENCODE_INVALID_COMMAND                 0x20
-#define SENCODE_LBA_OUT_OF_RANGE                0x21
-#define SENCODE_INVALID_CDB_FIELD               0x24
-#define SENCODE_LUN_NOT_SUPPORTED               0x25
-#define SENCODE_INVALID_PARAM_FIELD             0x26
-#define SENCODE_PARAM_NOT_SUPPORTED             0x26
-#define SENCODE_PARAM_VALUE_INVALID             0x26
-#define SENCODE_RESET_OCCURRED                  0x29
-#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
-#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
-#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
-#define SENCODE_DIAGNOSTIC_FAILURE              0x40
-#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
-#define SENCODE_INVALID_MESSAGE_ERROR           0x49
-#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
-#define SENCODE_OVERLAPPED_COMMAND              0x4E
+
+#define SENCODE_NO_SENSE                       0x00
+#define SENCODE_END_OF_DATA                    0x00
+#define SENCODE_BECOMING_READY                 0x04
+#define SENCODE_INIT_CMD_REQUIRED              0x04
+#define SENCODE_PARAM_LIST_LENGTH_ERROR                0x1A
+#define SENCODE_INVALID_COMMAND                        0x20
+#define SENCODE_LBA_OUT_OF_RANGE               0x21
+#define SENCODE_INVALID_CDB_FIELD              0x24
+#define SENCODE_LUN_NOT_SUPPORTED              0x25
+#define SENCODE_INVALID_PARAM_FIELD            0x26
+#define SENCODE_PARAM_NOT_SUPPORTED            0x26
+#define SENCODE_PARAM_VALUE_INVALID            0x26
+#define SENCODE_RESET_OCCURRED                 0x29
+#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x3E
+#define SENCODE_INQUIRY_DATA_CHANGED           0x3F
+#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x39
+#define SENCODE_DIAGNOSTIC_FAILURE             0x40
+#define SENCODE_INTERNAL_TARGET_FAILURE                0x44
+#define SENCODE_INVALID_MESSAGE_ERROR          0x49
+#define SENCODE_LUN_FAILED_SELF_CONFIG         0x4c
+#define SENCODE_OVERLAPPED_COMMAND             0x4E
 
 /*
  *     Additional sense codes
  */
-#define ASENCODE_NO_SENSE                       0x00
-#define ASENCODE_END_OF_DATA                    0x05
-#define ASENCODE_BECOMING_READY                 0x01
-#define ASENCODE_INIT_CMD_REQUIRED              0x02
-#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
-#define ASENCODE_INVALID_COMMAND                0x00
-#define ASENCODE_LBA_OUT_OF_RANGE               0x00
-#define ASENCODE_INVALID_CDB_FIELD              0x00
-#define ASENCODE_LUN_NOT_SUPPORTED              0x00
-#define ASENCODE_INVALID_PARAM_FIELD            0x00
-#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
-#define ASENCODE_PARAM_VALUE_INVALID            0x02
-#define ASENCODE_RESET_OCCURRED                 0x00
-#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
-#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
-#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
-#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
-#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
-#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
-#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
-#define ASENCODE_OVERLAPPED_COMMAND             0x00
+
+#define ASENCODE_NO_SENSE                      0x00
+#define ASENCODE_END_OF_DATA                   0x05
+#define ASENCODE_BECOMING_READY                        0x01
+#define ASENCODE_INIT_CMD_REQUIRED             0x02
+#define ASENCODE_PARAM_LIST_LENGTH_ERROR       0x00
+#define ASENCODE_INVALID_COMMAND               0x00
+#define ASENCODE_LBA_OUT_OF_RANGE              0x00
+#define ASENCODE_INVALID_CDB_FIELD             0x00
+#define ASENCODE_LUN_NOT_SUPPORTED             0x00
+#define ASENCODE_INVALID_PARAM_FIELD           0x00
+#define ASENCODE_PARAM_NOT_SUPPORTED           0x01
+#define ASENCODE_PARAM_VALUE_INVALID           0x02
+#define ASENCODE_RESET_OCCURRED                        0x00
+#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET   0x00
+#define ASENCODE_INQUIRY_DATA_CHANGED          0x03
+#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED   0x00
+#define ASENCODE_DIAGNOSTIC_FAILURE            0x80
+#define ASENCODE_INTERNAL_TARGET_FAILURE       0x00
+#define ASENCODE_INVALID_MESSAGE_ERROR         0x00
+#define ASENCODE_LUN_FAILED_SELF_CONFIG                0x00
+#define ASENCODE_OVERLAPPED_COMMAND            0x00
 
 #define BYTE0(x) (unsigned char)(x)
 #define BYTE1(x) (unsigned char)((x) >> 8)
  *----------------------------------------------------------------------------*/
 /* SCSI inquiry data */
 struct inquiry_data {
-       u8 inqd_pdt;    /* Peripheral qualifier | Peripheral Device Type  */
-       u8 inqd_dtq;    /* RMB | Device Type Qualifier  */
+       u8 inqd_pdt;    /* Peripheral qualifier | Peripheral Device Type */
+       u8 inqd_dtq;    /* RMB | Device Type Qualifier */
        u8 inqd_ver;    /* ISO version | ECMA version | ANSI-approved version */
        u8 inqd_rdf;    /* AENC | TrmIOP | Response data format */
        u8 inqd_len;    /* Additional length (n-4) */
@@ -130,7 +130,7 @@ struct inquiry_data {
 /*
  *              M O D U L E   G L O B A L S
  */
+
 static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
 static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
 static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
@@ -141,9 +141,10 @@ static char *aac_get_status_string(u32 status);
 
 /*
  *     Non dasd selection is handled entirely in aachba now
- */    
+ */
+
 static int nondasd = -1;
+static int aac_cache = 0;
 static int dacmode = -1;
 
 int aac_commit = -1;
@@ -152,6 +153,8 @@ int aif_timeout = 120;
 
 module_param(nondasd, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache");
 module_param(dacmode, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
 module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
@@ -179,7 +182,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health che
 
 int aac_check_reset = 1;
 module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
+MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it.");
 
 int expose_physicals = -1;
 module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
@@ -193,12 +196,12 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
                struct fib *fibptr) {
        struct scsi_device *device;
 
-       if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
+       if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
                dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
-                aac_fib_complete(fibptr);
-                aac_fib_free(fibptr);
-                return 0;
-        }
+               aac_fib_complete(fibptr);
+               aac_fib_free(fibptr);
+               return 0;
+       }
        scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
        device = scsicmd->device;
        if (unlikely(!device || !scsi_device_online(device))) {
@@ -240,7 +243,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
                            FsaNormal,
                            1, 1,
                            NULL, NULL);
-       if (status < 0 ) {
+       if (status < 0) {
                printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
        } else {
                struct aac_get_config_status_resp *reply
@@ -264,10 +267,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
                        struct aac_commit_config * dinfo;
                        aac_fib_init(fibptr);
                        dinfo = (struct aac_commit_config *) fib_data(fibptr);
-       
+
                        dinfo->command = cpu_to_le32(VM_ContainerConfig);
                        dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
-       
+
                        status = aac_fib_send(ContainerCommand,
                                    fibptr,
                                    sizeof (struct aac_commit_config),
@@ -293,7 +296,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
 int aac_get_containers(struct aac_dev *dev)
 {
        struct fsa_dev_info *fsa_dev_ptr;
-       u32 index; 
+       u32 index;
        int status = 0;
        struct fib * fibptr;
        struct aac_get_container_count *dinfo;
@@ -363,6 +366,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
        if (buf && transfer_len > 0)
                memcpy(buf + offset, data, transfer_len);
 
+       flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset));
        kunmap_atomic(buf - sg->offset, KM_IRQ0);
 
 }
@@ -395,7 +399,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
                        do {
                                *dp++ = (*sp) ? *sp++ : ' ';
                        } while (--count > 0);
-                       aac_internal_transfer(scsicmd, d, 
+                       aac_internal_transfer(scsicmd, d,
                          offsetof(struct inquiry_data, inqd_pid), sizeof(d));
                }
        }
@@ -431,13 +435,13 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
        dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
 
        status = aac_fib_send(ContainerCommand,
-                 cmd_fibcontext, 
+                 cmd_fibcontext,
                  sizeof (struct aac_get_name),
-                 FsaNormal, 
-                 0, 1, 
-                 (fib_callback) get_container_name_callback, 
+                 FsaNormal,
+                 0, 1,
+                 (fib_callback)get_container_name_callback,
                  (void *) scsicmd);
-       
+
        /*
         *      Check that the command queued to the controller
         */
@@ -445,7 +449,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
                scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
                return 0;
        }
-               
+
        printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
        aac_fib_complete(cmd_fibcontext);
        aac_fib_free(cmd_fibcontext);
@@ -652,42 +656,47 @@ struct scsi_inq {
  *     @a:     string to copy from
  *     @b:     string to copy to
  *
- *     Copy a String from one location to another
+ *     Copy a String from one location to another
  *     without copying \0
  */
 
 static void inqstrcpy(char *a, char *b)
 {
 
-       while(*a != (char)0) 
+       while (*a != (char)0)
                *b++ = *a++;
 }
 
 static char *container_types[] = {
-        "None",
-        "Volume",
-        "Mirror",
-        "Stripe",
-        "RAID5",
-        "SSRW",
-        "SSRO",
-        "Morph",
-        "Legacy",
-        "RAID4",
-        "RAID10",             
-        "RAID00",             
-        "V-MIRRORS",          
-        "PSEUDO R4",          
+       "None",
+       "Volume",
+       "Mirror",
+       "Stripe",
+       "RAID5",
+       "SSRW",
+       "SSRO",
+       "Morph",
+       "Legacy",
+       "RAID4",
+       "RAID10",
+       "RAID00",
+       "V-MIRRORS",
+       "PSEUDO R4",
        "RAID50",
        "RAID5D",
        "RAID5D0",
        "RAID1E",
        "RAID6",
        "RAID60",
-        "Unknown"
+       "Unknown"
 };
 
-
+char * get_container_type(unsigned tindex)
+{
+       if (tindex >= ARRAY_SIZE(container_types))
+               tindex = ARRAY_SIZE(container_types) - 1;
+       return container_types[tindex];
+}
 
 /* Function: setinqstr
  *
@@ -707,16 +716,21 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
 
        if (dev->supplement_adapter_info.AdapterTypeText[0]) {
                char * cp = dev->supplement_adapter_info.AdapterTypeText;
-               int c = sizeof(str->vid);
-               while (*cp && *cp != ' ' && --c)
-                       ++cp;
-               c = *cp;
-               *cp = '\0';
-               inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
-                 str->vid); 
-               *cp = c;
-               while (*cp && *cp != ' ')
-                       ++cp;
+               int c;
+               if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
+                       inqstrcpy("SMC", str->vid);
+               else {
+                       c = sizeof(str->vid);
+                       while (*cp && *cp != ' ' && --c)
+                               ++cp;
+                       c = *cp;
+                       *cp = '\0';
+                       inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
+                                  str->vid);
+                       *cp = c;
+                       while (*cp && *cp != ' ')
+                               ++cp;
+               }
                while (*cp == ' ')
                        ++cp;
                /* last six chars reserved for vol type */
@@ -898,9 +912,8 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
                            ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
                            0, 0);
                memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer))
-                   ? sizeof(cmd->sense_buffer)
-                   : sizeof(dev->fsa_dev[cid].sense_data));
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
                cmd->scsi_done(cmd);
                return 1;
        }
@@ -981,7 +994,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
        aac_fib_init(fib);
        readcmd = (struct aac_read *) fib_data(fib);
        readcmd->command = cpu_to_le32(VM_CtBlockRead);
-       readcmd->cid = cpu_to_le16(scmd_id(cmd));
+       readcmd->cid = cpu_to_le32(scmd_id(cmd));
        readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
        readcmd->count = cpu_to_le32(count * 512);
 
@@ -1013,7 +1026,8 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
        writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
        writecmd->count = cpu_to_le32(count<<9);
        writecmd->cid = cpu_to_le16(scmd_id(cmd));
-       writecmd->flags = fua ?
+       writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
+         (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
                cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
                cpu_to_le16(IO_TYPE_WRITE);
        writecmd->bpTotal = 0;
@@ -1072,7 +1086,7 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
        aac_fib_init(fib);
        writecmd = (struct aac_write *) fib_data(fib);
        writecmd->command = cpu_to_le32(VM_CtBlockWrite);
-       writecmd->cid = cpu_to_le16(scmd_id(cmd));
+       writecmd->cid = cpu_to_le32(scmd_id(cmd));
        writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
        writecmd->count = cpu_to_le32(count * 512);
        writecmd->sg.count = cpu_to_le32(1);
@@ -1190,6 +1204,15 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
                                  (fib_callback) aac_srb_callback, (void *) cmd);
 }
 
+static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
+{
+       if ((sizeof(dma_addr_t) > 4) &&
+        (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) &&
+        (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
+               return FAILED;
+       return aac_scsi_32(fib, cmd);
+}
+
 int aac_get_adapter_info(struct aac_dev* dev)
 {
        struct fib* fibptr;
@@ -1207,11 +1230,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
        memset(info,0,sizeof(*info));
 
        rcode = aac_fib_send(RequestAdapterInfo,
-                        fibptr, 
+                        fibptr,
                         sizeof(*info),
-                        FsaNormal, 
+                        FsaNormal,
                         -1, 1, /* First `interrupt' command uses special wait */
-                        NULL, 
+                        NULL,
                         NULL);
 
        if (rcode < 0) {
@@ -1222,29 +1245,29 @@ int aac_get_adapter_info(struct aac_dev* dev)
        memcpy(&dev->adapter_info, info, sizeof(*info));
 
        if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
-               struct aac_supplement_adapter_info * info;
+               struct aac_supplement_adapter_info * sinfo;
 
                aac_fib_init(fibptr);
 
-               info = (struct aac_supplement_adapter_info *) fib_data(fibptr);
+               sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
 
-               memset(info,0,sizeof(*info));
+               memset(sinfo,0,sizeof(*sinfo));
 
                rcode = aac_fib_send(RequestSupplementAdapterInfo,
                                 fibptr,
-                                sizeof(*info),
+                                sizeof(*sinfo),
                                 FsaNormal,
                                 1, 1,
                                 NULL,
                                 NULL);
 
                if (rcode >= 0)
-                       memcpy(&dev->supplement_adapter_info, info, sizeof(*info));
+                       memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
        }
 
 
-       /* 
-        * GetBusInfo 
+       /*
+        * GetBusInfo
         */
 
        aac_fib_init(fibptr);
@@ -1267,6 +1290,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
                         1, 1,
                         NULL, NULL);
 
+       /* reasoned default */
+       dev->maximum_num_physicals = 16;
        if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
                dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
                dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
@@ -1276,7 +1301,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
                char buffer[16];
                tmp = le32_to_cpu(dev->adapter_info.kernelrev);
                printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
-                       dev->name, 
+                       dev->name,
                        dev->id,
                        tmp>>24,
                        (tmp>>16)&0xff,
@@ -1305,19 +1330,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
                          (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
                          dev->supplement_adapter_info.VpdInfo.Tsid);
                }
-               if (!aac_check_reset ||
+               if (!aac_check_reset || ((aac_check_reset != 1) &&
                  (dev->supplement_adapter_info.SupportedOptions2 &
-                 le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
+                 AAC_OPTION_IGNORE_RESET))) {
                        printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
                          dev->name, dev->id);
                }
        }
 
+       dev->cache_protected = 0;
+       dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
+               AAC_FEATURE_JBOD) != 0);
        dev->nondasd_support = 0;
        dev->raid_scsi_mode = 0;
-       if(dev->adapter_info.options & AAC_OPT_NONDASD){
+       if(dev->adapter_info.options & AAC_OPT_NONDASD)
                dev->nondasd_support = 1;
-       }
 
        /*
         * If the firmware supports ROMB RAID/SCSI mode and we are currently
@@ -1338,11 +1365,10 @@ int aac_get_adapter_info(struct aac_dev* dev)
        if (dev->raid_scsi_mode != 0)
                printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
                                dev->name, dev->id);
-               
-       if(nondasd != -1) {  
+
+       if (nondasd != -1)
                dev->nondasd_support = (nondasd!=0);
-       }
-       if(dev->nondasd_support != 0){
+       if(dev->nondasd_support != 0) {
                printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
        }
 
@@ -1371,12 +1397,14 @@ int aac_get_adapter_info(struct aac_dev* dev)
                        rcode = -ENOMEM;
                }
        }
-       /* 
+       /*
         * Deal with configuring for the individualized limits of each packet
         * interface.
         */
        dev->a_ops.adapter_scsi = (dev->dac_support)
-                               ? aac_scsi_64
+         ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
+                               ? aac_scsi_32_64
+                               : aac_scsi_64)
                                : aac_scsi_32;
        if (dev->raw_io_interface) {
                dev->a_ops.adapter_bounds = (dev->raw_io_64)
@@ -1393,8 +1421,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
                if (dev->dac_support) {
                        dev->a_ops.adapter_read = aac_read_block64;
                        dev->a_ops.adapter_write = aac_write_block64;
-                       /* 
-                        * 38 scatter gather elements 
+                       /*
+                        * 38 scatter gather elements
                         */
                        dev->scsi_host_ptr->sg_tablesize =
                                (dev->max_fib_size -
@@ -1498,9 +1526,8 @@ static void io_callback(void *context, struct fib * fibptr)
                                    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
                                    0, 0);
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
-                   ? sizeof(scsicmd->sense_buffer)
-                   : sizeof(dev->fsa_dev[cid].sense_data));
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
        }
        aac_fib_complete(fibptr);
        aac_fib_free(fibptr);
@@ -1524,7 +1551,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
        case READ_6:
                dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
 
-               lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
+               lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
                        (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
                count = scsicmd->cmnd[4];
 
@@ -1534,32 +1561,32 @@ static int aac_read(struct scsi_cmnd * scsicmd)
        case READ_16:
                dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
 
-               lba =   ((u64)scsicmd->cmnd[2] << 56) |
-                       ((u64)scsicmd->cmnd[3] << 48) |
+               lba =   ((u64)scsicmd->cmnd[2] << 56) |
+                       ((u64)scsicmd->cmnd[3] << 48) |
                        ((u64)scsicmd->cmnd[4] << 40) |
                        ((u64)scsicmd->cmnd[5] << 32) |
-                       ((u64)scsicmd->cmnd[6] << 24) | 
+                       ((u64)scsicmd->cmnd[6] << 24) |
                        (scsicmd->cmnd[7] << 16) |
                        (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
-               count = (scsicmd->cmnd[10] << 24) | 
+               count = (scsicmd->cmnd[10] << 24) |
                        (scsicmd->cmnd[11] << 16) |
                        (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
                break;
        case READ_12:
                dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
 
-               lba = ((u64)scsicmd->cmnd[2] << 24) | 
+               lba = ((u64)scsicmd->cmnd[2] << 24) |
                        (scsicmd->cmnd[3] << 16) |
-                       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
-               count = (scsicmd->cmnd[6] << 24) | 
+                       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+               count = (scsicmd->cmnd[6] << 24) |
                        (scsicmd->cmnd[7] << 16) |
-                       (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+                       (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
                break;
        default:
                dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
 
-               lba = ((u64)scsicmd->cmnd[2] << 24) | 
-                       (scsicmd->cmnd[3] << 16) | 
+               lba = ((u64)scsicmd->cmnd[2] << 24) |
+                       (scsicmd->cmnd[3] << 16) |
                        (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
                count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
                break;
@@ -1584,7 +1611,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
                scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
                return 0;
        }
-               
+
        printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
        /*
         *      For some reason, the Fib didn't queue, return QUEUE_FULL
@@ -1619,11 +1646,11 @@ static int aac_write(struct scsi_cmnd * scsicmd)
        } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
                dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
 
-               lba =   ((u64)scsicmd->cmnd[2] << 56) |
+               lba =   ((u64)scsicmd->cmnd[2] << 56) |
                        ((u64)scsicmd->cmnd[3] << 48) |
                        ((u64)scsicmd->cmnd[4] << 40) |
                        ((u64)scsicmd->cmnd[5] << 32) |
-                       ((u64)scsicmd->cmnd[6] << 24) | 
+                       ((u64)scsicmd->cmnd[6] << 24) |
                        (scsicmd->cmnd[7] << 16) |
                        (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
                count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
@@ -1712,8 +1739,8 @@ static void synchronize_callback(void *context, struct fib *fibptr)
                                    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
                                    0, 0);
                memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-                 min(sizeof(dev->fsa_dev[cid].sense_data),
-                         sizeof(cmd->sense_buffer)));
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
        }
 
        aac_fib_complete(fibptr);
@@ -1798,7 +1825,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
        if (active)
                return SCSI_MLQUEUE_DEVICE_BUSY;
 
-       aac = (struct aac_dev *)scsicmd->device->host->hostdata;
+       aac = (struct aac_dev *)sdev->host->hostdata;
        if (aac->in_reset)
                return SCSI_MLQUEUE_HOST_BUSY;
 
@@ -1850,14 +1877,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
  *     Emulate a SCSI command and queue the required request for the
  *     aacraid firmware.
  */
+
 int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 {
        u32 cid;
        struct Scsi_Host *host = scsicmd->device->host;
        struct aac_dev *dev = (struct aac_dev *)host->hostdata;
        struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
-       
+
        if (fsa_dev_ptr == NULL)
                return -1;
        /*
@@ -1898,7 +1925,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                }
                        }
                } else {  /* check for physical non-dasd devices */
-                       if ((dev->nondasd_support == 1) || expose_physicals) {
+                       if (dev->nondasd_support || expose_physicals ||
+                                       dev->jbod) {
                                if (dev->in_reset)
                                        return -1;
                                return aac_send_srb_fib(scsicmd);
@@ -1913,7 +1941,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
         * else Command for the controller itself
         */
        else if ((scsicmd->cmnd[0] != INQUIRY) &&       /* only INQUIRY & TUR cmnd supported for controller */
-               (scsicmd->cmnd[0] != TEST_UNIT_READY)) 
+               (scsicmd->cmnd[0] != TEST_UNIT_READY))
        {
                dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
@@ -1922,9 +1950,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                            SENCODE_INVALID_COMMAND,
                            ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
-                   ? sizeof(scsicmd->sense_buffer)
-                   : sizeof(dev->fsa_dev[cid].sense_data));
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
                scsicmd->scsi_done(scsicmd);
                return 0;
        }
@@ -1939,7 +1966,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
                memset(&inq_data, 0, sizeof (struct inquiry_data));
 
-               if (scsicmd->cmnd[1] & 0x1 ) {
+               if (scsicmd->cmnd[1] & 0x1) {
                        char *arr = (char *)&inq_data;
 
                        /* EVPD bit set */
@@ -1974,10 +2001,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                  ASENCODE_NO_SENSE, 0, 7, 2, 0);
                                memcpy(scsicmd->sense_buffer,
                                  &dev->fsa_dev[cid].sense_data,
-                                 (sizeof(dev->fsa_dev[cid].sense_data) >
-                                   sizeof(scsicmd->sense_buffer))
-                                      ? sizeof(scsicmd->sense_buffer)
-                                      : sizeof(dev->fsa_dev[cid].sense_data));
+                                 min_t(size_t,
+                                       sizeof(dev->fsa_dev[cid].sense_data),
+                                       SCSI_SENSE_BUFFERSIZE));
                        }
                        scsicmd->scsi_done(scsicmd);
                        return 0;
@@ -2092,7 +2118,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                mode_buf[2] = 0;        /* Device-specific param,
                                           bit 8: 0/1 = write enabled/protected
                                           bit 4: 0/1 = FUA enabled */
-               if (dev->raw_io_interface)
+               if (dev->raw_io_interface && ((aac_cache & 5) != 1))
                        mode_buf[2] = 0x10;
                mode_buf[3] = 0;        /* Block descriptor length */
                if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
@@ -2100,7 +2126,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        mode_buf[0] = 6;
                        mode_buf[4] = 8;
                        mode_buf[5] = 1;
-                       mode_buf[6] = 0x04; /* WCE */
+                       mode_buf[6] = ((aac_cache & 6) == 2)
+                               ? 0 : 0x04; /* WCE */
                        mode_buf_length = 7;
                        if (mode_buf_length > scsicmd->cmnd[4])
                                mode_buf_length = scsicmd->cmnd[4];
@@ -2123,7 +2150,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                mode_buf[3] = 0;        /* Device-specific param,
                                           bit 8: 0/1 = write enabled/protected
                                           bit 4: 0/1 = FUA enabled */
-               if (dev->raw_io_interface)
+               if (dev->raw_io_interface && ((aac_cache & 5) != 1))
                        mode_buf[3] = 0x10;
                mode_buf[4] = 0;        /* reserved */
                mode_buf[5] = 0;        /* reserved */
@@ -2134,7 +2161,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        mode_buf[1] = 9;
                        mode_buf[8] = 8;
                        mode_buf[9] = 1;
-                       mode_buf[10] = 0x04; /* WCE */
+                       mode_buf[10] = ((aac_cache & 6) == 2)
+                               ? 0 : 0x04; /* WCE */
                        mode_buf_length = 11;
                        if (mode_buf_length > scsicmd->cmnd[8])
                                mode_buf_length = scsicmd->cmnd[8];
@@ -2179,7 +2207,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                return 0;
        }
 
-       switch (scsicmd->cmnd[0]) 
+       switch (scsicmd->cmnd[0])
        {
                case READ_6:
                case READ_10:
@@ -2192,11 +2220,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                         *      corresponds to a container. Needed to convert
                         *      containers to /dev/sd device names
                         */
-                        
+
                        if (scsicmd->request->rq_disk)
                                strlcpy(fsa_dev_ptr[cid].devname,
                                scsicmd->request->rq_disk->disk_name,
-                               min(sizeof(fsa_dev_ptr[cid].devname),
+                               min(sizeof(fsa_dev_ptr[cid].devname),
                                sizeof(scsicmd->request->rq_disk->disk_name) + 1));
 
                        return aac_read(scsicmd);
@@ -2210,9 +2238,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        return aac_write(scsicmd);
 
                case SYNCHRONIZE_CACHE:
+                       if (((aac_cache & 6) == 6) && dev->cache_protected) {
+                               scsicmd->result = DID_OK << 16 |
+                                       COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+                               scsicmd->scsi_done(scsicmd);
+                               return 0;
+                       }
                        /* Issue FIB to tell Firmware to flush it's cache */
-                       return aac_synchronize(scsicmd);
-                       
+                       if ((aac_cache & 6) != 2)
+                               return aac_synchronize(scsicmd);
+                       /* FALLTHRU */
                default:
                        /*
                         *      Unhandled commands
@@ -2223,9 +2258,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
                                ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
                        memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-                         (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
-                           ? sizeof(scsicmd->sense_buffer)
-                           : sizeof(dev->fsa_dev[cid].sense_data));
+                               min_t(size_t,
+                                     sizeof(dev->fsa_dev[cid].sense_data),
+                                     SCSI_SENSE_BUFFERSIZE));
                        scsicmd->scsi_done(scsicmd);
                        return 0;
        }
@@ -2243,7 +2278,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
                return -EFAULT;
        if (qd.cnum == -1)
                qd.cnum = qd.id;
-       else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
+       else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
        {
                if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
                        return -EINVAL;
@@ -2370,7 +2405,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 
        scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
        /*
-        *      Calculate resid for sg 
+        *      Calculate resid for sg
         */
 
        scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
@@ -2385,10 +2420,8 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        if (le32_to_cpu(srbreply->status) != ST_OK){
                int len;
                printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
-               len = (le32_to_cpu(srbreply->sense_data_size) > 
-                               sizeof(scsicmd->sense_buffer)) ?
-                               sizeof(scsicmd->sense_buffer) : 
-                               le32_to_cpu(srbreply->sense_data_size);
+               len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+                           SCSI_SENSE_BUFFERSIZE);
                scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
                memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
        }
@@ -2412,7 +2445,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                case  WRITE_12:
                case  READ_16:
                case  WRITE_16:
-                       if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
+                       if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
                                printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
                        } else {
                                printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
@@ -2481,26 +2514,23 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
                        le32_to_cpu(srbreply->srb_status) & 0x3F,
                        aac_get_status_string(
-                               le32_to_cpu(srbreply->srb_status) & 0x3F), 
-                       scsicmd->cmnd[0], 
+                               le32_to_cpu(srbreply->srb_status) & 0x3F),
+                       scsicmd->cmnd[0],
                        le32_to_cpu(srbreply->scsi_status));
 #endif
                scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
                break;
        }
-       if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
+       if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
                int len;
                scsicmd->result |= SAM_STAT_CHECK_CONDITION;
-               len = (le32_to_cpu(srbreply->sense_data_size) > 
-                               sizeof(scsicmd->sense_buffer)) ?
-                               sizeof(scsicmd->sense_buffer) :
-                               le32_to_cpu(srbreply->sense_data_size);
+               len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+                           SCSI_SENSE_BUFFERSIZE);
 #ifdef AAC_DETAILED_STATUS_INFO
                printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
                                        le32_to_cpu(srbreply->status), len);
 #endif
                memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
-               
        }
        /*
         * OR in the scsi status (already shifted up a bit)
@@ -2517,7 +2547,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
  * aac_send_scb_fib
  * @scsicmd: the scsi command block
  *
- * This routine will form a FIB and fill in the aac_srb from the 
+ * This routine will form a FIB and fill in the aac_srb from the
  * scsicmd passed in.
  */
 
@@ -2731,7 +2761,7 @@ static struct aac_srb_status_info srb_status_info[] = {
        { SRB_STATUS_ERROR_RECOVERY,    "Error Recovery"},
        { SRB_STATUS_NOT_STARTED,       "Not Started"},
        { SRB_STATUS_NOT_IN_USE,        "Not In Use"},
-       { SRB_STATUS_FORCE_ABORT,       "Force Abort"},
+       { SRB_STATUS_FORCE_ABORT,       "Force Abort"},
        { SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
        { 0xff,                         "Unknown Error"}
 };
index 9abba8b90f70db5afc23c3dc1d200ba4c3fbc67c..3195d29f21779b0436ef16250e4b5ee0a6fc48ea 100644 (file)
@@ -1,4 +1,4 @@
-#if (!defined(dprintk))
+#ifndef dprintk
 # define dprintk(x)
 #endif
 /* eg: if (nblank(dprintk(x))) */
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2449
+# define AAC_DRIVER_BUILD 2455
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
@@ -50,9 +50,9 @@ struct diskparm
 /*
  *     Firmware constants
  */
+
 #define                CT_NONE                 0
-#define        CT_OK                   218
+#define                CT_OK                   218
 #define                FT_FILESYS      8       /* ADAPTEC's "FSA"(tm) filesystem */
 #define                FT_DRIVE        9       /* physical disk - addressable in scsi by bus/id/lun */
 
@@ -107,12 +107,12 @@ struct user_sgentryraw {
 
 struct sgmap {
        __le32          count;
-       struct sgentry  sg[1]; 
+       struct sgentry  sg[1];
 };
 
 struct user_sgmap {
        u32             count;
-       struct user_sgentry     sg[1]; 
+       struct user_sgentry     sg[1];
 };
 
 struct sgmap64 {
@@ -137,18 +137,18 @@ struct user_sgmapraw {
 
 struct creation_info
 {
-       u8              buildnum;               /* e.g., 588 */
-       u8              usec;                   /* e.g., 588 */
-       u8              via;                    /* e.g., 1 = FSU,
-                                                *       2 = API
+       u8              buildnum;               /* e.g., 588 */
+       u8              usec;                   /* e.g., 588 */
+       u8              via;                    /* e.g., 1 = FSU,
+                                                *       2 = API
                                                 */
-       u8              year;                   /* e.g., 1997 = 97 */
+       u8              year;                   /* e.g., 1997 = 97 */
        __le32          date;                   /*
-                                                * unsigned     Month           :4;     // 1 - 12
-                                                * unsigned     Day             :6;     // 1 - 32
-                                                * unsigned     Hour            :6;     // 0 - 23
-                                                * unsigned     Minute          :6;     // 0 - 60
-                                                * unsigned     Second          :6;     // 0 - 60
+                                                * unsigned     Month           :4;     // 1 - 12
+                                                * unsigned     Day             :6;     // 1 - 32
+                                                * unsigned     Hour            :6;     // 0 - 23
+                                                * unsigned     Minute          :6;     // 0 - 60
+                                                * unsigned     Second          :6;     // 0 - 60
                                                 */
        __le32          serial[2];                      /* e.g., 0x1DEADB0BFAFAF001 */
 };
@@ -184,7 +184,7 @@ struct creation_info
 /*
  *     Set the queues on a 16 byte alignment
  */
+
 #define QUEUE_ALIGNMENT                16
 
 /*
@@ -203,9 +203,9 @@ struct aac_entry {
  *     The adapter assumes the ProducerIndex and ConsumerIndex are grouped
  *     adjacently and in that order.
  */
+
 struct aac_qhdr {
-       __le64 header_addr;/* Address to hand the adapter to access 
+       __le64 header_addr;/* Address to hand the adapter to access
                              to this queue head */
        __le32 *producer; /* The producer index for this queue (host address) */
        __le32 *consumer; /* The consumer index for this queue (host address) */
@@ -215,7 +215,7 @@ struct aac_qhdr {
  *     Define all the events which the adapter would like to notify
  *     the host of.
  */
+
 #define                HostNormCmdQue          1       /* Change in host normal priority command queue */
 #define                HostHighCmdQue          2       /* Change in host high priority command queue */
 #define                HostNormRespQue         3       /* Change in host normal priority response queue */
@@ -286,17 +286,17 @@ struct aac_fibhdr {
        u8 StructType;          /* Type FIB */
        u8 Flags;               /* Flags for FIB */
        __le16 Size;            /* Size of this FIB in bytes */
-       __le16 SenderSize;      /* Size of the FIB in the sender 
+       __le16 SenderSize;      /* Size of the FIB in the sender
                                   (for response sizing) */
        __le32 SenderFibAddress;  /* Host defined data in the FIB */
-       __le32 ReceiverFibAddress;/* Logical address of this FIB for 
+       __le32 ReceiverFibAddress;/* Logical address of this FIB for
                                     the adapter */
        u32 SenderData;         /* Place holder for the sender to store data */
        union {
                struct {
-                   __le32 _ReceiverTimeStart;  /* Timestamp for 
+                   __le32 _ReceiverTimeStart;  /* Timestamp for
                                                   receipt of fib */
-                   __le32 _ReceiverTimeDone;   /* Timestamp for 
+                   __le32 _ReceiverTimeDone;   /* Timestamp for
                                                   completion of fib */
                } _s;
        } _u;
@@ -311,7 +311,7 @@ struct hw_fib {
  *     FIB commands
  */
 
-#define        TestCommandResponse             1
+#define                TestCommandResponse             1
 #define                TestAdapterCommand              2
 /*
  *     Lowlevel and comm commands
@@ -349,10 +349,6 @@ struct hw_fib {
 #define                ContainerCommand                500
 #define                ContainerCommand64              501
 #define                ContainerRawIo                  502
-/*
- *     Cluster Commands
- */
-#define                ClusterCommand                  550
 /*
  *     Scsi Port commands (scsi passthrough)
  */
@@ -375,19 +371,19 @@ struct hw_fib {
  */
 
 enum fib_xfer_state {
-       HostOwned                       = (1<<0),
-       AdapterOwned                    = (1<<1),
-       FibInitialized                  = (1<<2),
-       FibEmpty                        = (1<<3),
-       AllocatedFromPool               = (1<<4),
-       SentFromHost                    = (1<<5),
-       SentFromAdapter                 = (1<<6),
-       ResponseExpected                = (1<<7),
-       NoResponseExpected              = (1<<8),
-       AdapterProcessed                = (1<<9),
-       HostProcessed                   = (1<<10),
-       HighPriority                    = (1<<11),
-       NormalPriority                  = (1<<12),
+       HostOwned                       = (1<<0),
+       AdapterOwned                    = (1<<1),
+       FibInitialized                  = (1<<2),
+       FibEmpty                        = (1<<3),
+       AllocatedFromPool               = (1<<4),
+       SentFromHost                    = (1<<5),
+       SentFromAdapter                 = (1<<6),
+       ResponseExpected                = (1<<7),
+       NoResponseExpected              = (1<<8),
+       AdapterProcessed                = (1<<9),
+       HostProcessed                   = (1<<10),
+       HighPriority                    = (1<<11),
+       NormalPriority                  = (1<<12),
        Async                           = (1<<13),
        AsyncIo                         = (1<<13),      // rpbfix: remove with new regime
        PageFileIo                      = (1<<14),      // rpbfix: remove with new regime
@@ -420,7 +416,7 @@ struct aac_init
        __le32  AdapterFibAlign;
        __le32  printfbuf;
        __le32  printfbufsiz;
-       __le32  HostPhysMemPages;   /* number of 4k pages of host 
+       __le32  HostPhysMemPages;   /* number of 4k pages of host
                                       physical memory */
        __le32  HostElapsedSeconds; /* number of seconds since 1970. */
        /*
@@ -481,7 +477,7 @@ struct adapter_ops
 
 struct aac_driver_ident
 {
-       int     (*init)(struct aac_dev *dev);
+       int     (*init)(struct aac_dev *dev);
        char *  name;
        char *  vname;
        char *  model;
@@ -489,7 +485,7 @@ struct aac_driver_ident
        int     quirks;
 };
 /*
- * Some adapter firmware needs communication memory 
+ * Some adapter firmware needs communication memory
  * below 2gig. This tells the init function to set the
  * dma mask such that fib memory will be allocated where the
  * adapter firmware can get to it.
@@ -520,34 +516,40 @@ struct aac_driver_ident
  */
 #define AAC_QUIRK_17SG 0x0010
 
+/*
+ *     Some adapter firmware does not support 64 bit scsi passthrough
+ * commands.
+ */
+#define AAC_QUIRK_SCSI_32      0x0020
+
 /*
  *     The adapter interface specs all queues to be located in the same
  *     physically contigous block. The host structure that defines the
  *     commuication queues will assume they are each a separate physically
  *     contigous memory region that will support them all being one big
- *     contigous block. 
+ *     contigous block.
  *     There is a command and response queue for each level and direction of
  *     commuication. These regions are accessed by both the host and adapter.
  */
+
 struct aac_queue {
-       u64                     logical;        /*address we give the adapter */
+       u64                     logical;        /*address we give the adapter */
        struct aac_entry        *base;          /*system virtual address */
-       struct aac_qhdr         headers;        /*producer,consumer q headers*/
-       u32                     entries;        /*Number of queue entries */
+       struct aac_qhdr         headers;        /*producer,consumer q headers*/
+       u32                     entries;        /*Number of queue entries */
        wait_queue_head_t       qfull;          /*Event to wait on if q full */
        wait_queue_head_t       cmdready;       /*Cmd ready from the adapter */
-                  /* This is only valid for adapter to host command queues. */ 
-       spinlock_t              *lock;          /* Spinlock for this queue must take this lock before accessing the lock */
+               /* This is only valid for adapter to host command queues. */
+       spinlock_t              *lock;          /* Spinlock for this queue must take this lock before accessing the lock */
        spinlock_t              lockdata;       /* Actual lock (used only on one side of the lock) */
-       struct list_head        cmdq;           /* A queue of FIBs which need to be prcessed by the FS thread. This is */
-                                               /* only valid for command queues which receive entries from the adapter. */
+       struct list_head        cmdq;           /* A queue of FIBs which need to be prcessed by the FS thread. This is */
+                                               /* only valid for command queues which receive entries from the adapter. */
        u32                     numpending;     /* Number of entries on outstanding queue. */
        struct aac_dev *        dev;            /* Back pointer to adapter structure */
 };
 
 /*
- *     Message queues. The order here is important, see also the 
+ *     Message queues. The order here is important, see also the
  *     queue type ordering
  */
 
@@ -559,12 +561,12 @@ struct aac_queue_block
 /*
  *     SaP1 Message Unit Registers
  */
+
 struct sa_drawbridge_CSR {
-                               /*      Offset  |  Name */
+                               /*      Offset  |  Name */
        __le32  reserved[10];   /*      00h-27h |  Reserved */
        u8      LUT_Offset;     /*      28h     |  Lookup Table Offset */
-       u8      reserved1[3];   /*      29h-2bh |  Reserved */
+       u8      reserved1[3];   /*      29h-2bh |  Reserved */
        __le32  LUT_Data;       /*      2ch     |  Looup Table Data */
        __le32  reserved2[26];  /*      30h-97h |  Reserved */
        __le16  PRICLEARIRQ;    /*      98h     |  Primary Clear Irq */
@@ -583,8 +585,8 @@ struct sa_drawbridge_CSR {
        __le32  MAILBOX5;       /*      bch     |  Scratchpad 5 */
        __le32  MAILBOX6;       /*      c0h     |  Scratchpad 6 */
        __le32  MAILBOX7;       /*      c4h     |  Scratchpad 7 */
-       __le32  ROM_Setup_Data; /*      c8h     |  Rom Setup and Data */
-       __le32  ROM_Control_Addr;/*     cch     |  Rom Control and Address */
+       __le32  ROM_Setup_Data; /*      c8h     |  Rom Setup and Data */
+       __le32  ROM_Control_Addr;/*     cch     |  Rom Control and Address */
        __le32  reserved3[12];  /*      d0h-ffh |  reserved */
        __le32  LUT[64];        /*    100h-1ffh |  Lookup Table Entries */
 };
@@ -597,7 +599,7 @@ struct sa_drawbridge_CSR {
 #define Mailbox5       SaDbCSR.MAILBOX5
 #define Mailbox6       SaDbCSR.MAILBOX6
 #define Mailbox7       SaDbCSR.MAILBOX7
-       
+
 #define DoorbellReg_p SaDbCSR.PRISETIRQ
 #define DoorbellReg_s SaDbCSR.SECSETIRQ
 #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
@@ -611,19 +613,19 @@ struct sa_drawbridge_CSR {
 #define DOORBELL_5     0x0020
 #define DOORBELL_6     0x0040
 
-       
+
 #define PrintfReady    DOORBELL_5
 #define PrintfDone     DOORBELL_5
-       
+
 struct sa_registers {
        struct sa_drawbridge_CSR        SaDbCSR;                        /* 98h - c4h */
 };
-       
+
 
 #define Sa_MINIPORT_REVISION                   1
 
 #define sa_readw(AEP, CSR)             readl(&((AEP)->regs.sa->CSR))
-#define sa_readl(AEP,  CSR)            readl(&((AEP)->regs.sa->CSR))
+#define sa_readl(AEP, CSR)             readl(&((AEP)->regs.sa->CSR))
 #define sa_writew(AEP, CSR, value)     writew(value, &((AEP)->regs.sa->CSR))
 #define sa_writel(AEP, CSR, value)     writel(value, &((AEP)->regs.sa->CSR))
 
@@ -640,21 +642,21 @@ struct rx_mu_registers {
        __le32  IMRx[2];    /*  1310h  | 10h | Inbound Message Registers */
        __le32  OMRx[2];    /*  1318h  | 18h | Outbound Message Registers */
        __le32  IDR;        /*  1320h  | 20h | Inbound Doorbell Register */
-       __le32  IISR;       /*  1324h  | 24h | Inbound Interrupt 
+       __le32  IISR;       /*  1324h  | 24h | Inbound Interrupt
                                                Status Register */
-       __le32  IIMR;       /*  1328h  | 28h | Inbound Interrupt 
-                                               Mask Register */
+       __le32  IIMR;       /*  1328h  | 28h | Inbound Interrupt
+                                               Mask Register */
        __le32  ODR;        /*  132Ch  | 2Ch | Outbound Doorbell Register */
-       __le32  OISR;       /*  1330h  | 30h | Outbound Interrupt 
+       __le32  OISR;       /*  1330h  | 30h | Outbound Interrupt
                                                Status Register */
-       __le32  OIMR;       /*  1334h  | 34h | Outbound Interrupt 
+       __le32  OIMR;       /*  1334h  | 34h | Outbound Interrupt
                                                Mask Register */
        __le32  reserved2;  /*  1338h  | 38h | Reserved */
        __le32  reserved3;  /*  133Ch  | 3Ch | Reserved */
        __le32  InboundQueue;/* 1340h  | 40h | Inbound Queue Port relative to firmware */
        __le32  OutboundQueue;/*1344h  | 44h | Outbound Queue Port relative to firmware */
-                           /* * Must access through ATU Inbound 
-                                Translation Window */
+                           /* * Must access through ATU Inbound
+                                Translation Window */
 };
 
 struct rx_inbound {
@@ -710,12 +712,12 @@ struct rkt_registers {
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 
 struct aac_fib_context {
-       s16                     type;           // used for verification of structure   
-       s16                     size;
+       s16                     type;           // used for verification of structure
+       s16                     size;
        u32                     unique;         // unique value representing this context
        ulong                   jiffies;        // used for cleanup - dmb changed to ulong
        struct list_head        next;           // used to link context's into a linked list
-       struct semaphore        wait_sem;       // this is used to wait for the next fib to arrive.
+       struct semaphore        wait_sem;       // this is used to wait for the next fib to arrive.
        int                     wait;           // Set to true when thread is in WaitForSingleObject
        unsigned long           count;          // total number of FIBs on FibList
        struct list_head        fib_list;       // this holds fibs and their attachd hw_fibs
@@ -734,9 +736,9 @@ struct sense_data {
        u8 EOM:1;               /* End Of Medium - reserved for random access devices */
        u8 filemark:1;          /* Filemark - reserved for random access devices */
 
-       u8 information[4];      /* for direct-access devices, contains the unsigned 
-                                * logical block address or residue associated with 
-                                * the sense key 
+       u8 information[4];      /* for direct-access devices, contains the unsigned
+                                * logical block address or residue associated with
+                                * the sense key
                                 */
        u8 add_sense_len;       /* number of additional sense bytes to follow this field */
        u8 cmnd_info[4];        /* not used */
@@ -746,7 +748,7 @@ struct sense_data {
        u8 bit_ptr:3;           /* indicates which byte of the CDB or parameter data
                                 * was in error
                                 */
-       u8 BPV:1;               /* bit pointer valid (BPV): 1- indicates that 
+       u8 BPV:1;               /* bit pointer valid (BPV): 1- indicates that
                                 * the bit_ptr field has valid value
                                 */
        u8 reserved2:2;
@@ -780,24 +782,24 @@ struct fib {
        /*
         *      The Adapter that this I/O is destined for.
         */
-       struct aac_dev          *dev;
+       struct aac_dev          *dev;
        /*
         *      This is the event the sendfib routine will wait on if the
         *      caller did not pass one and this is synch io.
         */
-       struct semaphore        event_wait;
+       struct semaphore        event_wait;
        spinlock_t              event_lock;
 
        u32                     done;   /* gets set to 1 when fib is complete */
-       fib_callback            callback;
-       void                    *callback_data;
+       fib_callback            callback;
+       void                    *callback_data;
        u32                     flags; // u32 dmb was ulong
        /*
         *      And for the internal issue/reply queues (we may be able
         *      to merge these two)
         */
        struct list_head        fiblink;
-       void                    *data;
+       void                    *data;
        struct hw_fib           *hw_fib_va;             /* Actual shared object */
        dma_addr_t              hw_fib_pa;              /* physical address of hw_fib*/
 };
@@ -807,7 +809,7 @@ struct fib {
  *
  *     This is returned by the RequestAdapterInfo block
  */
+
 struct aac_adapter_info
 {
        __le32  platform;
@@ -826,7 +828,7 @@ struct aac_adapter_info
        __le32  biosrev;
        __le32  biosbuild;
        __le32  cluster;
-       __le32  clusterchannelmask; 
+       __le32  clusterchannelmask;
        __le32  serial[2];
        __le32  battery;
        __le32  options;
@@ -863,9 +865,10 @@ struct aac_supplement_adapter_info
        __le32  SupportedOptions2;
        __le32  ReservedGrowth[1];
 };
-#define AAC_FEATURE_FALCON     0x00000010
-#define AAC_OPTION_MU_RESET    0x00000001
-#define AAC_OPTION_IGNORE_RESET        0x00000002
+#define AAC_FEATURE_FALCON     cpu_to_le32(0x00000010)
+#define AAC_FEATURE_JBOD       cpu_to_le32(0x08000000)
+#define AAC_OPTION_MU_RESET    cpu_to_le32(0x00000001)
+#define AAC_OPTION_IGNORE_RESET        cpu_to_le32(0x00000002)
 #define AAC_SIS_VERSION_V3     3
 #define AAC_SIS_SLOT_UNKNOWN   0xFF
 
@@ -916,13 +919,13 @@ struct aac_bus_info_response {
 #define AAC_OPT_HOST_TIME_FIB          cpu_to_le32(1<<4)
 #define AAC_OPT_RAID50                 cpu_to_le32(1<<5)
 #define AAC_OPT_4GB_WINDOW             cpu_to_le32(1<<6)
-#define AAC_OPT_SCSI_UPGRADEABLE       cpu_to_le32(1<<7)
+#define AAC_OPT_SCSI_UPGRADEABLE       cpu_to_le32(1<<7)
 #define AAC_OPT_SOFT_ERR_REPORT                cpu_to_le32(1<<8)
-#define AAC_OPT_SUPPORTED_RECONDITION  cpu_to_le32(1<<9)
+#define AAC_OPT_SUPPORTED_RECONDITION  cpu_to_le32(1<<9)
 #define AAC_OPT_SGMAP_HOST64           cpu_to_le32(1<<10)
 #define AAC_OPT_ALARM                  cpu_to_le32(1<<11)
 #define AAC_OPT_NONDASD                        cpu_to_le32(1<<12)
-#define AAC_OPT_SCSI_MANAGED           cpu_to_le32(1<<13)
+#define AAC_OPT_SCSI_MANAGED           cpu_to_le32(1<<13)
 #define AAC_OPT_RAID_SCSI_MODE         cpu_to_le32(1<<14)
 #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO        cpu_to_le32(1<<16)
 #define AAC_OPT_NEW_COMM               cpu_to_le32(1<<17)
@@ -942,7 +945,7 @@ struct aac_dev
 
        /*
         *      Map for 128 fib objects (64k)
-        */     
+        */
        dma_addr_t              hw_fib_pa;
        struct hw_fib           *hw_fib_va;
        struct hw_fib           *aif_base_va;
@@ -953,24 +956,24 @@ struct aac_dev
 
        struct fib              *free_fib;
        spinlock_t              fib_lock;
-       
+
        struct aac_queue_block *queues;
        /*
         *      The user API will use an IOCTL to register itself to receive
         *      FIBs from the adapter.  The following list is used to keep
         *      track of all the threads that have requested these FIBs.  The
-        *      mutex is used to synchronize access to all data associated 
+        *      mutex is used to synchronize access to all data associated
         *      with the adapter fibs.
         */
        struct list_head        fib_list;
 
        struct adapter_ops      a_ops;
        unsigned long           fsrev;          /* Main driver's revision number */
-       
+
        unsigned                base_size;      /* Size of mapped in region */
        struct aac_init         *init;          /* Holds initialization info to communicate with adapter */
-       dma_addr_t              init_pa;        /* Holds physical address of the init struct */
-       
+       dma_addr_t              init_pa;        /* Holds physical address of the init struct */
+
        struct pci_dev          *pdev;          /* Our PCI interface */
        void *                  printfbuf;      /* pointer to buffer used for printf's from the adapter */
        void *                  comm_addr;      /* Base address of Comm area */
@@ -984,11 +987,11 @@ struct aac_dev
        struct fsa_dev_info     *fsa_dev;
        struct task_struct      *thread;
        int                     cardtype;
-       
+
        /*
         *      The following is the device specific extension.
         */
-#if (!defined(AAC_MIN_FOOTPRINT_SIZE))
+#ifndef AAC_MIN_FOOTPRINT_SIZE
 #      define AAC_MIN_FOOTPRINT_SIZE 8192
 #endif
        union
@@ -1009,7 +1012,9 @@ struct aac_dev
        /* These are in adapter info but they are in the io flow so
         * lets break them out so we don't have to do an AND to check them
         */
-       u8                      nondasd_support; 
+       u8                      nondasd_support;
+       u8                      jbod;
+       u8                      cache_protected;
        u8                      dac_support;
        u8                      raid_scsi_mode;
        u8                      comm_interface;
@@ -1066,18 +1071,19 @@ struct aac_dev
        (dev)->a_ops.adapter_comm(dev, comm)
 
 #define FIB_CONTEXT_FLAG_TIMED_OUT             (0x00000001)
+#define FIB_CONTEXT_FLAG                       (0x00000002)
 
 /*
  *     Define the command values
  */
+
 #define                Null                    0
-#define        GetAttributes           1
-#define        SetAttributes           2
-#define        Lookup                  3
-#define        ReadLink                4
-#define        Read                    5
-#define        Write                   6
+#define                GetAttributes           1
+#define                SetAttributes           2
+#define                Lookup                  3
+#define                ReadLink                4
+#define                Read                    5
+#define                Write                   6
 #define                Create                  7
 #define                MakeDirectory           8
 #define                SymbolicLink            9
@@ -1173,19 +1179,19 @@ struct aac_dev
 
 struct aac_read
 {
-       __le32          command;
-       __le32          cid;
-       __le32          block;
-       __le32          count;
+       __le32          command;
+       __le32          cid;
+       __le32          block;
+       __le32          count;
        struct sgmap    sg;     // Must be last in struct because it is variable
 };
 
 struct aac_read64
 {
-       __le32          command;
-       __le16          cid;
-       __le16          sector_count;
-       __le32          block;
+       __le32          command;
+       __le16          cid;
+       __le16          sector_count;
+       __le32          block;
        __le16          pad;
        __le16          flags;
        struct sgmap64  sg;     // Must be last in struct because it is variable
@@ -1193,26 +1199,26 @@ struct aac_read64
 
 struct aac_read_reply
 {
-       __le32          status;
-       __le32          count;
+       __le32          status;
+       __le32          count;
 };
 
 struct aac_write
 {
        __le32          command;
-       __le32          cid;
-       __le32          block;
-       __le32          count;
-       __le32          stable; // Not used
+       __le32          cid;
+       __le32          block;
+       __le32          count;
+       __le32          stable; // Not used
        struct sgmap    sg;     // Must be last in struct because it is variable
 };
 
 struct aac_write64
 {
-       __le32          command;
-       __le16          cid;
-       __le16          sector_count;
-       __le32          block;
+       __le32          command;
+       __le16          cid;
+       __le16          sector_count;
+       __le32          block;
        __le16          pad;
        __le16          flags;
 #define        IO_TYPE_WRITE 0x00000000
@@ -1223,7 +1229,7 @@ struct aac_write64
 struct aac_write_reply
 {
        __le32          status;
-       __le32          count;
+       __le32          count;
        __le32          committed;
 };
 
@@ -1326,10 +1332,10 @@ struct aac_srb_reply
 #define                SRB_NoDataXfer           0x0000
 #define                SRB_DisableDisconnect    0x0004
 #define                SRB_DisableSynchTransfer 0x0008
-#define        SRB_BypassFrozenQueue    0x0010
+#define                SRB_BypassFrozenQueue    0x0010
 #define                SRB_DisableAutosense     0x0020
 #define                SRB_DataIn               0x0040
-#define        SRB_DataOut              0x0080
+#define                SRB_DataOut              0x0080
 
 /*
  * SRB Functions - set in aac_srb->function
@@ -1352,7 +1358,7 @@ struct aac_srb_reply
 #define        SRBF_RemoveDevice       0x0016
 #define        SRBF_DomainValidation   0x0017
 
-/* 
+/*
  * SRB SCSI Status - set in aac_srb->scsi_status
  */
 #define SRB_STATUS_PENDING                  0x00
@@ -1511,17 +1517,17 @@ struct aac_get_container_count_resp {
  */
 
 struct aac_mntent {
-       __le32                  oid;
+       __le32                  oid;
        u8                      name[16];       /* if applicable */
        struct creation_info    create_info;    /* if applicable */
        __le32                  capacity;
-       __le32                  vol;            /* substrate structure */
-       __le32                  obj;            /* FT_FILESYS, etc. */
-       __le32                  state;          /* unready for mounting, 
+       __le32                  vol;            /* substrate structure */
+       __le32                  obj;            /* FT_FILESYS, etc. */
+       __le32                  state;          /* unready for mounting,
                                                   readonly, etc. */
-       union aac_contentinfo   fileinfo;       /* Info specific to content 
+       union aac_contentinfo   fileinfo;       /* Info specific to content
                                                   manager (eg, filesystem) */
-       __le32                  altoid;         /* != oid <==> snapshot or 
+       __le32                  altoid;         /* != oid <==> snapshot or
                                                   broken mirror exists */
        __le32                  capacityhigh;
 };
@@ -1538,7 +1544,7 @@ struct aac_query_mount {
 
 struct aac_mount {
        __le32          status;
-       __le32          type;           /* should be same as that requested */
+       __le32          type;           /* should be same as that requested */
        __le32          count;
        struct aac_mntent mnt[1];
 };
@@ -1608,7 +1614,7 @@ struct aac_delete_disk {
        u32     disknum;
        u32     cnum;
 };
+
 struct fib_ioctl
 {
        u32     fibctx;
@@ -1622,10 +1628,10 @@ struct revision
        __le32 version;
        __le32 build;
 };
-       
+
 
 /*
- *     Ugly - non Linux like ioctl coding for back compat.
+ *     Ugly - non Linux like ioctl coding for back compat.
  */
 
 #define CTL_CODE(function, method) (                 \
@@ -1633,7 +1639,7 @@ struct revision
 )
 
 /*
- *     Define the method codes for how buffers are passed for I/O and FS 
+ *     Define the method codes for how buffers are passed for I/O and FS
  *     controls
  */
 
@@ -1644,15 +1650,15 @@ struct revision
  *     Filesystem ioctls
  */
 
-#define FSACTL_SENDFIB                         CTL_CODE(2050, METHOD_BUFFERED)
-#define FSACTL_SEND_RAW_SRB                    CTL_CODE(2067, METHOD_BUFFERED)
+#define FSACTL_SENDFIB                         CTL_CODE(2050, METHOD_BUFFERED)
+#define FSACTL_SEND_RAW_SRB                    CTL_CODE(2067, METHOD_BUFFERED)
 #define FSACTL_DELETE_DISK                     0x163
 #define FSACTL_QUERY_DISK                      0x173
 #define FSACTL_OPEN_GET_ADAPTER_FIB            CTL_CODE(2100, METHOD_BUFFERED)
 #define FSACTL_GET_NEXT_ADAPTER_FIB            CTL_CODE(2101, METHOD_BUFFERED)
 #define FSACTL_CLOSE_GET_ADAPTER_FIB           CTL_CODE(2102, METHOD_BUFFERED)
 #define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
-#define FSACTL_GET_PCI_INFO                    CTL_CODE(2119, METHOD_BUFFERED)
+#define FSACTL_GET_PCI_INFO                    CTL_CODE(2119, METHOD_BUFFERED)
 #define FSACTL_FORCE_DELETE_DISK               CTL_CODE(2120, METHOD_NEITHER)
 #define FSACTL_GET_CONTAINERS                  2131
 #define FSACTL_SEND_LARGE_FIB                  CTL_CODE(2138, METHOD_BUFFERED)
@@ -1661,7 +1667,7 @@ struct revision
 struct aac_common
 {
        /*
-        *      If this value is set to 1 then interrupt moderation will occur 
+        *      If this value is set to 1 then interrupt moderation will occur
         *      in the base commuication support.
         */
        u32 irq_mod;
@@ -1690,11 +1696,11 @@ extern struct aac_common aac_config;
  *     The following macro is used when sending and receiving FIBs. It is
  *     only used for debugging.
  */
+
 #ifdef DBG
 #define        FIB_COUNTER_INCREMENT(counter)          (counter)++
 #else
-#define        FIB_COUNTER_INCREMENT(counter)          
+#define        FIB_COUNTER_INCREMENT(counter)
 #endif
 
 /*
@@ -1726,17 +1732,17 @@ extern struct aac_common aac_config;
  *
  *     The adapter reports is present state through the phase.  Only
  *     a single phase should be ever be set.  Each phase can have multiple
- *     phase status bits to provide more detailed information about the 
- *     state of the board.  Care should be taken to ensure that any phase 
+ *     phase status bits to provide more detailed information about the
+ *     state of the board.  Care should be taken to ensure that any phase
  *     status bits that are set when changing the phase are also valid
  *     for the new phase or be cleared out.  Adapter software (monitor,
- *     iflash, kernel) is responsible for properly maintining the phase 
+ *     iflash, kernel) is responsible for properly maintining the phase
  *     status mailbox when it is running.
- *                                                                                     
- *     MONKER_API Phases                                                       
  *
- *     Phases are bit oriented.  It is NOT valid  to have multiple bits set                                            
- */                                    
+ *     MONKER_API Phases
+ *
+ *     Phases are bit oriented.  It is NOT valid  to have multiple bits set
+ */
 
 #define        SELF_TEST_FAILED                0x00000004
 #define        MONITOR_PANIC                   0x00000020
@@ -1759,16 +1765,22 @@ extern struct aac_common aac_config;
  *     For FIB communication, we need all of the following things
  *     to send back to the user.
  */
-#define        AifCmdEventNotify       1       /* Notify of event */
+
+#define                AifCmdEventNotify       1       /* Notify of event */
 #define                        AifEnConfigChange       3       /* Adapter configuration change */
 #define                        AifEnContainerChange    4       /* Container configuration change */
 #define                        AifEnDeviceFailure      5       /* SCSI device failed */
+#define                        AifEnEnclosureManagement 13     /* EM_DRIVE_* */
+#define                                EM_DRIVE_INSERTION      31
+#define                                EM_DRIVE_REMOVAL        32
+#define                        AifEnBatteryEvent       14      /* Change in Battery State */
 #define                        AifEnAddContainer       15      /* A new array was created */
 #define                        AifEnDeleteContainer    16      /* A container was deleted */
 #define                        AifEnExpEvent           23      /* Firmware Event Log */
 #define                        AifExeFirmwarePanic     3       /* Firmware Event Panic */
 #define                        AifHighPriority         3       /* Highest Priority Event */
+#define                        AifEnAddJBOD            30      /* JBOD created */
+#define                        AifEnDeleteJBOD         31      /* JBOD deleted */
 
 #define                AifCmdJobProgress       2       /* Progress report */
 #define                        AifJobCtrZero   101     /* Array Zero progress */
@@ -1780,11 +1792,11 @@ extern struct aac_common aac_config;
 #define                        AifDenVolumeExtendComplete 201 /* A volume extend completed */
 #define                AifReqJobList           100     /* Gets back complete job list */
 #define                AifReqJobsForCtr        101     /* Gets back jobs for specific container */
-#define                AifReqJobsForScsi       102     /* Gets back jobs for specific SCSI device */ 
-#define                AifReqJobReport         103     /* Gets back a specific job report or list of them */ 
+#define                AifReqJobsForScsi       102     /* Gets back jobs for specific SCSI device */
+#define                AifReqJobReport         103     /* Gets back a specific job report or list of them */
 #define                AifReqTerminateJob      104     /* Terminates job */
 #define                AifReqSuspendJob        105     /* Suspends a job */
-#define                AifReqResumeJob         106     /* Resumes a job */ 
+#define                AifReqResumeJob         106     /* Resumes a job */
 #define                AifReqSendAPIReport     107     /* API generic report requests */
 #define                AifReqAPIJobStart       108     /* Start a job from the API */
 #define                AifReqAPIJobUpdate      109     /* Update a job report from the API */
@@ -1803,8 +1815,8 @@ struct aac_aifcmd {
 };
 
 /**
- *     Convert capacity to cylinders
- *     accounting for the fact capacity could be a 64 bit value
+ *     Convert capacity to cylinders
+ *     accounting for the fact capacity could be a 64 bit value
  *
  */
 static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
@@ -1861,6 +1873,7 @@ int aac_probe_container(struct aac_dev *dev, int cid);
 int _aac_rx_init(struct aac_dev *dev);
 int aac_rx_select_comm(struct aac_dev *dev, int comm);
 int aac_rx_deliver_producer(struct fib * fib);
+char * get_container_type(unsigned type);
 extern int numacb;
 extern int acbsize;
 extern char aac_driver_version[];
index 1e6d7a9c75bfa28e2f62a5d45d4accd53f572925..851a7e599c500bc5f4e24b2a3aba4a23a4e153f9 100644 (file)
  *     ioctl_send_fib  -       send a FIB from userspace
  *     @dev:   adapter is being processed
  *     @arg:   arguments to the ioctl call
- *     
+ *
  *     This routine sends a fib to the adapter on behalf of a user level
  *     program.
  */
 # define AAC_DEBUG_PREAMBLE    KERN_INFO
 # define AAC_DEBUG_POSTAMBLE
+
 static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
 {
        struct hw_fib * kfib;
@@ -71,7 +71,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
        if(fibptr == NULL) {
                return -ENOMEM;
        }
-               
+
        kfib = fibptr->hw_fib_va;
        /*
         *      First copy in the header so that we can check the size field.
@@ -109,7 +109,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
        if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
                aac_adapter_interrupt(dev);
                /*
-                * Since we didn't really send a fib, zero out the state to allow 
+                * Since we didn't really send a fib, zero out the state to allow
                 * cleanup code not to assert.
                 */
                kfib->header.XferState = 0;
@@ -169,7 +169,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
 
                fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
                fibctx->size = sizeof(struct aac_fib_context);
-               /*
+               /*
                 *      Yes yes, I know this could be an index, but we have a
                 * better guarantee of uniqueness for the locked loop below.
                 * Without the aid of a persistent history, this also helps
@@ -189,7 +189,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
                INIT_LIST_HEAD(&fibctx->fib_list);
                fibctx->jiffies = jiffies/HZ;
                /*
-                *      Now add this context onto the adapter's 
+                *      Now add this context onto the adapter's
                 *      AdapterFibContext list.
                 */
                spin_lock_irqsave(&dev->fib_lock, flags);
@@ -207,12 +207,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
                }
                list_add_tail(&fibctx->next, &dev->fib_list);
                spin_unlock_irqrestore(&dev->fib_lock, flags);
-               if (copy_to_user(arg,  &fibctx->unique, 
+               if (copy_to_user(arg, &fibctx->unique,
                                                sizeof(fibctx->unique))) {
                        status = -EFAULT;
                } else {
                        status = 0;
-               }       
+               }
        }
        return status;
 }
@@ -221,8 +221,8 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
  *     next_getadapter_fib     -       get the next fib
  *     @dev: adapter to use
  *     @arg: ioctl argument
- *     
- *     This routine will get the next Fib, if available, from the AdapterFibContext
+ *
+ *     This routine will get the next Fib, if available, from the AdapterFibContext
  *     passed in from the user.
  */
 
@@ -234,7 +234,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
        int status;
        struct list_head * entry;
        unsigned long flags;
-       
+
        if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
                return -EFAULT;
        /*
@@ -243,6 +243,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
         *      Search the list of AdapterFibContext addresses on the adapter
         *      to be sure this is a valid address
         */
+       spin_lock_irqsave(&dev->fib_lock, flags);
        entry = dev->fib_list.next;
        fibctx = NULL;
 
@@ -251,37 +252,37 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
                /*
                 *      Extract the AdapterFibContext from the Input parameters.
                 */
-               if (fibctx->unique == f.fibctx) {   /* We found a winner */
+               if (fibctx->unique == f.fibctx) { /* We found a winner */
                        break;
                }
                entry = entry->next;
                fibctx = NULL;
        }
        if (!fibctx) {
+               spin_unlock_irqrestore(&dev->fib_lock, flags);
                dprintk ((KERN_INFO "Fib Context not found\n"));
                return -EINVAL;
        }
 
        if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
                 (fibctx->size != sizeof(struct aac_fib_context))) {
+               spin_unlock_irqrestore(&dev->fib_lock, flags);
                dprintk ((KERN_INFO "Fib Context corrupt?\n"));
                return -EINVAL;
        }
        status = 0;
-       spin_lock_irqsave(&dev->fib_lock, flags);
        /*
         *      If there are no fibs to send back, then either wait or return
         *      -EAGAIN
         */
 return_fib:
        if (!list_empty(&fibctx->fib_list)) {
-               struct list_head * entry;
                /*
                 *      Pull the next fib from the fibs
                 */
                entry = fibctx->fib_list.next;
                list_del(entry);
-               
+
                fib = list_entry(entry, struct fib, fiblink);
                fibctx->count--;
                spin_unlock_irqrestore(&dev->fib_lock, flags);
@@ -289,7 +290,7 @@ return_fib:
                        kfree(fib->hw_fib_va);
                        kfree(fib);
                        return -EFAULT;
-               }       
+               }
                /*
                 *      Free the space occupied by this copy of the fib.
                 */
@@ -318,7 +319,7 @@ return_fib:
                        }
                } else {
                        status = -EAGAIN;
-               }       
+               }
        }
        fibctx->jiffies = jiffies/HZ;
        return status;
@@ -327,7 +328,9 @@ return_fib:
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
 {
        struct fib *fib;
+       unsigned long flags;
 
+       spin_lock_irqsave(&dev->fib_lock, flags);
        /*
         *      First free any FIBs that have not been consumed.
         */
@@ -350,6 +353,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
         *      Remove the Context from the AdapterFibContext List
         */
        list_del(&fibctx->next);
+       spin_unlock_irqrestore(&dev->fib_lock, flags);
        /*
         *      Invalidate context
         */
@@ -368,7 +372,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
  *
  *     This routine will close down the fibctx passed in from the user.
  */
+
 static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
        struct aac_fib_context *fibctx;
@@ -415,8 +419,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
  *     @arg: ioctl arguments
  *
  *     This routine returns the driver version.
- *      Under Linux, there have been no version incompatibilities, so this is 
- *      simple!
+ *     Under Linux, there have been no version incompatibilities, so this is
+ *     simple!
  */
 
 static int check_revision(struct aac_dev *dev, void __user *arg)
@@ -426,12 +430,12 @@ static int check_revision(struct aac_dev *dev, void __user *arg)
        u32 version;
 
        response.compat = 1;
-       version = (simple_strtol(driver_version, 
+       version = (simple_strtol(driver_version,
                                &driver_version, 10) << 24) | 0x00000400;
        version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
        version += simple_strtol(driver_version + 1, NULL, 10);
        response.version = cpu_to_le32(version);
-#      if (defined(AAC_DRIVER_BUILD))
+#      ifdef AAC_DRIVER_BUILD
                response.build = cpu_to_le32(AAC_DRIVER_BUILD);
 #      else
                response.build = cpu_to_le32(9999);
@@ -464,7 +468,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
        u32 data_dir;
        void __user *sg_user[32];
        void *sg_list[32];
-       u32   sg_indx = 0;
+       u32 sg_indx = 0;
        u32 byte_count = 0;
        u32 actual_fibsize64, actual_fibsize = 0;
        int i;
@@ -475,7 +479,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                return -EBUSY;
        }
        if (!capable(CAP_SYS_ADMIN)){
-               dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 
+               dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
                return -EPERM;
        }
        /*
@@ -490,7 +494,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 
        memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
        if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
-               dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 
+               dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n"));
                rcode = -EFAULT;
                goto cleanup;
        }
@@ -507,7 +511,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                goto cleanup;
        }
        if(copy_from_user(user_srbcmd, user_srb,fibsize)){
-               dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 
+               dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n"));
                rcode = -EFAULT;
                goto cleanup;
        }
@@ -518,15 +522,15 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
        // Fix up srb for endian and force some values
 
        srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);       // Force this
-       srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
+       srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
        srbcmd->id       = cpu_to_le32(user_srbcmd->id);
-       srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
-       srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
-       srbcmd->flags    = cpu_to_le32(flags);
+       srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
+       srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
+       srbcmd->flags    = cpu_to_le32(flags);
        srbcmd->retry_limit = 0; // Obsolete parameter
        srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
        memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
-       
+
        switch (flags & (SRB_DataIn | SRB_DataOut)) {
        case SRB_DataOut:
                data_dir = DMA_TO_DEVICE;
@@ -582,7 +586,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                void* p;
                                /* Does this really need to be GFP_DMA? */
                                p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-                               if(p == 0) {
+                               if(!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                          upsg->sg[i].count,i,upsg->count));
                                        rcode = -ENOMEM;
@@ -594,7 +598,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_list[i] = p; // save so we can clean up later
                                sg_indx = i;
 
-                               if( flags & SRB_DataOut ){
+                               if (flags & SRB_DataOut) {
                                        if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
                                                rcode = -EFAULT;
@@ -626,7 +630,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                void* p;
                                /* Does this really need to be GFP_DMA? */
                                p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-                               if(p == 0) {
+                               if(!p) {
                                        kfree (usg);
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                          usg->sg[i].count,i,usg->count));
@@ -637,7 +641,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_list[i] = p; // save so we can clean up later
                                sg_indx = i;
 
-                               if( flags & SRB_DataOut ){
+                               if (flags & SRB_DataOut) {
                                        if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
                                                kfree (usg);
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
@@ -668,7 +672,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                void* p;
                                /* Does this really need to be GFP_DMA? */
                                p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-                               if(p == 0) {
+                               if(!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                          usg->sg[i].count,i,usg->count));
                                        rcode = -ENOMEM;
@@ -680,7 +684,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_list[i] = p; // save so we can clean up later
                                sg_indx = i;
 
-                               if( flags & SRB_DataOut ){
+                               if (flags & SRB_DataOut) {
                                        if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
                                                rcode = -EFAULT;
@@ -698,7 +702,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                dma_addr_t addr;
                                void* p;
                                p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
-                               if(p == 0) {
+                               if (!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                          upsg->sg[i].count, i, upsg->count));
                                        rcode = -ENOMEM;
@@ -708,7 +712,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_list[i] = p; // save so we can clean up later
                                sg_indx = i;
 
-                               if( flags & SRB_DataOut ){
+                               if (flags & SRB_DataOut) {
                                        if(copy_from_user(p, sg_user[i],
                                                        upsg->sg[i].count)) {
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
@@ -734,19 +738,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
        }
 
        if (status != 0){
-               dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 
+               dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
                rcode = -ENXIO;
                goto cleanup;
        }
 
-       if( flags & SRB_DataIn ) {
+       if (flags & SRB_DataIn) {
                for(i = 0 ; i <= sg_indx; i++){
                        byte_count = le32_to_cpu(
                          (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
                              ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
                              : srbcmd->sg.sg[i].count);
                        if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
-                               dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 
+                               dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n"));
                                rcode = -EFAULT;
                                goto cleanup;
 
@@ -756,7 +760,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 
        reply = (struct aac_srb_reply *) fib_data(srbfib);
        if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
-               dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); 
+               dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n"));
                rcode = -EFAULT;
                goto cleanup;
        }
@@ -775,34 +779,34 @@ cleanup:
 }
 
 struct aac_pci_info {
-        u32 bus;
-        u32 slot;
+       u32 bus;
+       u32 slot;
 };
 
 
 static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
 {
-        struct aac_pci_info pci_info;
+       struct aac_pci_info pci_info;
 
        pci_info.bus = dev->pdev->bus->number;
        pci_info.slot = PCI_SLOT(dev->pdev->devfn);
 
-       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
-               dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
-               return -EFAULT;
+       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
+               dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
+               return -EFAULT;
        }
-        return 0;
+       return 0;
 }
+
 
 int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
 {
        int status;
-       
+
        /*
         *      HBA gets first crack
         */
-        
+
        status = aac_dev_ioctl(dev, cmd, arg);
        if(status != -ENOTTY)
                return status;
@@ -832,7 +836,7 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
                break;
        default:
                status = -ENOTTY;
-               break;  
+               break;
        }
        return status;
 }
index 8736813a029657b494d143b93f7b83f484523693..89cc8b7b42a2028f515f5e3fbe150c621d311405 100644 (file)
@@ -301,10 +301,10 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
        if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
                0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
                        (status[0] == 0x00000001)) {
-               if (status[1] & AAC_OPT_NEW_COMM_64)
+               if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
                        dev->raw_io_64 = 1;
                if (dev->a_ops.adapter_comm &&
-                   (status[1] & AAC_OPT_NEW_COMM))
+                   (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)))
                        dev->comm_interface = AAC_COMM_MESSAGE;
                if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
                    (status[2] > dev->base_size)) {
index abce48ccc85b620f92f5779f37c23aa487d37a4a..81b36923e0ef487726715660035e25f176d44432 100644 (file)
@@ -56,7 +56,7 @@
  *     Allocate and map the shared PCI space for the FIB blocks used to
  *     talk to the Adaptec firmware.
  */
+
 static int fib_map_alloc(struct aac_dev *dev)
 {
        dprintk((KERN_INFO
@@ -109,14 +109,16 @@ int aac_fib_setup(struct aac_dev * dev)
        }
        if (i<0)
                return -ENOMEM;
-               
+
        hw_fib = dev->hw_fib_va;
        hw_fib_pa = dev->hw_fib_pa;
        memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
        /*
         *      Initialise the fibs
         */
-       for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) 
+       for (i = 0, fibptr = &dev->fibs[i];
+               i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+               i++, fibptr++)
        {
                fibptr->dev = dev;
                fibptr->hw_fib_va = hw_fib;
@@ -148,13 +150,13 @@ int aac_fib_setup(struct aac_dev * dev)
  *     Allocate a fib from the adapter fib pool. If the pool is empty we
  *     return NULL.
  */
+
 struct fib *aac_fib_alloc(struct aac_dev *dev)
 {
        struct fib * fibptr;
        unsigned long flags;
        spin_lock_irqsave(&dev->fib_lock, flags);
-       fibptr = dev->free_fib; 
+       fibptr = dev->free_fib;
        if(!fibptr){
                spin_unlock_irqrestore(&dev->fib_lock, flags);
                return fibptr;
@@ -171,6 +173,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
         *      each I/O
         */
        fibptr->hw_fib_va->header.XferState = 0;
+       fibptr->flags = 0;
        fibptr->callback = NULL;
        fibptr->callback_data = NULL;
 
@@ -183,7 +186,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
  *
  *     Frees up a fib and places it on the appropriate queue
  */
+
 void aac_fib_free(struct fib *fibptr)
 {
        unsigned long flags;
@@ -204,10 +207,10 @@ void aac_fib_free(struct fib *fibptr)
 /**
  *     aac_fib_init    -       initialise a fib
  *     @fibptr: The fib to initialize
- *     
+ *
  *     Set up the generic fib fields ready for use
  */
+
 void aac_fib_init(struct fib *fibptr)
 {
        struct hw_fib *hw_fib = fibptr->hw_fib_va;
@@ -227,12 +230,12 @@ void aac_fib_init(struct fib *fibptr)
  *     Will deallocate and return to the free pool the FIB pointed to by the
  *     caller.
  */
+
 static void fib_dealloc(struct fib * fibptr)
 {
        struct hw_fib *hw_fib = fibptr->hw_fib_va;
        BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
-       hw_fib->header.XferState = 0;        
+       hw_fib->header.XferState = 0;
 }
 
 /*
@@ -241,7 +244,7 @@ static void fib_dealloc(struct fib * fibptr)
  *     these routines and are the only routines which have a knowledge of the
  *      how these queues are implemented.
  */
+
 /**
  *     aac_get_entry           -       get a queue entry
  *     @dev: Adapter
@@ -254,7 +257,7 @@ static void fib_dealloc(struct fib * fibptr)
  *     is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is
  *     returned.
  */
+
 static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
 {
        struct aac_queue * q;
@@ -279,26 +282,27 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
                                idx = ADAP_NORM_RESP_ENTRIES;
                }
                if (idx != le32_to_cpu(*(q->headers.consumer)))
-                       *nonotify = 1; 
+                       *nonotify = 1;
        }
 
        if (qid == AdapNormCmdQueue) {
-               if (*index >= ADAP_NORM_CMD_ENTRIES) 
+               if (*index >= ADAP_NORM_CMD_ENTRIES)
                        *index = 0; /* Wrap to front of the Producer Queue. */
        } else {
-               if (*index >= ADAP_NORM_RESP_ENTRIES) 
+               if (*index >= ADAP_NORM_RESP_ENTRIES)
                        *index = 0; /* Wrap to front of the Producer Queue. */
        }
 
-        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
+       /* Queue is full */
+       if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) {
                printk(KERN_WARNING "Queue %d full, %u outstanding.\n",
                                qid, q->numpending);
                return 0;
        } else {
-               *entry = q->base + *index;
+               *entry = q->base + *index;
                return 1;
        }
-}   
+}
 
 /**
  *     aac_queue_get           -       get the next free QE
@@ -320,31 +324,29 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
 {
        struct aac_entry * entry = NULL;
        int map = 0;
-           
+
        if (qid == AdapNormCmdQueue) {
                /*  if no entries wait for some if caller wants to */
-               while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
-               {
+               while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
                        printk(KERN_ERR "GetEntries failed\n");
                }
-               /*
-                *      Setup queue entry with a command, status and fib mapped
-                */
-               entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
-               map = 1;
+               /*
+                *      Setup queue entry with a command, status and fib mapped
+                */
+               entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+               map = 1;
        } else {
-               while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
-               {
+               while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
                        /* if no entries wait for some if caller wants to */
                }
-               /*
-                *      Setup queue entry with command, status and fib mapped
-                */
-               entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
-               entry->addr = hw_fib->header.SenderFibAddress;
-                       /* Restore adapters pointer to the FIB */
+               /*
+                *      Setup queue entry with command, status and fib mapped
+                */
+               entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+               entry->addr = hw_fib->header.SenderFibAddress;
+                       /* Restore adapters pointer to the FIB */
                hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;    /* Let the adapter now where to find its data */
-               map = 0;
+               map = 0;
        }
        /*
         *      If MapFib is true than we need to map the Fib and put pointers
@@ -356,8 +358,8 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
 }
 
 /*
- *     Define the highest level of host to adapter communication routines. 
- *     These routines will support host to adapter FS commuication. These 
+ *     Define the highest level of host to adapter communication routines.
+ *     These routines will support host to adapter FS commuication. These
  *     routines have no knowledge of the commuication method used. This level
  *     sends and receives FIBs. This level has no knowledge of how these FIBs
  *     get passed back and forth.
@@ -379,7 +381,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
  *     an event to wait on must be supplied. This event will be set when a
  *     response FIB is received from the adapter.
  */
+
 int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                int priority, int wait, int reply, fib_callback callback,
                void *callback_data)
@@ -392,16 +394,17 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
        if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
                return -EBUSY;
        /*
-        *      There are 5 cases with the wait and reponse requested flags. 
+        *      There are 5 cases with the wait and reponse requested flags.
         *      The only invalid cases are if the caller requests to wait and
         *      does not request a response and if the caller does not want a
         *      response and the Fib is not allocated from pool. If a response
         *      is not requesed the Fib will just be deallocaed by the DPC
         *      routine when the response comes back from the adapter. No
-        *      further processing will be done besides deleting the Fib. We 
+        *      further processing will be done besides deleting the Fib. We
         *      will have a debug mode where the adapter can notify the host
         *      it had a problem and the host can log that fact.
         */
+       fibptr->flags = 0;
        if (wait && !reply) {
                return -EINVAL;
        } else if (!wait && reply) {
@@ -413,7 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
        } else if (wait && reply) {
                hw_fib->header.XferState |= cpu_to_le32(ResponseExpected);
                FIB_COUNTER_INCREMENT(aac_config.NormalSent);
-       } 
+       }
        /*
         *      Map the fib into 32bits by using the fib number
         */
@@ -436,7 +439,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
        hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
        if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {
                return -EMSGSIZE;
-       }                
+       }
        /*
         *      Get a queue entry connect the FIB to it and send an notify
         *      the adapter a command is ready.
@@ -450,10 +453,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
        if (!wait) {
                fibptr->callback = callback;
                fibptr->callback_data = callback_data;
+               fibptr->flags = FIB_CONTEXT_FLAG;
        }
 
        fibptr->done = 0;
-       fibptr->flags = 0;
 
        FIB_COUNTER_INCREMENT(aac_config.FibsSent);
 
@@ -473,9 +476,9 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
        aac_adapter_deliver(fibptr);
 
        /*
-        *      If the caller wanted us to wait for response wait now. 
+        *      If the caller wanted us to wait for response wait now.
         */
-    
+
        if (wait) {
                spin_unlock_irqrestore(&fibptr->event_lock, flags);
                /* Only set for first known interruptable command */
@@ -522,7 +525,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                }
                spin_unlock_irqrestore(&fibptr->event_lock, flags);
                BUG_ON(fibptr->done == 0);
-                       
+
                if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
                        return -ETIMEDOUT;
                return 0;
@@ -537,15 +540,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                return 0;
 }
 
-/** 
+/**
  *     aac_consumer_get        -       get the top of the queue
  *     @dev: Adapter
  *     @q: Queue
  *     @entry: Return entry
  *
  *     Will return a pointer to the entry on the top of the queue requested that
- *     we are a consumer of, and return the address of the queue entry. It does
- *     not change the state of the queue. 
+ *     we are a consumer of, and return the address of the queue entry. It does
+ *     not change the state of the queue.
  */
 
 int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry)
@@ -560,10 +563,10 @@ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entr
                 *      the end of the queue, else we just use the entry
                 *      pointed to by the header index
                 */
-               if (le32_to_cpu(*q->headers.consumer) >= q->entries) 
-                       index = 0;              
+               if (le32_to_cpu(*q->headers.consumer) >= q->entries)
+                       index = 0;
                else
-                       index = le32_to_cpu(*q->headers.consumer);
+                       index = le32_to_cpu(*q->headers.consumer);
                *entry = q->base + index;
                status = 1;
        }
@@ -587,12 +590,12 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
 
        if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))
                wasfull = 1;
-        
+
        if (le32_to_cpu(*q->headers.consumer) >= q->entries)
                *q->headers.consumer = cpu_to_le32(1);
        else
                *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
-        
+
        if (wasfull) {
                switch (qid) {
 
@@ -608,7 +611,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
                }
                aac_adapter_notify(dev, notify);
        }
-}        
+}
 
 /**
  *     aac_fib_adapter_complete        -       complete adapter issued fib
@@ -630,32 +633,32 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
        if (hw_fib->header.XferState == 0) {
                if (dev->comm_interface == AAC_COMM_MESSAGE)
                        kfree (hw_fib);
-               return 0;
+               return 0;
        }
        /*
         *      If we plan to do anything check the structure type first.
-        */ 
-       if ( hw_fib->header.StructType != FIB_MAGIC ) {
+        */
+       if (hw_fib->header.StructType != FIB_MAGIC) {
                if (dev->comm_interface == AAC_COMM_MESSAGE)
                        kfree (hw_fib);
-               return -EINVAL;
+               return -EINVAL;
        }
        /*
         *      This block handles the case where the adapter had sent us a
         *      command and we have finished processing the command. We
-        *      call completeFib when we are done processing the command 
-        *      and want to send a response back to the adapter. This will 
+        *      call completeFib when we are done processing the command
+        *      and want to send a response back to the adapter. This will
         *      send the completed cdb to the adapter.
         */
        if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
                if (dev->comm_interface == AAC_COMM_MESSAGE) {
                        kfree (hw_fib);
                } else {
-                       u32 index;
-                       hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
+                       u32 index;
+                       hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
                        if (size) {
                                size += sizeof(struct aac_fibhdr);
-                               if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
+                               if (size > le16_to_cpu(hw_fib->header.SenderSize))
                                        return -EMSGSIZE;
                                hw_fib->header.Size = cpu_to_le16(size);
                        }
@@ -667,12 +670,11 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
                        if (!(nointr & (int)aac_config.irq_mod))
                                aac_adapter_notify(dev, AdapNormRespQueue);
                }
+       } else {
+               printk(KERN_WARNING "aac_fib_adapter_complete: "
+                       "Unknown xferstate detected.\n");
+               BUG();
        }
-       else 
-       {
-               printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n");
-               BUG();
-       }   
        return 0;
 }
 
@@ -682,7 +684,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
  *
  *     Will do all necessary work to complete a FIB.
  */
+
 int aac_fib_complete(struct fib *fibptr)
 {
        struct hw_fib * hw_fib = fibptr->hw_fib_va;
@@ -692,15 +694,15 @@ int aac_fib_complete(struct fib *fibptr)
         */
 
        if (hw_fib->header.XferState == 0)
-               return 0;
+               return 0;
        /*
         *      If we plan to do anything check the structure type first.
-        */ 
+        */
 
        if (hw_fib->header.StructType != FIB_MAGIC)
-               return -EINVAL;
+               return -EINVAL;
        /*
-        *      This block completes a cdb which orginated on the host and we 
+        *      This block completes a cdb which orginated on the host and we
         *      just need to deallocate the cdb or reinit it. At this point the
         *      command is complete that we had sent to the adapter and this
         *      cdb could be reused.
@@ -721,7 +723,7 @@ int aac_fib_complete(struct fib *fibptr)
                fib_dealloc(fibptr);
        } else {
                BUG();
-       }   
+       }
        return 0;
 }
 
@@ -741,7 +743,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
        {
                int length = val & 0xffff;
                int level = (val >> 16) & 0xffff;
-               
+
                /*
                 *      The size of the printfbuf is set in port.c
                 *      There is no variable or define for it
@@ -755,7 +757,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
                else
                        printk(KERN_INFO "%s:%s", dev->name, cp);
        }
-       memset(cp, 0,  256);
+       memset(cp, 0, 256);
 }
 
 
@@ -773,20 +775,20 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 {
        struct hw_fib * hw_fib = fibptr->hw_fib_va;
        struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
-       u32 container;
+       u32 channel, id, lun, container;
        struct scsi_device *device;
        enum {
                NOTHING,
                DELETE,
                ADD,
                CHANGE
-       } device_config_needed;
+       } device_config_needed = NOTHING;
 
        /* Sniff for container changes */
 
        if (!dev || !dev->fsa_dev)
                return;
-       container = (u32)-1;
+       container = channel = id = lun = (u32)-1;
 
        /*
         *      We have set this up to try and minimize the number of
@@ -796,13 +798,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
         */
        switch (le32_to_cpu(aifcmd->command)) {
        case AifCmdDriverNotify:
-               switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+               switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
                /*
                 *      Morph or Expand complete
                 */
                case AifDenMorphComplete:
                case AifDenVolumeExtendComplete:
-                       container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+                       container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
                        if (container >= dev->maximum_num_containers)
                                break;
 
@@ -814,9 +816,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                         */
 
                        if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {
-                               device = scsi_device_lookup(dev->scsi_host_ptr, 
-                                       CONTAINER_TO_CHANNEL(container), 
-                                       CONTAINER_TO_ID(container), 
+                               device = scsi_device_lookup(dev->scsi_host_ptr,
+                                       CONTAINER_TO_CHANNEL(container),
+                                       CONTAINER_TO_ID(container),
                                        CONTAINER_TO_LUN(container));
                                if (device) {
                                        dev->fsa_dev[container].config_needed = CHANGE;
@@ -835,25 +837,29 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                        if (container >= dev->maximum_num_containers)
                                break;
                        if ((dev->fsa_dev[container].config_waiting_on ==
-                           le32_to_cpu(*(u32 *)aifcmd->data)) &&
+                           le32_to_cpu(*(__le32 *)aifcmd->data)) &&
                         time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
                                dev->fsa_dev[container].config_waiting_on = 0;
                } else for (container = 0;
                    container < dev->maximum_num_containers; ++container) {
                        if ((dev->fsa_dev[container].config_waiting_on ==
-                           le32_to_cpu(*(u32 *)aifcmd->data)) &&
+                           le32_to_cpu(*(__le32 *)aifcmd->data)) &&
                         time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
                                dev->fsa_dev[container].config_waiting_on = 0;
                }
                break;
 
        case AifCmdEventNotify:
-               switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+               switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
+               case AifEnBatteryEvent:
+                       dev->cache_protected =
+                               (((__le32 *)aifcmd->data)[1] == cpu_to_le32(3));
+                       break;
                /*
                 *      Add an Array.
                 */
                case AifEnAddContainer:
-                       container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+                       container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
                        if (container >= dev->maximum_num_containers)
                                break;
                        dev->fsa_dev[container].config_needed = ADD;
@@ -866,7 +872,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                 *      Delete an Array.
                 */
                case AifEnDeleteContainer:
-                       container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+                       container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
                        if (container >= dev->maximum_num_containers)
                                break;
                        dev->fsa_dev[container].config_needed = DELETE;
@@ -880,7 +886,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                 * waiting on something else, setup to wait on a Config Change.
                 */
                case AifEnContainerChange:
-                       container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+                       container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
                        if (container >= dev->maximum_num_containers)
                                break;
                        if (dev->fsa_dev[container].config_waiting_on &&
@@ -895,6 +901,60 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                case AifEnConfigChange:
                        break;
 
+               case AifEnAddJBOD:
+               case AifEnDeleteJBOD:
+                       container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
+                       if ((container >> 28))
+                               break;
+                       channel = (container >> 24) & 0xF;
+                       if (channel >= dev->maximum_num_channels)
+                               break;
+                       id = container & 0xFFFF;
+                       if (id >= dev->maximum_num_physicals)
+                               break;
+                       lun = (container >> 16) & 0xFF;
+                       channel = aac_phys_to_logical(channel);
+                       device_config_needed =
+                         (((__le32 *)aifcmd->data)[0] ==
+                           cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
+                       break;
+
+               case AifEnEnclosureManagement:
+                       /*
+                        * If in JBOD mode, automatic exposure of new
+                        * physical target to be suppressed until configured.
+                        */
+                       if (dev->jbod)
+                               break;
+                       switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) {
+                       case EM_DRIVE_INSERTION:
+                       case EM_DRIVE_REMOVAL:
+                               container = le32_to_cpu(
+                                       ((__le32 *)aifcmd->data)[2]);
+                               if ((container >> 28))
+                                       break;
+                               channel = (container >> 24) & 0xF;
+                               if (channel >= dev->maximum_num_channels)
+                                       break;
+                               id = container & 0xFFFF;
+                               lun = (container >> 16) & 0xFF;
+                               if (id >= dev->maximum_num_physicals) {
+                                       /* legacy dev_t ? */
+                                       if ((0x2000 <= id) || lun || channel ||
+                                         ((channel = (id >> 7) & 0x3F) >=
+                                         dev->maximum_num_channels))
+                                               break;
+                                       lun = (id >> 4) & 7;
+                                       id &= 0xF;
+                               }
+                               channel = aac_phys_to_logical(channel);
+                               device_config_needed =
+                                 (((__le32 *)aifcmd->data)[3]
+                                   == cpu_to_le32(EM_DRIVE_INSERTION)) ?
+                                 ADD : DELETE;
+                               break;
+                       }
+                       break;
                }
 
                /*
@@ -905,13 +965,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                        if (container >= dev->maximum_num_containers)
                                break;
                        if ((dev->fsa_dev[container].config_waiting_on ==
-                           le32_to_cpu(*(u32 *)aifcmd->data)) &&
+                           le32_to_cpu(*(__le32 *)aifcmd->data)) &&
                         time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
                                dev->fsa_dev[container].config_waiting_on = 0;
                } else for (container = 0;
                    container < dev->maximum_num_containers; ++container) {
                        if ((dev->fsa_dev[container].config_waiting_on ==
-                           le32_to_cpu(*(u32 *)aifcmd->data)) &&
+                           le32_to_cpu(*(__le32 *)aifcmd->data)) &&
                         time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
                                dev->fsa_dev[container].config_waiting_on = 0;
                }
@@ -926,9 +986,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                 * wait for a container change.
                 */
 
-               if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
-                && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
-                 || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
+               if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
+                   (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] ||
+                    ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) {
                        for (container = 0;
                            container < dev->maximum_num_containers;
                            ++container) {
@@ -943,9 +1003,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                                        jiffies;
                        }
                }
-               if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
-                && (((u32 *)aifcmd->data)[6] == 0)
-                && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
+               if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
+                   ((__le32 *)aifcmd->data)[6] == 0 &&
+                   ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) {
                        for (container = 0;
                            container < dev->maximum_num_containers;
                            ++container) {
@@ -963,7 +1023,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                break;
        }
 
-       device_config_needed = NOTHING;
+       if (device_config_needed == NOTHING)
        for (container = 0; container < dev->maximum_num_containers;
            ++container) {
                if ((dev->fsa_dev[container].config_waiting_on == 0) &&
@@ -972,6 +1032,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                        device_config_needed =
                                dev->fsa_dev[container].config_needed;
                        dev->fsa_dev[container].config_needed = NOTHING;
+                       channel = CONTAINER_TO_CHANNEL(container);
+                       id = CONTAINER_TO_ID(container);
+                       lun = CONTAINER_TO_LUN(container);
                        break;
                }
        }
@@ -995,34 +1058,56 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
        /*
         * force reload of disk info via aac_probe_container
         */
-       if ((device_config_needed == CHANGE)
-        && (dev->fsa_dev[container].valid == 1))
-               dev->fsa_dev[container].valid = 2;
-       if ((device_config_needed == CHANGE) ||
-                       (device_config_needed == ADD))
+       if ((channel == CONTAINER_CHANNEL) &&
+         (device_config_needed != NOTHING)) {
+               if (dev->fsa_dev[container].valid == 1)
+                       dev->fsa_dev[container].valid = 2;
                aac_probe_container(dev, container);
-       device = scsi_device_lookup(dev->scsi_host_ptr, 
-               CONTAINER_TO_CHANNEL(container), 
-               CONTAINER_TO_ID(container), 
-               CONTAINER_TO_LUN(container));
+       }
+       device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun);
        if (device) {
                switch (device_config_needed) {
                case DELETE:
+                       if (scsi_device_online(device)) {
+                               scsi_device_set_state(device, SDEV_OFFLINE);
+                               sdev_printk(KERN_INFO, device,
+                                       "Device offlined - %s\n",
+                                       (channel == CONTAINER_CHANNEL) ?
+                                               "array deleted" :
+                                               "enclosure services event");
+                       }
+                       break;
+               case ADD:
+                       if (!scsi_device_online(device)) {
+                               sdev_printk(KERN_INFO, device,
+                                       "Device online - %s\n",
+                                       (channel == CONTAINER_CHANNEL) ?
+                                               "array created" :
+                                               "enclosure services event");
+                               scsi_device_set_state(device, SDEV_RUNNING);
+                       }
+                       /* FALLTHRU */
                case CHANGE:
+                       if ((channel == CONTAINER_CHANNEL)
+                        && (!dev->fsa_dev[container].valid)) {
+                               if (!scsi_device_online(device))
+                                       break;
+                               scsi_device_set_state(device, SDEV_OFFLINE);
+                               sdev_printk(KERN_INFO, device,
+                                       "Device offlined - %s\n",
+                                       "array failed");
+                               break;
+                       }
                        scsi_rescan_device(&device->sdev_gendev);
 
                default:
                        break;
                }
                scsi_device_put(device);
+               device_config_needed = NOTHING;
        }
-       if (device_config_needed == ADD) {
-               scsi_add_device(dev->scsi_host_ptr,
-                 CONTAINER_TO_CHANNEL(container),
-                 CONTAINER_TO_ID(container),
-                 CONTAINER_TO_LUN(container));
-       }
-
+       if (device_config_needed == ADD)
+               scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
 }
 
 static int _aac_reset_adapter(struct aac_dev *aac, int forced)
@@ -1099,7 +1184,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
        free_irq(aac->pdev->irq, aac);
        kfree(aac->fsa_dev);
        aac->fsa_dev = NULL;
-       if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
+       quirks = aac_get_driver_ident(index)->quirks;
+       if (quirks & AAC_QUIRK_31BIT) {
                if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
                  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
                        goto out;
@@ -1110,7 +1196,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
        }
        if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
                goto out;
-       if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
+       if (quirks & AAC_QUIRK_31BIT)
                if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
                        goto out;
        if (jafo) {
@@ -1121,15 +1207,14 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
                }
        }
        (void)aac_get_adapter_info(aac);
-       quirks = aac_get_driver_ident(index)->quirks;
        if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
-               host->sg_tablesize = 34;
-               host->max_sectors = (host->sg_tablesize * 8) + 112;
-       }
-       if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
-               host->sg_tablesize = 17;
-               host->max_sectors = (host->sg_tablesize * 8) + 112;
-       }
+               host->sg_tablesize = 34;
+               host->max_sectors = (host->sg_tablesize * 8) + 112;
+       }
+       if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
+               host->sg_tablesize = 17;
+               host->max_sectors = (host->sg_tablesize * 8) + 112;
+       }
        aac_get_config_status(aac, 1);
        aac_get_containers(aac);
        /*
@@ -1217,12 +1302,13 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
        }
 
        /* Quiesce build, flush cache, write through mode */
-       aac_send_shutdown(aac);
+       if (forced < 2)
+               aac_send_shutdown(aac);
        spin_lock_irqsave(host->host_lock, flagv);
-       retval = _aac_reset_adapter(aac, forced);
+       retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1)));
        spin_unlock_irqrestore(host->host_lock, flagv);
 
-       if (retval == -ENODEV) {
+       if ((forced < 2) && (retval == -ENODEV)) {
                /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
                struct fib * fibctx = aac_fib_alloc(aac);
                if (fibctx) {
@@ -1338,11 +1424,11 @@ int aac_check_health(struct aac_dev * aac)
                        fib->data = hw_fib->data;
                        aif = (struct aac_aifcmd *)hw_fib->data;
                        aif->command = cpu_to_le32(AifCmdEventNotify);
-                       aif->seqnum = cpu_to_le32(0xFFFFFFFF);
-                       aif->data[0] = AifEnExpEvent;
-                       aif->data[1] = AifExeFirmwarePanic;
-                       aif->data[2] = AifHighPriority;
-                       aif->data[3] = BlinkLED;
+                       aif->seqnum = cpu_to_le32(0xFFFFFFFF);
+                       ((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent);
+                       ((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic);
+                       ((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority);
+                       ((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED);
 
                        /*
                         * Put the FIB onto the
@@ -1372,14 +1458,14 @@ int aac_check_health(struct aac_dev * aac)
 
        printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
 
-       if (!aac_check_reset ||
+       if (!aac_check_reset || ((aac_check_reset != 1) &&
                (aac->supplement_adapter_info.SupportedOptions2 &
-                       le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+                       AAC_OPTION_IGNORE_RESET)))
                goto out;
        host = aac->scsi_host_ptr;
        if (aac->thread->pid != current->pid)
                spin_lock_irqsave(host->host_lock, flagv);
-       BlinkLED = _aac_reset_adapter(aac, 0);
+       BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1);
        if (aac->thread->pid != current->pid)
                spin_unlock_irqrestore(host->host_lock, flagv);
        return BlinkLED;
@@ -1399,7 +1485,7 @@ out:
  *     until the queue is empty. When the queue is empty it will wait for
  *     more FIBs.
  */
+
 int aac_command_thread(void *data)
 {
        struct aac_dev *dev = data;
@@ -1425,30 +1511,29 @@ int aac_command_thread(void *data)
        add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
        dprintk ((KERN_INFO "aac_command_thread start\n"));
-       while(1) 
-       {
+       while (1) {
                spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
                while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
                        struct list_head *entry;
                        struct aac_aifcmd * aifcmd;
 
                        set_current_state(TASK_RUNNING);
-       
+
                        entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
                        list_del(entry);
-               
+
                        spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
                        fib = list_entry(entry, struct fib, fiblink);
                        /*
-                        *      We will process the FIB here or pass it to a 
-                        *      worker thread that is TBD. We Really can't 
+                        *      We will process the FIB here or pass it to a
+                        *      worker thread that is TBD. We Really can't
                         *      do anything at this point since we don't have
                         *      anything defined for this thread to do.
                         */
                        hw_fib = fib->hw_fib_va;
                        memset(fib, 0, sizeof(struct fib));
                        fib->type = FSAFS_NTC_FIB_CONTEXT;
-                       fib->size = sizeof( struct fib );
+                       fib->size = sizeof(struct fib);
                        fib->hw_fib_va = hw_fib;
                        fib->data = hw_fib->data;
                        fib->dev = dev;
@@ -1462,20 +1547,19 @@ int aac_command_thread(void *data)
                                *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
                                aac_fib_adapter_complete(fib, (u16)sizeof(u32));
                        } else {
-                               struct list_head *entry;
                                /* The u32 here is important and intended. We are using
                                   32bit wrapping time to fit the adapter field */
-                                  
+
                                u32 time_now, time_last;
                                unsigned long flagv;
                                unsigned num;
                                struct hw_fib ** hw_fib_pool, ** hw_fib_p;
                                struct fib ** fib_pool, ** fib_p;
-                       
+
                                /* Sniff events */
-                               if ((aifcmd->command == 
+                               if ((aifcmd->command ==
                                     cpu_to_le32(AifCmdEventNotify)) ||
-                                   (aifcmd->command == 
+                                   (aifcmd->command ==
                                     cpu_to_le32(AifCmdJobProgress))) {
                                        aac_handle_aif(dev, fib);
                                }
@@ -1527,7 +1611,7 @@ int aac_command_thread(void *data)
                                spin_lock_irqsave(&dev->fib_lock, flagv);
                                entry = dev->fib_list.next;
                                /*
-                                * For each Context that is on the 
+                                * For each Context that is on the
                                 * fibctxList, make a copy of the
                                 * fib, and then set the event to wake up the
                                 * thread that is waiting for it.
@@ -1552,7 +1636,7 @@ int aac_command_thread(void *data)
                                                 */
                                                time_last = fibctx->jiffies;
                                                /*
-                                                * Has it been > 2 minutes 
+                                                * Has it been > 2 minutes
                                                 * since the last read off
                                                 * the queue?
                                                 */
@@ -1583,7 +1667,7 @@ int aac_command_thread(void *data)
                                                 */
                                                list_add_tail(&newfib->fiblink, &fibctx->fib_list);
                                                fibctx->count++;
-                                               /* 
+                                               /*
                                                 * Set the event to wake up the
                                                 * thread that is waiting.
                                                 */
@@ -1655,11 +1739,11 @@ int aac_command_thread(void *data)
                                struct fib *fibptr;
 
                                if ((fibptr = aac_fib_alloc(dev))) {
-                                       u32 * info;
+                                       __le32 *info;
 
                                        aac_fib_init(fibptr);
 
-                                       info = (u32 *) fib_data(fibptr);
+                                       info = (__le32 *) fib_data(fibptr);
                                        if (now.tv_usec > 500000)
                                                ++now.tv_sec;
 
index e6032ffc66a693597b685c859fc994cac64eedc0..d1163ded132bd2ab395d396a89d206e612df4bd9 100644 (file)
@@ -120,6 +120,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
                         *      NOTE:  we cannot touch the fib after this
                         *          call, because it may have been deallocated.
                         */
+                       fib->flags = 0;
                        fib->callback(fib->callback_data, fib);
                } else {
                        unsigned long flagv;
@@ -229,11 +230,9 @@ unsigned int aac_command_normal(struct aac_queue *q)
  *     all QE there are and wake up all the waiters before exiting.
  */
 
-unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
+unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
 {
-       u32 index = le32_to_cpu(Index);
-
-       dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
+       dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
        if ((index & 0x00000002L)) {
                struct hw_fib * hw_fib;
                struct fib * fib;
@@ -301,7 +300,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
 
                if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
                {
-                       u32 *pstatus = (u32 *)hwfib->data;
+                       __le32 *pstatus = (__le32 *)hwfib->data;
                        if (*pstatus & cpu_to_le32(0xffff0000))
                                *pstatus = cpu_to_le32(ST_OK);
                }
@@ -315,6 +314,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
                         *      NOTE:  we cannot touch the fib after this
                         *          call, because it may have been deallocated.
                         */
+                       fib->flags = 0;
                        fib->callback(fib->callback_data, fib);
                } else {
                        unsigned long flagv;
index 9dd331bc29b01386f89532e4c057d5a126f516e0..61be22774e99786390ca0702cb932b3aa1812799 100644 (file)
@@ -159,27 +159,27 @@ static struct pci_device_id aac_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
 
 /*
- * dmb - For now we add the number of channels to this structure.  
+ * dmb - For now we add the number of channels to this structure.
  * In the future we should add a fib that reports the number of channels
  * for the card.  At that time we can remove the channels from here
  */
 static struct aac_driver_ident aac_drivers[] = {
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */
-       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */
-       { aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */
-       { aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */
+       { aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */
+       { aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */
+       { aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */
 
        { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado) */
@@ -224,8 +224,8 @@ static struct aac_driver_ident aac_drivers[] = {
        { aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
        { aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
 
-       { aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
-       { aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
+       { aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */
+       { aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
        { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
        { aac_nark_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec NEMER/ARK Catch All */
@@ -239,7 +239,7 @@ static struct aac_driver_ident aac_drivers[] = {
  *     Queues a command for execution by the associated Host Adapter.
  *
  *     TODO: unify with aac_scsi_cmd().
- */ 
+ */
 
 static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
@@ -258,7 +258,7 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
        }
        cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
        return (aac_scsi_cmd(cmd) ? FAILED : 0);
-} 
+}
 
 /**
  *     aac_info                -       Returns the host adapter name
@@ -292,21 +292,21 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype)
  *     @capacity: the sector capacity of the disk
  *     @geom: geometry block to fill in
  *
- *     Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
- *     The default disk geometry is 64 heads, 32 sectors, and the appropriate 
- *     number of cylinders so as not to exceed drive capacity.  In order for 
+ *     Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.
+ *     The default disk geometry is 64 heads, 32 sectors, and the appropriate
+ *     number of cylinders so as not to exceed drive capacity.  In order for
  *     disks equal to or larger than 1 GB to be addressable by the BIOS
- *     without exceeding the BIOS limitation of 1024 cylinders, Extended 
- *     Translation should be enabled.   With Extended Translation enabled, 
- *     drives between 1 GB inclusive and 2 GB exclusive are given a disk 
- *     geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
- *     are given a disk geometry of 255 heads and 63 sectors.  However, if 
- *     the BIOS detects that the Extended Translation setting does not match 
- *     the geometry in the partition table, then the translation inferred 
- *     from the partition table will be used by the BIOS, and a warning may 
+ *     without exceeding the BIOS limitation of 1024 cylinders, Extended
+ *     Translation should be enabled.   With Extended Translation enabled,
+ *     drives between 1 GB inclusive and 2 GB exclusive are given a disk
+ *     geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive
+ *     are given a disk geometry of 255 heads and 63 sectors.  However, if
+ *     the BIOS detects that the Extended Translation setting does not match
+ *     the geometry in the partition table, then the translation inferred
+ *     from the partition table will be used by the BIOS, and a warning may
  *     be displayed.
  */
+
 static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
                        sector_t capacity, int *geom)
 {
@@ -333,10 +333,10 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 
        param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
 
-       /* 
+       /*
         *      Read the first 1024 bytes from the disk device, if the boot
         *      sector partition table is valid, search for a partition table
-        *      entry whose end_head matches one of the standard geometry 
+        *      entry whose end_head matches one of the standard geometry
         *      translations ( 64/32, 128/32, 255/63 ).
         */
        buf = scsi_bios_ptable(bdev);
@@ -401,30 +401,44 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 
 static int aac_slave_configure(struct scsi_device *sdev)
 {
+       struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
        if ((sdev->type == TYPE_DISK) &&
-                       (sdev_channel(sdev) != CONTAINER_CHANNEL)) {
+                       (sdev_channel(sdev) != CONTAINER_CHANNEL) &&
+                       (!aac->jbod || sdev->inq_periph_qual) &&
+                       (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) {
                if (expose_physicals == 0)
                        return -ENXIO;
-               if (expose_physicals < 0) {
-                       struct aac_dev *aac =
-                               (struct aac_dev *)sdev->host->hostdata;
-                       if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
-                               sdev->no_uld_attach = 1;
-               }
+               if (expose_physicals < 0)
+                       sdev->no_uld_attach = 1;
        }
        if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
-                       (sdev_channel(sdev) == CONTAINER_CHANNEL)) {
+                       (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) &&
+                       !sdev->no_uld_attach) {
                struct scsi_device * dev;
                struct Scsi_Host *host = sdev->host;
                unsigned num_lsu = 0;
                unsigned num_one = 0;
                unsigned depth;
+               unsigned cid;
 
+               /*
+                * Firmware has an individual device recovery time typically
+                * of 35 seconds, give us a margin.
+                */
+               if (sdev->timeout < (45 * HZ))
+                       sdev->timeout = 45 * HZ;
+               for (cid = 0; cid < aac->maximum_num_containers; ++cid)
+                       if (aac->fsa_dev[cid].valid)
+                               ++num_lsu;
                __shost_for_each_device(dev, host) {
                        if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
-                               (sdev_channel(dev) == CONTAINER_CHANNEL))
-                               ++num_lsu;
-                       else
+                                       (!aac->raid_scsi_mode ||
+                                               (sdev_channel(sdev) != 2)) &&
+                                       !dev->no_uld_attach) {
+                               if ((sdev_channel(dev) != CONTAINER_CHANNEL)
+                                || !aac->fsa_dev[sdev_id(dev)].valid)
+                                       ++num_lsu;
+                       } else
                                ++num_one;
                }
                if (num_lsu == 0)
@@ -481,9 +495,35 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
        return sdev->queue_depth;
 }
 
+static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct scsi_device * sdev = to_scsi_device(dev);
+       if (sdev_channel(sdev) != CONTAINER_CHANNEL)
+               return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach
+                 ? "Hidden\n" : "JBOD");
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+         get_container_type(((struct aac_dev *)(sdev->host->hostdata))
+           ->fsa_dev[sdev_id(sdev)].type));
+}
+
+static struct device_attribute aac_raid_level_attr = {
+       .attr = {
+               .name = "level",
+               .mode = S_IRUGO,
+       },
+       .show = aac_show_raid_level
+};
+
+static struct device_attribute *aac_dev_attrs[] = {
+       &aac_raid_level_attr,
+       NULL,
+};
+
 static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
 {
        struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
        return aac_do_ioctl(dev, cmd, arg);
 }
 
@@ -506,17 +546,33 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
                        break;
        case INQUIRY:
        case READ_CAPACITY:
-       case TEST_UNIT_READY:
                /* Mark associated FIB to not complete, eh handler does this */
                for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
                        struct fib * fib = &aac->fibs[count];
                        if (fib->hw_fib_va->header.XferState &&
+                         (fib->flags & FIB_CONTEXT_FLAG) &&
                          (fib->callback_data == cmd)) {
                                fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
                                cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
                                ret = SUCCESS;
                        }
                }
+               break;
+       case TEST_UNIT_READY:
+               /* Mark associated FIB to not complete, eh handler does this */
+               for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+                       struct scsi_cmnd * command;
+                       struct fib * fib = &aac->fibs[count];
+                       if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) &&
+                         (fib->flags & FIB_CONTEXT_FLAG) &&
+                         ((command = fib->callback_data)) &&
+                         (command->device == cmd->device)) {
+                               fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+                               command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+                               if (command == cmd)
+                                       ret = SUCCESS;
+                       }
+               }
        }
        return ret;
 }
@@ -539,12 +595,13 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
        for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
                struct fib * fib = &aac->fibs[count];
                if (fib->hw_fib_va->header.XferState &&
+                 (fib->flags & FIB_CONTEXT_FLAG) &&
                  (fib->callback_data == cmd)) {
                        fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
                        cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
                }
        }
-       printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
+       printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
                                        AAC_DRIVERNAME);
 
        if ((count = aac_check_health(aac)))
@@ -584,8 +641,11 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
         * support a register, instead of a commanded, reset.
         */
        if ((aac->supplement_adapter_info.SupportedOptions2 &
-         le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
-         le32_to_cpu(AAC_OPTION_MU_RESET))
+          AAC_OPTION_MU_RESET) &&
+         aac_check_reset &&
+         ((aac_check_reset != 1) ||
+          (aac->supplement_adapter_info.SupportedOptions2 &
+           AAC_OPTION_IGNORE_RESET)))
                aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
        return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
 }
@@ -632,8 +692,8 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
  *     Bugs: Needs locking against parallel ioctls lower down
  *     Bugs: Needs to handle hot plugging
  */
-static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
+
+static int aac_cfg_ioctl(struct inode *inode, struct file *file,
                unsigned int cmd, unsigned long arg)
 {
        if (!capable(CAP_SYS_RAWIO))
@@ -646,7 +706,7 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
 {
        long ret;
        lock_kernel();
-       switch (cmd) { 
+       switch (cmd) {
        case FSACTL_MINIPORT_REV_CHECK:
        case FSACTL_SENDFIB:
        case FSACTL_OPEN_GET_ADAPTER_FIB:
@@ -656,14 +716,14 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
        case FSACTL_QUERY_DISK:
        case FSACTL_DELETE_DISK:
        case FSACTL_FORCE_DELETE_DISK:
-       case FSACTL_GET_CONTAINERS: 
+       case FSACTL_GET_CONTAINERS:
        case FSACTL_SEND_LARGE_FIB:
                ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
                break;
 
        case FSACTL_GET_NEXT_ADAPTER_FIB: {
                struct fib_ioctl __user *f;
-               
+
                f = compat_alloc_user_space(sizeof(*f));
                ret = 0;
                if (clear_user(f, sizeof(*f)))
@@ -676,9 +736,9 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
        }
 
        default:
-               ret = -ENOIOCTLCMD; 
+               ret = -ENOIOCTLCMD;
                break;
-       } 
+       }
        unlock_kernel();
        return ret;
 }
@@ -735,6 +795,25 @@ static ssize_t aac_show_vendor(struct class_device *class_dev,
        return len;
 }
 
+static ssize_t aac_show_flags(struct class_device *class_dev, char *buf)
+{
+       int len = 0;
+       struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+
+       if (nblank(dprintk(x)))
+               len = snprintf(buf, PAGE_SIZE, "dprintk\n");
+#ifdef AAC_DETAILED_STATUS_INFO
+       len += snprintf(buf + len, PAGE_SIZE - len,
+                       "AAC_DETAILED_STATUS_INFO\n");
+#endif
+       if (dev->raw_io_interface && dev->raw_io_64)
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "SAI_READ_CAPACITY_16\n");
+       if (dev->jbod)
+               len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
+       return len;
+}
+
 static ssize_t aac_show_kernel_version(struct class_device *class_dev,
                char *buf)
 {
@@ -742,7 +821,7 @@ static ssize_t aac_show_kernel_version(struct class_device *class_dev,
        int len, tmp;
 
        tmp = le32_to_cpu(dev->adapter_info.kernelrev);
-       len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+       len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
          tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
          le32_to_cpu(dev->adapter_info.kernelbuild));
        return len;
@@ -755,7 +834,7 @@ static ssize_t aac_show_monitor_version(struct class_device *class_dev,
        int len, tmp;
 
        tmp = le32_to_cpu(dev->adapter_info.monitorrev);
-       len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+       len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
          tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
          le32_to_cpu(dev->adapter_info.monitorbuild));
        return len;
@@ -768,7 +847,7 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev,
        int len, tmp;
 
        tmp = le32_to_cpu(dev->adapter_info.biosrev);
-       len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+       len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
          tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
          le32_to_cpu(dev->adapter_info.biosbuild));
        return len;
@@ -844,6 +923,13 @@ static struct class_device_attribute aac_vendor = {
        },
        .show = aac_show_vendor,
 };
+static struct class_device_attribute aac_flags = {
+       .attr = {
+               .name = "flags",
+               .mode = S_IRUGO,
+       },
+       .show = aac_show_flags,
+};
 static struct class_device_attribute aac_kernel_version = {
        .attr = {
                .name = "hba_kernel_version",
@@ -898,6 +984,7 @@ static struct class_device_attribute aac_reset = {
 static struct class_device_attribute *aac_attrs[] = {
        &aac_model,
        &aac_vendor,
+       &aac_flags,
        &aac_kernel_version,
        &aac_monitor_version,
        &aac_bios_version,
@@ -928,21 +1015,22 @@ static struct scsi_host_template aac_driver_template = {
        .compat_ioctl                   = aac_compat_ioctl,
 #endif
        .queuecommand                   = aac_queuecommand,
-       .bios_param                     = aac_biosparm, 
+       .bios_param                     = aac_biosparm,
        .shost_attrs                    = aac_attrs,
        .slave_configure                = aac_slave_configure,
        .change_queue_depth             = aac_change_queue_depth,
+       .sdev_attrs                     = aac_dev_attrs,
        .eh_abort_handler               = aac_eh_abort,
        .eh_host_reset_handler          = aac_eh_reset,
-       .can_queue                      = AAC_NUM_IO_FIB,       
+       .can_queue                      = AAC_NUM_IO_FIB,
        .this_id                        = MAXIMUM_NUM_CONTAINERS,
        .sg_tablesize                   = 16,
        .max_sectors                    = 128,
 #if (AAC_NUM_IO_FIB > 256)
        .cmd_per_lun                    = 256,
-#else          
-       .cmd_per_lun                    = AAC_NUM_IO_FIB, 
-#endif 
+#else
+       .cmd_per_lun                    = AAC_NUM_IO_FIB,
+#endif
        .use_clustering                 = ENABLE_CLUSTERING,
        .use_sg_chaining                = ENABLE_SG_CHAINING,
        .emulated                       = 1,
@@ -979,18 +1067,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
                goto out;
        error = -ENODEV;
 
-       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || 
+       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
                        pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
                goto out_disable_pdev;
        /*
         * If the quirk31 bit is set, the adapter needs adapter
         * to driver communication memory to be allocated below 2gig
         */
-       if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
+       if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
                if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
                                pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
                        goto out_disable_pdev;
-       
+
        pci_set_master(pdev);
 
        shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev));
@@ -1003,7 +1091,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        shost->max_cmd_len = 16;
 
        aac = (struct aac_dev *)shost->hostdata;
-       aac->scsi_host_ptr = shost;     
+       aac->scsi_host_ptr = shost;
        aac->pdev = pdev;
        aac->name = aac_driver_template.name;
        aac->id = shost->unique_id;
@@ -1040,7 +1128,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
                if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
                        goto out_deinit;
+
        aac->maximum_num_channels = aac_drivers[index].channels;
        error = aac_get_adapter_info(aac);
        if (error < 0)
@@ -1049,7 +1137,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        /*
         * Lets override negotiations and drop the maximum SG limit to 34
         */
-       if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && 
+       if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
                        (aac->scsi_host_ptr->sg_tablesize > 34)) {
                aac->scsi_host_ptr->sg_tablesize = 34;
                aac->scsi_host_ptr->max_sectors
@@ -1066,17 +1154,17 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        /*
         * Firware printf works only with older firmware.
         */
-       if (aac_drivers[index].quirks & AAC_QUIRK_34SG) 
+       if (aac_drivers[index].quirks & AAC_QUIRK_34SG)
                aac->printf_enabled = 1;
        else
                aac->printf_enabled = 0;
+
        /*
         * max channel will be the physical channels plus 1 virtual channel
         * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
         * physical channels are address by their actual physical number+1
         */
-       if ((aac->nondasd_support == 1) || expose_physicals)
+       if (aac->nondasd_support || expose_physicals || aac->jbod)
                shost->max_channel = aac->maximum_num_channels;
        else
                shost->max_channel = 0;
@@ -1148,10 +1236,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
        kfree(aac->queues);
 
        aac_adapter_ioremap(aac, 0);
-       
+
        kfree(aac->fibs);
        kfree(aac->fsa_dev);
-       
+
        list_del(&aac->entry);
        scsi_host_put(shost);
        pci_disable_device(pdev);
@@ -1172,7 +1260,7 @@ static struct pci_driver aac_pci_driver = {
 static int __init aac_init(void)
 {
        int error;
-       
+
        printk(KERN_INFO "Adaptec %s driver %s\n",
          AAC_DRIVERNAME, aac_driver_version);
 
index 73eef3dc5dc629d0056a1e8ba2178a1205bc9f4e..a08bbf1fd76c9613681b7c1048e5241fae65620b 100644 (file)
@@ -465,7 +465,7 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
        u32 var;
 
        if (!(dev->supplement_adapter_info.SupportedOptions2 &
-         le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
+         AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
                if (bled)
                        printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
                                dev->name, dev->id, bled);
@@ -549,7 +549,9 @@ int _aac_rx_init(struct aac_dev *dev)
        dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
        if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
          !aac_rx_restart_adapter(dev, 0))
-               ++restart;
+               /* Make sure the Hardware FIFO is empty */
+               while ((++restart < 512) &&
+                 (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
        /*
         *      Check to see if the board panic'd while booting.
         */
index 9dd3952516c548c84b61b0754ab406b14ae36dd0..374ed025dc5a1da2636061e4e9b12f97f0691905 100644 (file)
@@ -8233,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
                        if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
                                ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
                                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                                                 sizeof(scp->sense_buffer));
+                                                 SCSI_SENSE_BUFFERSIZE);
                                /*
                                 * Note: The 'status_byte()' macro used by
                                 * target drivers defined in scsi.h shifts the
@@ -9136,7 +9136,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
        BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
 
        dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
-                       sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+                        SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
        /*
         * 'qdonep' contains the command's ending status.
         */
@@ -9166,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
                        if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
                                ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
                                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                                                 sizeof(scp->sense_buffer));
+                                                 SCSI_SENSE_BUFFERSIZE);
                                /*
                                 * Note: The 'status_byte()' macro used by
                                 * target drivers defined in scsi.h shifts the
@@ -9881,9 +9881,9 @@ static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
 {
        struct asc_board *board = shost_priv(scp->device->host);
        scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
-                               sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+                                            SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
        dma_cache_sync(board->dev, scp->sense_buffer,
-                               sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+                      SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
        return cpu_to_le32(scp->SCp.dma_handle);
 }
 
@@ -9914,7 +9914,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
        asc_scsi_q->q2.target_ix =
            ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
        asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
-       asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
+       asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE;
 
        /*
         * If there are any outstanding requests for the current target,
@@ -10173,7 +10173,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
        scsiqp->target_lun = scp->device->lun;
 
        scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-       scsiqp->sense_len = sizeof(scp->sense_buffer);
+       scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
        /* Build ADV_SCSI_REQ_Q */
 
@@ -13906,7 +13906,7 @@ static int advansys_release(struct Scsi_Host *shost)
 
 #define ASC_IOADR_TABLE_MAX_IX  11
 
-static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = {
        0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
        0x0210, 0x0230, 0x0250, 0x0330
 };
index ea8c699476446cc8c09587d33dd8b84ced275461..6ccdc96cc480559c4e259a79d004e4589d316300 100644 (file)
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_spi.h>
+#include <scsi/scsi_eh.h>
 #include "aha152x.h"
 
 static LIST_HEAD(aha152x_host_list);
@@ -558,9 +559,7 @@ struct aha152x_hostdata {
 struct aha152x_scdata {
        Scsi_Cmnd *next;        /* next sc in queue */
        struct completion *done;/* semaphore to block on */
-       unsigned char aha_orig_cmd_len;
-       unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE];
-       int aha_orig_resid;
+       struct scsi_eh_save ses;
 };
 
 /* access macros for hostdata */
@@ -1017,16 +1016,10 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
           SCp.buffers_residual : left buffers in list
           SCp.phase            : current state of the command */
 
-       if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) {
-               if (phase & check_condition) {
-                       SCpnt->SCp.ptr           = SCpnt->sense_buffer;
-                       SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
-                       scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer));
-               } else {
-                       SCpnt->SCp.ptr           = NULL;
-                       SCpnt->SCp.this_residual = 0;
-                       scsi_set_resid(SCpnt, 0);
-               }
+       if ((phase & resetting) || !scsi_sglist(SCpnt)) {
+               SCpnt->SCp.ptr           = NULL;
+               SCpnt->SCp.this_residual = 0;
+               scsi_set_resid(SCpnt, 0);
                SCpnt->SCp.buffer           = NULL;
                SCpnt->SCp.buffers_residual = 0;
        } else {
@@ -1561,10 +1554,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
                        }
 #endif
 
-                       /* restore old command */
-                       memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd));
-                       cmd->cmd_len = sc->aha_orig_cmd_len;
-                       scsi_set_resid(cmd, sc->aha_orig_resid);
+                       scsi_eh_restore_cmnd(cmd, &sc->ses);
 
                        cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
 
@@ -1587,22 +1577,10 @@ static void busfree_run(struct Scsi_Host *shpnt)
                                DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
 #endif
 
-                               /* save old command */
                                sc = SCDATA(ptr);
                                /* It was allocated in aha152x_internal_queue? */
                                BUG_ON(!sc);
-                               memcpy(sc->aha_orig_cmnd, ptr->cmnd,
-                                                           sizeof(ptr->cmnd));
-                               sc->aha_orig_cmd_len = ptr->cmd_len;
-                               sc->aha_orig_resid = scsi_get_resid(ptr);
-
-                               ptr->cmnd[0]         = REQUEST_SENSE;
-                               ptr->cmnd[1]         = 0;
-                               ptr->cmnd[2]         = 0;
-                               ptr->cmnd[3]         = 0;
-                               ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
-                               ptr->cmnd[5]         = 0;
-                               ptr->cmd_len         = 6;
+                               scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
 
                                DO_UNLOCK(flags);
                                aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
index bbcc2c52d79fed550b90fe623fbfa105ca90a921..190568ebea3c12e15131bfb6868c212c9463caa0 100644 (file)
 #define SCSI_BUF_PA(address)   isa_virt_to_bus(address)
 #define SCSI_SG_PA(sgent)      (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset)
 
-static void BAD_DMA(void *address, unsigned int length)
-{
-       printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
-              address,
-              SCSI_BUF_PA(address),
-              length);
-       panic("Buffer at physical address > 16Mb used for aha1542");
-}
-
 static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
                       struct scatterlist *sgp,
                       int nseg,
@@ -545,7 +536,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
                   we will still have it in the cdb when we come back */
                if (ccb[mbo].tarstat == 2)
                        memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
-                              sizeof(SCtmp->sense_buffer));
+                              SCSI_SENSE_BUFFERSIZE);
 
 
                /* is there mail :-) */
@@ -597,8 +588,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        unchar target = SCpnt->device->id;
        unchar lun = SCpnt->device->lun;
        unsigned long flags;
-       void *buff = SCpnt->request_buffer;
-       int bufflen = SCpnt->request_bufflen;
+       int bufflen = scsi_bufflen(SCpnt);
        int mbo;
        struct mailbox *mb;
        struct ccb *ccb;
@@ -619,7 +609,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 #if 0
                /* scsi_request_sense() provides a buffer of size 256,
                   so there is no reason to expect equality */
-               if (bufflen != sizeof(SCpnt->sense_buffer))
+               if (bufflen != SCSI_SENSE_BUFFERSIZE)
                        printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
                               "for request sense (%d)\n", bufflen);
 #endif
@@ -689,42 +679,29 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 
        memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
 
-       if (SCpnt->use_sg) {
+       if (bufflen) {
                struct scatterlist *sg;
                struct chain *cptr;
 #ifdef DEBUG
                unsigned char *ptr;
 #endif
-               int i;
+               int i, sg_count = scsi_sg_count(SCpnt);
                ccb[mbo].op = 2;        /* SCSI Initiator Command  w/scatter-gather */
-               SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA);
+               SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
+                                                        GFP_KERNEL | GFP_DMA);
                cptr = (struct chain *) SCpnt->host_scribble;
                if (cptr == NULL) {
                        /* free the claimed mailbox slot */
                        HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
                        return SCSI_MLQUEUE_HOST_BUSY;
                }
-               scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
-                       if (sg->length == 0 || SCpnt->use_sg > 16 ||
-                           (((int) sg->offset) & 1) || (sg->length & 1)) {
-                               unsigned char *ptr;
-                               printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
-                               scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
-                                       printk(KERN_CRIT "%d: %p %d\n", i,
-                                              sg_virt(sg), sg->length);
-                               };
-                               printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
-                               ptr = (unsigned char *) &cptr[i];
-                               for (i = 0; i < 18; i++)
-                                       printk("%02x ", ptr[i]);
-                               panic("Foooooooood fight!");
-                       };
+               scsi_for_each_sg(SCpnt, sg, sg_count, i) {
                        any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg));
                        if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD)
-                               BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i);
+                               BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i);
                        any2scsi(cptr[i].datalen, sg->length);
                };
-               any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
+               any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
                any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
 #ifdef DEBUG
                printk("cptr %x: ", cptr);
@@ -735,10 +712,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        } else {
                ccb[mbo].op = 0;        /* SCSI Initiator Command */
                SCpnt->host_scribble = NULL;
-               any2scsi(ccb[mbo].datalen, bufflen);
-               if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
-                       BAD_DMA(buff, bufflen);
-               any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff));
+               any2scsi(ccb[mbo].datalen, 0);
+               any2scsi(ccb[mbo].dataptr, 0);
        };
        ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);     /*SCSI Target Id */
        ccb[mbo].rsalen = 16;
index f6722fd46008a2f451ceb645411e93f6b4115fae..be58a0b097c76752d0827ee097c4c198db09fe17 100644 (file)
@@ -286,7 +286,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
                           cdb when we come back */
                        if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
                                memcpy(SCtmp->sense_buffer, ecbptr->sense, 
-                                      sizeof(SCtmp->sense_buffer));
+                                      SCSI_SENSE_BUFFERSIZE);
                                errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
                        } else
                                errstatus = 0;
index 9a6ce19a40304f6483d7cbfd711cf38d4d5ec0c7..e4f70c563bc295cc6b0a6a022f83998708964183 100644 (file)
@@ -33,11 +33,10 @@ aic79xx-y                                   += aic79xx_osm.o        \
                                                   aic79xx_proc.o       \
                                                   aic79xx_osm_pci.o
 
-EXTRA_CFLAGS += -Idrivers/scsi
+ccflags-y += -Idrivers/scsi
 ifdef WARNINGS_BECOME_ERRORS
-EXTRA_CFLAGS += -Werror
+ccflags-y += -Werror
 endif
-#EXTRA_CFLAGS += -g
 
 # Files generated that shall be removed upon make clean
 clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c
@@ -46,53 +45,45 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c
 # Dependencies for generated files need to be listed explicitly
 
 $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
+$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h
 $(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
-$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
-$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
+$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h
 
-$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h
-$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h
+$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h
+$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h
 
-aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)   := $(obj)/aic7xxx_seq.h \
-                                                  $(obj)/aic7xxx_reg.h
+aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)   := $(obj)/aic7xxx_reg.h
 aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += $(obj)/aic7xxx_reg_print.c
 
 aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \
        -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h
 
 ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
-# Create a dependency chain in generated files
-# to avoid concurrent invocations of the single
-# rule that builds them all.
-aic7xxx_seq.h: aic7xxx_reg.h
-ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
-aic7xxx_reg.h: aic7xxx_reg_print.c
-endif
-$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
+$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
        $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \
                              $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \
                              $(src)/aic7xxx.seq
+
+$(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h
+else
+$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
 endif
 
-aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)   := $(obj)/aic79xx_seq.h \
-                                                  $(obj)/aic79xx_reg.h
+aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)   := $(obj)/aic79xx_reg.h
 aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) += $(obj)/aic79xx_reg_print.c
 
 aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \
        -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h
 
 ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
-# Create a dependency chain in generated files
-# to avoid concurrent invocations of the single
-# rule that builds them all.
-aic79xx_seq.h: aic79xx_reg.h
-ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
-aic79xx_reg.h: aic79xx_reg_print.c
-endif
-$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
+$(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
        $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \
                              $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \
                              $(src)/aic79xx.seq
+
+$(aic79xx-gen-y): $(obj)/aic79xx_seq.h
+else
+$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
 endif
 
 $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl]
index 2d020405480c7755cae40a67dda23713971bbc40..0e4708fd43c8e00d861b80392c976683d43145fa 100644 (file)
@@ -1784,7 +1784,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
                        if (scb->flags & SCB_SENSE) {
                                sense_size = min(sizeof(struct scsi_sense_data)
                                               - ahd_get_sense_residual(scb),
-                                                (u_long)sizeof(cmd->sense_buffer));
+                                                (u_long)SCSI_SENSE_BUFFERSIZE);
                                sense_offset = 0;
                        } else {
                                /*
@@ -1795,11 +1795,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
                                    scb->sense_data;
                                sense_size = min_t(size_t,
                                                scsi_4btoul(siu->sense_length),
-                                               sizeof(cmd->sense_buffer));
+                                               SCSI_SENSE_BUFFERSIZE);
                                sense_offset = SIU_SENSE_OFFSET(siu);
                        }
 
-                       memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+                       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
                        memcpy(cmd->sense_buffer,
                               ahd_get_sense_buf(ahd, scb)
                               + sense_offset, sense_size);
index 390b0fc991c5930dcb8e42057f5aa1ba9ec6644a..e310e414067fc767ef0e8ede1a6864d90650ca6a 100644 (file)
@@ -1801,12 +1801,12 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
 
                        sense_size = min(sizeof(struct scsi_sense_data)
                                       - ahc_get_sense_residual(scb),
-                                        (u_long)sizeof(cmd->sense_buffer));
+                                        (u_long)SCSI_SENSE_BUFFERSIZE);
                        memcpy(cmd->sense_buffer,
                               ahc_get_sense_buf(ahc, scb), sense_size);
-                       if (sense_size < sizeof(cmd->sense_buffer))
+                       if (sense_size < SCSI_SENSE_BUFFERSIZE)
                                memset(&cmd->sense_buffer[sense_size], 0,
-                                      sizeof(cmd->sense_buffer) - sense_size);
+                                      SCSI_SENSE_BUFFERSIZE - sense_size);
                        cmd->result |= (DRIVER_SENSE << 24);
 #ifdef AHC_DEBUG
                        if (ahc_debug & AHC_SHOW_SENSE) {
index 8f8db5f0aef7306568ecf32f2324ff8378ef6bfd..bcb0b870320c166b56f2c08c6ee07113d6fa915d 100644 (file)
@@ -2696,7 +2696,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   {
     pci_unmap_single(p->pdev,
                      le32_to_cpu(scb->sg_list[0].address),
-                     sizeof(cmd->sense_buffer),
+                     SCSI_SENSE_BUFFERSIZE,
                      PCI_DMA_FROMDEVICE);
   }
   if (scb->flags & SCB_RECOVERY_SCB)
@@ -4267,13 +4267,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                        sizeof(generic_sense));
 
                 scb->sense_cmd[1] = (cmd->device->lun << 5);
-                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+                scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE;
 
                 scb->sg_list[0].length = 
-                  cpu_to_le32(sizeof(cmd->sense_buffer));
+                  cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
                scb->sg_list[0].address =
                         cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
-                                                   sizeof(cmd->sense_buffer),
+                                                   SCSI_SENSE_BUFFERSIZE,
                                                    PCI_DMA_FROMDEVICE));
 
                 /*
@@ -4296,7 +4296,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 hscb->residual_data_count[2] = 0;
 
                 scb->sg_count = hscb->SG_segment_count = 1;
-                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->sg_length = SCSI_SENSE_BUFFERSIZE;
                 scb->tag_action = 0;
                 scb->flags |= SCB_SENSE;
                 /*
@@ -10293,7 +10293,6 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
   aic7xxx_position(cmd) = scb->hscb->tag;
   cmd->scsi_done = fn;
   cmd->result = DID_OK;
-  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
   aic7xxx_error(cmd) = DID_OK;
   aic7xxx_status(cmd) = 0;
   cmd->host_scribble = NULL;
index 3dce618bf4148c293f4eff51b7f2ac27c1c22277..72042cae7768551a68e597c4a1734ec1eb9f74f1 100644 (file)
@@ -165,7 +165,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
        if (dev->port->oob_mode != SATA_OOB_MODE) {
                flags |= OPEN_REQUIRED;
                if ((dev->dev_type == SATA_DEV) ||
-                   (dev->tproto & SAS_PROTO_STP)) {
+                   (dev->tproto & SAS_PROTOCOL_STP)) {
                        struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
                        if (rps_resp->frame_type == SMP_RESPONSE &&
                            rps_resp->function == SMP_REPORT_PHY_SATA &&
@@ -193,7 +193,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
        asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
 
        flags = 0;
-       if (dev->tproto & SAS_PROTO_STP)
+       if (dev->tproto & SAS_PROTOCOL_STP)
                flags |= STP_CL_POL_NO_TX;
        asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
 
@@ -201,7 +201,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
        asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
        asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
 
-       if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
+       if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
                i = asd_init_sata(dev);
                if (i < 0) {
                        asd_free_ddb(asd_ha, ddb);
index 6bd8e3059d27d8a551b823c7dc54007f956d3380..3d8c4ff1f2efe225628f6d082b47c4bf84d1374f 100644 (file)
@@ -903,11 +903,11 @@ void asd_dump_frame_rcvd(struct asd_phy *phy,
        int i;
 
        switch ((dl->status_block[1] & 0x70) >> 3) {
-       case SAS_PROTO_STP:
+       case SAS_PROTOCOL_STP:
                ASD_DPRINTK("STP proto device-to-host FIS:\n");
                break;
        default:
-       case SAS_PROTO_SSP:
+       case SAS_PROTOCOL_SSP:
                ASD_DPRINTK("SAS proto IDENTIFY:\n");
                break;
        }
index 0cd7eed9196c44eec8065fd71be58d9c2359af0c..098b5f39cd31b3a2da7954e8488e265de442fdf0 100644 (file)
@@ -91,7 +91,7 @@ static int asd_init_phy(struct asd_phy *phy)
 
        sas_phy->enabled = 1;
        sas_phy->class = SAS;
-       sas_phy->iproto = SAS_PROTO_ALL;
+       sas_phy->iproto = SAS_PROTOCOL_ALL;
        sas_phy->tproto = 0;
        sas_phy->type = PHY_TYPE_PHYSICAL;
        sas_phy->role = PHY_ROLE_INITIATOR;
index 491e5d8a98bcffe819a11998f5110ef265f4ca0a..150f6706d23f8d95a024fbd5836da76bcd8ac91c 100644 (file)
@@ -72,6 +72,7 @@ struct flash_struct {
        u8     manuf;
        u8     dev_id;
        u8     sec_prot;
+       u8     method;
 
        u32    dir_offs;
 };
@@ -216,6 +217,8 @@ struct asd_ha_struct {
        struct dma_pool  *scb_pool;
 
        struct asd_seq_data  seq; /* sequencer related */
+       u32    bios_status;
+       const struct firmware *bios_image;
 };
 
 /* ---------- Common macros ---------- */
index b70d6e7f96e951e55829cc118337946e80dc7101..5d761eb67442356fa50e360e4cde33af360c8612 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 
 #include <scsi/scsi_host.h>
 
@@ -36,6 +37,7 @@
 #include "aic94xx_reg.h"
 #include "aic94xx_hwi.h"
 #include "aic94xx_seq.h"
+#include "aic94xx_sds.h"
 
 /* The format is "version.release.patchlevel" */
 #define ASD_DRIVER_VERSION "1.0.3"
@@ -134,7 +136,7 @@ Err:
        return err;
 }
 
-static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
 {
        struct asd_ha_addrspace *io_handle;
 
@@ -171,7 +173,7 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
        return err;
 }
 
-static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ioport(struct asd_ha_struct *asd_ha)
 {
        pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
 }
@@ -208,7 +210,7 @@ Err:
        return err;
 }
 
-static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ha(struct asd_ha_struct *asd_ha)
 {
        if (asd_ha->iospace)
                asd_unmap_ioport(asd_ha);
@@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
 }
 static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
 
+#define FLASH_CMD_NONE      0x00
+#define FLASH_CMD_UPDATE    0x01
+#define FLASH_CMD_VERIFY    0x02
+
+struct flash_command {
+     u8      command[8];
+     int     code;
+};
+
+static struct flash_command flash_command_table[] =
+{
+     {"verify",      FLASH_CMD_VERIFY},
+     {"update",      FLASH_CMD_UPDATE},
+     {"",            FLASH_CMD_NONE}      /* Last entry should be NULL. */
+};
+
+struct error_bios {
+     char    *reason;
+     int     err_code;
+};
+
+static struct error_bios flash_error_table[] =
+{
+     {"Failed to open bios image file",      FAIL_OPEN_BIOS_FILE},
+     {"PCI ID mismatch",                     FAIL_CHECK_PCI_ID},
+     {"Checksum mismatch",                   FAIL_CHECK_SUM},
+     {"Unknown Error",                       FAIL_UNKNOWN},
+     {"Failed to verify.",                   FAIL_VERIFY},
+     {"Failed to reset flash chip.",         FAIL_RESET_FLASH},
+     {"Failed to find flash chip type.",     FAIL_FIND_FLASH_ID},
+     {"Failed to erash flash chip.",         FAIL_ERASE_FLASH},
+     {"Failed to program flash chip.",       FAIL_WRITE_FLASH},
+     {"Flash in progress",                   FLASH_IN_PROGRESS},
+     {"Image file size Error",               FAIL_FILE_SIZE},
+     {"Input parameter error",               FAIL_PARAMETERS},
+     {"Out of memory",                       FAIL_OUT_MEMORY},
+     {"OK", 0} /* Last entry err_code = 0. */
+};
+
+static ssize_t asd_store_update_bios(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+       char *cmd_ptr, *filename_ptr;
+       struct bios_file_header header, *hdr_ptr;
+       int res, i;
+       u32 csum = 0;
+       int flash_command = FLASH_CMD_NONE;
+       int err = 0;
+
+       cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+
+       if (!cmd_ptr) {
+               err = FAIL_OUT_MEMORY;
+               goto out;
+       }
+
+       filename_ptr = cmd_ptr + count;
+       res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
+       if (res != 2) {
+               err = FAIL_PARAMETERS;
+               goto out1;
+       }
+
+       for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
+               if (!memcmp(flash_command_table[i].command,
+                                cmd_ptr, strlen(cmd_ptr))) {
+                       flash_command = flash_command_table[i].code;
+                       break;
+               }
+       }
+       if (flash_command == FLASH_CMD_NONE) {
+               err = FAIL_PARAMETERS;
+               goto out1;
+       }
+
+       if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
+               err = FLASH_IN_PROGRESS;
+               goto out1;
+       }
+       err = request_firmware(&asd_ha->bios_image,
+                                  filename_ptr,
+                                  &asd_ha->pcidev->dev);
+       if (err) {
+               asd_printk("Failed to load bios image file %s, error %d\n",
+                          filename_ptr, err);
+               err = FAIL_OPEN_BIOS_FILE;
+               goto out1;
+       }
+
+       hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
+
+       if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
+               hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
+               (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
+               hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
+
+               ASD_DPRINTK("The PCI vendor or device id does not match\n");
+               ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
+               " pci vendor=%x pci dev=%x\n",
+               hdr_ptr->contrl_id.vendor,
+               hdr_ptr->contrl_id.device,
+               hdr_ptr->contrl_id.sub_vendor,
+               hdr_ptr->contrl_id.sub_device,
+               asd_ha->pcidev->vendor,
+               asd_ha->pcidev->device);
+               err = FAIL_CHECK_PCI_ID;
+               goto out2;
+       }
+
+       if (hdr_ptr->filelen != asd_ha->bios_image->size) {
+               err = FAIL_FILE_SIZE;
+               goto out2;
+       }
+
+       /* calculate checksum */
+       for (i = 0; i < hdr_ptr->filelen; i++)
+               csum += asd_ha->bios_image->data[i];
+
+       if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
+               ASD_DPRINTK("BIOS file checksum mismatch\n");
+               err = FAIL_CHECK_SUM;
+               goto out2;
+       }
+       if (flash_command == FLASH_CMD_UPDATE) {
+               asd_ha->bios_status = FLASH_IN_PROGRESS;
+               err = asd_write_flash_seg(asd_ha,
+                       &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+                       0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+               if (!err)
+                       err = asd_verify_flash_seg(asd_ha,
+                               &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+                               0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+       } else {
+               asd_ha->bios_status = FLASH_IN_PROGRESS;
+               err = asd_verify_flash_seg(asd_ha,
+                       &asd_ha->bios_image->data[sizeof(header)],
+                       0, hdr_ptr->filelen-sizeof(header));
+       }
+
+out2:
+       release_firmware(asd_ha->bios_image);
+out1:
+       kfree(cmd_ptr);
+out:
+       asd_ha->bios_status = err;
+
+       if (!err)
+               return count;
+       else
+               return -err;
+}
+
+static ssize_t asd_show_update_bios(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       int i;
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+
+       for (i = 0; flash_error_table[i].err_code != 0; i++) {
+               if (flash_error_table[i].err_code == asd_ha->bios_status)
+                       break;
+       }
+       if (asd_ha->bios_status != FLASH_IN_PROGRESS)
+               asd_ha->bios_status = FLASH_OK;
+
+       return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
+                       flash_error_table[i].err_code,
+                       flash_error_table[i].reason);
+}
+
+static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
+       asd_show_update_bios, asd_store_update_bios);
+
 static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
 {
        int err;
@@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
        err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
        if (err)
                goto err_biosb;
+       err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
+       if (err)
+               goto err_update_bios;
 
        return 0;
 
+err_update_bios:
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
 err_biosb:
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
 err_rev:
@@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
 }
 
 /* The first entry, 0, is used for dynamic ids, the rest for devices
@@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
        asd_ha->sas_ha.lldd_ha = asd_ha;
 
+       asd_ha->bios_status = FLASH_OK;
        asd_ha->name = asd_dev->name;
        asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
 
index db6ab1a3b81e888f5ae9469c70285b6c6af0a965..0febad4dd75f69bdf631fb0c847cc25cfe4ec518 100644 (file)
@@ -788,12 +788,12 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
 
                /* initiator port settings are in the hi nibble */
                if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
-                       control_phy->port_type = SAS_PROTO_ALL << 4;
+                       control_phy->port_type = SAS_PROTOCOL_ALL << 4;
                else if (phy->sas_phy.role == PHY_ROLE_TARGET)
-                       control_phy->port_type = SAS_PROTO_ALL;
+                       control_phy->port_type = SAS_PROTOCOL_ALL;
                else
                        control_phy->port_type =
-                               (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
+                               (SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL;
 
                /* link reset retries, this should be nominal */
                control_phy->link_reset_retries = 10;
index 06509bff71f7b5fa23cbd37295ba0294c4e99cee..2a4c933eb89c060a906da809908dd7fb929747e1 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "aic94xx.h"
 #include "aic94xx_reg.h"
+#include "aic94xx_sds.h"
 
 /* ---------- OCM stuff ---------- */
 
@@ -1083,3 +1084,391 @@ out:
        kfree(flash_dir);
        return err;
 }
+
+/**
+ * asd_verify_flash_seg - verify data with flash memory
+ * @asd_ha: pointer to the host adapter structure
+ * @src: pointer to the source data to be verified
+ * @dest_offset: offset from flash memory
+ * @bytes_to_verify: total bytes to verify
+ */
+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
+               void *src, u32 dest_offset, u32 bytes_to_verify)
+{
+       u8 *src_buf;
+       u8 flash_char;
+       int err;
+       u32 nv_offset, reg, i;
+
+       reg = asd_ha->hw_prof.flash.bar;
+       src_buf = NULL;
+
+       err = FLASH_OK;
+       nv_offset = dest_offset;
+       src_buf = (u8 *)src;
+       for (i = 0; i < bytes_to_verify; i++) {
+               flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i);
+               if (flash_char != src_buf[i]) {
+                       err = FAIL_VERIFY;
+                       break;
+               }
+       }
+       return err;
+}
+
+/**
+ * asd_write_flash_seg - write data into flash memory
+ * @asd_ha: pointer to the host adapter structure
+ * @src: pointer to the source data to be written
+ * @dest_offset: offset from flash memory
+ * @bytes_to_write: total bytes to write
+ */
+int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
+               void *src, u32 dest_offset, u32 bytes_to_write)
+{
+       u8 *src_buf;
+       u32 nv_offset, reg, i;
+       int err;
+
+       reg = asd_ha->hw_prof.flash.bar;
+       src_buf = NULL;
+
+       err = asd_check_flash_type(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err);
+               return err;
+       }
+
+       nv_offset = dest_offset;
+       err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write);
+       if (err) {
+               ASD_DPRINTK("Erase failed at offset:0x%x\n",
+                       nv_offset);
+               return err;
+       }
+
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+               return err;
+       }
+
+       src_buf = (u8 *)src;
+       for (i = 0; i < bytes_to_write; i++) {
+               /* Setup program command sequence */
+               switch (asd_ha->hw_prof.flash.method) {
+               case FLASH_METHOD_A:
+               {
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + 0xAAA), 0xAA);
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + 0x555), 0x55);
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + 0xAAA), 0xA0);
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + nv_offset + i),
+                                       (*(src_buf + i)));
+                       break;
+               }
+               case FLASH_METHOD_B:
+               {
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + 0x555), 0xAA);
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + 0x2AA), 0x55);
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + 0x555), 0xA0);
+                       asd_write_reg_byte(asd_ha,
+                                       (reg + nv_offset + i),
+                                       (*(src_buf + i)));
+                       break;
+               }
+               default:
+                       break;
+               }
+               if (asd_chk_write_status(asd_ha,
+                               (nv_offset + i), 0) != 0) {
+                       ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
+                               reg + nv_offset + i);
+                       return FAIL_WRITE_FLASH;
+               }
+       }
+
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+               return err;
+       }
+       return 0;
+}
+
+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
+        u32 sector_addr, u8 erase_flag)
+{
+       u32 reg;
+       u32 loop_cnt;
+       u8  nv_data1, nv_data2;
+       u8  toggle_bit1;
+
+       /*
+        * Read from DQ2 requires sector address
+        * while it's dont care for DQ6
+        */
+       reg = asd_ha->hw_prof.flash.bar;
+
+       for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) {
+               nv_data1 = asd_read_reg_byte(asd_ha, reg);
+               nv_data2 = asd_read_reg_byte(asd_ha, reg);
+
+               toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
+                                ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
+
+               if (toggle_bit1 == 0) {
+                       return 0;
+               } else {
+                       if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
+                               nv_data1 = asd_read_reg_byte(asd_ha,
+                                                               reg);
+                               nv_data2 = asd_read_reg_byte(asd_ha,
+                                                               reg);
+                               toggle_bit1 =
+                               ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
+                               ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
+
+                               if (toggle_bit1 == 0)
+                                       return 0;
+                       }
+               }
+
+               /*
+                * ERASE is a sector-by-sector operation and requires
+                * more time to finish while WRITE is byte-byte-byte
+                * operation and takes lesser time to finish.
+                *
+                * For some strange reason a reduced ERASE delay gives different
+                * behaviour across different spirit boards. Hence we set
+                * a optimum balance of 50mus for ERASE which works well
+                * across all boards.
+                */
+               if (erase_flag) {
+                       udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
+               } else {
+                       udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
+               }
+       }
+       return -1;
+}
+
+/**
+ * asd_hwi_erase_nv_sector - Erase the flash memory sectors.
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_addr: pointer to offset from flash memory
+ * @size: total bytes to erase.
+ */
+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size)
+{
+       u32 reg;
+       u32 sector_addr;
+
+       reg = asd_ha->hw_prof.flash.bar;
+
+       /* sector staring address */
+       sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
+
+       /*
+        * Erasing an flash sector needs to be done in six consecutive
+        * write cyles.
+        */
+       while (sector_addr < flash_addr+size) {
+               switch (asd_ha->hw_prof.flash.method) {
+               case FLASH_METHOD_A:
+                       asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
+                       asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
+                       break;
+               case FLASH_METHOD_B:
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
+                       break;
+               default:
+                       break;
+               }
+
+               if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0)
+                       return FAIL_ERASE_FLASH;
+
+               sector_addr += FLASH_SECTOR_SIZE;
+       }
+
+       return 0;
+}
+
+int asd_check_flash_type(struct asd_ha_struct *asd_ha)
+{
+       u8 manuf_id;
+       u8 dev_id;
+       u8 sec_prot;
+       u32 inc;
+       u32 reg;
+       int err;
+
+       /* get Flash memory base address */
+       reg = asd_ha->hw_prof.flash.bar;
+
+       /* Determine flash info */
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+               return err;
+       }
+
+       asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
+       asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
+       asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
+
+       /* Get flash info. This would most likely be AMD Am29LV family flash.
+        * First try the sequence for word mode.  It is the same as for
+        * 008B (byte mode only), 160B (word mode) and 800D (word mode).
+        */
+       inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
+       asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
+       asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
+       asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
+       manuf_id = asd_read_reg_byte(asd_ha, reg);
+       dev_id = asd_read_reg_byte(asd_ha, reg + inc);
+       sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
+       /* Get out of autoselect mode. */
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+               return err;
+       }
+       ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) "
+               "sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot);
+       err = asd_reset_flash(asd_ha);
+       if (err != 0)
+               return err;
+
+       switch (manuf_id) {
+       case FLASH_MANUF_ID_AMD:
+               switch (sec_prot) {
+               case FLASH_DEV_ID_AM29LV800DT:
+               case FLASH_DEV_ID_AM29LV640MT:
+               case FLASH_DEV_ID_AM29F800B:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case FLASH_MANUF_ID_ST:
+               switch (sec_prot) {
+               case FLASH_DEV_ID_STM29W800DT:
+               case FLASH_DEV_ID_STM29LV640:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case FLASH_MANUF_ID_FUJITSU:
+               switch (sec_prot) {
+               case FLASH_DEV_ID_MBM29LV800TE:
+               case FLASH_DEV_ID_MBM29DL800TA:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               }
+               break;
+       case FLASH_MANUF_ID_MACRONIX:
+               switch (sec_prot) {
+               case FLASH_DEV_ID_MX29LV800BT:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               }
+               break;
+       }
+
+       if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
+               err = asd_reset_flash(asd_ha);
+               if (err) {
+                       ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+                       return err;
+               }
+
+               /* Issue Unlock sequence for AM29LV008BT */
+               asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+               asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+               asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
+               manuf_id = asd_read_reg_byte(asd_ha, reg);
+               dev_id = asd_read_reg_byte(asd_ha, reg + inc);
+               sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
+
+               ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot"
+                       "(0x%x)\n", manuf_id, dev_id, sec_prot);
+
+               err = asd_reset_flash(asd_ha);
+               if (err != 0) {
+                       ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+                       return err;
+               }
+
+               switch (manuf_id) {
+               case FLASH_MANUF_ID_AMD:
+                       switch (dev_id) {
+                       case FLASH_DEV_ID_AM29LV008BT:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case FLASH_MANUF_ID_ST:
+                       switch (dev_id) {
+                       case FLASH_DEV_ID_STM29008:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case FLASH_MANUF_ID_FUJITSU:
+                       switch (dev_id) {
+                       case FLASH_DEV_ID_MBM29LV008TA:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       }
+                       break;
+               case FLASH_MANUF_ID_INTEL:
+                       switch (dev_id) {
+                       case FLASH_DEV_ID_I28LV00TAT:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       }
+                       break;
+               case FLASH_MANUF_ID_MACRONIX:
+                       switch (dev_id) {
+                       case FLASH_DEV_ID_I28LV00TAT:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       }
+                       break;
+               default:
+                       return FAIL_FIND_FLASH_ID;
+               }
+       }
+
+       if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
+             return FAIL_FIND_FLASH_ID;
+
+       asd_ha->hw_prof.flash.manuf = manuf_id;
+       asd_ha->hw_prof.flash.dev_id = dev_id;
+       asd_ha->hw_prof.flash.sec_prot = sec_prot;
+       return 0;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h
new file mode 100644 (file)
index 0000000..bb9795a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Gilbert Wu <gilbert_wu@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#ifndef _AIC94XX_SDS_H_
+#define _AIC94XX_SDS_H_
+
+enum {
+       FLASH_METHOD_UNKNOWN,
+       FLASH_METHOD_A,
+       FLASH_METHOD_B
+};
+
+#define FLASH_MANUF_ID_AMD              0x01
+#define FLASH_MANUF_ID_ST               0x20
+#define FLASH_MANUF_ID_FUJITSU          0x04
+#define FLASH_MANUF_ID_MACRONIX         0xC2
+#define FLASH_MANUF_ID_INTEL            0x89
+#define FLASH_MANUF_ID_UNKNOWN          0xFF
+
+#define FLASH_DEV_ID_AM29LV008BT        0x3E
+#define FLASH_DEV_ID_AM29LV800DT        0xDA
+#define FLASH_DEV_ID_STM29W800DT        0xD7
+#define FLASH_DEV_ID_STM29LV640         0xDE
+#define FLASH_DEV_ID_STM29008           0xEA
+#define FLASH_DEV_ID_MBM29LV800TE       0xDA
+#define FLASH_DEV_ID_MBM29DL800TA       0x4A
+#define FLASH_DEV_ID_MBM29LV008TA       0x3E
+#define FLASH_DEV_ID_AM29LV640MT        0x7E
+#define FLASH_DEV_ID_AM29F800B          0xD6
+#define FLASH_DEV_ID_MX29LV800BT        0xDA
+#define FLASH_DEV_ID_MX29LV008CT        0xDA
+#define FLASH_DEV_ID_I28LV00TAT         0x3E
+#define FLASH_DEV_ID_UNKNOWN            0xFF
+
+/* status bit mask values */
+#define FLASH_STATUS_BIT_MASK_DQ6       0x40
+#define FLASH_STATUS_BIT_MASK_DQ5       0x20
+#define FLASH_STATUS_BIT_MASK_DQ2       0x04
+
+/* minimum value in micro seconds needed for checking status */
+#define FLASH_STATUS_ERASE_DELAY_COUNT  50
+#define FLASH_STATUS_WRITE_DELAY_COUNT  25
+
+#define FLASH_SECTOR_SIZE               0x010000
+#define FLASH_SECTOR_SIZE_MASK          0xffff0000
+
+#define FLASH_OK                        0x000000
+#define FAIL_OPEN_BIOS_FILE             0x000100
+#define FAIL_CHECK_PCI_ID               0x000200
+#define FAIL_CHECK_SUM                  0x000300
+#define FAIL_UNKNOWN                    0x000400
+#define FAIL_VERIFY                     0x000500
+#define FAIL_RESET_FLASH                0x000600
+#define FAIL_FIND_FLASH_ID              0x000700
+#define FAIL_ERASE_FLASH                0x000800
+#define FAIL_WRITE_FLASH                0x000900
+#define FAIL_FILE_SIZE                  0x000a00
+#define FAIL_PARAMETERS                 0x000b00
+#define FAIL_OUT_MEMORY                 0x000c00
+#define FLASH_IN_PROGRESS               0x001000
+
+struct controller_id {
+       u32 vendor;     /* PCI Vendor ID */
+       u32 device;     /* PCI Device ID */
+       u32 sub_vendor; /* PCI Subvendor ID */
+       u32 sub_device; /* PCI Subdevice ID */
+};
+
+struct image_info {
+       u32 ImageId;       /* Identifies the image */
+       u32 ImageOffset;   /* Offset the beginning of the file */
+       u32 ImageLength;   /* length of the image */
+       u32 ImageChecksum; /* Image checksum */
+       u32 ImageVersion;  /* Version of the image, could be build number */
+};
+
+struct bios_file_header {
+       u8 signature[32]; /* Signature/Cookie to identify the file */
+       u32 checksum;     /*Entire file checksum with this field zero */
+       u32 antidote;     /* Entire file checksum with this field 0xFFFFFFFF */
+       struct controller_id contrl_id; /*PCI id to identify the controller */
+       u32 filelen;      /*Length of the entire file*/
+       u32 chunk_num;    /*The chunk/part number for multiple Image files */
+       u32 total_chunks; /*Total number of chunks/parts in the image file */
+       u32 num_images;   /* Number of images in the file */
+       u32 build_num;    /* Build number of this image */
+       struct image_info image_header;
+};
+
+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
+               void *src, u32 dest_offset, u32 bytes_to_verify);
+int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
+               void *src, u32 dest_offset, u32 bytes_to_write);
+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
+               u32 sector_addr, u8 erase_flag);
+int asd_check_flash_type(struct asd_ha_struct *asd_ha);
+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha,
+               u32 flash_addr, u32 size);
+#endif
index ee0a98bffcd4c0fec572afd6e67e707c4ddb1cca..965d4bb999d919f314ec83e810c8ad85b0f17075 100644 (file)
@@ -187,29 +187,13 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
        ts->buf_valid_size = 0;
        edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
        r = edb->vaddr;
-       if (task->task_proto == SAS_PROTO_SSP) {
+       if (task->task_proto == SAS_PROTOCOL_SSP) {
                struct ssp_response_iu *iu =
                        r + 16 + sizeof(struct ssp_frame_hdr);
 
                ts->residual = le32_to_cpu(*(__le32 *)r);
-               ts->resp = SAS_TASK_COMPLETE;
-               if (iu->datapres == 0)
-                       ts->stat = iu->status;
-               else if (iu->datapres == 1)
-                       ts->stat = iu->resp_data[3];
-               else if (iu->datapres == 2) {
-                       ts->stat = SAM_CHECK_COND;
-                       ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
-                                        be32_to_cpu(iu->sense_data_len));
-                       memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
-                       if (iu->status != SAM_CHECK_COND) {
-                               ASD_DPRINTK("device %llx sent sense data, but "
-                                           "stat(0x%x) is not CHECK_CONDITION"
-                                           "\n",
-                                           SAS_ADDR(task->dev->sas_addr),
-                                           iu->status);
-                       }
-               }
+
+               sas_ssp_task_response(&asd_ha->pcidev->dev, task, iu);
        }  else {
                struct ata_task_resp *resp = (void *) &ts->buf[0];
 
@@ -341,14 +325,14 @@ Again:
        }
 
        switch (task->task_proto) {
-       case SATA_PROTO:
-       case SAS_PROTO_STP:
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
                asd_unbuild_ata_ascb(ascb);
                break;
-       case SAS_PROTO_SMP:
+       case SAS_PROTOCOL_SMP:
                asd_unbuild_smp_ascb(ascb);
                break;
-       case SAS_PROTO_SSP:
+       case SAS_PROTOCOL_SSP:
                asd_unbuild_ssp_ascb(ascb);
        default:
                break;
@@ -586,17 +570,17 @@ int asd_execute_task(struct sas_task *task, const int num,
        list_for_each_entry(a, &alist, list) {
                t = a->uldd_task;
                a->uldd_timer = 1;
-               if (t->task_proto & SAS_PROTO_STP)
-                       t->task_proto = SAS_PROTO_STP;
+               if (t->task_proto & SAS_PROTOCOL_STP)
+                       t->task_proto = SAS_PROTOCOL_STP;
                switch (t->task_proto) {
-               case SATA_PROTO:
-               case SAS_PROTO_STP:
+               case SAS_PROTOCOL_SATA:
+               case SAS_PROTOCOL_STP:
                        res = asd_build_ata_ascb(a, t, gfp_flags);
                        break;
-               case SAS_PROTO_SMP:
+               case SAS_PROTOCOL_SMP:
                        res = asd_build_smp_ascb(a, t, gfp_flags);
                        break;
-               case SAS_PROTO_SSP:
+               case SAS_PROTOCOL_SSP:
                        res = asd_build_ssp_ascb(a, t, gfp_flags);
                        break;
                default:
@@ -633,14 +617,14 @@ out_err_unmap:
                        t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
                        spin_unlock_irqrestore(&t->task_state_lock, flags);
                        switch (t->task_proto) {
-                       case SATA_PROTO:
-                       case SAS_PROTO_STP:
+                       case SAS_PROTOCOL_SATA:
+                       case SAS_PROTOCOL_STP:
                                asd_unbuild_ata_ascb(a);
                                break;
-                       case SAS_PROTO_SMP:
+                       case SAS_PROTOCOL_SMP:
                                asd_unbuild_smp_ascb(a);
                                break;
-                       case SAS_PROTO_SSP:
+                       case SAS_PROTOCOL_SSP:
                                asd_unbuild_ssp_ascb(a);
                        default:
                                break;
index c0d0b7d7a8ce0d34b33dc7b4a8ea3990e6212155..87b2f6e6adfef417b346014ba7c566ea4a4a6e10 100644 (file)
@@ -372,21 +372,21 @@ int asd_abort_task(struct sas_task *task)
        scb->header.opcode = ABORT_TASK;
 
        switch (task->task_proto) {
-       case SATA_PROTO:
-       case SAS_PROTO_STP:
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
                scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
                break;
-       case SAS_PROTO_SSP:
+       case SAS_PROTOCOL_SSP:
                scb->abort_task.proto_conn_rate  = (1 << 4); /* SSP */
                scb->abort_task.proto_conn_rate |= task->dev->linkrate;
                break;
-       case SAS_PROTO_SMP:
+       case SAS_PROTOCOL_SMP:
                break;
        default:
                break;
        }
 
-       if (task->task_proto == SAS_PROTO_SSP) {
+       if (task->task_proto == SAS_PROTOCOL_SSP) {
                scb->abort_task.ssp_frame.frame_type = SSP_TASK;
                memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
                       task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
@@ -512,7 +512,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
        int res = 1;
        struct scb *scb;
 
-       if (!(dev->tproto & SAS_PROTO_SSP))
+       if (!(dev->tproto & SAS_PROTOCOL_SSP))
                return TMF_RESP_FUNC_ESUPP;
 
        ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
index d466a2dac1dbcba2d5e28d44260408bfa6979792..d80dba913a750c8e051b16ec28215348cb55ef41 100644 (file)
@@ -634,9 +634,9 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
        pcmd->result = DID_OK << 16;
        if (sensebuffer) {
                int sense_data_length =
-                       sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
-                       ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
-               memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
+                       sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
+                       ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
+               memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
                memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
                sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
                sensebuffer->Valid = 1;
index a9680b5e8ac642b11979dfc24f4b7ff789822be9..93b61f148653c5507dc076151c26fde0af73f14c 100644 (file)
@@ -511,9 +511,9 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
         * various queues are valid.
         */
 
-       if (cmd->use_sg) {
-               cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
-               cmd->SCp.buffers_residual = cmd->use_sg - 1;
+       if (scsi_bufflen(cmd)) {
+               cmd->SCp.buffer = scsi_sglist(cmd);
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
                /* ++roman: Try to merge some scatter-buffers if they are at
@@ -523,8 +523,8 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
        } else {
                cmd->SCp.buffer = NULL;
                cmd->SCp.buffers_residual = 0;
-               cmd->SCp.ptr = (char *)cmd->request_buffer;
-               cmd->SCp.this_residual = cmd->request_bufflen;
+               cmd->SCp.ptr = NULL;
+               cmd->SCp.this_residual = 0;
        }
 }
 
@@ -936,21 +936,21 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
        }
 # endif
 # ifdef NCR5380_STAT_LIMIT
-       if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+       if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
                switch (cmd->cmnd[0]) {
                case WRITE:
                case WRITE_6:
                case WRITE_10:
                        hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-                       hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+                       hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
                        hostdata->pendingw++;
                        break;
                case READ:
                case READ_6:
                case READ_10:
                        hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-                       hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+                       hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
                        hostdata->pendingr++;
                        break;
                }
@@ -1352,21 +1352,21 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
 static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
 {
 # ifdef NCR5380_STAT_LIMIT
-       if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+       if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
                switch (cmd->cmnd[0]) {
                case WRITE:
                case WRITE_6:
                case WRITE_10:
                        hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
-                       /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+                       /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
                        hostdata->pendingw--;
                        break;
                case READ:
                case READ_6:
                case READ_10:
                        hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
-                       /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+                       /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
                        hostdata->pendingr--;
                        break;
                }
@@ -1868,7 +1868,7 @@ static int do_abort(struct Scsi_Host *host)
         * the target sees, so we just handshake.
         */
 
-       while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
+       while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
                ;
 
        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
index fec58cc47f1cce78de21d0fc05c878d0a92d4c74..db6de5e6afb3e4d434ec4e1111a34d3fbe0fec18 100644 (file)
@@ -471,18 +471,8 @@ go_42:
                        /*
                         *      Complete the command
                         */
-                       if (workreq->use_sg) {
-                               pci_unmap_sg(dev->pdev,
-                                       (struct scatterlist *)workreq->request_buffer,
-                                       workreq->use_sg,
-                                       workreq->sc_data_direction);
-                       } else if (workreq->request_bufflen &&
-                                       workreq->sc_data_direction != DMA_NONE) {
-                               pci_unmap_single(dev->pdev,
-                                       workreq->SCp.dma_handle,
-                                       workreq->request_bufflen,
-                                       workreq->sc_data_direction);
-                       }                       
+                       scsi_dma_unmap(workreq);
+
                        spin_lock_irqsave(dev->host->host_lock, flags);
                        (*workreq->scsi_done) (workreq);
 #ifdef ED_DBGP
@@ -624,7 +614,7 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p,
 
        c = scmd_channel(req_p);
        req_p->sense_buffer[0]=0;
-       req_p->resid = 0;
+       scsi_set_resid(req_p, 0);
        if (scmd_channel(req_p) > 1) {
                req_p->result = 0x00040000;
                done(req_p);
@@ -722,7 +712,6 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
        unsigned short int tmpcip, w;
        unsigned long l, bttl = 0;
        unsigned int workport;
-       struct scatterlist *sgpnt;
        unsigned long  sg_count;
 
        if (dev->in_snd[c] != 0) {
@@ -793,6 +782,8 @@ oktosend:
        }
        printk("\n");
 #endif 
+       l = scsi_bufflen(workreq);
+
        if (dev->dev_id == ATP885_DEVID) {
                j = inb(dev->baseport + 0x29) & 0xfe;
                outb(j, dev->baseport + 0x29);
@@ -800,12 +791,11 @@ oktosend:
        }
        
        if (workreq->cmnd[0] == READ_CAPACITY) {
-               if (workreq->request_bufflen > 8) {
-                       workreq->request_bufflen = 0x08;
-               }
+               if (l > 8)
+                       l = 8;
        }
        if (workreq->cmnd[0] == 0x00) {
-               workreq->request_bufflen = 0;
+               l = 0;
        }
 
        tmport = workport + 0x1b;
@@ -852,40 +842,8 @@ oktosend:
 #ifdef ED_DBGP 
        printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
 #endif
-       /*
-        *      Figure out the transfer size
-        */
-       if (workreq->use_sg) {
-#ifdef ED_DBGP
-               printk("Using SGL\n");
-#endif         
-               l = 0;
-               
-               sgpnt = (struct scatterlist *) workreq->request_buffer;
-               sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg,
-                               workreq->sc_data_direction);            
-               
-               for (i = 0; i < workreq->use_sg; i++) {
-                       if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) {
-                               panic("Foooooooood fight!");
-                       }
-                       l += sgpnt[i].length;
-               }
-#ifdef ED_DBGP         
-               printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);
-#endif
-       } else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {
-#ifdef ED_DBGP
-               printk("Not using SGL\n");
-#endif                                 
-               workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer,
-                               workreq->request_bufflen,
-                               workreq->sc_data_direction);            
-               l = workreq->request_bufflen;
-#ifdef ED_DBGP         
-               printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);
-#endif
-       } else l = 0;
+
+       sg_count = scsi_dma_map(workreq);
        /*
         *      Write transfer size
         */
@@ -938,16 +896,16 @@ oktosend:
         *      a linear chain.
         */
 
-       if (workreq->use_sg) {
-               sgpnt = (struct scatterlist *) workreq->request_buffer;
+       if (l) {
+               struct scatterlist *sgpnt;
                i = 0;
-               for (j = 0; j < workreq->use_sg; j++) {
-                       bttl = sg_dma_address(&sgpnt[j]);
-                       l=sg_dma_len(&sgpnt[j]);
+               scsi_for_each_sg(workreq, sgpnt, sg_count, j) {
+                       bttl = sg_dma_address(sgpnt);
+                       l=sg_dma_len(sgpnt);
 #ifdef ED_DBGP         
-               printk("1. bttl %x, l %x\n",bttl, l);
+                       printk("1. bttl %x, l %x\n",bttl, l);
 #endif                 
-               while (l > 0x10000) {
+                       while (l > 0x10000) {
                                (((u16 *) (prd))[i + 3]) = 0x0000;
                                (((u16 *) (prd))[i + 2]) = 0x0000;
                                (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
@@ -965,32 +923,6 @@ oktosend:
                printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
                printk("2. bttl %x, l %x\n",bttl, l);
 #endif                 
-       } else {
-               /*
-                *      For a linear request write a chain of blocks
-                */        
-               bttl = workreq->SCp.dma_handle;
-               l = workreq->request_bufflen;
-               i = 0;
-#ifdef ED_DBGP         
-               printk("3. bttl %x, l %x\n",bttl, l);
-#endif                 
-               while (l > 0x10000) {
-                               (((u16 *) (prd))[i + 3]) = 0x0000;
-                               (((u16 *) (prd))[i + 2]) = 0x0000;
-                               (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
-                               l -= 0x10000;
-                               bttl += 0x10000;
-                               i += 0x04;
-                       }
-                       (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
-                       (((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
-                       (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);          
-#ifdef ED_DBGP         
-               printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
-               printk("4. bttl %x, l %x\n",bttl, l);
-#endif                 
-               
        }
        tmpcip += 4;
 #ifdef ED_DBGP         
index 2311019304c00ef22ec4a8b63167a7c65c7dc488..7aad15436d24d25002cfacee35837401db5e5bee 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/compat.h>
 #include <linux/chio.h>                        /* here are all the ioctls */
 #include <linux/mutex.h>
+#include <linux/idr.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -33,6 +34,7 @@
 
 #define CH_DT_MAX       16
 #define CH_TYPES        8
+#define CH_MAX_DEVS     128
 
 MODULE_DESCRIPTION("device driver for scsi media changer devices");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
@@ -88,17 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = {
 
 #define MAX_RETRIES   1
 
-static int  ch_probe(struct device *);
-static int  ch_remove(struct device *);
-static int  ch_open(struct inode * inode, struct file * filp);
-static int  ch_release(struct inode * inode, struct file * filp);
-static int  ch_ioctl(struct inode * inode, struct file * filp,
-                    unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long ch_ioctl_compat(struct file * filp,
-                           unsigned int cmd, unsigned long arg);
-#endif
-
 static struct class * ch_sysfs_class;
 
 typedef struct {
@@ -114,30 +105,8 @@ typedef struct {
        struct mutex        lock;
 } scsi_changer;
 
-static LIST_HEAD(ch_devlist);
-static DEFINE_SPINLOCK(ch_devlist_lock);
-static int ch_devcount;
-
-static struct scsi_driver ch_template =
-{
-       .owner          = THIS_MODULE,
-       .gendrv         = {
-               .name   = "ch",
-               .probe  = ch_probe,
-               .remove = ch_remove,
-       },
-};
-
-static const struct file_operations changer_fops =
-{
-       .owner        = THIS_MODULE,
-       .open         = ch_open,
-       .release      = ch_release,
-       .ioctl        = ch_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = ch_ioctl_compat,
-#endif
-};
+static DEFINE_IDR(ch_index_idr);
+static DEFINE_SPINLOCK(ch_index_lock);
 
 static const struct {
        unsigned char  sense;
@@ -207,7 +176,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
 {
        int errno, retries = 0, timeout, result;
        struct scsi_sense_hdr sshdr;
-       
+
        timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
                ? timeout_init : timeout_move;
 
@@ -245,7 +214,7 @@ static int
 ch_elem_to_typecode(scsi_changer *ch, u_int elem)
 {
        int i;
-       
+
        for (i = 0; i < CH_TYPES; i++) {
                if (elem >= ch->firsts[i]  &&
                    elem <  ch->firsts[i] +
@@ -261,15 +230,15 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
        u_char  cmd[12];
        u_char  *buffer;
        int     result;
-       
+
        buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
        if(!buffer)
                return -ENOMEM;
-       
+
  retry:
        memset(cmd,0,sizeof(cmd));
        cmd[0] = READ_ELEMENT_STATUS;
-       cmd[1] = (ch->device->lun << 5) | 
+       cmd[1] = (ch->device->lun << 5) |
                (ch->voltags ? 0x10 : 0) |
                ch_elem_to_typecode(ch,elem);
        cmd[2] = (elem >> 8) & 0xff;
@@ -296,7 +265,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
        return result;
 }
 
-static int 
+static int
 ch_init_elem(scsi_changer *ch)
 {
        int err;
@@ -322,7 +291,7 @@ ch_readconfig(scsi_changer *ch)
        buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
        if (!buffer)
                return -ENOMEM;
-       
+
        memset(cmd,0,sizeof(cmd));
        cmd[0] = MODE_SENSE;
        cmd[1] = ch->device->lun << 5;
@@ -365,7 +334,7 @@ ch_readconfig(scsi_changer *ch)
        } else {
                vprintk("reading element address assigment page failed!\n");
        }
-       
+
        /* vendor specific element types */
        for (i = 0; i < 4; i++) {
                if (0 == vendor_counts[i])
@@ -443,7 +412,7 @@ static int
 ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
 {
        u_char  cmd[10];
-       
+
        dprintk("position: 0x%x\n",elem);
        if (0 == trans)
                trans = ch->firsts[CHET_MT];
@@ -462,7 +431,7 @@ static int
 ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
 {
        u_char  cmd[12];
-       
+
        dprintk("move: 0x%x => 0x%x\n",src,dest);
        if (0 == trans)
                trans = ch->firsts[CHET_MT];
@@ -484,7 +453,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
            u_int dest1, u_int dest2, int rotate1, int rotate2)
 {
        u_char  cmd[12];
-       
+
        dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
                src,dest1,dest2);
        if (0 == trans)
@@ -501,7 +470,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
        cmd[8]  = (dest2 >> 8) & 0xff;
        cmd[9]  =  dest2       & 0xff;
        cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
-       
+
        return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
 }
 
@@ -539,14 +508,14 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
                elem, tag);
        memset(cmd,0,sizeof(cmd));
        cmd[0]  = SEND_VOLUME_TAG;
-       cmd[1] = (ch->device->lun << 5) | 
+       cmd[1] = (ch->device->lun << 5) |
                ch_elem_to_typecode(ch,elem);
        cmd[2] = (elem >> 8) & 0xff;
        cmd[3] = elem        & 0xff;
        cmd[5] = clear
                ? (alternate ? 0x0d : 0x0c)
                : (alternate ? 0x0b : 0x0a);
-       
+
        cmd[9] = 255;
 
        memcpy(buffer,tag,32);
@@ -562,7 +531,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
        int retval = 0;
        u_char data[16];
        unsigned int i;
-       
+
        mutex_lock(&ch->lock);
        for (i = 0; i < ch->counts[type]; i++) {
                if (0 != ch_read_element_status
@@ -599,20 +568,17 @@ ch_release(struct inode *inode, struct file *file)
 static int
 ch_open(struct inode *inode, struct file *file)
 {
-       scsi_changer *tmp, *ch;
+       scsi_changer *ch;
        int minor = iminor(inode);
 
-       spin_lock(&ch_devlist_lock);
-       ch = NULL;
-       list_for_each_entry(tmp,&ch_devlist,list) {
-               if (tmp->minor == minor)
-                       ch = tmp;
-       }
+       spin_lock(&ch_index_lock);
+       ch = idr_find(&ch_index_idr, minor);
+
        if (NULL == ch || scsi_device_get(ch->device)) {
-               spin_unlock(&ch_devlist_lock);
+               spin_unlock(&ch_index_lock);
                return -ENXIO;
        }
-       spin_unlock(&ch_devlist_lock);
+       spin_unlock(&ch_index_lock);
 
        file->private_data = ch;
        return 0;
@@ -626,24 +592,24 @@ ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
        return 0;
 }
 
-static int ch_ioctl(struct inode * inode, struct file * file,
+static long ch_ioctl(struct file *file,
                    unsigned int cmd, unsigned long arg)
 {
        scsi_changer *ch = file->private_data;
        int retval;
        void __user *argp = (void __user *)arg;
-       
+
        switch (cmd) {
        case CHIOGPARAMS:
        {
                struct changer_params params;
-               
+
                params.cp_curpicker = 0;
                params.cp_npickers  = ch->counts[CHET_MT];
                params.cp_nslots    = ch->counts[CHET_ST];
                params.cp_nportals  = ch->counts[CHET_IE];
                params.cp_ndrives   = ch->counts[CHET_DT];
-               
+
                if (copy_to_user(argp, &params, sizeof(params)))
                        return -EFAULT;
                return 0;
@@ -673,11 +639,11 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        return -EFAULT;
                return 0;
        }
-       
+
        case CHIOPOSITION:
        {
                struct changer_position pos;
-               
+
                if (copy_from_user(&pos, argp, sizeof (pos)))
                        return -EFAULT;
 
@@ -692,7 +658,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                mutex_unlock(&ch->lock);
                return retval;
        }
-       
+
        case CHIOMOVE:
        {
                struct changer_move mv;
@@ -705,7 +671,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        dprintk("CHIOMOVE: invalid parameter\n");
                        return -EBADSLT;
                }
-               
+
                mutex_lock(&ch->lock);
                retval = ch_move(ch,0,
                                 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
@@ -718,7 +684,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
        case CHIOEXCHANGE:
        {
                struct changer_exchange mv;
-               
+
                if (copy_from_user(&mv, argp, sizeof (mv)))
                        return -EFAULT;
 
@@ -728,7 +694,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        dprintk("CHIOEXCHANGE: invalid parameter\n");
                        return -EBADSLT;
                }
-               
+
                mutex_lock(&ch->lock);
                retval = ch_exchange
                        (ch,0,
@@ -743,7 +709,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
        case CHIOGSTATUS:
        {
                struct changer_element_status ces;
-               
+
                if (copy_from_user(&ces, argp, sizeof (ces)))
                        return -EFAULT;
                if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
@@ -759,19 +725,19 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                u_char  *buffer;
                unsigned int elem;
                int     result,i;
-               
+
                if (copy_from_user(&cge, argp, sizeof (cge)))
                        return -EFAULT;
 
                if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
                        return -EINVAL;
                elem = ch->firsts[cge.cge_type] + cge.cge_unit;
-               
+
                buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
                if (!buffer)
                        return -ENOMEM;
                mutex_lock(&ch->lock);
-               
+
        voltag_retry:
                memset(cmd,0,sizeof(cmd));
                cmd[0] = READ_ELEMENT_STATUS;
@@ -782,7 +748,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                cmd[3] = elem        & 0xff;
                cmd[5] = 1;
                cmd[9] = 255;
-               
+
                if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
                        cge.cge_status = buffer[18];
                        cge.cge_flags = 0;
@@ -822,7 +788,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                }
                kfree(buffer);
                mutex_unlock(&ch->lock);
-               
+
                if (copy_to_user(argp, &cge, sizeof (cge)))
                        return -EFAULT;
                return result;
@@ -835,7 +801,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                mutex_unlock(&ch->lock);
                return retval;
        }
-               
+
        case CHIOSVOLTAG:
        {
                struct changer_set_voltag csv;
@@ -876,7 +842,7 @@ static long ch_ioctl_compat(struct file * file,
                            unsigned int cmd, unsigned long arg)
 {
        scsi_changer *ch = file->private_data;
-       
+
        switch (cmd) {
        case CHIOGPARAMS:
        case CHIOGVPARAMS:
@@ -887,13 +853,12 @@ static long ch_ioctl_compat(struct file * file,
        case CHIOINITELEM:
        case CHIOSVOLTAG:
                /* compatible */
-               return ch_ioctl(NULL /* inode, unused */,
-                               file, cmd, arg);
+               return ch_ioctl(file, cmd, arg);
        case CHIOGSTATUS32:
        {
                struct changer_element_status32 ces32;
                unsigned char __user *data;
-               
+
                if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
                        return -EFAULT;
                if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
@@ -915,63 +880,100 @@ static long ch_ioctl_compat(struct file * file,
 static int ch_probe(struct device *dev)
 {
        struct scsi_device *sd = to_scsi_device(dev);
+       struct class_device *class_dev;
+       int minor, ret = -ENOMEM;
        scsi_changer *ch;
-       
+
        if (sd->type != TYPE_MEDIUM_CHANGER)
                return -ENODEV;
-    
+
        ch = kzalloc(sizeof(*ch), GFP_KERNEL);
        if (NULL == ch)
                return -ENOMEM;
 
-       ch->minor = ch_devcount;
+       if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
+               goto free_ch;
+
+       spin_lock(&ch_index_lock);
+       ret = idr_get_new(&ch_index_idr, ch, &minor);
+       spin_unlock(&ch_index_lock);
+
+       if (ret)
+               goto free_ch;
+
+       if (minor > CH_MAX_DEVS) {
+               ret = -ENODEV;
+               goto remove_idr;
+       }
+
+       ch->minor = minor;
        sprintf(ch->name,"ch%d",ch->minor);
+
+       class_dev = class_device_create(ch_sysfs_class, NULL,
+                                       MKDEV(SCSI_CHANGER_MAJOR, ch->minor),
+                                       dev, "s%s", ch->name);
+       if (IS_ERR(class_dev)) {
+               printk(KERN_WARNING "ch%d: class_device_create failed\n",
+                      ch->minor);
+               ret = PTR_ERR(class_dev);
+               goto remove_idr;
+       }
+
        mutex_init(&ch->lock);
        ch->device = sd;
        ch_readconfig(ch);
        if (init)
                ch_init_elem(ch);
 
-       class_device_create(ch_sysfs_class, NULL,
-                           MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
-                           dev, "s%s", ch->name);
-
+       dev_set_drvdata(dev, ch);
        sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
-       
-       spin_lock(&ch_devlist_lock);
-       list_add_tail(&ch->list,&ch_devlist);
-       ch_devcount++;
-       spin_unlock(&ch_devlist_lock);
+
        return 0;
+remove_idr:
+       idr_remove(&ch_index_idr, minor);
+free_ch:
+       kfree(ch);
+       return ret;
 }
 
 static int ch_remove(struct device *dev)
 {
-       struct scsi_device *sd = to_scsi_device(dev);
-       scsi_changer *tmp, *ch;
+       scsi_changer *ch = dev_get_drvdata(dev);
 
-       spin_lock(&ch_devlist_lock);
-       ch = NULL;
-       list_for_each_entry(tmp,&ch_devlist,list) {
-               if (tmp->device == sd)
-                       ch = tmp;
-       }
-       BUG_ON(NULL == ch);
-       list_del(&ch->list);
-       spin_unlock(&ch_devlist_lock);
+       spin_lock(&ch_index_lock);
+       idr_remove(&ch_index_idr, ch->minor);
+       spin_unlock(&ch_index_lock);
 
        class_device_destroy(ch_sysfs_class,
                             MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
        kfree(ch->dt);
        kfree(ch);
-       ch_devcount--;
        return 0;
 }
 
+static struct scsi_driver ch_template = {
+       .owner          = THIS_MODULE,
+       .gendrv         = {
+               .name   = "ch",
+               .probe  = ch_probe,
+               .remove = ch_remove,
+       },
+};
+
+static const struct file_operations changer_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ch_open,
+       .release        = ch_release,
+       .unlocked_ioctl = ch_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ch_ioctl_compat,
+#endif
+};
+
 static int __init init_ch_module(void)
 {
        int rc;
-       
+
        printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
         ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
         if (IS_ERR(ch_sysfs_class)) {
@@ -996,11 +998,12 @@ static int __init init_ch_module(void)
        return rc;
 }
 
-static void __exit exit_ch_module(void) 
+static void __exit exit_ch_module(void)
 {
        scsi_unregister_driver(&ch_template.gendrv);
        unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
        class_destroy(ch_sysfs_class);
+       idr_destroy(&ch_index_idr);
 }
 
 module_init(init_ch_module);
index 024553f9c247c669ab4769aef2ee5ef0c58c361e..403a7f2d8f9b21a92fbd2b687560b06e71e5db99 100644 (file)
@@ -362,7 +362,6 @@ void scsi_print_command(struct scsi_cmnd *cmd)
 EXPORT_SYMBOL(scsi_print_command);
 
 /**
- *
  *     scsi_print_status - print scsi status description
  *     @scsi_status: scsi status value
  *
@@ -1369,7 +1368,7 @@ EXPORT_SYMBOL(scsi_print_sense);
 static const char * const hostbyte_table[]={
 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
-"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
+"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"};
 #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
 
 static const char * const driverbyte_table[]={
index a9def6e1d30e6a5bd761a481b1fe522f924bd107..f93c73c0ba53d7081a187f17e5c17bf7224da77d 100644 (file)
@@ -1629,8 +1629,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
-               DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-                             sizeof(srb->cmd->sense_buffer));
+               DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
        } else {
                ptr = (u8 *)srb->cmd->cmnd;
@@ -1915,8 +1914,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
-               DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-                             sizeof(srb->cmd->sense_buffer));
+               DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
                DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
        }
        srb->state |= SRB_COMMAND;
@@ -3685,7 +3683,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
        srb->target_status = 0;
 
        /* KG: Can this prevent crap sense data ? */
-       memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
        /* Save some data */
        srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
@@ -3694,15 +3692,15 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
            srb->segment_x[0].length;
        srb->xferred = srb->total_xfer_length;
        /* srb->segment_x : a one entry of S/G list table */
-       srb->total_xfer_length = sizeof(cmd->sense_buffer);
-       srb->segment_x[0].length = sizeof(cmd->sense_buffer);
+       srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
+       srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
        /* Map sense buffer */
        srb->segment_x[0].address =
            pci_map_single(acb->dev, cmd->sense_buffer,
-                          sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
+                          SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
        dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
               cmd->sense_buffer, srb->segment_x[0].address,
-              sizeof(cmd->sense_buffer));
+              SCSI_SENSE_BUFFERSIZE);
        srb->sg_count = 1;
        srb->sg_index = 0;
 
index b31d1c95c9fbd4d1a16c04856e088a54411801d5..19cce125124c8d423fc9cd500175f2b70bd9e7ce 100644 (file)
@@ -2296,9 +2296,8 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
 
                // copy over the request sense data if it was a check
                // condition status
-               if(dev_status == 0x02 /*CHECK_CONDITION*/) {
-                       u32 len = sizeof(cmd->sense_buffer);
-                       len = (len > 40) ?  40 : len;
+               if (dev_status == SAM_STAT_CHECK_CONDITION) {
+                       u32 len = min(SCSI_SENSE_BUFFERSIZE, 40);
                        // Copy over the sense data
                        memcpy_fromio(cmd->sense_buffer, (reply+28) , len);
                        if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && 
index 7ead5210de968dfb0ece36e1d81058a018875d14..05163cefec12f7f2f806009de76da5d77767a0ed 100644 (file)
@@ -1623,9 +1623,9 @@ static void map_dma(unsigned int i, struct hostdata *ha)
        if (SCpnt->sense_buffer)
                cpp->sense_addr =
                    H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer,
-                          sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+                          SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
 
-       cpp->sense_len = sizeof SCpnt->sense_buffer;
+       cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
        count = scsi_dma_map(SCpnt);
        BUG_ON(count < 0);
index 982c5092be11fa055952f0f0d0f68c3758741a09..b5a60926e556657f7c9e1ead702548ffc002a381 100644 (file)
@@ -369,7 +369,6 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
        cp = &hd->ccb[y];
 
        memset(cp, 0, sizeof(struct eata_ccb));
-       memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
 
        cp->status = USED;      /* claim free slot */
 
@@ -385,7 +384,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
                cp->DataIn = 0; /* Input mode  */
 
        cp->Interpret = (cmd->device->id == hd->hostid);
-       cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
+       cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd));
        cp->Auto_Req_Sen = 0;
        cp->cp_reqDMA = 0;
        cp->reqlen = 0;
@@ -402,14 +401,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
        cp->cmd = cmd;
        cmd->host_scribble = (char *) &hd->ccb[y];
 
-       if (cmd->use_sg == 0) {
+       if (!scsi_bufflen(cmd)) {
                cmd->SCp.buffers_residual = 1;
-               cmd->SCp.ptr = cmd->request_buffer;
-               cmd->SCp.this_residual = cmd->request_bufflen;
+               cmd->SCp.ptr = NULL;
+               cmd->SCp.this_residual = 0;
                cmd->SCp.buffer = NULL;
        } else {
-               cmd->SCp.buffer = cmd->request_buffer;
-               cmd->SCp.buffers_residual = cmd->use_sg;
+               cmd->SCp.buffer = scsi_sglist(cmd);
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd);
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        }
index 8335b608e5717b2687b9fae230d200274671b67d..85bd54c77b50b950947157d4521370ce2dec36b3 100644 (file)
@@ -1017,24 +1017,6 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
                printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
 #endif
 
-#if ERRORS_ONLY
-               if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
-                       if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
-                               unsigned char key;
-                               unsigned char code;
-                               unsigned char qualifier;
-
-                               key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
-                               code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
-                               qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
-
-                               if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
-                                   && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
-
-                                       printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
-                       }
-               }
-#endif
 #if EVERY_ACCESS
                printk("BEFORE MY_DONE. . .");
 #endif
@@ -1097,7 +1079,9 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
        }
 #if EVERY_ACCESS
-       printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
+       printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+               SCpnt->target, *(unsigned char *) SCpnt->cmnd,
+               scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
 #endif
 
        fd_mcs_make_bus_idle(shpnt);
@@ -1107,14 +1091,14 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 
        /* Initialize static data */
 
-       if (current_SC->use_sg) {
-               current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
+       if (scsi_bufflen(current_SC)) {
+               current_SC->SCp.buffer = scsi_sglist(current_SC);
                current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-               current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+               current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
        } else {
-               current_SC->SCp.ptr = (char *) current_SC->request_buffer;
-               current_SC->SCp.this_residual = current_SC->request_bufflen;
+               current_SC->SCp.ptr = NULL;
+               current_SC->SCp.this_residual = 0;
                current_SC->SCp.buffer = NULL;
                current_SC->SCp.buffers_residual = 0;
        }
@@ -1166,7 +1150,9 @@ static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
                break;
        }
 
-       printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
+       printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+               SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
+               scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
        printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
 #if DEBUG_RACE
        printk("in_interrupt_flag = %d\n", in_interrupt_flag);
index b253b8c718d362e3215e2520e6a7eb576296474b..c82523908c2e757d3f668a7fd7d8b72562723780 100644 (file)
 static void gdth_delay(int milliseconds);
 static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
 static irqreturn_t gdth_interrupt(int irq, void *dev_id);
-static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
                                     int gdth_from_wait, int* pIndex);
 static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
                                                                Scsi_Cmnd *scp);
@@ -165,7 +165,6 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
 static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
 
 static void gdth_enable_int(gdth_ha_str *ha);
-static unchar gdth_get_status(gdth_ha_str *ha, int irq);
 static int gdth_test_busy(gdth_ha_str *ha);
 static int gdth_get_cmd_index(gdth_ha_str *ha);
 static void gdth_release_event(gdth_ha_str *ha);
@@ -1334,14 +1333,12 @@ static void __init gdth_enable_int(gdth_ha_str *ha)
 }
 
 /* return IStatus if interrupt was from this card else 0 */
-static unchar gdth_get_status(gdth_ha_str *ha, int irq)
+static unchar gdth_get_status(gdth_ha_str *ha)
 {
     unchar IStatus = 0;
 
-    TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
+    TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count));
 
-        if (ha->irq != (unchar)irq)             /* check IRQ */
-            return false;
         if (ha->type == GDT_EISA)
             IStatus = inb((ushort)ha->bmic + EDOORREG);
         else if (ha->type == GDT_ISA)
@@ -1523,7 +1520,7 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
         return 1;                               /* no wait required */
 
     do {
-        __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
+       __gdth_interrupt(ha, true, &wait_index);
         if (wait_index == index) {
             answer_found = TRUE;
             break;
@@ -3036,7 +3033,7 @@ static void gdth_clear_events(void)
 
 /* SCSI interface functions */
 
-static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
                                     int gdth_from_wait, int* pIndex)
 {
     gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
@@ -3054,7 +3051,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
     int act_int_coal = 0;       
 #endif
 
-    TRACE(("gdth_interrupt() IRQ %d\n",irq));
+    TRACE(("gdth_interrupt() IRQ %d\n", ha->irq));
 
     /* if polling and not from gdth_wait() -> return */
     if (gdth_polling) {
@@ -3067,7 +3064,8 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
         spin_lock_irqsave(&ha->smp_lock, flags);
 
     /* search controller */
-    if (0 == (IStatus = gdth_get_status(ha, irq))) {
+    IStatus = gdth_get_status(ha);
+    if (IStatus == 0) {
         /* spurious interrupt */
         if (!gdth_polling)
             spin_unlock_irqrestore(&ha->smp_lock, flags);
@@ -3294,9 +3292,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
 
 static irqreturn_t gdth_interrupt(int irq, void *dev_id)
 {
-       gdth_ha_str *ha = (gdth_ha_str *)dev_id;
+       gdth_ha_str *ha = dev_id;
 
-       return __gdth_interrupt(ha, irq, false, NULL);
+       return __gdth_interrupt(ha, false, NULL);
 }
 
 static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
index 24271a871b8c6a03c8cc971d823527374732e52e..5ea1f986220cf052e2786d6f91a5d7e86aebcf39 100644 (file)
@@ -54,8 +54,7 @@ static struct class shost_class = {
 };
 
 /**
- *     scsi_host_set_state - Take the given host through the host
- *             state model.
+ *     scsi_host_set_state - Take the given host through the host state model.
  *     @shost: scsi host to change the state of.
  *     @state: state to change to.
  *
@@ -429,9 +428,17 @@ void scsi_unregister(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL(scsi_unregister);
 
+static int __scsi_host_match(struct class_device *cdev, void *data)
+{
+       struct Scsi_Host *p;
+       unsigned short *hostnum = (unsigned short *)data;
+
+       p = class_to_shost(cdev);
+       return p->host_no == *hostnum;
+}
+
 /**
  * scsi_host_lookup - get a reference to a Scsi_Host by host no
- *
  * @hostnum:   host number to locate
  *
  * Return value:
@@ -439,19 +446,12 @@ EXPORT_SYMBOL(scsi_unregister);
  **/
 struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
 {
-       struct class *class = &shost_class;
        struct class_device *cdev;
-       struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
+       struct Scsi_Host *shost = ERR_PTR(-ENXIO);
 
-       down(&class->sem);
-       list_for_each_entry(cdev, &class->children, node) {
-               p = class_to_shost(cdev);
-               if (p->host_no == hostnum) {
-                       shost = scsi_host_get(p);
-                       break;
-               }
-       }
-       up(&class->sem);
+       cdev = class_find_child(&shost_class, &hostnum, __scsi_host_match);
+       if (cdev)
+               shost = scsi_host_get(class_to_shost(cdev));
 
        return shost;
 }
index 0844331abb87f6fb151bf3335134799a3c23576f..e7b2f3575ce99466c1ddf50991744205b4d0c0fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * HighPoint RR3xxx controller driver for Linux
+ * HighPoint RR3xxx/4xxx controller driver for Linux
  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
 #include "hptiop.h"
 
 MODULE_AUTHOR("HighPoint Technologies, Inc.");
-MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
+MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
 
 static char driver_name[] = "hptiop";
-static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
-static const char driver_ver[] = "v1.2 (070830)";
-
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
-static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
+static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
+static const char driver_ver[] = "v1.3 (071203)";
+
+static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
+static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
+                               struct hpt_iop_request_scsi_command *req);
+static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
+static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
 static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
 
-static inline void hptiop_pci_posting_flush(struct hpt_iopmu __iomem *iop)
-{
-       readl(&iop->outbound_intstatus);
-}
-
-static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
+static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
 {
        u32 req = 0;
        int i;
 
        for (i = 0; i < millisec; i++) {
-               req = readl(&iop->inbound_queue);
+               req = readl(&hba->u.itl.iop->inbound_queue);
                if (req != IOPMU_QUEUE_EMPTY)
                        break;
                msleep(1);
        }
 
        if (req != IOPMU_QUEUE_EMPTY) {
-               writel(req, &iop->outbound_queue);
-               hptiop_pci_posting_flush(iop);
+               writel(req, &hba->u.itl.iop->outbound_queue);
+               readl(&hba->u.itl.iop->outbound_intstatus);
                return 0;
        }
 
        return -1;
 }
 
-static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
+static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
+{
+       return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
+}
+
+static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
 {
        if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
-               return hptiop_host_request_callback(hba,
+               hptiop_host_request_callback_itl(hba,
                                tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
        else
-               return hptiop_iop_request_callback(hba, tag);
+               hptiop_iop_request_callback_itl(hba, tag);
 }
 
-static inline void hptiop_drain_outbound_queue(struct hptiop_hba *hba)
+static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
 {
        u32 req;
 
-       while ((req = readl(&hba->iop->outbound_queue)) != IOPMU_QUEUE_EMPTY) {
+       while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
+                                               IOPMU_QUEUE_EMPTY) {
 
                if (req & IOPMU_QUEUE_MASK_HOST_BITS)
-                       hptiop_request_callback(hba, req);
+                       hptiop_request_callback_itl(hba, req);
                else {
                        struct hpt_iop_request_header __iomem * p;
 
                        p = (struct hpt_iop_request_header __iomem *)
-                               ((char __iomem *)hba->iop + req);
+                               ((char __iomem *)hba->u.itl.iop + req);
 
                        if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
                                if (readl(&p->context))
-                                       hptiop_request_callback(hba, req);
+                                       hptiop_request_callback_itl(hba, req);
                                else
                                        writel(1, &p->context);
                        }
                        else
-                               hptiop_request_callback(hba, req);
+                               hptiop_request_callback_itl(hba, req);
                }
        }
 }
 
-static int __iop_intr(struct hptiop_hba *hba)
+static int iop_intr_itl(struct hptiop_hba *hba)
 {
-       struct hpt_iopmu __iomem *iop = hba->iop;
+       struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
        u32 status;
        int ret = 0;
 
@@ -119,6 +123,7 @@ static int __iop_intr(struct hptiop_hba *hba)
 
        if (status & IOPMU_OUTBOUND_INT_MSG0) {
                u32 msg = readl(&iop->outbound_msgaddr0);
+
                dprintk("received outbound msg %x\n", msg);
                writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
                hptiop_message_callback(hba, msg);
@@ -126,31 +131,115 @@ static int __iop_intr(struct hptiop_hba *hba)
        }
 
        if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
-               hptiop_drain_outbound_queue(hba);
+               hptiop_drain_outbound_queue_itl(hba);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
+{
+       u32 outbound_tail = readl(&mu->outbound_tail);
+       u32 outbound_head = readl(&mu->outbound_head);
+
+       if (outbound_tail != outbound_head) {
+               u64 p;
+
+               memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
+               outbound_tail++;
+
+               if (outbound_tail == MVIOP_QUEUE_LEN)
+                       outbound_tail = 0;
+               writel(outbound_tail, &mu->outbound_tail);
+               return p;
+       } else
+               return 0;
+}
+
+static void mv_inbound_write(u64 p, struct hptiop_hba *hba)
+{
+       u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
+       u32 head = inbound_head + 1;
+
+       if (head == MVIOP_QUEUE_LEN)
+               head = 0;
+
+       memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
+       writel(head, &hba->u.mv.mu->inbound_head);
+       writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
+                       &hba->u.mv.regs->inbound_doorbell);
+}
+
+static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
+{
+       u32 req_type = (tag >> 5) & 0x7;
+       struct hpt_iop_request_scsi_command *req;
+
+       dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
+
+       BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
+
+       switch (req_type) {
+       case IOP_REQUEST_TYPE_GET_CONFIG:
+       case IOP_REQUEST_TYPE_SET_CONFIG:
+               hba->msg_done = 1;
+               break;
+
+       case IOP_REQUEST_TYPE_SCSI_COMMAND:
+               req = hba->reqs[tag >> 8].req_virt;
+               if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
+                       req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
+
+               hptiop_finish_scsi_req(hba, tag>>8, req);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int iop_intr_mv(struct hptiop_hba *hba)
+{
+       u32 status;
+       int ret = 0;
+
+       status = readl(&hba->u.mv.regs->outbound_doorbell);
+       writel(~status, &hba->u.mv.regs->outbound_doorbell);
+
+       if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
+               u32 msg;
+               msg = readl(&hba->u.mv.mu->outbound_msg);
+               dprintk("received outbound msg %x\n", msg);
+               hptiop_message_callback(hba, msg);
+               ret = 1;
+       }
+
+       if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
+               u64 tag;
+
+               while ((tag = mv_outbound_read(hba->u.mv.mu)))
+                       hptiop_request_callback_mv(hba, tag);
                ret = 1;
        }
 
        return ret;
 }
 
-static int iop_send_sync_request(struct hptiop_hba *hba,
+static int iop_send_sync_request_itl(struct hptiop_hba *hba,
                                        void __iomem *_req, u32 millisec)
 {
        struct hpt_iop_request_header __iomem *req = _req;
        u32 i;
 
-       writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST,
-                       &req->flags);
-
+       writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
        writel(0, &req->context);
-
-       writel((unsigned long)req - (unsigned long)hba->iop,
-                       &hba->iop->inbound_queue);
-
-       hptiop_pci_posting_flush(hba->iop);
+       writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
+                       &hba->u.itl.iop->inbound_queue);
+       readl(&hba->u.itl.iop->outbound_intstatus);
 
        for (i = 0; i < millisec; i++) {
-               __iop_intr(hba);
+               iop_intr_itl(hba);
                if (readl(&req->context))
                        return 0;
                msleep(1);
@@ -159,19 +248,49 @@ static int iop_send_sync_request(struct hptiop_hba *hba,
        return -1;
 }
 
-static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
+static int iop_send_sync_request_mv(struct hptiop_hba *hba,
+                                       u32 size_bits, u32 millisec)
 {
+       struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
        u32 i;
 
        hba->msg_done = 0;
+       reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
+       mv_inbound_write(hba->u.mv.internal_req_phy |
+                       MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
+
+       for (i = 0; i < millisec; i++) {
+               iop_intr_mv(hba);
+               if (hba->msg_done)
+                       return 0;
+               msleep(1);
+       }
+       return -1;
+}
+
+static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
+{
+       writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
+       readl(&hba->u.itl.iop->outbound_intstatus);
+}
+
+static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
+{
+       writel(msg, &hba->u.mv.mu->inbound_msg);
+       writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
+       readl(&hba->u.mv.regs->inbound_doorbell);
+}
 
-       writel(msg, &hba->iop->inbound_msgaddr0);
+static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
+{
+       u32 i;
 
-       hptiop_pci_posting_flush(hba->iop);
+       hba->msg_done = 0;
+       hba->ops->post_msg(hba, msg);
 
        for (i = 0; i < millisec; i++) {
                spin_lock_irq(hba->host->host_lock);
-               __iop_intr(hba);
+               hba->ops->iop_intr(hba);
                spin_unlock_irq(hba->host->host_lock);
                if (hba->msg_done)
                        break;
@@ -181,46 +300,67 @@ static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
        return hba->msg_done? 0 : -1;
 }
 
-static int iop_get_config(struct hptiop_hba *hba,
+static int iop_get_config_itl(struct hptiop_hba *hba,
                                struct hpt_iop_request_get_config *config)
 {
        u32 req32;
        struct hpt_iop_request_get_config __iomem *req;
 
-       req32 = readl(&hba->iop->inbound_queue);
+       req32 = readl(&hba->u.itl.iop->inbound_queue);
        if (req32 == IOPMU_QUEUE_EMPTY)
                return -1;
 
        req = (struct hpt_iop_request_get_config __iomem *)
-                       ((unsigned long)hba->iop + req32);
+                       ((unsigned long)hba->u.itl.iop + req32);
 
        writel(0, &req->header.flags);
        writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
        writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
        writel(IOP_RESULT_PENDING, &req->header.result);
 
-       if (iop_send_sync_request(hba, req, 20000)) {
+       if (iop_send_sync_request_itl(hba, req, 20000)) {
                dprintk("Get config send cmd failed\n");
                return -1;
        }
 
        memcpy_fromio(config, req, sizeof(*config));
-       writel(req32, &hba->iop->outbound_queue);
+       writel(req32, &hba->u.itl.iop->outbound_queue);
+       return 0;
+}
+
+static int iop_get_config_mv(struct hptiop_hba *hba,
+                               struct hpt_iop_request_get_config *config)
+{
+       struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
+
+       req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
+       req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
+       req->header.size =
+               cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
+       req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
+       req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_GET_CONFIG<<5);
+
+       if (iop_send_sync_request_mv(hba, 0, 20000)) {
+               dprintk("Get config send cmd failed\n");
+               return -1;
+       }
+
+       memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
        return 0;
 }
 
-static int iop_set_config(struct hptiop_hba *hba,
+static int iop_set_config_itl(struct hptiop_hba *hba,
                                struct hpt_iop_request_set_config *config)
 {
        u32 req32;
        struct hpt_iop_request_set_config __iomem *req;
 
-       req32 = readl(&hba->iop->inbound_queue);
+       req32 = readl(&hba->u.itl.iop->inbound_queue);
        if (req32 == IOPMU_QUEUE_EMPTY)
                return -1;
 
        req = (struct hpt_iop_request_set_config __iomem *)
-                       ((unsigned long)hba->iop + req32);
+                       ((unsigned long)hba->u.itl.iop + req32);
 
        memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
                (u8 *)config + sizeof(struct hpt_iop_request_header),
@@ -232,22 +372,52 @@ static int iop_set_config(struct hptiop_hba *hba,
        writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
        writel(IOP_RESULT_PENDING, &req->header.result);
 
-       if (iop_send_sync_request(hba, req, 20000)) {
+       if (iop_send_sync_request_itl(hba, req, 20000)) {
                dprintk("Set config send cmd failed\n");
                return -1;
        }
 
-       writel(req32, &hba->iop->outbound_queue);
+       writel(req32, &hba->u.itl.iop->outbound_queue);
        return 0;
 }
 
-static int hptiop_initialize_iop(struct hptiop_hba *hba)
+static int iop_set_config_mv(struct hptiop_hba *hba,
+                               struct hpt_iop_request_set_config *config)
 {
-       struct hpt_iopmu __iomem *iop = hba->iop;
+       struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
 
-       /* enable interrupts */
+       memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
+       req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
+       req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
+       req->header.size =
+               cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
+       req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
+       req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_SET_CONFIG<<5);
+
+       if (iop_send_sync_request_mv(hba, 0, 20000)) {
+               dprintk("Set config send cmd failed\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void hptiop_enable_intr_itl(struct hptiop_hba *hba)
+{
        writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
-                       &iop->outbound_intmask);
+               &hba->u.itl.iop->outbound_intmask);
+}
+
+static void hptiop_enable_intr_mv(struct hptiop_hba *hba)
+{
+       writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
+               &hba->u.mv.regs->outbound_intmask);
+}
+
+static int hptiop_initialize_iop(struct hptiop_hba *hba)
+{
+       /* enable interrupts */
+       hba->ops->enable_intr(hba);
 
        hba->initialized = 1;
 
@@ -261,37 +431,74 @@ static int hptiop_initialize_iop(struct hptiop_hba *hba)
        return 0;
 }
 
-static int hptiop_map_pci_bar(struct hptiop_hba *hba)
+static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
 {
        u32 mem_base_phy, length;
        void __iomem *mem_base_virt;
+
        struct pci_dev *pcidev = hba->pcidev;
 
-       if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
+
+       if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
                printk(KERN_ERR "scsi%d: pci resource invalid\n",
                                hba->host->host_no);
-               return -1;
+               return 0;
        }
 
-       mem_base_phy = pci_resource_start(pcidev, 0);
-       length = pci_resource_len(pcidev, 0);
+       mem_base_phy = pci_resource_start(pcidev, index);
+       length = pci_resource_len(pcidev, index);
        mem_base_virt = ioremap(mem_base_phy, length);
 
        if (!mem_base_virt) {
                printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
                                hba->host->host_no);
+               return 0;
+       }
+       return mem_base_virt;
+}
+
+static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
+{
+       hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
+       if (hba->u.itl.iop)
+               return 0;
+       else
+               return -1;
+}
+
+static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
+{
+       iounmap(hba->u.itl.iop);
+}
+
+static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
+{
+       hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
+       if (hba->u.mv.regs == 0)
+               return -1;
+
+       hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
+       if (hba->u.mv.mu == 0) {
+               iounmap(hba->u.mv.regs);
                return -1;
        }
 
-       hba->iop = mem_base_virt;
-       dprintk("hptiop_map_pci_bar: iop=%p\n", hba->iop);
        return 0;
 }
 
+static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
+{
+       iounmap(hba->u.mv.regs);
+       iounmap(hba->u.mv.mu);
+}
+
 static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
 {
        dprintk("iop message 0x%x\n", msg);
 
+       if (msg == IOPMU_INBOUND_MSG0_NOP)
+               hba->msg_done = 1;
+
        if (!hba->initialized)
                return;
 
@@ -303,7 +510,7 @@ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
                hba->msg_done = 1;
 }
 
-static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
+static struct hptiop_request *get_req(struct hptiop_hba *hba)
 {
        struct hptiop_request *ret;
 
@@ -316,30 +523,19 @@ static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
        return ret;
 }
 
-static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
+static void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
 {
        dprintk("free_req(%d, %p)\n", req->index, req);
        req->next = hba->req_list;
        hba->req_list = req;
 }
 
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
+static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
+                               struct hpt_iop_request_scsi_command *req)
 {
-       struct hpt_iop_request_scsi_command *req;
        struct scsi_cmnd *scp;
-       u32 tag;
-
-       if (hba->iopintf_v2) {
-               tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
-               req = hba->reqs[tag].req_virt;
-               if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
-                       req->header.result = IOP_RESULT_SUCCESS;
-       } else {
-               tag = _tag;
-               req = hba->reqs[tag].req_virt;
-       }
 
-       dprintk("hptiop_host_request_callback: req=%p, type=%d, "
+       dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
                        "result=%d, context=0x%x tag=%d\n",
                        req, req->header.type, req->header.result,
                        req->header.context, tag);
@@ -354,6 +550,8 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
 
        switch (le32_to_cpu(req->header.result)) {
        case IOP_RESULT_SUCCESS:
+               scsi_set_resid(scp,
+                       scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
                scp->result = (DID_OK<<16);
                break;
        case IOP_RESULT_BAD_TARGET:
@@ -371,12 +569,12 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
        case IOP_RESULT_INVALID_REQUEST:
                scp->result = (DID_ABORT<<16);
                break;
-       case IOP_RESULT_MODE_SENSE_CHECK_CONDITION:
+       case IOP_RESULT_CHECK_CONDITION:
+               scsi_set_resid(scp,
+                       scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
                scp->result = SAM_STAT_CHECK_CONDITION;
-               memset(&scp->sense_buffer,
-                               0, sizeof(scp->sense_buffer));
                memcpy(&scp->sense_buffer, &req->sg_list,
-                               min(sizeof(scp->sense_buffer),
+                               min_t(size_t, SCSI_SENSE_BUFFERSIZE,
                                        le32_to_cpu(req->dataxfer_length)));
                break;
 
@@ -391,15 +589,33 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
        free_req(hba, &hba->reqs[tag]);
 }
 
-void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
+static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
+{
+       struct hpt_iop_request_scsi_command *req;
+       u32 tag;
+
+       if (hba->iopintf_v2) {
+               tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
+               req = hba->reqs[tag].req_virt;
+               if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
+                       req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
+       } else {
+               tag = _tag;
+               req = hba->reqs[tag].req_virt;
+       }
+
+       hptiop_finish_scsi_req(hba, tag, req);
+}
+
+void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
 {
        struct hpt_iop_request_header __iomem *req;
        struct hpt_iop_request_ioctl_command __iomem *p;
        struct hpt_ioctl_k *arg;
 
        req = (struct hpt_iop_request_header __iomem *)
-                       ((unsigned long)hba->iop + tag);
-       dprintk("hptiop_iop_request_callback: req=%p, type=%d, "
+                       ((unsigned long)hba->u.itl.iop + tag);
+       dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
                        "result=%d, context=0x%x tag=%d\n",
                        req, readl(&req->type), readl(&req->result),
                        readl(&req->context), tag);
@@ -427,7 +643,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
                arg->result = HPT_IOCTL_RESULT_FAILED;
 
        arg->done(arg);
-       writel(tag, &hba->iop->outbound_queue);
+       writel(tag, &hba->u.itl.iop->outbound_queue);
 }
 
 static irqreturn_t hptiop_intr(int irq, void *dev_id)
@@ -437,7 +653,7 @@ static irqreturn_t hptiop_intr(int irq, void *dev_id)
        unsigned long flags;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
-       handled = __iop_intr(hba);
+       handled = hba->ops->iop_intr(hba);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
        return handled;
@@ -469,6 +685,57 @@ static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
        return HPT_SCP(scp)->sgcnt;
 }
 
+static void hptiop_post_req_itl(struct hptiop_hba *hba,
+                                       struct hptiop_request *_req)
+{
+       struct hpt_iop_request_header *reqhdr = _req->req_virt;
+
+       reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
+                                                       (u32)_req->index);
+       reqhdr->context_hi32 = 0;
+
+       if (hba->iopintf_v2) {
+               u32 size, size_bits;
+
+               size = le32_to_cpu(reqhdr->size);
+               if (size < 256)
+                       size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
+               else if (size < 512)
+                       size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
+               else
+                       size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
+                                               IOPMU_QUEUE_ADDR_HOST_BIT;
+               writel(_req->req_shifted_phy | size_bits,
+                       &hba->u.itl.iop->inbound_queue);
+       } else
+               writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
+                                       &hba->u.itl.iop->inbound_queue);
+}
+
+static void hptiop_post_req_mv(struct hptiop_hba *hba,
+                                       struct hptiop_request *_req)
+{
+       struct hpt_iop_request_header *reqhdr = _req->req_virt;
+       u32 size, size_bit;
+
+       reqhdr->context = cpu_to_le32(_req->index<<8 |
+                                       IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
+       reqhdr->context_hi32 = 0;
+       size = le32_to_cpu(reqhdr->size);
+
+       if (size <= 256)
+               size_bit = 0;
+       else if (size <= 256*2)
+               size_bit = 1;
+       else if (size <= 256*3)
+               size_bit = 2;
+       else
+               size_bit = 3;
+
+       mv_inbound_write((_req->req_shifted_phy << 5) |
+               MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
+}
+
 static int hptiop_queuecommand(struct scsi_cmnd *scp,
                                void (*done)(struct scsi_cmnd *))
 {
@@ -518,9 +785,6 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
        req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
        req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
        req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
-       req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
-                                                       (u32)_req->index);
-       req->header.context_hi32 = 0;
        req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
        req->channel = scp->device->channel;
        req->target = scp->device->id;
@@ -531,21 +795,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
                                 + sg_count * sizeof(struct hpt_iopsg));
 
        memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
-
-       if (hba->iopintf_v2) {
-               u32 size_bits;
-               if (req->header.size < 256)
-                       size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
-               else if (req->header.size < 512)
-                       size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
-               else
-                       size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
-                                               IOPMU_QUEUE_ADDR_HOST_BIT;
-               writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
-       } else
-               writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
-                                       &hba->iop->inbound_queue);
-
+       hba->ops->post_req(hba, _req);
        return 0;
 
 cmd_done:
@@ -563,9 +813,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
 {
        if (atomic_xchg(&hba->resetting, 1) == 0) {
                atomic_inc(&hba->reset_count);
-               writel(IOPMU_INBOUND_MSG0_RESET,
-                               &hba->iop->inbound_msgaddr0);
-               hptiop_pci_posting_flush(hba->iop);
+               hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
        }
 
        wait_event_timeout(hba->reset_wq,
@@ -601,8 +849,10 @@ static int hptiop_reset(struct scsi_cmnd *scp)
 static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
                                                int queue_depth)
 {
-       if(queue_depth > 256)
-               queue_depth = 256;
+       struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
+
+       if (queue_depth > hba->max_requests)
+               queue_depth = hba->max_requests;
        scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
        return queue_depth;
 }
@@ -663,6 +913,26 @@ static struct scsi_host_template driver_template = {
        .change_queue_depth         = hptiop_adjust_disk_queue_depth,
 };
 
+static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
+{
+       hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
+                       0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
+       if (hba->u.mv.internal_req)
+               return 0;
+       else
+               return -1;
+}
+
+static int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
+{
+       if (hba->u.mv.internal_req) {
+               dma_free_coherent(&hba->pcidev->dev, 0x800,
+                       hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
+               return 0;
+       } else
+               return -1;
+}
+
 static int __devinit hptiop_probe(struct pci_dev *pcidev,
                                        const struct pci_device_id *id)
 {
@@ -708,6 +978,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 
        hba = (struct hptiop_hba *)host->hostdata;
 
+       hba->ops = (struct hptiop_adapter_ops *)id->driver_data;
        hba->pcidev = pcidev;
        hba->host = host;
        hba->initialized = 0;
@@ -725,16 +996,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
        host->n_io_port = 0;
        host->irq = pcidev->irq;
 
-       if (hptiop_map_pci_bar(hba))
+       if (hba->ops->map_pci_bar(hba))
                goto free_scsi_host;
 
-       if (iop_wait_ready(hba->iop, 20000)) {
+       if (hba->ops->iop_wait_ready(hba, 20000)) {
                printk(KERN_ERR "scsi%d: firmware not ready\n",
                                hba->host->host_no);
                goto unmap_pci_bar;
        }
 
-       if (iop_get_config(hba, &iop_config)) {
+       if (hba->ops->internal_memalloc) {
+               if (hba->ops->internal_memalloc(hba)) {
+                       printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
+                               hba->host->host_no);
+                       goto unmap_pci_bar;
+               }
+       }
+
+       if (hba->ops->get_config(hba, &iop_config)) {
                printk(KERN_ERR "scsi%d: get config failed\n",
                                hba->host->host_no);
                goto unmap_pci_bar;
@@ -770,7 +1049,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
        set_config.vbus_id = cpu_to_le16(host->host_no);
        set_config.max_host_request_size = cpu_to_le16(req_size);
 
-       if (iop_set_config(hba, &set_config)) {
+       if (hba->ops->set_config(hba, &set_config)) {
                printk(KERN_ERR "scsi%d: set config failed\n",
                                hba->host->host_no);
                goto unmap_pci_bar;
@@ -839,21 +1118,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 
 free_request_mem:
        dma_free_coherent(&hba->pcidev->dev,
-                       hba->req_size*hba->max_requests + 0x20,
+                       hba->req_size * hba->max_requests + 0x20,
                        hba->dma_coherent, hba->dma_coherent_handle);
 
 free_request_irq:
        free_irq(hba->pcidev->irq, hba);
 
 unmap_pci_bar:
-       iounmap(hba->iop);
+       if (hba->ops->internal_memfree)
+               hba->ops->internal_memfree(hba);
 
-free_pci_regions:
-       pci_release_regions(pcidev) ;
+       hba->ops->unmap_pci_bar(hba);
 
 free_scsi_host:
        scsi_host_put(host);
 
+free_pci_regions:
+       pci_release_regions(pcidev);
+
 disable_pci_device:
        pci_disable_device(pcidev);
 
@@ -865,8 +1147,6 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pcidev);
        struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
-       struct hpt_iopmu __iomem *iop = hba->iop;
-       u32    int_mask;
 
        dprintk("hptiop_shutdown(%p)\n", hba);
 
@@ -876,11 +1156,24 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
                                        hba->host->host_no);
 
        /* disable all outbound interrupts */
-       int_mask = readl(&iop->outbound_intmask);
+       hba->ops->disable_intr(hba);
+}
+
+static void hptiop_disable_intr_itl(struct hptiop_hba *hba)
+{
+       u32 int_mask;
+
+       int_mask = readl(&hba->u.itl.iop->outbound_intmask);
        writel(int_mask |
                IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
-               &iop->outbound_intmask);
-       hptiop_pci_posting_flush(iop);
+               &hba->u.itl.iop->outbound_intmask);
+       readl(&hba->u.itl.iop->outbound_intmask);
+}
+
+static void hptiop_disable_intr_mv(struct hptiop_hba *hba)
+{
+       writel(0, &hba->u.mv.regs->outbound_intmask);
+       readl(&hba->u.mv.regs->outbound_intmask);
 }
 
 static void hptiop_remove(struct pci_dev *pcidev)
@@ -901,7 +1194,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
                        hba->dma_coherent,
                        hba->dma_coherent_handle);
 
-       iounmap(hba->iop);
+       if (hba->ops->internal_memfree)
+               hba->ops->internal_memfree(hba);
+
+       hba->ops->unmap_pci_bar(hba);
 
        pci_release_regions(hba->pcidev);
        pci_set_drvdata(hba->pcidev, NULL);
@@ -910,11 +1206,50 @@ static void hptiop_remove(struct pci_dev *pcidev)
        scsi_host_put(host);
 }
 
+static struct hptiop_adapter_ops hptiop_itl_ops = {
+       .iop_wait_ready    = iop_wait_ready_itl,
+       .internal_memalloc = 0,
+       .internal_memfree  = 0,
+       .map_pci_bar       = hptiop_map_pci_bar_itl,
+       .unmap_pci_bar     = hptiop_unmap_pci_bar_itl,
+       .enable_intr       = hptiop_enable_intr_itl,
+       .disable_intr      = hptiop_disable_intr_itl,
+       .get_config        = iop_get_config_itl,
+       .set_config        = iop_set_config_itl,
+       .iop_intr          = iop_intr_itl,
+       .post_msg          = hptiop_post_msg_itl,
+       .post_req          = hptiop_post_req_itl,
+};
+
+static struct hptiop_adapter_ops hptiop_mv_ops = {
+       .iop_wait_ready    = iop_wait_ready_mv,
+       .internal_memalloc = hptiop_internal_memalloc_mv,
+       .internal_memfree  = hptiop_internal_memfree_mv,
+       .map_pci_bar       = hptiop_map_pci_bar_mv,
+       .unmap_pci_bar     = hptiop_unmap_pci_bar_mv,
+       .enable_intr       = hptiop_enable_intr_mv,
+       .disable_intr      = hptiop_disable_intr_mv,
+       .get_config        = iop_get_config_mv,
+       .set_config        = iop_set_config_mv,
+       .iop_intr          = iop_intr_mv,
+       .post_msg          = hptiop_post_msg_mv,
+       .post_req          = hptiop_post_req_mv,
+};
+
 static struct pci_device_id hptiop_id_table[] = {
-       { PCI_VDEVICE(TTI, 0x3220) },
-       { PCI_VDEVICE(TTI, 0x3320) },
-       { PCI_VDEVICE(TTI, 0x3520) },
-       { PCI_VDEVICE(TTI, 0x4320) },
+       { PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
+       { PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
+       { PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
        {},
 };
 
index 2a5e46e001cba5ebd2357354b26d5352887ea3da..a0289f2197524f66ec97e81cd8ce20385a1cce09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * HighPoint RR3xxx controller driver for Linux
+ * HighPoint RR3xxx/4xxx controller driver for Linux
  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,7 @@
 #ifndef _HPTIOP_H_
 #define _HPTIOP_H_
 
-struct hpt_iopmu
-{
+struct hpt_iopmu_itl {
        __le32 resrved0[4];
        __le32 inbound_msgaddr0;
        __le32 inbound_msgaddr1;
@@ -54,6 +53,40 @@ struct hpt_iopmu
 #define IOPMU_INBOUND_INT_ERROR      8
 #define IOPMU_INBOUND_INT_POSTQUEUE  0x10
 
+#define MVIOP_QUEUE_LEN  512
+
+struct hpt_iopmu_mv {
+       __le32 inbound_head;
+       __le32 inbound_tail;
+       __le32 outbound_head;
+       __le32 outbound_tail;
+       __le32 inbound_msg;
+       __le32 outbound_msg;
+       __le32 reserve[10];
+       __le64 inbound_q[MVIOP_QUEUE_LEN];
+       __le64 outbound_q[MVIOP_QUEUE_LEN];
+};
+
+struct hpt_iopmv_regs {
+       __le32 reserved[0x20400 / 4];
+       __le32 inbound_doorbell;
+       __le32 inbound_intmask;
+       __le32 outbound_doorbell;
+       __le32 outbound_intmask;
+};
+
+#define MVIOP_MU_QUEUE_ADDR_HOST_MASK   (~(0x1full))
+#define MVIOP_MU_QUEUE_ADDR_HOST_BIT    4
+
+#define MVIOP_MU_QUEUE_ADDR_IOP_HIGH32  0xffffffff
+#define MVIOP_MU_QUEUE_REQUEST_RESULT_BIT   1
+#define MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT 2
+
+#define MVIOP_MU_INBOUND_INT_MSG        1
+#define MVIOP_MU_INBOUND_INT_POSTQUEUE  2
+#define MVIOP_MU_OUTBOUND_INT_MSG       1
+#define MVIOP_MU_OUTBOUND_INT_POSTQUEUE 2
+
 enum hpt_iopmu_message {
        /* host-to-iop messages */
        IOPMU_INBOUND_MSG0_NOP = 0,
@@ -72,8 +105,7 @@ enum hpt_iopmu_message {
        IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_MAX = 0x3ff,
 };
 
-struct hpt_iop_request_header
-{
+struct hpt_iop_request_header {
        __le32 size;
        __le32 type;
        __le32 flags;
@@ -104,11 +136,10 @@ enum hpt_iop_result_type {
        IOP_RESULT_RESET,
        IOP_RESULT_INVALID_REQUEST,
        IOP_RESULT_BAD_TARGET,
-       IOP_RESULT_MODE_SENSE_CHECK_CONDITION,
+       IOP_RESULT_CHECK_CONDITION,
 };
 
-struct hpt_iop_request_get_config
-{
+struct hpt_iop_request_get_config {
        struct hpt_iop_request_header header;
        __le32 interface_version;
        __le32 firmware_version;
@@ -121,8 +152,7 @@ struct hpt_iop_request_get_config
        __le32 sdram_size;
 };
 
-struct hpt_iop_request_set_config
-{
+struct hpt_iop_request_set_config {
        struct hpt_iop_request_header header;
        __le32 iop_id;
        __le16 vbus_id;
@@ -130,15 +160,13 @@ struct hpt_iop_request_set_config
        __le32 reserve[6];
 };
 
-struct hpt_iopsg
-{
+struct hpt_iopsg {
        __le32 size;
        __le32 eot; /* non-zero: end of table */
        __le64 pci_address;
 };
 
-struct hpt_iop_request_block_command
-{
+struct hpt_iop_request_block_command {
        struct hpt_iop_request_header header;
        u8     channel;
        u8     target;
@@ -156,8 +184,7 @@ struct hpt_iop_request_block_command
 #define IOP_BLOCK_COMMAND_FLUSH    4
 #define IOP_BLOCK_COMMAND_SHUTDOWN 5
 
-struct hpt_iop_request_scsi_command
-{
+struct hpt_iop_request_scsi_command {
        struct hpt_iop_request_header header;
        u8     channel;
        u8     target;
@@ -168,8 +195,7 @@ struct hpt_iop_request_scsi_command
        struct hpt_iopsg sg_list[1];
 };
 
-struct hpt_iop_request_ioctl_command
-{
+struct hpt_iop_request_ioctl_command {
        struct hpt_iop_request_header header;
        __le32 ioctl_code;
        __le32 inbuf_size;
@@ -182,11 +208,11 @@ struct hpt_iop_request_ioctl_command
 #define HPTIOP_MAX_REQUESTS  256u
 
 struct hptiop_request {
-       struct hptiop_request * next;
-       void *                  req_virt;
-       u32                     req_shifted_phy;
-       struct scsi_cmnd *      scp;
-       int                     index;
+       struct hptiop_request *next;
+       void                  *req_virt;
+       u32                   req_shifted_phy;
+       struct scsi_cmnd      *scp;
+       int                   index;
 };
 
 struct hpt_scsi_pointer {
@@ -198,9 +224,21 @@ struct hpt_scsi_pointer {
 #define HPT_SCP(scp) ((struct hpt_scsi_pointer *)&(scp)->SCp)
 
 struct hptiop_hba {
-       struct hpt_iopmu __iomem * iop;
-       struct Scsi_Host * host;
-       struct pci_dev * pcidev;
+       struct hptiop_adapter_ops *ops;
+       union {
+               struct {
+                       struct hpt_iopmu_itl __iomem *iop;
+               } itl;
+               struct {
+                       struct hpt_iopmv_regs *regs;
+                       struct hpt_iopmu_mv __iomem *mu;
+                       void *internal_req;
+                       dma_addr_t internal_req_phy;
+               } mv;
+       } u;
+
+       struct Scsi_Host *host;
+       struct pci_dev *pcidev;
 
        /* IOP config info */
        u32     interface_version;
@@ -213,15 +251,15 @@ struct hptiop_hba {
 
        u32     req_size; /* host-allocated request buffer size */
 
-       int     iopintf_v2: 1;
-       int     initialized: 1;
-       int     msg_done: 1;
+       u32     iopintf_v2: 1;
+       u32     initialized: 1;
+       u32     msg_done: 1;
 
        struct hptiop_request * req_list;
        struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
 
        /* used to free allocated dma area */
-       void *      dma_coherent;
+       void        *dma_coherent;
        dma_addr_t  dma_coherent_handle;
 
        atomic_t    reset_count;
@@ -231,19 +269,35 @@ struct hptiop_hba {
        wait_queue_head_t ioctl_wq;
 };
 
-struct hpt_ioctl_k
-{
+struct hpt_ioctl_k {
        struct hptiop_hba * hba;
        u32    ioctl_code;
        u32    inbuf_size;
        u32    outbuf_size;
-       void inbuf;
-       void outbuf;
-       u32  bytes_returned;
+       void   *inbuf;
+       void   *outbuf;
+       u32    *bytes_returned;
        void (*done)(struct hpt_ioctl_k *);
        int    result; /* HPT_IOCTL_RESULT_ */
 };
 
+struct hptiop_adapter_ops {
+       int  (*iop_wait_ready)(struct hptiop_hba *hba, u32 millisec);
+       int  (*internal_memalloc)(struct hptiop_hba *hba);
+       int  (*internal_memfree)(struct hptiop_hba *hba);
+       int  (*map_pci_bar)(struct hptiop_hba *hba);
+       void (*unmap_pci_bar)(struct hptiop_hba *hba);
+       void (*enable_intr)(struct hptiop_hba *hba);
+       void (*disable_intr)(struct hptiop_hba *hba);
+       int  (*get_config)(struct hptiop_hba *hba,
+                               struct hpt_iop_request_get_config *config);
+       int  (*set_config)(struct hptiop_hba *hba,
+                               struct hpt_iop_request_set_config *config);
+       int  (*iop_intr)(struct hptiop_hba *hba);
+       void (*post_msg)(struct hptiop_hba *hba, u32 msg);
+       void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req);
+};
+
 #define HPT_IOCTL_RESULT_OK         0
 #define HPT_IOCTL_RESULT_FAILED     (-1)
 
index 5f2396c03958924393864718485d1de683bda6b1..30819012898fca80eb828e81ed2a3aa2c3d308cd 100644 (file)
@@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
                list_del(&evt_struct->list);
                del_timer(&evt_struct->timer);
 
+               /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
+                * Firmware will send a CRQ with a transport event (0xFF) to
+                * tell this client what has happened to the transport.  This
+                * will be handled in ibmvscsi_handle_crq()
+                */
+               if (rc == H_CLOSED) {
+                       dev_warn(hostdata->dev, "send warning. "
+                                "Receive queue closed, will retry.\n");
+                       goto send_busy;
+               }
                dev_err(hostdata->dev, "send error %d\n", rc);
                atomic_inc(&hostdata->request_limit);
                goto send_error;
@@ -976,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        int rsp_rc;
        unsigned long flags;
        u16 lun = lun_from_dev(cmd->device);
+       unsigned long wait_switch = 0;
 
        /* First, find this command in our sent list so we can figure
         * out the correct tag
         */
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       found_evt = NULL;
-       list_for_each_entry(tmp_evt, &hostdata->sent, list) {
-               if (tmp_evt->cmnd == cmd) {
-                       found_evt = tmp_evt;
-                       break;
+       wait_switch = jiffies + (init_timeout * HZ);
+       do {
+               found_evt = NULL;
+               list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+                       if (tmp_evt->cmnd == cmd) {
+                               found_evt = tmp_evt;
+                               break;
+                       }
                }
-       }
 
-       if (!found_evt) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               return SUCCESS;
-       }
+               if (!found_evt) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       return SUCCESS;
+               }
 
-       evt = get_event_struct(&hostdata->pool);
-       if (evt == NULL) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
-               return FAILED;
-       }
+               evt = get_event_struct(&hostdata->pool);
+               if (evt == NULL) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       sdev_printk(KERN_ERR, cmd->device,
+                               "failed to allocate abort event\n");
+                       return FAILED;
+               }
        
-       init_event_struct(evt,
-                         sync_completion,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout);
+               init_event_struct(evt,
+                                 sync_completion,
+                                 VIOSRP_SRP_FORMAT,
+                                 init_timeout);
 
-       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+               tsk_mgmt = &evt->iu.srp.tsk_mgmt;
        
-       /* Set up an abort SRP command */
-       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-       tsk_mgmt->opcode = SRP_TSK_MGMT;
-       tsk_mgmt->lun = ((u64) lun) << 48;
-       tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
-       tsk_mgmt->task_tag = (u64) found_evt;
-
-       sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
-                   tsk_mgmt->lun, tsk_mgmt->task_tag);
-
-       evt->sync_srp = &srp_rsp;
-       init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+               /* Set up an abort SRP command */
+               memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+               tsk_mgmt->opcode = SRP_TSK_MGMT;
+               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
+               tsk_mgmt->task_tag = (u64) found_evt;
+
+               evt->sync_srp = &srp_rsp;
+
+               init_completion(&evt->comp);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+               if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+                       break;
+
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
+       } while (time_before(jiffies, wait_switch));
+
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
        if (rsp_rc != 0) {
                sdev_printk(KERN_ERR, cmd->device,
                            "failed to send abort() event. rc=%d\n", rsp_rc);
                return FAILED;
        }
 
+       sdev_printk(KERN_INFO, cmd->device,
+                    "aborting command. lun 0x%lx, tag 0x%lx\n",
+                   (((u64) lun) << 48), (u64) found_evt);
+
        wait_for_completion(&evt->comp);
 
        /* make sure we got a good response */
@@ -1099,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        int rsp_rc;
        unsigned long flags;
        u16 lun = lun_from_dev(cmd->device);
+       unsigned long wait_switch = 0;
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       evt = get_event_struct(&hostdata->pool);
-       if (evt == NULL) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
-               return FAILED;
-       }
+       wait_switch = jiffies + (init_timeout * HZ);
+       do {
+               evt = get_event_struct(&hostdata->pool);
+               if (evt == NULL) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       sdev_printk(KERN_ERR, cmd->device,
+                               "failed to allocate reset event\n");
+                       return FAILED;
+               }
        
-       init_event_struct(evt,
-                         sync_completion,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout);
+               init_event_struct(evt,
+                                 sync_completion,
+                                 VIOSRP_SRP_FORMAT,
+                                 init_timeout);
 
-       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+               tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 
-       /* Set up a lun reset SRP command */
-       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-       tsk_mgmt->opcode = SRP_TSK_MGMT;
-       tsk_mgmt->lun = ((u64) lun) << 48;
-       tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
+               /* Set up a lun reset SRP command */
+               memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+               tsk_mgmt->opcode = SRP_TSK_MGMT;
+               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
 
-       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
-                   tsk_mgmt->lun);
+               evt->sync_srp = &srp_rsp;
+
+               init_completion(&evt->comp);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+               if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+                       break;
+
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
+       } while (time_before(jiffies, wait_switch));
 
-       evt->sync_srp = &srp_rsp;
-       init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
        if (rsp_rc != 0) {
                sdev_printk(KERN_ERR, cmd->device,
                            "failed to send reset event. rc=%d\n", rsp_rc);
                return FAILED;
        }
 
+       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+                   (((u64) lun) << 48));
+
        wait_for_completion(&evt->comp);
 
        /* make sure we got a good response */
@@ -1386,8 +1427,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
        unsigned long lock_flags = 0;
 
        spin_lock_irqsave(shost->host_lock, lock_flags);
-       if (sdev->type == TYPE_DISK)
+       if (sdev->type == TYPE_DISK) {
                sdev->allow_restart = 1;
+               sdev->timeout = 60 * HZ;
+       }
        scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
        spin_unlock_irqrestore(shost->host_lock, lock_flags);
        return 0;
index 82bcab688b44895fa0a17389100c65af7d95cf1c..d63f11e95abf7f428ec6fb903af3720e04c0a701 100644 (file)
@@ -292,7 +292,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
        dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
                cmd->usg_sg);
 
-       if (sc->use_sg)
+       if (scsi_sg_count(sc))
                err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
 
        spin_lock_irqsave(&target->lock, flags);
index 9706de9d98d51969044a68f8cf0663fac4dde80e..02e91893064d89d6a80a25ef78daee53b1b9f0a8 100644 (file)
@@ -395,14 +395,12 @@ static int idescsi_expiry(ide_drive_t *drive)
 static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
        idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-       idescsi_pc_t *pc=scsi->pc;
+       ide_hwif_t *hwif = drive->hwif;
+       idescsi_pc_t *pc = scsi->pc;
        struct request *rq = pc->rq;
-       atapi_bcount_t bcount;
-       atapi_status_t status;
-       atapi_ireason_t ireason;
-       atapi_feature_t feature;
-
        unsigned int temp;
+       u16 bcount;
+       u8 stat, ireason;
 
 #if IDESCSI_DEBUG_LOG
        printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
@@ -425,30 +423,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
                (void) HWIF(drive)->ide_dma_end(drive);
        }
 
-       feature.all = 0;
        /* Clear the interrupt */
-       status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = drive->hwif->INB(IDE_STATUS_REG);
 
-       if (!status.b.drq) {
+       if ((stat & DRQ_STAT) == 0) {
                /* No more interrupts */
                if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
                        printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
                local_irq_enable_in_hardirq();
-               if (status.b.check)
+               if (stat & ERR_STAT)
                        rq->errors++;
                idescsi_end_request (drive, 1, 0);
                return ide_stopped;
        }
-       bcount.b.low    = HWIF(drive)->INB(IDE_BCOUNTL_REG);
-       bcount.b.high   = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-       ireason.all     = HWIF(drive)->INB(IDE_IREASON_REG);
+       bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+                 hwif->INB(IDE_BCOUNTL_REG);
+       ireason = hwif->INB(IDE_IREASON_REG);
 
-       if (ireason.b.cod) {
+       if (ireason & CD) {
                printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
                return ide_do_reset (drive);
        }
-       if (ireason.b.io) {
-               temp = pc->actually_transferred + bcount.all;
+       if (ireason & IO) {
+               temp = pc->actually_transferred + bcount;
                if (temp > pc->request_transfer) {
                        if (temp > pc->buffer_size) {
                                printk(KERN_ERR "ide-scsi: The scsi wants to "
@@ -461,11 +458,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
                                                idescsi_input_buffers(drive, pc, temp);
                                        else
                                                drive->hwif->atapi_input_bytes(drive, pc->current_position, temp);
-                                       printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
+                                       printk(KERN_ERR "ide-scsi: transferred"
+                                                       " %d of %d bytes\n",
+                                                       temp, bcount);
                                }
                                pc->actually_transferred += temp;
                                pc->current_position += temp;
-                               idescsi_discard_data(drive, bcount.all - temp);
+                               idescsi_discard_data(drive, bcount - temp);
                                ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
                                return ide_started;
                        }
@@ -474,22 +473,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 #endif /* IDESCSI_DEBUG_LOG */
                }
        }
-       if (ireason.b.io) {
+       if (ireason & IO) {
                clear_bit(PC_WRITING, &pc->flags);
                if (pc->sg)
-                       idescsi_input_buffers(drive, pc, bcount.all);
+                       idescsi_input_buffers(drive, pc, bcount);
                else
-                       HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+                       hwif->atapi_input_bytes(drive, pc->current_position,
+                                               bcount);
        } else {
                set_bit(PC_WRITING, &pc->flags);
                if (pc->sg)
-                       idescsi_output_buffers (drive, pc, bcount.all);
+                       idescsi_output_buffers(drive, pc, bcount);
                else
-                       HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+                       hwif->atapi_output_bytes(drive, pc->current_position,
+                                                bcount);
        }
        /* Update the current position */
-       pc->actually_transferred += bcount.all;
-       pc->current_position += bcount.all;
+       pc->actually_transferred += bcount;
+       pc->current_position += bcount;
 
        /* And set the interrupt handler again */
        ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
@@ -501,16 +502,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        idescsi_scsi_t *scsi = drive_to_idescsi(drive);
        idescsi_pc_t *pc = scsi->pc;
-       atapi_ireason_t ireason;
        ide_startstop_t startstop;
+       u8 ireason;
 
        if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
                printk(KERN_ERR "ide-scsi: Strange, packet command "
                        "initiated yet DRQ isn't asserted\n");
                return startstop;
        }
-       ireason.all     = HWIF(drive)->INB(IDE_IREASON_REG);
-       if (!ireason.b.cod || ireason.b.io) {
+       ireason = hwif->INB(IDE_IREASON_REG);
+       if ((ireason & CD) == 0 || (ireason & IO)) {
                printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
                                "issuing a packet command\n");
                return ide_do_reset (drive);
@@ -573,30 +574,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
        idescsi_scsi_t *scsi = drive_to_idescsi(drive);
        ide_hwif_t *hwif = drive->hwif;
-       atapi_feature_t feature;
-       atapi_bcount_t bcount;
+       u16 bcount;
+       u8 dma = 0;
 
        scsi->pc=pc;                                                    /* Set the current packet command */
        pc->actually_transferred=0;                                     /* We haven't transferred any data yet */
        pc->current_position=pc->buffer;
-       bcount.all = min(pc->request_transfer, 63 * 1024);              /* Request to transfer the entire buffer at once */
+       /* Request to transfer the entire buffer at once */
+       bcount = min(pc->request_transfer, 63 * 1024);
 
-       feature.all = 0;
        if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
                hwif->sg_mapped = 1;
-               feature.b.dma = !hwif->dma_setup(drive);
+               dma = !hwif->dma_setup(drive);
                hwif->sg_mapped = 0;
        }
 
        SELECT_DRIVE(drive);
-       if (IDE_CONTROL_REG)
-               HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
 
-       HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
-       HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-       HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+       ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma);
 
-       if (feature.b.dma)
+       if (dma)
                set_bit(PC_DMA_OK, &pc->flags);
 
        if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
index a3d0c6b149583156fda2f7e2267654c6aab9f47a..f97d172844be8e084cca57e3750752be77529816 100644 (file)
@@ -837,19 +837,16 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
 
                /* Phase 4 - Setup scatter/gather buffers */
        case 4:
-               if (cmd->use_sg) {
-                       /* if many buffers are available, start filling the first */
-                       cmd->SCp.buffer =
-                           (struct scatterlist *) cmd->request_buffer;
+               if (scsi_bufflen(cmd)) {
+                       cmd->SCp.buffer = scsi_sglist(cmd);
                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
                        cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                } else {
-                       /* else fill the only available buffer */
                        cmd->SCp.buffer = NULL;
-                       cmd->SCp.this_residual = cmd->request_bufflen;
-                       cmd->SCp.ptr = cmd->request_buffer;
+                       cmd->SCp.this_residual = 0;
+                       cmd->SCp.ptr = NULL;
                }
-               cmd->SCp.buffers_residual = cmd->use_sg - 1;
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.phase++;
                if (cmd->SCp.this_residual & 0x01)
                        cmd->SCp.this_residual++;
index c8b452f2878c4a019822775769b1003206b549ed..8053b1e86ccbf78730bf7dc46904379cabbc9aea 100644 (file)
@@ -369,16 +369,16 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
  *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
-       if (cmd->use_sg) {
-               cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-               cmd->SCp.buffers_residual = cmd->use_sg - 1;
+       if (scsi_bufflen(cmd)) {
+               cmd->SCp.buffer = scsi_sglist(cmd);
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
                cmd->SCp.buffers_residual = 0;
-               cmd->SCp.ptr = (char *) cmd->request_buffer;
-               cmd->SCp.this_residual = cmd->request_bufflen;
+               cmd->SCp.ptr = NULL;
+               cmd->SCp.this_residual = 0;
        }
        cmd->SCp.have_data_in = 0;
 
index 01bf0189367dc8ef3bf30ff1668bf8eac31c1c7f..a10a5c74b48db6d2150905b252f52fbc3b0d3362 100644 (file)
@@ -823,7 +823,7 @@ static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_b
 {
 
 #if DEBUG_QUEUE
-       printk("append busy SCB %o; ", scbp);
+       printk("append busy SCB %p; ", scbp);
 #endif
        if (scbp->tagmsg)
                host->act_tags[scbp->target]++;
@@ -2609,6 +2609,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
                cblk->bufptr = cpu_to_le32((u32)dma_addr);
                cmnd->SCp.dma_handle = dma_addr;
 
+               cblk->sglen = nseg;
 
                cblk->flags |= SCF_SG;  /* Turn on SG list flag       */
                total_len = 0;
@@ -2869,6 +2870,7 @@ static int initio_probe_one(struct pci_dev *pdev,
        host = (struct initio_host *)shost->hostdata;
        memset(host, 0, sizeof(struct initio_host));
        host->addr = pci_resource_start(pdev, 0);
+       host->bios_addr = bios_seg;
 
        if (!request_region(host->addr, 256, "i91u")) {
                printk(KERN_WARNING "initio: I/O port range 0x%x is busy.\n", host->addr);
@@ -2895,6 +2897,8 @@ static int initio_probe_one(struct pci_dev *pdev,
 
        host->pci_dev = pdev;
 
+       host->semaph = 1;
+       spin_lock_init(&host->semaph_lock);
        host->num_scbs = num_scb;
        host->scb = scb;
        host->next_pending = scb;
@@ -2911,7 +2915,7 @@ static int initio_probe_one(struct pci_dev *pdev,
        host->last_avail = prev;
        spin_lock_init(&host->avail_lock);
 
-       initio_init(host, phys_to_virt(bios_seg << 4));
+       initio_init(host, phys_to_virt(((u32)bios_seg << 4)));
 
        host->jsstatus0 = 0;
 
index 0841df01bc19921d7d34f99d08116c0076b7954c..73270ff892d9699c63cd5388ae0ace773dcfc3de 100644 (file)
@@ -84,7 +84,7 @@
 /*
  *   Global Data
  */
-static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head);
+static LIST_HEAD(ipr_ioa_head);
 static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
 static unsigned int ipr_max_speed = 1;
 static int ipr_testmode = 0;
@@ -5142,6 +5142,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
        struct ipr_ioadl_desc *last_ioadl = NULL;
        int len = qc->nbytes + qc->pad_len;
        struct scatterlist *sg;
+       unsigned int si;
 
        if (len == 0)
                return;
@@ -5159,7 +5160,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
                        cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
        }
 
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
                ioadl->address = cpu_to_be32(sg_dma_address(sg));
 
@@ -5222,12 +5223,12 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
                regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
                break;
 
-       case ATA_PROT_ATAPI:
-       case ATA_PROT_ATAPI_NODATA:
+       case ATAPI_PROT_PIO:
+       case ATAPI_PROT_NODATA:
                regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
                break;
 
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
                regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
                regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
                break;
index 5c5a9b2628fc446f6ddc7c385122607a8cb6c0ef..7505cca8e68e3d1825e06c9a977e948c3a0dacf2 100644 (file)
@@ -389,17 +389,17 @@ static struct  pci_device_id  ips_pci_table[] = {
 MODULE_DEVICE_TABLE( pci, ips_pci_table );
 
 static char ips_hot_plug_name[] = "ips";
-   
+
 static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
 static void __devexit ips_remove_device(struct pci_dev *pci_dev);
-   
+
 static struct pci_driver ips_pci_driver = {
        .name           = ips_hot_plug_name,
        .id_table       = ips_pci_table,
        .probe          = ips_insert_device,
        .remove         = __devexit_p(ips_remove_device),
 };
-           
+
 
 /*
  * Necessary forward function protoypes
@@ -587,7 +587,7 @@ static void
 ips_setup_funclist(ips_ha_t * ha)
 {
 
-       /*                                
+       /*
         * Setup Functions
         */
        if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
@@ -702,12 +702,8 @@ ips_release(struct Scsi_Host *sh)
        /* free extra memory */
        ips_free(ha);
 
-       /* Free I/O Region */
-       if (ha->io_addr)
-               release_region(ha->io_addr, ha->io_len);
-
        /* free IRQ */
-       free_irq(ha->irq, ha);
+       free_irq(ha->pcidev->irq, ha);
 
        scsi_host_put(sh);
 
@@ -1637,7 +1633,7 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
                                return (IPS_FAILURE);
                        }
 
-                       if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+                       if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
                            pt->CoppCP.cmd.flashfw.op_code ==
                            IPS_CMD_RW_BIOSFW) {
                                ret = ips_flash_copperhead(ha, pt, scb);
@@ -2021,7 +2017,7 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
        pt->ExtendedStatus = scb->extended_status;
        pt->AdapterType = ha->ad_type;
 
-       if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+       if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
            (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
             scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
                ips_free_flash_copperhead(ha);
@@ -2075,13 +2071,13 @@ ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
                          ha->mem_ptr);
        }
 
-       copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
+       copy_info(&info, "\tIRQ number                        : %d\n", ha->pcidev->irq);
 
     /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
     /* That keeps everything happy for "text" operations on the proc file.                    */
 
        if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
-        if (ha->nvram->bios_low[3] == 0) { 
+       if (ha->nvram->bios_low[3] == 0) {
             copy_info(&info,
                                  "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
                                  ha->nvram->bios_high[0], ha->nvram->bios_high[1],
@@ -2232,31 +2228,31 @@ ips_identify_controller(ips_ha_t * ha)
 {
        METHOD_TRACE("ips_identify_controller", 1);
 
-       switch (ha->device_id) {
+       switch (ha->pcidev->device) {
        case IPS_DEVICEID_COPPERHEAD:
-               if (ha->revision_id <= IPS_REVID_SERVERAID) {
+               if (ha->pcidev->revision <= IPS_REVID_SERVERAID) {
                        ha->ad_type = IPS_ADTYPE_SERVERAID;
-               } else if (ha->revision_id == IPS_REVID_SERVERAID2) {
+               } else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) {
                        ha->ad_type = IPS_ADTYPE_SERVERAID2;
-               } else if (ha->revision_id == IPS_REVID_NAVAJO) {
+               } else if (ha->pcidev->revision == IPS_REVID_NAVAJO) {
                        ha->ad_type = IPS_ADTYPE_NAVAJO;
-               } else if ((ha->revision_id == IPS_REVID_SERVERAID2)
+               } else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2)
                           && (ha->slot_num == 0)) {
                        ha->ad_type = IPS_ADTYPE_KIOWA;
-               } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
-                          (ha->revision_id <= IPS_REVID_CLARINETP3)) {
+               } else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) &&
+                          (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) {
                        if (ha->enq->ucMaxPhysicalDevices == 15)
                                ha->ad_type = IPS_ADTYPE_SERVERAID3L;
                        else
                                ha->ad_type = IPS_ADTYPE_SERVERAID3;
-               } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
-                          (ha->revision_id <= IPS_REVID_TROMBONE64)) {
+               } else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) &&
+                          (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) {
                        ha->ad_type = IPS_ADTYPE_SERVERAID4H;
                }
                break;
 
        case IPS_DEVICEID_MORPHEUS:
-               switch (ha->subdevice_id) {
+               switch (ha->pcidev->subsystem_device) {
                case IPS_SUBDEVICEID_4L:
                        ha->ad_type = IPS_ADTYPE_SERVERAID4L;
                        break;
@@ -2285,7 +2281,7 @@ ips_identify_controller(ips_ha_t * ha)
                break;
 
        case IPS_DEVICEID_MARCO:
-               switch (ha->subdevice_id) {
+               switch (ha->pcidev->subsystem_device) {
                case IPS_SUBDEVICEID_6M:
                        ha->ad_type = IPS_ADTYPE_SERVERAID6M;
                        break;
@@ -2332,20 +2328,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
        strncpy(ha->bios_version, "       ?", 8);
 
-       if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
+       if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) {
                if (IPS_USE_MEMIO(ha)) {
                        /* Memory Mapped I/O */
 
                        /* test 1st byte */
                        writel(0, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
                                return;
 
                        writel(1, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
@@ -2353,20 +2349,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
                        /* Get Major version */
                        writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        major = readb(ha->mem_ptr + IPS_REG_FLDP);
 
                        /* Get Minor version */
                        writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
                        minor = readb(ha->mem_ptr + IPS_REG_FLDP);
 
                        /* Get SubMinor version */
                        writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
                        subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
 
@@ -2375,14 +2371,14 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
                        /* test 1st byte */
                        outl(0, ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
                                return;
 
                        outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
@@ -2390,21 +2386,21 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
                        /* Get Major version */
                        outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        major = inb(ha->io_addr + IPS_REG_FLDP);
 
                        /* Get Minor version */
                        outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        minor = inb(ha->io_addr + IPS_REG_FLDP);
 
                        /* Get SubMinor version */
                        outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        subminor = inb(ha->io_addr + IPS_REG_FLDP);
@@ -2740,8 +2736,6 @@ ips_next(ips_ha_t * ha, int intr)
                SC->result = DID_OK;
                SC->host_scribble = NULL;
 
-               memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
-
                scb->target_id = SC->device->id;
                scb->lun = SC->device->lun;
                scb->bus = SC->device->channel;
@@ -2780,10 +2774,11 @@ ips_next(ips_ha_t * ha, int intr)
                scb->dcdb.cmd_attribute =
                    ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
-        /* Allow a WRITE BUFFER Command to Have no Data */
-        /* This is Used by Tape Flash Utilites          */
-        if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) 
-            scb->dcdb.cmd_attribute = 0;                  
+               /* Allow a WRITE BUFFER Command to Have no Data */
+               /* This is Used by Tape Flash Utilites          */
+               if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) &&
+                               (scb->data_len == 0))
+                       scb->dcdb.cmd_attribute = 0;
 
                if (!(scb->dcdb.cmd_attribute & 0x3))
                        scb->dcdb.transfer_length = 0;
@@ -3404,7 +3399,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
 
                                /* Restrict access to physical DASD */
                                if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
-                                   ips_scmd_buf_read(scb->scsi_cmd, 
+                                   ips_scmd_buf_read(scb->scsi_cmd,
                                       &inquiryData, sizeof (inquiryData));
                                    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
                                        errcode = DID_TIME_OUT;
@@ -3438,13 +3433,11 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
                                            (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
                                        memcpy(scb->scsi_cmd->sense_buffer,
                                               tapeDCDB->sense_info,
-                                              sizeof (scb->scsi_cmd->
-                                                      sense_buffer));
+                                              SCSI_SENSE_BUFFERSIZE);
                                } else {
                                        memcpy(scb->scsi_cmd->sense_buffer,
                                               scb->dcdb.sense_info,
-                                              sizeof (scb->scsi_cmd->
-                                                      sense_buffer));
+                                              SCSI_SENSE_BUFFERSIZE);
                                }
                                device_error = 2;       /* check condition */
                        }
@@ -3824,7 +3817,6 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
                        /* attempted, a Check Condition occurred, and Sense   */
                        /* Data indicating an Invalid CDB OpCode is returned. */
                        sp = (char *) scb->scsi_cmd->sense_buffer;
-                       memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
 
                        sp[0] = 0x70;   /* Error Code               */
                        sp[2] = ILLEGAL_REQUEST;        /* Sense Key 5 Illegal Req. */
@@ -4090,10 +4082,10 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
                        scb->scsi_cmd->result = errcode << 16;
                } else {        /* bus == 0 */
                        /* restrict access to physical drives */
-                       if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 
-                           ips_scmd_buf_read(scb->scsi_cmd, 
+                       if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+                           ips_scmd_buf_read(scb->scsi_cmd,
                                   &inquiryData, sizeof (inquiryData));
-                           if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 
+                           if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK)
                                scb->scsi_cmd->result = DID_TIME_OUT << 16;
                        }
                }               /* else */
@@ -4393,8 +4385,6 @@ ips_free(ips_ha_t * ha)
                        ha->mem_ptr = NULL;
                }
 
-               if (ha->mem_addr)
-                       release_mem_region(ha->mem_addr, ha->mem_len);
                ha->mem_addr = 0;
 
        }
@@ -4661,8 +4651,8 @@ ips_isinit_morpheus(ips_ha_t * ha)
        uint32_t bits;
 
        METHOD_TRACE("ips_is_init_morpheus", 1);
-   
-       if (ips_isintr_morpheus(ha)) 
+
+       if (ips_isintr_morpheus(ha))
            ips_flush_and_reset(ha);
 
        post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
@@ -4686,7 +4676,7 @@ ips_isinit_morpheus(ips_ha_t * ha)
 /*   state ( was trying to INIT and an interrupt was already pending ) ...  */
 /*                                                                          */
 /****************************************************************************/
-static void 
+static void
 ips_flush_and_reset(ips_ha_t *ha)
 {
        ips_scb_t *scb;
@@ -4718,9 +4708,9 @@ ips_flush_and_reset(ips_ha_t *ha)
            if (ret == IPS_SUCCESS) {
                time = 60 * IPS_ONE_SEC;                      /* Max Wait time is 60 seconds */
                done = 0;
-                   
+
                while ((time > 0) && (!done)) {
-                  done = ips_poll_for_flush_complete(ha);         
+                  done = ips_poll_for_flush_complete(ha);
                   /* This may look evil, but it's only done during extremely rare start-up conditions ! */
                   udelay(1000);
                   time--;
@@ -4749,17 +4739,17 @@ static int
 ips_poll_for_flush_complete(ips_ha_t * ha)
 {
        IPS_STATUS cstatus;
-    
+
        while (TRUE) {
            cstatus.value = (*ha->func.statupd) (ha);
 
            if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */
                        break;
-            
+
            /* Success is when we see the Flush Command ID */
-           if (cstatus.fields.command_id == IPS_MAX_CMDS ) 
+           if (cstatus.fields.command_id == IPS_MAX_CMDS)
                return 1;
-        }      
+        }
 
        return 0;
 }
@@ -4903,7 +4893,7 @@ ips_init_copperhead(ips_ha_t * ha)
        /* Enable busmastering */
        outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
 
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                /* fix for anaconda64 */
                outl(0, ha->io_addr + IPS_REG_NDAE);
 
@@ -4997,7 +4987,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
        /* Enable busmastering */
        writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
 
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                /* fix for anaconda64 */
                writel(0, ha->mem_ptr + IPS_REG_NDAE);
 
@@ -5142,7 +5132,7 @@ ips_reset_copperhead(ips_ha_t * ha)
        METHOD_TRACE("ips_reset_copperhead", 1);
 
        DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
-                 ips_name, ha->host_num, ha->io_addr, ha->irq);
+                 ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq);
 
        reset_counter = 0;
 
@@ -5187,7 +5177,7 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
        METHOD_TRACE("ips_reset_copperhead_memio", 1);
 
        DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
-                 ips_name, ha->host_num, ha->mem_addr, ha->irq);
+                 ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
 
        reset_counter = 0;
 
@@ -5233,7 +5223,7 @@ ips_reset_morpheus(ips_ha_t * ha)
        METHOD_TRACE("ips_reset_morpheus", 1);
 
        DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
-                 ips_name, ha->host_num, ha->mem_addr, ha->irq);
+                 ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
 
        reset_counter = 0;
 
@@ -5920,7 +5910,7 @@ ips_read_config(ips_ha_t * ha, int intr)
 
                return (0);
        }
-       
+
        memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
        return (1);
 }
@@ -5959,7 +5949,7 @@ ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
        scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
        if (write)
                memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
-       
+
        /* issue the command */
        if (((ret =
              ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
@@ -6196,32 +6186,32 @@ ips_erase_bios(ips_ha_t * ha)
 
        /* Clear the status register */
        outl(0, ha->io_addr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        outb(0x50, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* Erase Setup */
        outb(0x20, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* Erase Confirm */
        outb(0xD0, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* Erase Status */
        outb(0x70, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        timeout = 80000;        /* 80 seconds */
 
        while (timeout > 0) {
-               if (ha->revision_id == IPS_REVID_TROMBONE64) {
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
                        outl(0, ha->io_addr + IPS_REG_FLAP);
                        udelay(25);     /* 25 us */
                }
@@ -6241,13 +6231,13 @@ ips_erase_bios(ips_ha_t * ha)
 
                /* try to suspend the erase */
                outb(0xB0, ha->io_addr + IPS_REG_FLDP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                /* wait for 10 seconds */
                timeout = 10000;
                while (timeout > 0) {
-                       if (ha->revision_id == IPS_REVID_TROMBONE64) {
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
                                outl(0, ha->io_addr + IPS_REG_FLAP);
                                udelay(25);     /* 25 us */
                        }
@@ -6277,12 +6267,12 @@ ips_erase_bios(ips_ha_t * ha)
        /* Otherwise, we were successful */
        /* clear status */
        outb(0x50, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* enable reads */
        outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        return (0);
@@ -6308,32 +6298,32 @@ ips_erase_bios_memio(ips_ha_t * ha)
 
        /* Clear the status register */
        writel(0, ha->mem_ptr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* Erase Setup */
        writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* Erase Confirm */
        writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* Erase Status */
        writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        timeout = 80000;        /* 80 seconds */
 
        while (timeout > 0) {
-               if (ha->revision_id == IPS_REVID_TROMBONE64) {
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
                        writel(0, ha->mem_ptr + IPS_REG_FLAP);
                        udelay(25);     /* 25 us */
                }
@@ -6353,13 +6343,13 @@ ips_erase_bios_memio(ips_ha_t * ha)
 
                /* try to suspend the erase */
                writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                /* wait for 10 seconds */
                timeout = 10000;
                while (timeout > 0) {
-                       if (ha->revision_id == IPS_REVID_TROMBONE64) {
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
                                writel(0, ha->mem_ptr + IPS_REG_FLAP);
                                udelay(25);     /* 25 us */
                        }
@@ -6389,12 +6379,12 @@ ips_erase_bios_memio(ips_ha_t * ha)
        /* Otherwise, we were successful */
        /* clear status */
        writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        /* enable reads */
        writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        return (0);
@@ -6423,21 +6413,21 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
        for (i = 0; i < buffersize; i++) {
                /* write a byte */
                outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                outb(0x40, ha->io_addr + IPS_REG_FLDP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                /* wait up to one second */
                timeout = 1000;
                while (timeout > 0) {
-                       if (ha->revision_id == IPS_REVID_TROMBONE64) {
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
                                outl(0, ha->io_addr + IPS_REG_FLAP);
                                udelay(25);     /* 25 us */
                        }
@@ -6454,11 +6444,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
                if (timeout == 0) {
                        /* timeout error */
                        outl(0, ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        return (1);
@@ -6468,11 +6458,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
                if (status & 0x18) {
                        /* programming error */
                        outl(0, ha->io_addr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        return (1);
@@ -6481,11 +6471,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
        /* Enable reading */
        outl(0, ha->io_addr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        return (0);
@@ -6514,21 +6504,21 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
        for (i = 0; i < buffersize; i++) {
                /* write a byte */
                writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                /* wait up to one second */
                timeout = 1000;
                while (timeout > 0) {
-                       if (ha->revision_id == IPS_REVID_TROMBONE64) {
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
                                writel(0, ha->mem_ptr + IPS_REG_FLAP);
                                udelay(25);     /* 25 us */
                        }
@@ -6545,11 +6535,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
                if (timeout == 0) {
                        /* timeout error */
                        writel(0, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        return (1);
@@ -6559,11 +6549,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
                if (status & 0x18) {
                        /* programming error */
                        writel(0, ha->mem_ptr + IPS_REG_FLAP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-                       if (ha->revision_id == IPS_REVID_TROMBONE64)
+                       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                                udelay(25);     /* 25 us */
 
                        return (1);
@@ -6572,11 +6562,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
        /* Enable reading */
        writel(0, ha->mem_ptr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        return (0);
@@ -6601,14 +6591,14 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
        /* test 1st byte */
        outl(0, ha->io_addr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
                return (1);
 
        outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
        if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
                return (1);
@@ -6617,7 +6607,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
        for (i = 2; i < buffersize; i++) {
 
                outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
@@ -6650,14 +6640,14 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
        /* test 1st byte */
        writel(0, ha->mem_ptr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
 
        if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
                return (1);
 
        writel(1, ha->mem_ptr + IPS_REG_FLAP);
-       if (ha->revision_id == IPS_REVID_TROMBONE64)
+       if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                udelay(25);     /* 25 us */
        if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
                return (1);
@@ -6666,7 +6656,7 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
        for (i = 2; i < buffersize; i++) {
 
                writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
-               if (ha->revision_id == IPS_REVID_TROMBONE64)
+               if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
                        udelay(25);     /* 25 us */
 
                checksum =
@@ -6837,24 +6827,18 @@ ips_register_scsi(int index)
        }
        ha = IPS_HA(sh);
        memcpy(ha, oldha, sizeof (ips_ha_t));
-       free_irq(oldha->irq, oldha);
+       free_irq(oldha->pcidev->irq, oldha);
        /* Install the interrupt handler with the new ha */
-       if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
+       if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to install interrupt handler\n");
-               scsi_host_put(sh);
-               return -1;
+               goto err_out_sh;
        }
 
        kfree(oldha);
-       ips_sh[index] = sh;
-       ips_ha[index] = ha;
 
        /* Store away needed values for later use */
-       sh->io_port = ha->io_addr;
-       sh->n_io_port = ha->io_addr ? 255 : 0;
        sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
-       sh->irq = ha->irq;
        sh->sg_tablesize = sh->hostt->sg_tablesize;
        sh->can_queue = sh->hostt->can_queue;
        sh->cmd_per_lun = sh->hostt->cmd_per_lun;
@@ -6867,10 +6851,21 @@ ips_register_scsi(int index)
        sh->max_channel = ha->nbus - 1;
        sh->can_queue = ha->max_cmds - 1;
 
-       scsi_add_host(sh, NULL);
+       if (scsi_add_host(sh, &ha->pcidev->dev))
+               goto err_out;
+
+       ips_sh[index] = sh;
+       ips_ha[index] = ha;
+
        scsi_scan_host(sh);
 
        return 0;
+
+err_out:
+       free_irq(ha->pcidev->irq, ha);
+err_out_sh:
+       scsi_host_put(sh);
+       return -1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -6882,20 +6877,14 @@ ips_register_scsi(int index)
 static void __devexit
 ips_remove_device(struct pci_dev *pci_dev)
 {
-       int i;
-       struct Scsi_Host *sh;
-       ips_ha_t *ha;
+       struct Scsi_Host *sh = pci_get_drvdata(pci_dev);
 
-       for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
-               ha = ips_ha[i];
-               if (ha) {
-                       if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
-                           (pci_dev->devfn == ha->pcidev->devfn)) {
-                               sh = ips_sh[i];
-                               ips_release(sh);
-                       }
-               }
-       }
+       pci_set_drvdata(pci_dev, NULL);
+
+       ips_release(sh);
+
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
 }
 
 /****************************************************************************/
@@ -6949,12 +6938,17 @@ module_exit(ips_module_exit);
 static int __devinit
 ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
 {
-       int uninitialized_var(index);
+       int index = -1;
        int rc;
 
        METHOD_TRACE("ips_insert_device", 1);
-       if (pci_enable_device(pci_dev))
-               return -1;
+       rc = pci_enable_device(pci_dev);
+       if (rc)
+               return rc;
+
+       rc = pci_request_regions(pci_dev, "ips");
+       if (rc)
+               goto err_out;
 
        rc = ips_init_phase1(pci_dev, &index);
        if (rc == SUCCESS)
@@ -6970,6 +6964,19 @@ ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
                ips_num_controllers++;
 
        ips_next_controller = ips_num_controllers;
+
+       if (rc < 0) {
+               rc = -ENODEV;
+               goto err_out_regions;
+       }
+
+       pci_set_drvdata(pci_dev, ips_sh[index]);
+       return 0;
+
+err_out_regions:
+       pci_release_regions(pci_dev);
+err_out:
+       pci_disable_device(pci_dev);
        return rc;
 }
 
@@ -6992,8 +6999,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
        uint32_t mem_len;
        uint8_t bus;
        uint8_t func;
-       uint8_t irq;
-       uint16_t subdevice_id;
        int j;
        int index;
        dma_addr_t dma_address;
@@ -7004,7 +7009,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
        METHOD_TRACE("ips_init_phase1", 1);
        index = IPS_MAX_ADAPTERS;
        for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
-               if (ips_ha[j] == 0) {
+               if (ips_ha[j] == NULL) {
                        index = j;
                        break;
                }
@@ -7014,7 +7019,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
                return -1;
 
        /* stuff that we get in dev */
-       irq = pci_dev->irq;
        bus = pci_dev->bus->number;
        func = pci_dev->devfn;
 
@@ -7042,34 +7046,17 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
                uint32_t base;
                uint32_t offs;
 
-               if (!request_mem_region(mem_addr, mem_len, "ips")) {
-                       IPS_PRINTK(KERN_WARNING, pci_dev,
-                                  "Couldn't allocate IO Memory space %x len %d.\n",
-                                  mem_addr, mem_len);
-                       return -1;
-               }
-
                base = mem_addr & PAGE_MASK;
                offs = mem_addr - base;
                ioremap_ptr = ioremap(base, PAGE_SIZE);
+               if (!ioremap_ptr)
+                       return -1;
                mem_ptr = ioremap_ptr + offs;
        } else {
                ioremap_ptr = NULL;
                mem_ptr = NULL;
        }
 
-       /* setup I/O mapped area (if applicable) */
-       if (io_addr) {
-               if (!request_region(io_addr, io_len, "ips")) {
-                       IPS_PRINTK(KERN_WARNING, pci_dev,
-                                  "Couldn't allocate IO space %x len %d.\n",
-                                  io_addr, io_len);
-                       return -1;
-               }
-       }
-
-       subdevice_id = pci_dev->subsystem_device;
-
        /* found a controller */
        ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
        if (ha == NULL) {
@@ -7078,13 +7065,11 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
                return -1;
        }
 
-
        ips_sh[index] = NULL;
        ips_ha[index] = ha;
        ha->active = 1;
 
        /* Store info in HA structure */
-       ha->irq = irq;
        ha->io_addr = io_addr;
        ha->io_len = io_len;
        ha->mem_addr = mem_addr;
@@ -7092,10 +7077,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
        ha->mem_ptr = mem_ptr;
        ha->ioremap_ptr = ioremap_ptr;
        ha->host_num = (uint32_t) index;
-       ha->revision_id = pci_dev->revision;
        ha->slot_num = PCI_SLOT(pci_dev->devfn);
-       ha->device_id = pci_dev->device;
-       ha->subdevice_id = subdevice_id;
        ha->pcidev = pci_dev;
 
        /*
@@ -7240,7 +7222,7 @@ ips_init_phase2(int index)
        }
 
        /* Install the interrupt handler */
-       if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
+       if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to install interrupt handler\n");
                return ips_abort_init(ha, index);
@@ -7253,14 +7235,14 @@ ips_init_phase2(int index)
        if (!ips_allocatescbs(ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to allocate a CCB\n");
-               free_irq(ha->irq, ha);
+               free_irq(ha->pcidev->irq, ha);
                return ips_abort_init(ha, index);
        }
 
        if (!ips_hainit(ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to initialize controller\n");
-               free_irq(ha->irq, ha);
+               free_irq(ha->pcidev->irq, ha);
                return ips_abort_init(ha, index);
        }
        /* Free the temporary SCB */
@@ -7270,7 +7252,7 @@ ips_init_phase2(int index)
        if (!ips_allocatescbs(ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to allocate CCBs\n");
-               free_irq(ha->irq, ha);
+               free_irq(ha->pcidev->irq, ha);
                return ips_abort_init(ha, index);
        }
 
index 3bcbd9ff056b07f124608ac8fbd979cdecb0175a..e0657b6f009c0b5488a969f43936cf719c9dcbc9 100644 (file)
     */
    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
-   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
-                                         (ha->revision_id >= IPS_REVID_TROMBONE32) && \
-                                         (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
-   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
-                                         (ha->revision_id >= IPS_REVID_CLARINETP1) && \
-                                         (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
-   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
-   #define IPS_IS_MARCO(ha)            (ha->device_id == IPS_DEVICEID_MARCO)
+   #define IPS_IS_TROMBONE(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
+                                         (ha->pcidev->revision >= IPS_REVID_TROMBONE32) && \
+                                         (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) ? 1 : 0)
+   #define IPS_IS_CLARINET(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
+                                         (ha->pcidev->revision >= IPS_REVID_CLARINETP1) && \
+                                         (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) ? 1 : 0)
+   #define IPS_IS_MORPHEUS(ha)         (ha->pcidev->device == IPS_DEVICEID_MORPHEUS)
+   #define IPS_IS_MARCO(ha)            (ha->pcidev->device == IPS_DEVICEID_MARCO)
    #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
                                          (IPS_IS_TROMBONE(ha) && \
                                           (ips_force_i2o))) ? 1 : 0)
@@ -92,7 +92,7 @@
    #ifndef min
       #define min(x,y) ((x) < (y) ? x : y)
    #endif
-   
+
    #ifndef __iomem       /* For clean compiles in earlier kernels without __iomem annotations */
       #define __iomem
    #endif
    #define IPS_CMD_DOWNLOAD             0x20
    #define IPS_CMD_RW_BIOSFW            0x22
    #define IPS_CMD_GET_VERSION_INFO     0xC6
-   #define IPS_CMD_RESET_CHANNEL        0x1A  
+   #define IPS_CMD_RESET_CHANNEL        0x1A
 
    /*
     * Adapter Equates
@@ -458,7 +458,7 @@ typedef struct {
    uint32_t reserved3;
    uint32_t buffer_addr;
    uint32_t reserved4;
-} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; 
+} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD;
 
 typedef struct {
    uint8_t  op_code;
@@ -552,7 +552,7 @@ typedef struct {
    uint32_t cccr;
 } IPS_NVRAM_CMD, *PIPS_NVRAM_CMD;
 
-typedef struct 
+typedef struct
 {
     uint8_t  op_code;
     uint8_t  command_id;
@@ -650,7 +650,7 @@ typedef struct {
    uint8_t   device_address;
    uint8_t   cmd_attribute;
    uint8_t   cdb_length;
-   uint8_t   reserved_for_LUN;          
+   uint8_t   reserved_for_LUN;
    uint32_t  transfer_length;
    uint32_t  buffer_pointer;
    uint16_t  sg_count;
@@ -790,7 +790,7 @@ typedef struct {
                                              /* SubSystem Parameter[4]      */
 #define  IPS_GET_VERSION_SUPPORT 0x00018000  /* Mask for Versioning Support */
 
-typedef struct 
+typedef struct
 {
    uint32_t  revision;
    uint8_t   bootBlkVersion[32];
@@ -1034,7 +1034,6 @@ typedef struct ips_ha {
    uint8_t            ha_id[IPS_MAX_CHANNELS+1];
    uint32_t           dcdb_active[IPS_MAX_CHANNELS];
    uint32_t           io_addr;            /* Base I/O address           */
-   uint8_t            irq;                /* IRQ for adapter            */
    uint8_t            ntargets;           /* Number of targets          */
    uint8_t            nbus;               /* Number of buses            */
    uint8_t            nlun;               /* Number of Luns             */
@@ -1066,10 +1065,7 @@ typedef struct ips_ha {
    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
    uint16_t           reset_count;        /* number of resets           */
    time_t             last_ffdc;          /* last time we sent ffdc info*/
-   uint8_t            revision_id;        /* Revision level             */
-   uint16_t           device_id;          /* PCI device ID              */
    uint8_t            slot_num;           /* PCI Slot Number            */
-   uint16_t           subdevice_id;       /* Subsystem device ID        */
    int                ioctl_len;          /* size of ioctl buffer       */
    dma_addr_t         ioctl_busaddr;      /* dma address of ioctl buffer*/
    uint8_t            bios_version[8];    /* BIOS Revision              */
index 57ce2251abc818a31a6db047666306d05fd5d785..e5be5fd4ef583f10ba907721da19249999d609bb 100644 (file)
@@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
              "Alex Aizman <itn780@yahoo.com>");
 MODULE_DESCRIPTION("iSCSI/TCP data-path");
 MODULE_LICENSE("GPL");
-/* #define DEBUG_TCP */
+#undef DEBUG_TCP
 #define DEBUG_ASSERT
 
 #ifdef DEBUG_TCP
@@ -67,115 +67,429 @@ MODULE_LICENSE("GPL");
 static unsigned int iscsi_max_lun = 512;
 module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
 
+static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
+                                  struct iscsi_segment *segment);
+
+/*
+ * Scatterlist handling: inside the iscsi_segment, we
+ * remember an index into the scatterlist, and set data/size
+ * to the current scatterlist entry. For highmem pages, we
+ * kmap as needed.
+ *
+ * Note that the page is unmapped when we return from
+ * TCP's data_ready handler, so we may end up mapping and
+ * unmapping the same page repeatedly. The whole reason
+ * for this is that we shouldn't keep the page mapped
+ * outside the softirq.
+ */
+
+/**
+ * iscsi_tcp_segment_init_sg - init indicated scatterlist entry
+ * @segment: the buffer object
+ * @sg: scatterlist
+ * @offset: byte offset into that sg entry
+ *
+ * This function sets up the segment so that subsequent
+ * data is copied to the indicated sg entry, at the given
+ * offset.
+ */
 static inline void
-iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
+iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
+                         struct scatterlist *sg, unsigned int offset)
 {
-       sg_init_one(&ibuf->sg, vbuf, size);
-       ibuf->sent = 0;
-       ibuf->use_sendmsg = 1;
+       segment->sg = sg;
+       segment->sg_offset = offset;
+       segment->size = min(sg->length - offset,
+                           segment->total_size - segment->total_copied);
+       segment->data = NULL;
 }
 
+/**
+ * iscsi_tcp_segment_map - map the current S/G page
+ * @segment: iscsi_segment
+ * @recv: 1 if called from recv path
+ *
+ * We only need to possibly kmap data if scatter lists are being used,
+ * because the iscsi passthrough and internal IO paths will never use high
+ * mem pages.
+ */
 static inline void
-iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
+iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
 {
-       sg_init_table(&ibuf->sg, 1);
-       sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset);
+       struct scatterlist *sg;
+
+       if (segment->data != NULL || !segment->sg)
+               return;
+
+       sg = segment->sg;
+       BUG_ON(segment->sg_mapped);
+       BUG_ON(sg->length == 0);
+
        /*
-        * Fastpath: sg element fits into single page
+        * If the page count is greater than one it is ok to send
+        * to the network layer's zero copy send path. If not we
+        * have to go the slow sendmsg path. We always map for the
+        * recv path.
         */
-       if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg)))
-               ibuf->use_sendmsg = 0;
-       else
-               ibuf->use_sendmsg = 1;
-       ibuf->sent = 0;
+       if (page_count(sg_page(sg)) >= 1 && !recv)
+               return;
+
+       debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit",
+                 segment);
+       segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
+       segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
 }
 
-static inline int
-iscsi_buf_left(struct iscsi_buf *ibuf)
+static inline void
+iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
 {
-       int rc;
+       debug_tcp("iscsi_tcp_segment_unmap %p\n", segment);
 
-       rc = ibuf->sg.length - ibuf->sent;
-       BUG_ON(rc < 0);
-       return rc;
+       if (segment->sg_mapped) {
+               debug_tcp("iscsi_tcp_segment_unmap valid\n");
+               kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0);
+               segment->sg_mapped = NULL;
+               segment->data = NULL;
+       }
 }
 
+/*
+ * Splice the digest buffer into the buffer
+ */
 static inline void
-iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
-                u8* crc)
+iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
 {
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
-       crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
-       buf->sg.length += sizeof(u32);
+       segment->data = digest;
+       segment->digest_len = ISCSI_DIGEST_SIZE;
+       segment->total_size += ISCSI_DIGEST_SIZE;
+       segment->size = ISCSI_DIGEST_SIZE;
+       segment->copied = 0;
+       segment->sg = NULL;
+       segment->hash = NULL;
 }
 
+/**
+ * iscsi_tcp_segment_done - check whether the segment is complete
+ * @segment: iscsi segment to check
+ * @recv: set to one of this is called from the recv path
+ * @copied: number of bytes copied
+ *
+ * Check if we're done receiving this segment. If the receive
+ * buffer is full but we expect more data, move on to the
+ * next entry in the scatterlist.
+ *
+ * If the amount of data we received isn't a multiple of 4,
+ * we will transparently receive the pad bytes, too.
+ *
+ * This function must be re-entrant.
+ */
 static inline int
-iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
+iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, unsigned copied)
 {
-       struct sk_buff *skb = tcp_conn->in.skb;
-
-       tcp_conn->in.zero_copy_hdr = 0;
+       static unsigned char padbuf[ISCSI_PAD_LEN];
+       struct scatterlist sg;
+       unsigned int pad;
 
-       if (tcp_conn->in.copy >= tcp_conn->hdr_size &&
-           tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) {
+       debug_tcp("copied %u %u size %u %s\n", segment->copied, copied,
+                 segment->size, recv ? "recv" : "xmit");
+       if (segment->hash && copied) {
                /*
-                * Zero-copy PDU Header: using connection context
-                * to store header pointer.
+                * If a segment is kmapd we must unmap it before sending
+                * to the crypto layer since that will try to kmap it again.
                 */
-               if (skb_shinfo(skb)->frag_list == NULL &&
-                   !skb_shinfo(skb)->nr_frags) {
-                       tcp_conn->in.hdr = (struct iscsi_hdr *)
-                               ((char*)skb->data + tcp_conn->in.offset);
-                       tcp_conn->in.zero_copy_hdr = 1;
+               iscsi_tcp_segment_unmap(segment);
+
+               if (!segment->data) {
+                       sg_init_table(&sg, 1);
+                       sg_set_page(&sg, sg_page(segment->sg), copied,
+                                   segment->copied + segment->sg_offset +
+                                                       segment->sg->offset);
+               } else
+                       sg_init_one(&sg, segment->data + segment->copied,
+                                   copied);
+               crypto_hash_update(segment->hash, &sg, copied);
+       }
+
+       segment->copied += copied;
+       if (segment->copied < segment->size) {
+               iscsi_tcp_segment_map(segment, recv);
+               return 0;
+       }
+
+       segment->total_copied += segment->copied;
+       segment->copied = 0;
+       segment->size = 0;
+
+       /* Unmap the current scatterlist page, if there is one. */
+       iscsi_tcp_segment_unmap(segment);
+
+       /* Do we have more scatterlist entries? */
+       debug_tcp("total copied %u total size %u\n", segment->total_copied,
+                  segment->total_size);
+       if (segment->total_copied < segment->total_size) {
+               /* Proceed to the next entry in the scatterlist. */
+               iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg),
+                                         0);
+               iscsi_tcp_segment_map(segment, recv);
+               BUG_ON(segment->size == 0);
+               return 0;
+       }
+
+       /* Do we need to handle padding? */
+       pad = iscsi_padding(segment->total_copied);
+       if (pad != 0) {
+               debug_tcp("consume %d pad bytes\n", pad);
+               segment->total_size += pad;
+               segment->size = pad;
+               segment->data = padbuf;
+               return 0;
+       }
+
+       /*
+        * Set us up for transferring the data digest. hdr digest
+        * is completely handled in hdr done function.
+        */
+       if (segment->hash) {
+               crypto_hash_final(segment->hash, segment->digest);
+               iscsi_tcp_segment_splice_digest(segment,
+                                recv ? segment->recv_digest : segment->digest);
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * iscsi_tcp_xmit_segment - transmit segment
+ * @tcp_conn: the iSCSI TCP connection
+ * @segment: the buffer to transmnit
+ *
+ * This function transmits as much of the buffer as
+ * the network layer will accept, and returns the number of
+ * bytes transmitted.
+ *
+ * If CRC hashing is enabled, the function will compute the
+ * hash as it goes. When the entire segment has been transmitted,
+ * it will retrieve the hash value and send it as well.
+ */
+static int
+iscsi_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
+                      struct iscsi_segment *segment)
+{
+       struct socket *sk = tcp_conn->sock;
+       unsigned int copied = 0;
+       int r = 0;
+
+       while (!iscsi_tcp_segment_done(segment, 0, r)) {
+               struct scatterlist *sg;
+               unsigned int offset, copy;
+               int flags = 0;
+
+               r = 0;
+               offset = segment->copied;
+               copy = segment->size - offset;
+
+               if (segment->total_copied + segment->size < segment->total_size)
+                       flags |= MSG_MORE;
+
+               /* Use sendpage if we can; else fall back to sendmsg */
+               if (!segment->data) {
+                       sg = segment->sg;
+                       offset += segment->sg_offset + sg->offset;
+                       r = tcp_conn->sendpage(sk, sg_page(sg), offset, copy,
+                                              flags);
                } else {
-                       /* ignoring return code since we checked
-                        * in.copy before */
-                       skb_copy_bits(skb, tcp_conn->in.offset,
-                               &tcp_conn->hdr, tcp_conn->hdr_size);
-                       tcp_conn->in.hdr = &tcp_conn->hdr;
+                       struct msghdr msg = { .msg_flags = flags };
+                       struct kvec iov = {
+                               .iov_base = segment->data + offset,
+                               .iov_len = copy
+                       };
+
+                       r = kernel_sendmsg(sk, &msg, &iov, 1, copy);
                }
-               tcp_conn->in.offset += tcp_conn->hdr_size;
-               tcp_conn->in.copy -= tcp_conn->hdr_size;
-       } else {
-               int hdr_remains;
-               int copylen;
 
-               /*
-                * PDU header scattered across SKB's,
-                * copying it... This'll happen quite rarely.
-                */
+               if (r < 0) {
+                       iscsi_tcp_segment_unmap(segment);
+                       if (copied || r == -EAGAIN)
+                               break;
+                       return r;
+               }
+               copied += r;
+       }
+       return copied;
+}
+
+/**
+ * iscsi_tcp_segment_recv - copy data to segment
+ * @tcp_conn: the iSCSI TCP connection
+ * @segment: the buffer to copy to
+ * @ptr: data pointer
+ * @len: amount of data available
+ *
+ * This function copies up to @len bytes to the
+ * given buffer, and returns the number of bytes
+ * consumed, which can actually be less than @len.
+ *
+ * If hash digest is enabled, the function will update the
+ * hash while copying.
+ * Combining these two operations doesn't buy us a lot (yet),
+ * but in the future we could implement combined copy+crc,
+ * just way we do for network layer checksums.
+ */
+static int
+iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
+                      struct iscsi_segment *segment, const void *ptr,
+                      unsigned int len)
+{
+       unsigned int copy = 0, copied = 0;
 
-               if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER)
-                       tcp_conn->in.hdr_offset = 0;
+       while (!iscsi_tcp_segment_done(segment, 1, copy)) {
+               if (copied == len) {
+                       debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
+                                 len);
+                       break;
+               }
 
-               hdr_remains = tcp_conn->hdr_size - tcp_conn->in.hdr_offset;
-               BUG_ON(hdr_remains <= 0);
+               copy = min(len - copied, segment->size - segment->copied);
+               debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy);
+               memcpy(segment->data + segment->copied, ptr + copied, copy);
+               copied += copy;
+       }
+       return copied;
+}
 
-               copylen = min(tcp_conn->in.copy, hdr_remains);
-               skb_copy_bits(skb, tcp_conn->in.offset,
-                       (char*)&tcp_conn->hdr + tcp_conn->in.hdr_offset,
-                       copylen);
+static inline void
+iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
+                     unsigned char digest[ISCSI_DIGEST_SIZE])
+{
+       struct scatterlist sg;
+
+       sg_init_one(&sg, hdr, hdrlen);
+       crypto_hash_digest(hash, &sg, hdrlen, digest);
+}
 
-               debug_tcp("PDU gather offset %d bytes %d in.offset %d "
-                      "in.copy %d\n", tcp_conn->in.hdr_offset, copylen,
-                      tcp_conn->in.offset, tcp_conn->in.copy);
+static inline int
+iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
+                     struct iscsi_segment *segment)
+{
+       if (!segment->digest_len)
+               return 1;
 
-               tcp_conn->in.offset += copylen;
-               tcp_conn->in.copy -= copylen;
-               if (copylen < hdr_remains)  {
-                       tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER;
-                       tcp_conn->in.hdr_offset += copylen;
-                       return -EAGAIN;
+       if (memcmp(segment->recv_digest, segment->digest,
+                  segment->digest_len)) {
+               debug_scsi("digest mismatch\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Helper function to set up segment buffer
+ */
+static inline void
+__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
+                    iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+{
+       memset(segment, 0, sizeof(*segment));
+       segment->total_size = size;
+       segment->done = done;
+
+       if (hash) {
+               segment->hash = hash;
+               crypto_hash_init(hash);
+       }
+}
+
+static inline void
+iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
+                         size_t size, iscsi_segment_done_fn_t *done,
+                         struct hash_desc *hash)
+{
+       __iscsi_segment_init(segment, size, done, hash);
+       segment->data = data;
+       segment->size = size;
+}
+
+static inline int
+iscsi_segment_seek_sg(struct iscsi_segment *segment,
+                     struct scatterlist *sg_list, unsigned int sg_count,
+                     unsigned int offset, size_t size,
+                     iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+{
+       struct scatterlist *sg;
+       unsigned int i;
+
+       debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
+                 offset, size);
+       __iscsi_segment_init(segment, size, done, hash);
+       for_each_sg(sg_list, sg, sg_count, i) {
+               debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
+                          sg->offset);
+               if (offset < sg->length) {
+                       iscsi_tcp_segment_init_sg(segment, sg, offset);
+                       return 0;
                }
-               tcp_conn->in.hdr = &tcp_conn->hdr;
-               tcp_conn->discontiguous_hdr_cnt++;
-               tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+               offset -= sg->length;
        }
 
+       return ISCSI_ERR_DATA_OFFSET;
+}
+
+/**
+ * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception
+ * @tcp_conn: iscsi connection to prep for
+ *
+ * This function always passes NULL for the hash argument, because when this
+ * function is called we do not yet know the final size of the header and want
+ * to delay the digest processing until we know that.
+ */
+static void
+iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
+{
+       debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn,
+                 tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : "");
+       iscsi_segment_init_linear(&tcp_conn->in.segment,
+                               tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
+                               iscsi_tcp_hdr_recv_done, NULL);
+}
+
+/*
+ * Handle incoming reply to any other type of command
+ */
+static int
+iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn,
+                        struct iscsi_segment *segment)
+{
+       struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+       int rc = 0;
+
+       if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+               return ISCSI_ERR_DATA_DGST;
+
+       rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr,
+                       conn->data, tcp_conn->in.datalen);
+       if (rc)
+               return rc;
+
+       iscsi_tcp_hdr_recv_prep(tcp_conn);
        return 0;
 }
 
+static void
+iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
+{
+       struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+       struct hash_desc *rx_hash = NULL;
+
+       if (conn->datadgst_en)
+               rx_hash = &tcp_conn->rx_hash;
+
+       iscsi_segment_init_linear(&tcp_conn->in.segment,
+                               conn->data, tcp_conn->in.datalen,
+                               iscsi_tcp_data_recv_done, rx_hash);
+}
+
 /*
  * must be called with session lock
  */
@@ -184,7 +498,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
        struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
        struct iscsi_r2t_info *r2t;
-       struct scsi_cmnd *sc;
 
        /* flush ctask's r2t queues */
        while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
@@ -193,12 +506,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
        }
 
-       sc = ctask->sc;
-       if (unlikely(!sc))
-               return;
-
-       tcp_ctask->xmstate = XMSTATE_VALUE_IDLE;
-       tcp_ctask->r2t = NULL;
+       r2t = tcp_ctask->r2t;
+       if (r2t != NULL) {
+               __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+                           sizeof(void*));
+               tcp_ctask->r2t = NULL;
+       }
 }
 
 /**
@@ -217,11 +530,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        int datasn = be32_to_cpu(rhdr->datasn);
 
        iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
-       /*
-        * setup Data-In byte counter (gets decremented..)
-        */
-       ctask->data_count = tcp_conn->in.datalen;
-
        if (tcp_conn->in.datalen == 0)
                return 0;
 
@@ -242,22 +550,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        }
 
        if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
+               sc->result = (DID_OK << 16) | rhdr->cmd_status;
                conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
-               if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
+               if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
+                                  ISCSI_FLAG_DATA_OVERFLOW)) {
                        int res_count = be32_to_cpu(rhdr->residual_count);
 
                        if (res_count > 0 &&
-                           res_count <= scsi_bufflen(sc)) {
+                           (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+                            res_count <= scsi_bufflen(sc)))
                                scsi_set_resid(sc, res_count);
-                               sc->result = (DID_OK << 16) | rhdr->cmd_status;
-                       } else
+                       else
                                sc->result = (DID_BAD_TARGET << 16) |
                                        rhdr->cmd_status;
-               } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
-                       scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
-                       sc->result = (DID_OK << 16) | rhdr->cmd_status;
-               } else
-                       sc->result = (DID_OK << 16) | rhdr->cmd_status;
+               }
        }
 
        conn->datain_pdus_cnt++;
@@ -281,9 +587,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                        struct iscsi_r2t_info *r2t)
 {
        struct iscsi_data *hdr;
-       struct scsi_cmnd *sc = ctask->sc;
-       int i, sg_count = 0;
-       struct scatterlist *sg;
 
        hdr = &r2t->dtask.hdr;
        memset(hdr, 0, sizeof(struct iscsi_data));
@@ -307,34 +610,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
        conn->dataout_pdus_cnt++;
 
        r2t->sent = 0;
-
-       iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
-                          sizeof(struct iscsi_hdr));
-
-       sg = scsi_sglist(sc);
-       r2t->sg = NULL;
-       for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) {
-               /* FIXME: prefetch ? */
-               if (sg_count + sg->length > r2t->data_offset) {
-                       int page_offset;
-
-                       /* sg page found! */
-
-                       /* offset within this page */
-                       page_offset = r2t->data_offset - sg_count;
-
-                       /* fill in this buffer */
-                       iscsi_buf_init_sg(&r2t->sendbuf, sg);
-                       r2t->sendbuf.sg.offset += page_offset;
-                       r2t->sendbuf.sg.length -= page_offset;
-
-                       /* xmit logic will continue with next one */
-                       r2t->sg = sg + 1;
-                       break;
-               }
-               sg_count += sg->length;
-       }
-       BUG_ON(r2t->sg == NULL);
 }
 
 /**
@@ -366,14 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        }
 
        /* fill-in new R2T associated with the task */
-       spin_lock(&session->lock);
        iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
 
-       if (!ctask->sc || ctask->mtask ||
-            session->state != ISCSI_STATE_LOGGED_IN) {
+       if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
                printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
                       "recovery...\n", ctask->itt);
-               spin_unlock(&session->lock);
                return 0;
        }
 
@@ -384,7 +656,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        r2t->data_length = be32_to_cpu(rhdr->data_length);
        if (r2t->data_length == 0) {
                printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
-               spin_unlock(&session->lock);
+               __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+                           sizeof(void*));
                return ISCSI_ERR_DATALEN;
        }
 
@@ -395,10 +668,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 
        r2t->data_offset = be32_to_cpu(rhdr->data_offset);
        if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
-               spin_unlock(&session->lock);
                printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
                       "offset %u and total length %d\n", r2t->data_length,
                       r2t->data_offset, scsi_bufflen(ctask->sc));
+               __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+                           sizeof(void*));
                return ISCSI_ERR_DATALEN;
        }
 
@@ -409,26 +683,55 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 
        tcp_ctask->exp_datasn = r2tsn + 1;
        __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
-       set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
-       list_move_tail(&ctask->running, &conn->xmitqueue);
-
-       scsi_queue_work(session->host, &conn->xmitwork);
        conn->r2t_pdus_cnt++;
-       spin_unlock(&session->lock);
 
+       iscsi_requeue_ctask(ctask);
        return 0;
 }
 
+/*
+ * Handle incoming reply to DataIn command
+ */
 static int
-iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
+iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
+                         struct iscsi_segment *segment)
+{
+       struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+       struct iscsi_hdr *hdr = tcp_conn->in.hdr;
+       int rc;
+
+       if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+               return ISCSI_ERR_DATA_DGST;
+
+       /* check for non-exceptional status */
+       if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+               rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
+               if (rc)
+                       return rc;
+       }
+
+       iscsi_tcp_hdr_recv_prep(tcp_conn);
+       return 0;
+}
+
+/**
+ * iscsi_tcp_hdr_dissect - process PDU header
+ * @conn: iSCSI connection
+ * @hdr: PDU header
+ *
+ * This function analyzes the header of the PDU received,
+ * and performs several sanity checks. If the PDU is accompanied
+ * by data, the receive buffer is set up to copy the incoming data
+ * to the correct location.
+ */
+static int
+iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 {
        int rc = 0, opcode, ahslen;
-       struct iscsi_hdr *hdr;
        struct iscsi_session *session = conn->session;
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       uint32_t cdgst, rdgst = 0, itt;
-
-       hdr = tcp_conn->in.hdr;
+       struct iscsi_cmd_task *ctask;
+       uint32_t itt;
 
        /* verify PDU length */
        tcp_conn->in.datalen = ntoh24(hdr->dlength);
@@ -437,78 +740,73 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
                       tcp_conn->in.datalen, conn->max_recv_dlength);
                return ISCSI_ERR_DATALEN;
        }
-       tcp_conn->data_copied = 0;
 
-       /* read AHS */
+       /* Additional header segments. So far, we don't
+        * process additional headers.
+        */
        ahslen = hdr->hlength << 2;
-       tcp_conn->in.offset += ahslen;
-       tcp_conn->in.copy -= ahslen;
-       if (tcp_conn->in.copy < 0) {
-               printk(KERN_ERR "iscsi_tcp: can't handle AHS with length "
-                      "%d bytes\n", ahslen);
-               return ISCSI_ERR_AHSLEN;
-       }
-
-       /* calculate read padding */
-       tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1);
-       if (tcp_conn->in.padding) {
-               tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding;
-               debug_scsi("read padding %d bytes\n", tcp_conn->in.padding);
-       }
-
-       if (conn->hdrdgst_en) {
-               struct scatterlist sg;
-
-               sg_init_one(&sg, (u8 *)hdr,
-                           sizeof(struct iscsi_hdr) + ahslen);
-               crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
-                                  (u8 *)&cdgst);
-               rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
-                                    ahslen);
-               if (cdgst != rdgst) {
-                       printk(KERN_ERR "iscsi_tcp: hdrdgst error "
-                              "recv 0x%x calc 0x%x\n", rdgst, cdgst);
-                       return ISCSI_ERR_HDR_DGST;
-               }
-       }
 
        opcode = hdr->opcode & ISCSI_OPCODE_MASK;
        /* verify itt (itt encoding: age+cid+itt) */
        rc = iscsi_verify_itt(conn, hdr, &itt);
-       if (rc == ISCSI_ERR_NO_SCSI_CMD) {
-               tcp_conn->in.datalen = 0; /* force drop */
-               return 0;
-       } else if (rc)
+       if (rc)
                return rc;
 
-       debug_tcp("opcode 0x%x offset %d copy %d ahslen %d datalen %d\n",
-                 opcode, tcp_conn->in.offset, tcp_conn->in.copy,
-                 ahslen, tcp_conn->in.datalen);
+       debug_tcp("opcode 0x%x ahslen %d datalen %d\n",
+                 opcode, ahslen, tcp_conn->in.datalen);
 
        switch(opcode) {
        case ISCSI_OP_SCSI_DATA_IN:
-               tcp_conn->in.ctask = session->cmds[itt];
-               rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
+               ctask = session->cmds[itt];
+               spin_lock(&conn->session->lock);
+               rc = iscsi_data_rsp(conn, ctask);
+               spin_unlock(&conn->session->lock);
                if (rc)
                        return rc;
+               if (tcp_conn->in.datalen) {
+                       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+                       struct hash_desc *rx_hash = NULL;
+
+                       /*
+                        * Setup copy of Data-In into the Scsi_Cmnd
+                        * Scatterlist case:
+                        * We set up the iscsi_segment to point to the next
+                        * scatterlist entry to copy to. As we go along,
+                        * we move on to the next scatterlist entry and
+                        * update the digest per-entry.
+                        */
+                       if (conn->datadgst_en)
+                               rx_hash = &tcp_conn->rx_hash;
+
+                       debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
+                                 "datalen=%d)\n", tcp_conn,
+                                 tcp_ctask->data_offset,
+                                 tcp_conn->in.datalen);
+                       return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+                                                    scsi_sglist(ctask->sc),
+                                                    scsi_sg_count(ctask->sc),
+                                                    tcp_ctask->data_offset,
+                                                    tcp_conn->in.datalen,
+                                                    iscsi_tcp_process_data_in,
+                                                    rx_hash);
+               }
                /* fall through */
        case ISCSI_OP_SCSI_CMD_RSP:
-               tcp_conn->in.ctask = session->cmds[itt];
-               if (tcp_conn->in.datalen)
-                       goto copy_hdr;
-
-               spin_lock(&session->lock);
-               rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
-               spin_unlock(&session->lock);
+               if (tcp_conn->in.datalen) {
+                       iscsi_tcp_data_recv_prep(tcp_conn);
+                       return 0;
+               }
+               rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
                break;
        case ISCSI_OP_R2T:
-               tcp_conn->in.ctask = session->cmds[itt];
+               ctask = session->cmds[itt];
                if (ahslen)
                        rc = ISCSI_ERR_AHSLEN;
-               else if (tcp_conn->in.ctask->sc->sc_data_direction ==
-                                                               DMA_TO_DEVICE)
-                       rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
-               else
+               else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
+                       spin_lock(&session->lock);
+                       rc = iscsi_r2t_rsp(conn, ctask);
+                       spin_unlock(&session->lock);
+               } else
                        rc = ISCSI_ERR_PROTO;
                break;
        case ISCSI_OP_LOGIN_RSP:
@@ -520,8 +818,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
                 * than 8K, but there are no targets that currently do this.
                 * For now we fail until we find a vendor that needs it
                 */
-               if (ISCSI_DEF_MAX_RECV_SEG_LEN <
-                   tcp_conn->in.datalen) {
+               if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) {
                        printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
                              "but conn buffer is only %u (opcode %0x)\n",
                              tcp_conn->in.datalen,
@@ -530,8 +827,13 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
                        break;
                }
 
-               if (tcp_conn->in.datalen)
-                       goto copy_hdr;
+               /* If there's data coming in with the response,
+                * receive it to the connection's buffer.
+                */
+               if (tcp_conn->in.datalen) {
+                       iscsi_tcp_data_recv_prep(tcp_conn);
+                       return 0;
+               }
        /* fall through */
        case ISCSI_OP_LOGOUT_RSP:
        case ISCSI_OP_NOOP_IN:
@@ -543,461 +845,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
                break;
        }
 
-       return rc;
-
-copy_hdr:
-       /*
-        * if we did zero copy for the header but we will need multiple
-        * skbs to complete the command then we have to copy the header
-        * for later use
-        */
-       if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <=
-          (tcp_conn->in.datalen + tcp_conn->in.padding +
-           (conn->datadgst_en ? 4 : 0))) {
-               debug_tcp("Copying header for later use. in.copy %d in.datalen"
-                         " %d\n", tcp_conn->in.copy, tcp_conn->in.datalen);
-               memcpy(&tcp_conn->hdr, tcp_conn->in.hdr,
-                      sizeof(struct iscsi_hdr));
-               tcp_conn->in.hdr = &tcp_conn->hdr;
-               tcp_conn->in.zero_copy_hdr = 0;
-       }
-       return 0;
-}
-
-/**
- * iscsi_ctask_copy - copy skb bits to the destanation cmd task
- * @conn: iscsi tcp connection
- * @ctask: scsi command task
- * @buf: buffer to copy to
- * @buf_size: size of buffer
- * @offset: offset within the buffer
- *
- * Notes:
- *     The function calls skb_copy_bits() and updates per-connection and
- *     per-cmd byte counters.
- *
- *     Read counters (in bytes):
- *
- *     conn->in.offset         offset within in progress SKB
- *     conn->in.copy           left to copy from in progress SKB
- *                             including padding
- *     conn->in.copied         copied already from in progress SKB
- *     conn->data_copied       copied already from in progress buffer
- *     ctask->sent             total bytes sent up to the MidLayer
- *     ctask->data_count       left to copy from in progress Data-In
- *     buf_left                left to copy from in progress buffer
- **/
-static inline int
-iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
-               void *buf, int buf_size, int offset)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       int buf_left = buf_size - (tcp_conn->data_copied + offset);
-       unsigned size = min(tcp_conn->in.copy, buf_left);
-       int rc;
-
-       size = min(size, ctask->data_count);
-
-       debug_tcp("ctask_copy %d bytes at offset %d copied %d\n",
-              size, tcp_conn->in.offset, tcp_conn->in.copied);
-
-       BUG_ON(size <= 0);
-       BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));
-
-       rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
-                          (char*)buf + (offset + tcp_conn->data_copied), size);
-       /* must fit into skb->len */
-       BUG_ON(rc);
-
-       tcp_conn->in.offset += size;
-       tcp_conn->in.copy -= size;
-       tcp_conn->in.copied += size;
-       tcp_conn->data_copied += size;
-       tcp_ctask->sent += size;
-       ctask->data_count -= size;
-
-       BUG_ON(tcp_conn->in.copy < 0);
-       BUG_ON(ctask->data_count < 0);
-
-       if (buf_size != (tcp_conn->data_copied + offset)) {
-               if (!ctask->data_count) {
-                       BUG_ON(buf_size - tcp_conn->data_copied < 0);
-                       /* done with this PDU */
-                       return buf_size - tcp_conn->data_copied;
-               }
-               return -EAGAIN;
+       if (rc == 0) {
+               /* Anything that comes with data should have
+                * been handled above. */
+               if (tcp_conn->in.datalen)
+                       return ISCSI_ERR_PROTO;
+               iscsi_tcp_hdr_recv_prep(tcp_conn);
        }
 
-       /* done with this buffer or with both - PDU and buffer */
-       tcp_conn->data_copied = 0;
-       return 0;
+       return rc;
 }
 
 /**
- * iscsi_tcp_copy - copy skb bits to the destanation buffer
- * @conn: iscsi tcp connection
+ * iscsi_tcp_hdr_recv_done - process PDU header
  *
- * Notes:
- *     The function calls skb_copy_bits() and updates per-connection
- *     byte counters.
- **/
-static inline int
-iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
-{
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       int buf_left = buf_size - tcp_conn->data_copied;
-       int size = min(tcp_conn->in.copy, buf_left);
-       int rc;
-
-       debug_tcp("tcp_copy %d bytes at offset %d copied %d\n",
-              size, tcp_conn->in.offset, tcp_conn->data_copied);
-       BUG_ON(size <= 0);
-
-       rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
-                          (char*)conn->data + tcp_conn->data_copied, size);
-       BUG_ON(rc);
-
-       tcp_conn->in.offset += size;
-       tcp_conn->in.copy -= size;
-       tcp_conn->in.copied += size;
-       tcp_conn->data_copied += size;
-
-       if (buf_size != tcp_conn->data_copied)
-               return -EAGAIN;
-
-       return 0;
-}
-
-static inline void
-partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
-                        int offset, int length)
-{
-       struct scatterlist temp;
-
-       sg_init_table(&temp, 1);
-       sg_set_page(&temp, sg_page(sg), length, offset);
-       crypto_hash_update(desc, &temp, length);
-}
-
-static void
-iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
-{
-       struct scatterlist tmp;
-
-       sg_init_one(&tmp, buf, len);
-       crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
-}
-
-static int iscsi_scsi_data_in(struct iscsi_conn *conn)
+ * This is the callback invoked when the PDU header has
+ * been received. If the header is followed by additional
+ * header segments, we go back for more data.
+ */
+static int
+iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
+                       struct iscsi_segment *segment)
 {
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       struct iscsi_cmd_task *ctask = tcp_conn->in.ctask;
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       struct scsi_cmnd *sc = ctask->sc;
-       struct scatterlist *sg;
-       int i, offset, rc = 0;
-
-       BUG_ON((void*)ctask != sc->SCp.ptr);
-
-       offset = tcp_ctask->data_offset;
-       sg = scsi_sglist(sc);
-
-       if (tcp_ctask->data_offset)
-               for (i = 0; i < tcp_ctask->sg_count; i++)
-                       offset -= sg[i].length;
-       /* we've passed through partial sg*/
-       if (offset < 0)
-               offset = 0;
-
-       for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
-               char *dest;
-
-               dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0);
-               rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
-                                     sg[i].length, offset);
-               kunmap_atomic(dest, KM_SOFTIRQ0);
-               if (rc == -EAGAIN)
-                       /* continue with the next SKB/PDU */
-                       return rc;
-               if (!rc) {
-                       if (conn->datadgst_en) {
-                               if (!offset)
-                                       crypto_hash_update(
-                                                       &tcp_conn->rx_hash,
-                                                       &sg[i], sg[i].length);
-                               else
-                                       partial_sg_digest_update(
-                                                       &tcp_conn->rx_hash,
-                                                       &sg[i],
-                                                       sg[i].offset + offset,
-                                                       sg[i].length - offset);
-                       }
-                       offset = 0;
-                       tcp_ctask->sg_count++;
-               }
-
-               if (!ctask->data_count) {
-                       if (rc && conn->datadgst_en)
-                               /*
-                                * data-in is complete, but buffer not...
-                                */
-                               partial_sg_digest_update(&tcp_conn->rx_hash,
-                                                        &sg[i],
-                                                        sg[i].offset,
-                                                        sg[i].length-rc);
-                       rc = 0;
-                       break;
-               }
-
-               if (!tcp_conn->in.copy)
-                       return -EAGAIN;
-       }
-       BUG_ON(ctask->data_count);
+       struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+       struct iscsi_hdr *hdr;
 
-       /* check for non-exceptional status */
-       if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
-               debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
-                          (long)sc, sc->result, ctask->itt,
-                          tcp_conn->in.hdr->flags);
-               spin_lock(&conn->session->lock);
-               __iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
-               spin_unlock(&conn->session->lock);
+       /* Check if there are additional header segments
+        * *prior* to computing the digest, because we
+        * may need to go back to the caller for more.
+        */
+       hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf;
+       if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) {
+               /* Bump the header length - the caller will
+                * just loop around and get the AHS for us, and
+                * call again. */
+               unsigned int ahslen = hdr->hlength << 2;
+
+               /* Make sure we don't overflow */
+               if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf))
+                       return ISCSI_ERR_AHSLEN;
+
+               segment->total_size += ahslen;
+               segment->size += ahslen;
+               return 0;
        }
 
-       return rc;
-}
-
-static int
-iscsi_data_recv(struct iscsi_conn *conn)
-{
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       int rc = 0, opcode;
-
-       opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK;
-       switch (opcode) {
-       case ISCSI_OP_SCSI_DATA_IN:
-               rc = iscsi_scsi_data_in(conn);
-               break;
-       case ISCSI_OP_SCSI_CMD_RSP:
-       case ISCSI_OP_TEXT_RSP:
-       case ISCSI_OP_LOGIN_RSP:
-       case ISCSI_OP_ASYNC_EVENT:
-       case ISCSI_OP_REJECT:
-               /*
-                * Collect data segment to the connection's data
-                * placeholder
-                */
-               if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
-                       rc = -EAGAIN;
-                       goto exit;
+       /* We're done processing the header. See if we're doing
+        * header digests; if so, set up the recv_digest buffer
+        * and go back for more. */
+       if (conn->hdrdgst_en) {
+               if (segment->digest_len == 0) {
+                       iscsi_tcp_segment_splice_digest(segment,
+                                                       segment->recv_digest);
+                       return 0;
                }
+               iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
+                                     segment->total_copied - ISCSI_DIGEST_SIZE,
+                                     segment->digest);
 
-               rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
-                                       tcp_conn->in.datalen);
-               if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
-                       iscsi_recv_digest_update(tcp_conn, conn->data,
-                                               tcp_conn->in.datalen);
-               break;
-       default:
-               BUG_ON(1);
+               if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+                       return ISCSI_ERR_HDR_DGST;
        }
-exit:
-       return rc;
+
+       tcp_conn->in.hdr = hdr;
+       return iscsi_tcp_hdr_dissect(conn, hdr);
 }
 
 /**
- * iscsi_tcp_data_recv - TCP receive in sendfile fashion
+ * iscsi_tcp_recv - TCP receive in sendfile fashion
  * @rd_desc: read descriptor
  * @skb: socket buffer
  * @offset: offset in skb
  * @len: skb->len - offset
  **/
 static int
-iscsi_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
-               unsigned int offset, size_t len)
+iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
+              unsigned int offset, size_t len)
 {
-       int rc;
        struct iscsi_conn *conn = rd_desc->arg.data;
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       int processed;
-       char pad[ISCSI_PAD_LEN];
-       struct scatterlist sg;
-
-       /*
-        * Save current SKB and its offset in the corresponding
-        * connection context.
-        */
-       tcp_conn->in.copy = skb->len - offset;
-       tcp_conn->in.offset = offset;
-       tcp_conn->in.skb = skb;
-       tcp_conn->in.len = tcp_conn->in.copy;
-       BUG_ON(tcp_conn->in.copy <= 0);
-       debug_tcp("in %d bytes\n", tcp_conn->in.copy);
+       struct iscsi_segment *segment = &tcp_conn->in.segment;
+       struct skb_seq_state seq;
+       unsigned int consumed = 0;
+       int rc = 0;
 
-more:
-       tcp_conn->in.copied = 0;
-       rc = 0;
+       debug_tcp("in %d bytes\n", skb->len - offset);
 
        if (unlikely(conn->suspend_rx)) {
                debug_tcp("conn %d Rx suspended!\n", conn->id);
                return 0;
        }
 
-       if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER ||
-           tcp_conn->in_progress == IN_PROGRESS_HEADER_GATHER) {
-               rc = iscsi_hdr_extract(tcp_conn);
-               if (rc) {
-                      if (rc == -EAGAIN)
-                               goto nomore;
-                      else {
-                               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-                               return 0;
-                      }
-               }
+       skb_prepare_seq_read(skb, offset, skb->len, &seq);
+       while (1) {
+               unsigned int avail;
+               const u8 *ptr;
 
-               /*
-                * Verify and process incoming PDU header.
-                */
-               rc = iscsi_tcp_hdr_recv(conn);
-               if (!rc && tcp_conn->in.datalen) {
-                       if (conn->datadgst_en)
-                               crypto_hash_init(&tcp_conn->rx_hash);
-                       tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
-               } else if (rc) {
-                       iscsi_conn_failure(conn, rc);
-                       return 0;
+               avail = skb_seq_read(consumed, &ptr, &seq);
+               if (avail == 0) {
+                       debug_tcp("no more data avail. Consumed %d\n",
+                                 consumed);
+                       break;
                }
-       }
-
-       if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
-           tcp_conn->in.copy) {
-               uint32_t recv_digest;
-
-               debug_tcp("extra data_recv offset %d copy %d\n",
-                         tcp_conn->in.offset, tcp_conn->in.copy);
-
-               if (!tcp_conn->data_copied) {
-                       if (tcp_conn->in.padding) {
-                               debug_tcp("padding -> %d\n",
-                                         tcp_conn->in.padding);
-                               memset(pad, 0, tcp_conn->in.padding);
-                               sg_init_one(&sg, pad, tcp_conn->in.padding);
-                               crypto_hash_update(&tcp_conn->rx_hash,
-                                                  &sg, sg.length);
+               BUG_ON(segment->copied >= segment->size);
+
+               debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail);
+               rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
+               BUG_ON(rc == 0);
+               consumed += rc;
+
+               if (segment->total_copied >= segment->total_size) {
+                       debug_tcp("segment done\n");
+                       rc = segment->done(tcp_conn, segment);
+                       if (rc != 0) {
+                               skb_abort_seq_read(&seq);
+                               goto error;
                        }
-                       crypto_hash_final(&tcp_conn->rx_hash,
-                                         (u8 *) &tcp_conn->in.datadgst);
-                       debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
-               }
 
-               rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
-               if (rc) {
-                       if (rc == -EAGAIN)
-                               goto again;
-                       iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-                       return 0;
-               }
-
-               memcpy(&recv_digest, conn->data, sizeof(uint32_t));
-               if (recv_digest != tcp_conn->in.datadgst) {
-                       debug_tcp("iscsi_tcp: data digest error!"
-                                 "0x%x != 0x%x\n", recv_digest,
-                                 tcp_conn->in.datadgst);
-                       iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
-                       return 0;
-               } else {
-                       debug_tcp("iscsi_tcp: data digest match!"
-                                 "0x%x == 0x%x\n", recv_digest,
-                                 tcp_conn->in.datadgst);
-                       tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+                       /* The done() functions sets up the
+                        * next segment. */
                }
        }
+       skb_abort_seq_read(&seq);
+       conn->rxdata_octets += consumed;
+       return consumed;
 
-       if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
-           tcp_conn->in.copy) {
-               debug_tcp("data_recv offset %d copy %d\n",
-                      tcp_conn->in.offset, tcp_conn->in.copy);
-
-               rc = iscsi_data_recv(conn);
-               if (rc) {
-                       if (rc == -EAGAIN)
-                               goto again;
-                       iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-                       return 0;
-               }
-
-               if (tcp_conn->in.padding)
-                       tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
-               else if (conn->datadgst_en)
-                       tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
-               else
-                       tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-               tcp_conn->data_copied = 0;
-       }
-
-       if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
-           tcp_conn->in.copy) {
-               int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
-                                 tcp_conn->in.copy);
-
-               tcp_conn->in.copy -= copylen;
-               tcp_conn->in.offset += copylen;
-               tcp_conn->data_copied += copylen;
-
-               if (tcp_conn->data_copied != tcp_conn->in.padding)
-                       tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
-               else if (conn->datadgst_en)
-                       tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
-               else
-                       tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-               tcp_conn->data_copied = 0;
-       }
-
-       debug_tcp("f, processed %d from out of %d padding %d\n",
-              tcp_conn->in.offset - offset, (int)len, tcp_conn->in.padding);
-       BUG_ON(tcp_conn->in.offset - offset > len);
-
-       if (tcp_conn->in.offset - offset != len) {
-               debug_tcp("continue to process %d bytes\n",
-                      (int)len - (tcp_conn->in.offset - offset));
-               goto more;
-       }
-
-nomore:
-       processed = tcp_conn->in.offset - offset;
-       BUG_ON(processed == 0);
-       return processed;
-
-again:
-       processed = tcp_conn->in.offset - offset;
-       debug_tcp("c, processed %d from out of %d rd_desc_cnt %d\n",
-                 processed, (int)len, (int)rd_desc->count);
-       BUG_ON(processed == 0);
-       BUG_ON(processed > len);
-
-       conn->rxdata_octets += processed;
-       return processed;
+error:
+       debug_tcp("Error receiving PDU, errno=%d\n", rc);
+       iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+       return 0;
 }
 
 static void
 iscsi_tcp_data_ready(struct sock *sk, int flag)
 {
        struct iscsi_conn *conn = sk->sk_user_data;
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
        read_descriptor_t rd_desc;
 
        read_lock(&sk->sk_callback_lock);
 
        /*
-        * Use rd_desc to pass 'conn' to iscsi_tcp_data_recv.
+        * Use rd_desc to pass 'conn' to iscsi_tcp_recv.
         * We set count to 1 because we want the network layer to
-        * hand us all the skbs that are available. iscsi_tcp_data_recv
+        * hand us all the skbs that are available. iscsi_tcp_recv
         * handled pdus that cross buffers or pdus that still need data.
         */
        rd_desc.arg.data = conn;
        rd_desc.count = 1;
-       tcp_read_sock(sk, &rd_desc, iscsi_tcp_data_recv);
+       tcp_read_sock(sk, &rd_desc, iscsi_tcp_recv);
 
        read_unlock(&sk->sk_callback_lock);
+
+       /* If we had to (atomically) map a highmem page,
+        * unmap it now. */
+       iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
 }
 
 static void
@@ -1077,121 +1079,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
 }
 
 /**
- * iscsi_send - generic send routine
- * @sk: kernel's socket
- * @buf: buffer to write from
- * @size: actual size to write
- * @flags: socket's flags
+ * iscsi_xmit - TCP transmit
+ **/
+static int
+iscsi_xmit(struct iscsi_conn *conn)
+{
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct iscsi_segment *segment = &tcp_conn->out.segment;
+       unsigned int consumed = 0;
+       int rc = 0;
+
+       while (1) {
+               rc = iscsi_tcp_xmit_segment(tcp_conn, segment);
+               if (rc < 0)
+                       goto error;
+               if (rc == 0)
+                       break;
+
+               consumed += rc;
+
+               if (segment->total_copied >= segment->total_size) {
+                       if (segment->done != NULL) {
+                               rc = segment->done(tcp_conn, segment);
+                               if (rc < 0)
+                                       goto error;
+                       }
+               }
+       }
+
+       debug_tcp("xmit %d bytes\n", consumed);
+
+       conn->txdata_octets += consumed;
+       return consumed;
+
+error:
+       /* Transmit error. We could initiate error recovery
+        * here. */
+       debug_tcp("Error sending PDU, errno=%d\n", rc);
+       iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+       return rc;
+}
+
+/**
+ * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit
  */
 static inline int
-iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
+iscsi_tcp_xmit_qlen(struct iscsi_conn *conn)
 {
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       struct socket *sk = tcp_conn->sock;
-       int offset = buf->sg.offset + buf->sent, res;
+       struct iscsi_segment *segment = &tcp_conn->out.segment;
 
-       /*
-        * if we got use_sg=0 or are sending something we kmallocd
-        * then we did not have to do kmap (kmap returns page_address)
-        *
-        * if we got use_sg > 0, but had to drop down, we do not
-        * set clustering so this should only happen for that
-        * slab case.
+       return segment->total_copied - segment->total_size;
+}
+
+static inline int
+iscsi_tcp_flush(struct iscsi_conn *conn)
+{
+       int rc;
+
+       while (iscsi_tcp_xmit_qlen(conn)) {
+               rc = iscsi_xmit(conn);
+               if (rc == 0)
+                       return -EAGAIN;
+               if (rc < 0)
+                       return rc;
+       }
+
+       return 0;
+}
+
+/*
+ * This is called when we're done sending the header.
+ * Simply copy the data_segment to the send segment, and return.
+ */
+static int
+iscsi_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn,
+                       struct iscsi_segment *segment)
+{
+       tcp_conn->out.segment = tcp_conn->out.data_segment;
+       debug_tcp("Header done. Next segment size %u total_size %u\n",
+                 tcp_conn->out.segment.size, tcp_conn->out.segment.total_size);
+       return 0;
+}
+
+static void
+iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen)
+{
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+       debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn,
+                       conn->hdrdgst_en? ", digest enabled" : "");
+
+       /* Clear the data segment - needs to be filled in by the
+        * caller using iscsi_tcp_send_data_prep() */
+       memset(&tcp_conn->out.data_segment, 0, sizeof(struct iscsi_segment));
+
+       /* If header digest is enabled, compute the CRC and
+        * place the digest into the same buffer. We make
+        * sure that both iscsi_tcp_ctask and mtask have
+        * sufficient room.
         */
-       if (buf->use_sendmsg)
-               res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags);
-       else
-               res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags);
-
-       if (res >= 0) {
-               conn->txdata_octets += res;
-               buf->sent += res;
-               return res;
+       if (conn->hdrdgst_en) {
+               iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen,
+                                     hdr + hdrlen);
+               hdrlen += ISCSI_DIGEST_SIZE;
        }
 
-       tcp_conn->sendpage_failures_cnt++;
-       if (res == -EAGAIN)
-               res = -ENOBUFS;
-       else
-               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-       return res;
+       /* Remember header pointer for later, when we need
+        * to decide whether there's a payload to go along
+        * with the header. */
+       tcp_conn->out.hdr = hdr;
+
+       iscsi_segment_init_linear(&tcp_conn->out.segment, hdr, hdrlen,
+                               iscsi_tcp_send_hdr_done, NULL);
 }
 
-/**
- * iscsi_sendhdr - send PDU Header via tcp_sendpage()
- * @conn: iscsi connection
- * @buf: buffer to write from
- * @datalen: lenght of data to be sent after the header
- *
- * Notes:
- *     (Tx, Fast Path)
- **/
-static inline int
-iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
+/*
+ * Prepare the send buffer for the payload data.
+ * Padding and checksumming will all be taken care
+ * of by the iscsi_segment routines.
+ */
+static int
+iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
+                        unsigned int count, unsigned int offset,
+                        unsigned int len)
 {
-       int flags = 0; /* MSG_DONTWAIT; */
-       int res, size;
-
-       size = buf->sg.length - buf->sent;
-       BUG_ON(buf->sent + size > buf->sg.length);
-       if (buf->sent + size != buf->sg.length || datalen)
-               flags |= MSG_MORE;
-
-       res = iscsi_send(conn, buf, size, flags);
-       debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
-       if (res >= 0) {
-               if (size != res)
-                       return -EAGAIN;
-               return 0;
-       }
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct hash_desc *tx_hash = NULL;
+       unsigned int hdr_spec_len;
 
-       return res;
-}
+       debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__,
+                       tcp_conn, offset, len,
+                       conn->datadgst_en? ", digest enabled" : "");
 
-/**
- * iscsi_sendpage - send one page of iSCSI Data-Out.
- * @conn: iscsi connection
- * @buf: buffer to write from
- * @count: remaining data
- * @sent: number of bytes sent
- *
- * Notes:
- *     (Tx, Fast Path)
- **/
-static inline int
-iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
-              int *count, int *sent)
-{
-       int flags = 0; /* MSG_DONTWAIT; */
-       int res, size;
-
-       size = buf->sg.length - buf->sent;
-       BUG_ON(buf->sent + size > buf->sg.length);
-       if (size > *count)
-               size = *count;
-       if (buf->sent + size != buf->sg.length || *count != size)
-               flags |= MSG_MORE;
-
-       res = iscsi_send(conn, buf, size, flags);
-       debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
-                 size, buf->sent, *count, *sent, res);
-       if (res >= 0) {
-               *count -= res;
-               *sent += res;
-               if (size != res)
-                       return -EAGAIN;
-               return 0;
-       }
+       /* Make sure the datalen matches what the caller
+          said he would send. */
+       hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
+       WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
+
+       if (conn->datadgst_en)
+               tx_hash = &tcp_conn->tx_hash;
 
-       return res;
+       return iscsi_segment_seek_sg(&tcp_conn->out.data_segment,
+                                  sg, count, offset, len,
+                                  NULL, tx_hash);
 }
 
-static inline void
-iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
-                     struct iscsi_tcp_cmd_task *tcp_ctask)
+static void
+iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data,
+                                  size_t len)
 {
-       crypto_hash_init(&tcp_conn->tx_hash);
-       tcp_ctask->digest_count = 4;
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct hash_desc *tx_hash = NULL;
+       unsigned int hdr_spec_len;
+
+       debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len,
+                 conn->datadgst_en? ", digest enabled" : "");
+
+       /* Make sure the datalen matches what the caller
+          said he would send. */
+       hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
+       WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
+
+       if (conn->datadgst_en)
+               tx_hash = &tcp_conn->tx_hash;
+
+       iscsi_segment_init_linear(&tcp_conn->out.data_segment,
+                               data, len, NULL, tx_hash);
 }
 
 /**
@@ -1207,12 +1261,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
  *
  *     Called under connection lock.
  **/
-static void
+static int
 iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-                       struct iscsi_r2t_info *r2t, int left)
+                       struct iscsi_r2t_info *r2t)
 {
        struct iscsi_data *hdr;
-       int new_offset;
+       int new_offset, left;
+
+       BUG_ON(r2t->data_length - r2t->sent < 0);
+       left = r2t->data_length - r2t->sent;
+       if (left == 0)
+               return 0;
 
        hdr = &r2t->dtask.hdr;
        memset(hdr, 0, sizeof(struct iscsi_data));
@@ -1233,43 +1292,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                r2t->data_count = left;
                hdr->flags = ISCSI_FLAG_CMD_FINAL;
        }
-       conn->dataout_pdus_cnt++;
-
-       iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
-                          sizeof(struct iscsi_hdr));
-
-       if (iscsi_buf_left(&r2t->sendbuf))
-               return;
-
-       iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
-       r2t->sg += 1;
-}
-
-static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
-                             unsigned long len)
-{
-       tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
-       if (!tcp_ctask->pad_count)
-               return;
 
-       tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
-       debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
-       set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
+       conn->dataout_pdus_cnt++;
+       return 1;
 }
 
 /**
- * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+ * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
  * @conn: iscsi connection
  * @ctask: scsi command task
  * @sc: scsi command
  **/
-static void
-iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
+static int
+iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
 {
        struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+       struct iscsi_conn *conn = ctask->conn;
+       struct scsi_cmnd *sc = ctask->sc;
+       int err;
 
        BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
-       tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT;
+       tcp_ctask->sent = 0;
+       tcp_ctask->exp_datasn = 0;
+
+       /* Prepare PDU, optionally w/ immediate data */
+       debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n",
+                   conn->id, ctask->itt, ctask->imm_count,
+                   ctask->unsol_count);
+       iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len);
+
+       if (!ctask->imm_count)
+               return 0;
+
+       /* If we have immediate data, attach a payload */
+       err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc),
+                                      0, ctask->imm_count);
+       if (err)
+               return err;
+       tcp_ctask->sent += ctask->imm_count;
+       ctask->imm_count = 0;
+       return 0;
 }
 
 /**
@@ -1281,484 +1343,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
  *     The function can return -EAGAIN in which case caller must
  *     call it again later, or recover. '0' return code means successful
  *     xmit.
- *
- *     Management xmit state machine consists of these states:
- *             XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header
- *             XMSTATE_BIT_IMM_HDR      - PDU Header xmit in progress
- *             XMSTATE_BIT_IMM_DATA     - PDU Data xmit in progress
- *             XMSTATE_VALUE_IDLE       - management PDU is done
  **/
 static int
 iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
 {
-       struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
        int rc;
 
-       debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
-               conn->id, tcp_mtask->xmstate, mtask->itt);
-
-       if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) {
-               iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
-                                  sizeof(struct iscsi_hdr));
-
-               if (mtask->data_count) {
-                       set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
-                       iscsi_buf_init_iov(&tcp_mtask->sendbuf,
-                                          (char*)mtask->data,
-                                          mtask->data_count);
-               }
-
-               if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
-                   conn->stop_stage != STOP_CONN_RECOVER &&
-                   conn->hdrdgst_en)
-                       iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
-                                       (u8*)tcp_mtask->hdrext);
-
-               tcp_mtask->sent = 0;
-               clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate);
-               set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
-       }
-
-       if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) {
-               rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
-                                  mtask->data_count);
-               if (rc)
-                       return rc;
-               clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
-       }
-
-       if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) {
-               BUG_ON(!mtask->data_count);
-               /* FIXME: implement.
-                * Virtual buffer could be spreaded across multiple pages...
-                */
-               do {
-                       int rc;
-
-                       rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
-                                       &mtask->data_count, &tcp_mtask->sent);
-                       if (rc) {
-                               set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
-                               return rc;
-                       }
-               } while (mtask->data_count);
-       }
+       /* Flush any pending data first. */
+       rc = iscsi_tcp_flush(conn);
+       if (rc < 0)
+               return rc;
 
-       BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE);
        if (mtask->hdr->itt == RESERVED_ITT) {
                struct iscsi_session *session = conn->session;
 
                spin_lock_bh(&session->lock);
-               list_del(&conn->mtask->running);
-               __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
-                           sizeof(void*));
+               iscsi_free_mgmt_task(conn, mtask);
                spin_unlock_bh(&session->lock);
        }
+
        return 0;
 }
 
+/*
+ * iscsi_tcp_ctask_xmit - xmit normal PDU task
+ * @conn: iscsi connection
+ * @ctask: iscsi command task
+ *
+ * We're expected to return 0 when everything was transmitted succesfully,
+ * -EAGAIN if there's still data in the queue, or != 0 for any other kind
+ * of error.
+ */
 static int
-iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
-       struct scsi_cmnd *sc = ctask->sc;
        struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+       struct scsi_cmnd *sc = ctask->sc;
        int rc = 0;
 
-       if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) {
-               tcp_ctask->sent = 0;
-               tcp_ctask->sg_count = 0;
-               tcp_ctask->exp_datasn = 0;
-
-               if (sc->sc_data_direction == DMA_TO_DEVICE) {
-                       struct scatterlist *sg = scsi_sglist(sc);
-
-                       iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
-                       tcp_ctask->sg = sg + 1;
-                       tcp_ctask->bad_sg = sg + scsi_sg_count(sc);
-
-                       debug_scsi("cmd [itt 0x%x total %d imm_data %d "
-                                  "unsol count %d, unsol offset %d]\n",
-                                  ctask->itt, scsi_bufflen(sc),
-                                  ctask->imm_count, ctask->unsol_count,
-                                  ctask->unsol_offset);
-               }
-
-               iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
-                                 sizeof(struct iscsi_hdr));
-
-               if (conn->hdrdgst_en)
-                       iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
-                                        (u8*)tcp_ctask->hdrext);
-               clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate);
-               set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
-       }
-
-       if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {
-               rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
-               if (rc)
-                       return rc;
-               clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
-
-               if (sc->sc_data_direction != DMA_TO_DEVICE)
-                       return 0;
-
-               if (ctask->imm_count) {
-                       set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
-                       iscsi_set_padding(tcp_ctask, ctask->imm_count);
-
-                       if (ctask->conn->datadgst_en) {
-                               iscsi_data_digest_init(ctask->conn->dd_data,
-                                                      tcp_ctask);
-                               tcp_ctask->immdigest = 0;
-                       }
-               }
-
-               if (ctask->unsol_count) {
-                       set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
-                       set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
-               }
-       }
-       return rc;
-}
-
-static int
-iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       int sent = 0, rc;
-
-       if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {
-               iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
-                                  tcp_ctask->pad_count);
-               if (conn->datadgst_en)
-                       crypto_hash_update(&tcp_conn->tx_hash,
-                                          &tcp_ctask->sendbuf.sg,
-                                          tcp_ctask->sendbuf.sg.length);
-       } else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))
-               return 0;
-
-       clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
-       clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
-       debug_scsi("sending %d pad bytes for itt 0x%x\n",
-                  tcp_ctask->pad_count, ctask->itt);
-       rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
-                          &sent);
-       if (rc) {
-               debug_scsi("padding send failed %d\n", rc);
-               set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
-       }
-       return rc;
-}
-
-static int
-iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-                       struct iscsi_buf *buf, uint32_t *digest)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask;
-       struct iscsi_tcp_conn *tcp_conn;
-       int rc, sent = 0;
-
-       if (!conn->datadgst_en)
-               return 0;
-
-       tcp_ctask = ctask->dd_data;
-       tcp_conn = conn->dd_data;
-
-       if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {
-               crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
-               iscsi_buf_init_iov(buf, (char*)digest, 4);
-       }
-       clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
-
-       rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
-       if (!rc)
-               debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
-                         ctask->itt);
-       else {
-               debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
-                         *digest, ctask->itt);
-               set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
-       }
-       return rc;
-}
-
-static int
-iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
-               struct scatterlist **sg, int *sent, int *count,
-               struct iscsi_buf *digestbuf, uint32_t *digest)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       struct iscsi_conn *conn = ctask->conn;
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-       int rc, buf_sent, offset;
-
-       while (*count) {
-               buf_sent = 0;
-               offset = sendbuf->sent;
-
-               rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
-               *sent = *sent + buf_sent;
-               if (buf_sent && conn->datadgst_en)
-                       partial_sg_digest_update(&tcp_conn->tx_hash,
-                               &sendbuf->sg, sendbuf->sg.offset + offset,
-                               buf_sent);
-               if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
-                       iscsi_buf_init_sg(sendbuf, *sg);
-                       *sg = *sg + 1;
-               }
-
-               if (rc)
-                       return rc;
-       }
-
-       rc = iscsi_send_padding(conn, ctask);
-       if (rc)
+flush:
+       /* Flush any pending data first. */
+       rc = iscsi_tcp_flush(conn);
+       if (rc < 0)
                return rc;
 
-       return iscsi_send_digest(conn, ctask, digestbuf, digest);
-}
-
-static int
-iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       struct iscsi_data_task *dtask;
-       int rc;
-
-       set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
-       if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {
-               dtask = &tcp_ctask->unsol_dtask;
-
-               iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
-               iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
-                                  sizeof(struct iscsi_hdr));
-               if (conn->hdrdgst_en)
-                       iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
-                                       (u8*)dtask->hdrext);
-
-               clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
-               iscsi_set_padding(tcp_ctask, ctask->data_count);
-       }
-
-       rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
-       if (rc) {
-               clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
-               set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
-               return rc;
-       }
+       /* Are we done already? */
+       if (sc->sc_data_direction != DMA_TO_DEVICE)
+               return 0;
 
-       if (conn->datadgst_en) {
-               dtask = &tcp_ctask->unsol_dtask;
-               iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
-               dtask->digest = 0;
-       }
+       if (ctask->unsol_count != 0) {
+               struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr;
 
-       debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
-                  ctask->itt, ctask->unsol_count, tcp_ctask->sent);
-       return 0;
-}
+               /* Prepare a header for the unsolicited PDU.
+                * The amount of data we want to send will be
+                * in ctask->data_count.
+                * FIXME: return the data count instead.
+                */
+               iscsi_prep_unsolicit_data_pdu(ctask, hdr);
 
-static int
-iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       int rc;
+               debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n",
+                               ctask->itt, tcp_ctask->sent, ctask->data_count);
 
-       if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {
-               BUG_ON(!ctask->unsol_count);
-send_hdr:
-               rc = iscsi_send_unsol_hdr(conn, ctask);
+               iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+               rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
+                                             scsi_sg_count(sc),
+                                             tcp_ctask->sent,
+                                             ctask->data_count);
                if (rc)
-                       return rc;
-       }
-
-       if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {
-               struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
-               int start = tcp_ctask->sent;
+                       goto fail;
+               tcp_ctask->sent += ctask->data_count;
+               ctask->unsol_count -= ctask->data_count;
+               goto flush;
+       } else {
+               struct iscsi_session *session = conn->session;
+               struct iscsi_r2t_info *r2t;
 
-               rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
-                                    &tcp_ctask->sent, &ctask->data_count,
-                                    &dtask->digestbuf, &dtask->digest);
-               ctask->unsol_count -= tcp_ctask->sent - start;
-               if (rc)
-                       return rc;
-               clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
-               /*
-                * Done with the Data-Out. Next, check if we need
-                * to send another unsolicited Data-Out.
+               /* All unsolicited PDUs sent. Check for solicited PDUs.
                 */
-               if (ctask->unsol_count) {
-                       debug_scsi("sending more uns\n");
-                       set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
-                       goto send_hdr;
+               spin_lock_bh(&session->lock);
+               r2t = tcp_ctask->r2t;
+               if (r2t != NULL) {
+                       /* Continue with this R2T? */
+                       if (!iscsi_solicit_data_cont(conn, ctask, r2t)) {
+                               debug_scsi("  done with r2t %p\n", r2t);
+
+                               __kfifo_put(tcp_ctask->r2tpool.queue,
+                                           (void*)&r2t, sizeof(void*));
+                               tcp_ctask->r2t = r2t = NULL;
+                       }
                }
-       }
-       return 0;
-}
-
-static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
-                             struct iscsi_cmd_task *ctask)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       struct iscsi_session *session = conn->session;
-       struct iscsi_r2t_info *r2t;
-       struct iscsi_data_task *dtask;
-       int left, rc;
 
-       if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {
-               if (!tcp_ctask->r2t) {
-                       spin_lock_bh(&session->lock);
+               if (r2t == NULL) {
                        __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
                                    sizeof(void*));
-                       spin_unlock_bh(&session->lock);
+                       r2t = tcp_ctask->r2t;
                }
-send_hdr:
-               r2t = tcp_ctask->r2t;
-               dtask = &r2t->dtask;
-
-               if (conn->hdrdgst_en)
-                       iscsi_hdr_digest(conn, &r2t->headbuf,
-                                       (u8*)dtask->hdrext);
-               clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
-               set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
-       }
-
-       if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {
-               r2t = tcp_ctask->r2t;
-               dtask = &r2t->dtask;
-
-               rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
-               if (rc)
-                       return rc;
-               clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
-               set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
+               spin_unlock_bh(&session->lock);
 
-               if (conn->datadgst_en) {
-                       iscsi_data_digest_init(conn->dd_data, tcp_ctask);
-                       dtask->digest = 0;
+               /* Waiting for more R2Ts to arrive. */
+               if (r2t == NULL) {
+                       debug_tcp("no R2Ts yet\n");
+                       return 0;
                }
 
-               iscsi_set_padding(tcp_ctask, r2t->data_count);
-               debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
-                       r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
-                       r2t->sent);
-       }
+               debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
+                       r2t, r2t->solicit_datasn - 1, ctask->itt,
+                       r2t->data_offset + r2t->sent, r2t->data_count);
 
-       if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {
-               r2t = tcp_ctask->r2t;
-               dtask = &r2t->dtask;
+               iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
+                                       sizeof(struct iscsi_hdr));
 
-               rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
-                                    &r2t->sent, &r2t->data_count,
-                                    &dtask->digestbuf, &dtask->digest);
+               rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
+                                             scsi_sg_count(sc),
+                                             r2t->data_offset + r2t->sent,
+                                             r2t->data_count);
                if (rc)
-                       return rc;
-               clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
-
-               /*
-                * Done with this Data-Out. Next, check if we have
-                * to send another Data-Out for this R2T.
-                */
-               BUG_ON(r2t->data_length - r2t->sent < 0);
-               left = r2t->data_length - r2t->sent;
-               if (left) {
-                       iscsi_solicit_data_cont(conn, ctask, r2t, left);
-                       goto send_hdr;
-               }
-
-               /*
-                * Done with this R2T. Check if there are more
-                * outstanding R2Ts ready to be processed.
-                */
-               spin_lock_bh(&session->lock);
-               tcp_ctask->r2t = NULL;
-               __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
-                           sizeof(void*));
-               if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
-                               sizeof(void*))) {
-                       tcp_ctask->r2t = r2t;
-                       spin_unlock_bh(&session->lock);
-                       goto send_hdr;
-               }
-               spin_unlock_bh(&session->lock);
+                       goto fail;
+               tcp_ctask->sent += r2t->data_count;
+               r2t->sent += r2t->data_count;
+               goto flush;
        }
        return 0;
-}
-
-/**
- * iscsi_tcp_ctask_xmit - xmit normal PDU task
- * @conn: iscsi connection
- * @ctask: iscsi command task
- *
- * Notes:
- *     The function can return -EAGAIN in which case caller must
- *     call it again later, or recover. '0' return code means successful
- *     xmit.
- *     The function is devided to logical helpers (above) for the different
- *     xmit stages.
- *
- *iscsi_send_cmd_hdr()
- *     XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate
- *                                Header Digest
- *     XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress
- *
- *iscsi_send_padding
- *     XMSTATE_BIT_W_PAD        - Prepare and send pading
- *     XMSTATE_BIT_W_RESEND_PAD - retry send pading
- *
- *iscsi_send_digest
- *     XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
- *     XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest
- *
- *iscsi_send_unsol_hdr
- *     XMSTATE_BIT_UNS_INIT     - prepare un-solicit data header and digest
- *     XMSTATE_BIT_UNS_HDR      - send un-solicit header
- *
- *iscsi_send_unsol_pdu
- *     XMSTATE_BIT_UNS_DATA     - send un-solicit data in progress
- *
- *iscsi_send_sol_pdu
- *     XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize
- *     XMSTATE_BIT_SOL_HDR      - send solicit header
- *     XMSTATE_BIT_SOL_DATA     - send solicit data
- *
- *iscsi_tcp_ctask_xmit
- *     XMSTATE_BIT_IMM_DATA     - xmit managment data (??)
- **/
-static int
-iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       int rc = 0;
-
-       debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
-               conn->id, tcp_ctask->xmstate, ctask->itt);
-
-       rc = iscsi_send_cmd_hdr(conn, ctask);
-       if (rc)
-               return rc;
-       if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
-               return 0;
-
-       if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {
-               rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
-                                    &tcp_ctask->sent, &ctask->imm_count,
-                                    &tcp_ctask->immbuf, &tcp_ctask->immdigest);
-               if (rc)
-                       return rc;
-               clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
-       }
-
-       rc = iscsi_send_unsol_pdu(conn, ctask);
-       if (rc)
-               return rc;
-
-       rc = iscsi_send_sol_pdu(conn, ctask);
-       if (rc)
-               return rc;
-
-       return rc;
+fail:
+       iscsi_conn_failure(conn, rc);
+       return -EIO;
 }
 
 static struct iscsi_cls_conn *
@@ -1784,9 +1492,6 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
 
        conn->dd_data = tcp_conn;
        tcp_conn->iscsi_conn = conn;
-       tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-       /* initial operational parameters */
-       tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
 
        tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
                                                  CRYPTO_ALG_ASYNC);
@@ -1863,11 +1568,9 @@ static void
 iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
 {
        struct iscsi_conn *conn = cls_conn->dd_data;
-       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 
        iscsi_conn_stop(cls_conn, flag);
        iscsi_tcp_release_conn(conn);
-       tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
 }
 
 static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
@@ -1967,7 +1670,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
        /*
         * set receive state machine into initial state
         */
-       tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+       iscsi_tcp_hdr_recv_prep(tcp_conn);
        return 0;
 
 free_socket:
@@ -1977,10 +1680,17 @@ free_socket:
 
 /* called with host lock */
 static void
-iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
+iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
 {
-       struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
-       tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT;
+       debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+
+       /* Prepare PDU, optionally w/ immediate data */
+       iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr));
+
+       /* If we have immediate data, attach a payload */
+       if (mtask->data_count)
+               iscsi_tcp_send_linear_data_prepare(conn, mtask->data,
+                                                  mtask->data_count);
 }
 
 static int
@@ -2003,8 +1713,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
                 */
 
                /* R2T pool */
-               if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4,
-                                   (void***)&tcp_ctask->r2ts,
+               if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL,
                                    sizeof(struct iscsi_r2t_info))) {
                        goto r2t_alloc_fail;
                }
@@ -2013,8 +1722,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
                tcp_ctask->r2tqueue = kfifo_alloc(
                      session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
                if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
-                       iscsi_pool_free(&tcp_ctask->r2tpool,
-                                       (void**)tcp_ctask->r2ts);
+                       iscsi_pool_free(&tcp_ctask->r2tpool);
                        goto r2t_alloc_fail;
                }
        }
@@ -2027,8 +1735,7 @@ r2t_alloc_fail:
                struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
                kfifo_free(tcp_ctask->r2tqueue);
-               iscsi_pool_free(&tcp_ctask->r2tpool,
-                               (void**)tcp_ctask->r2ts);
+               iscsi_pool_free(&tcp_ctask->r2tpool);
        }
        return -ENOMEM;
 }
@@ -2043,8 +1750,7 @@ iscsi_r2tpool_free(struct iscsi_session *session)
                struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
                kfifo_free(tcp_ctask->r2tqueue);
-               iscsi_pool_free(&tcp_ctask->r2tpool,
-                               (void**)tcp_ctask->r2ts);
+               iscsi_pool_free(&tcp_ctask->r2tpool);
        }
 }
 
@@ -2060,9 +1766,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
        switch(param) {
        case ISCSI_PARAM_HDRDGST_EN:
                iscsi_set_param(cls_conn, param, buf, buflen);
-               tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
-               if (conn->hdrdgst_en)
-                       tcp_conn->hdr_size += sizeof(__u32);
                break;
        case ISCSI_PARAM_DATADGST_EN:
                iscsi_set_param(cls_conn, param, buf, buflen);
@@ -2071,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
                break;
        case ISCSI_PARAM_MAX_R2T:
                sscanf(buf, "%d", &value);
-               if (session->max_r2t == roundup_pow_of_two(value))
+               if (value <= 0 || !is_power_of_2(value))
+                       return -EINVAL;
+               if (session->max_r2t == value)
                        break;
                iscsi_r2tpool_free(session);
                iscsi_set_param(cls_conn, param, buf, buflen);
-               if (session->max_r2t & (session->max_r2t - 1))
-                       session->max_r2t = roundup_pow_of_two(session->max_r2t);
                if (iscsi_r2tpool_alloc(session))
                        return -ENOMEM;
                break;
@@ -2183,14 +1886,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
                struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
                struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
-               ctask->hdr = &tcp_ctask->hdr;
+               ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
+               ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
        }
 
        for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
                struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
                struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
 
-               mtask->hdr = &tcp_mtask->hdr;
+               mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr;
        }
 
        if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
@@ -2222,12 +1926,14 @@ static struct scsi_host_template iscsi_sht = {
        .queuecommand           = iscsi_queuecommand,
        .change_queue_depth     = iscsi_change_queue_depth,
        .can_queue              = ISCSI_DEF_XMIT_CMDS_MAX - 1,
-       .sg_tablesize           = ISCSI_SG_TABLESIZE,
+       .sg_tablesize           = 4096,
        .max_sectors            = 0xFFFF,
        .cmd_per_lun            = ISCSI_DEF_CMD_PER_LUN,
        .eh_abort_handler       = iscsi_eh_abort,
+       .eh_device_reset_handler= iscsi_eh_device_reset,
        .eh_host_reset_handler  = iscsi_eh_host_reset,
        .use_clustering         = DISABLE_CLUSTERING,
+       .use_sg_chaining        = ENABLE_SG_CHAINING,
        .slave_configure        = iscsi_tcp_slave_configure,
        .proc_name              = "iscsi_tcp",
        .this_id                = -1,
@@ -2257,14 +1963,17 @@ static struct iscsi_transport iscsi_tcp_transport = {
                                  ISCSI_PERSISTENT_ADDRESS |
                                  ISCSI_TARGET_NAME | ISCSI_TPGT |
                                  ISCSI_USERNAME | ISCSI_PASSWORD |
-                                 ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+                                 ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+                                 ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+                                 ISCSI_LU_RESET_TMO |
+                                 ISCSI_PING_TMO | ISCSI_RECV_TMO,
        .host_param_mask        = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
                                  ISCSI_HOST_INITIATOR_NAME |
                                  ISCSI_HOST_NETDEV_NAME,
        .host_template          = &iscsi_sht,
        .conndata_size          = sizeof(struct iscsi_conn),
        .max_conn               = 1,
-       .max_cmd_len            = ISCSI_TCP_MAX_CMD_LEN,
+       .max_cmd_len            = 16,
        /* session management */
        .create_session         = iscsi_tcp_session_create,
        .destroy_session        = iscsi_tcp_session_destroy,
@@ -2283,8 +1992,8 @@ static struct iscsi_transport iscsi_tcp_transport = {
        /* IO */
        .send_pdu               = iscsi_conn_send_pdu,
        .get_stats              = iscsi_conn_get_stats,
-       .init_cmd_task          = iscsi_tcp_cmd_init,
-       .init_mgmt_task         = iscsi_tcp_mgmt_init,
+       .init_cmd_task          = iscsi_tcp_ctask_init,
+       .init_mgmt_task         = iscsi_tcp_mtask_init,
        .xmit_cmd_task          = iscsi_tcp_ctask_xmit,
        .xmit_mgmt_task         = iscsi_tcp_mtask_xmit,
        .cleanup_cmd_task       = iscsi_tcp_cleanup_ctask,
index 68c36cc8997e47f451f4c7c7227ab378dbd57c07..ed0b991d1e720b50e25897ac74642ce7c5530375 100644 (file)
 
 #include <scsi/libiscsi.h>
 
-/* Socket's Receive state machine */
-#define IN_PROGRESS_WAIT_HEADER                0x0
-#define IN_PROGRESS_HEADER_GATHER      0x1
-#define IN_PROGRESS_DATA_RECV          0x2
-#define IN_PROGRESS_DDIGEST_RECV       0x3
-#define IN_PROGRESS_PAD_RECV           0x4
-
-/* xmit state machine */
-#define XMSTATE_VALUE_IDLE                     0
-#define XMSTATE_BIT_CMD_HDR_INIT               0
-#define XMSTATE_BIT_CMD_HDR_XMIT               1
-#define XMSTATE_BIT_IMM_HDR                    2
-#define XMSTATE_BIT_IMM_DATA                   3
-#define XMSTATE_BIT_UNS_INIT                   4
-#define XMSTATE_BIT_UNS_HDR                    5
-#define XMSTATE_BIT_UNS_DATA                   6
-#define XMSTATE_BIT_SOL_HDR                    7
-#define XMSTATE_BIT_SOL_DATA                   8
-#define XMSTATE_BIT_W_PAD                      9
-#define XMSTATE_BIT_W_RESEND_PAD               10
-#define XMSTATE_BIT_W_RESEND_DATA_DIGEST       11
-#define XMSTATE_BIT_IMM_HDR_INIT               12
-#define XMSTATE_BIT_SOL_HDR_INIT               13
-
-#define ISCSI_PAD_LEN                  4
-#define ISCSI_SG_TABLESIZE             SG_ALL
-#define ISCSI_TCP_MAX_CMD_LEN          16
-
 struct crypto_hash;
 struct socket;
+struct iscsi_tcp_conn;
+struct iscsi_segment;
+
+typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
+                                   struct iscsi_segment *);
+
+struct iscsi_segment {
+       unsigned char           *data;
+       unsigned int            size;
+       unsigned int            copied;
+       unsigned int            total_size;
+       unsigned int            total_copied;
+
+       struct hash_desc        *hash;
+       unsigned char           recv_digest[ISCSI_DIGEST_SIZE];
+       unsigned char           digest[ISCSI_DIGEST_SIZE];
+       unsigned int            digest_len;
+
+       struct scatterlist      *sg;
+       void                    *sg_mapped;
+       unsigned int            sg_offset;
+
+       iscsi_segment_done_fn_t *done;
+};
 
 /* Socket connection recieve helper */
 struct iscsi_tcp_recv {
        struct iscsi_hdr        *hdr;
-       struct sk_buff          *skb;
-       int                     offset;
-       int                     len;
-       int                     hdr_offset;
-       int                     copy;
-       int                     copied;
-       int                     padding;
-       struct iscsi_cmd_task   *ctask;         /* current cmd in progress */
+       struct iscsi_segment    segment;
+
+       /* Allocate buffer for BHS + AHS */
+       uint32_t                hdr_buf[64];
 
        /* copied and flipped values */
        int                     datalen;
-       int                     datadgst;
-       char                    zero_copy_hdr;
+};
+
+/* Socket connection send helper */
+struct iscsi_tcp_send {
+       struct iscsi_hdr        *hdr;
+       struct iscsi_segment    segment;
+       struct iscsi_segment    data_segment;
 };
 
 struct iscsi_tcp_conn {
        struct iscsi_conn       *iscsi_conn;
        struct socket           *sock;
-       struct iscsi_hdr        hdr;            /* header placeholder */
-       char                    hdrext[4*sizeof(__u16) +
-                                   sizeof(__u32)];
-       int                     data_copied;
        int                     stop_stage;     /* conn_stop() flag: *
                                                 * stop to recover,  *
                                                 * stop to terminate */
-       /* iSCSI connection-wide sequencing */
-       int                     hdr_size;       /* PDU header size */
-
        /* control data */
        struct iscsi_tcp_recv   in;             /* TCP receive context */
-       int                     in_progress;    /* connection state machine */
+       struct iscsi_tcp_send   out;            /* TCP send context */
 
        /* old values for socket callbacks */
        void                    (*old_data_ready)(struct sock *, int);
@@ -103,29 +93,19 @@ struct iscsi_tcp_conn {
        uint32_t                sendpage_failures_cnt;
        uint32_t                discontiguous_hdr_cnt;
 
-       ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
-};
+       int                     error;
 
-struct iscsi_buf {
-       struct scatterlist      sg;
-       unsigned int            sent;
-       char                    use_sendmsg;
+       ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
 };
 
 struct iscsi_data_task {
        struct iscsi_data       hdr;                    /* PDU */
-       char                    hdrext[sizeof(__u32)];  /* Header-Digest */
-       struct iscsi_buf        digestbuf;              /* digest buffer */
-       uint32_t                digest;                 /* data digest */
+       char                    hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
 };
 
 struct iscsi_tcp_mgmt_task {
        struct iscsi_hdr        hdr;
-       char                    hdrext[sizeof(__u32)]; /* Header-Digest */
-       unsigned long           xmstate;        /* mgmt xmit progress */
-       struct iscsi_buf        headbuf;        /* header buffer */
-       struct iscsi_buf        sendbuf;        /* in progress buffer */
-       int                     sent;
+       char                    hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
 };
 
 struct iscsi_r2t_info {
@@ -133,38 +113,26 @@ struct iscsi_r2t_info {
        __be32                  exp_statsn;     /* copied from R2T */
        uint32_t                data_length;    /* copied from R2T */
        uint32_t                data_offset;    /* copied from R2T */
-       struct iscsi_buf        headbuf;        /* Data-Out Header Buffer */
-       struct iscsi_buf        sendbuf;        /* Data-Out in progress buffer*/
        int                     sent;           /* R2T sequence progress */
        int                     data_count;     /* DATA-Out payload progress */
-       struct scatterlist      *sg;            /* per-R2T SG list */
        int                     solicit_datasn;
-       struct iscsi_data_task   dtask;        /* which data task */
+       struct iscsi_data_task  dtask;          /* Data-Out header buf */
 };
 
 struct iscsi_tcp_cmd_task {
-       struct iscsi_cmd        hdr;
-       char                    hdrext[4*sizeof(__u16)+ /* AHS */
-                                   sizeof(__u32)];     /* HeaderDigest */
-       char                    pad[ISCSI_PAD_LEN];
-       int                     pad_count;              /* padded bytes */
-       struct iscsi_buf        headbuf;                /* header buf (xmit) */
-       struct iscsi_buf        sendbuf;                /* in progress buffer*/
-       unsigned long           xmstate;                /* xmit xtate machine */
+       struct iscsi_hdr_buff {
+               struct iscsi_cmd        cmd_hdr;
+               char                    hdrextbuf[ISCSI_MAX_AHS_SIZE +
+                                                 ISCSI_DIGEST_SIZE];
+       } hdr;
+
        int                     sent;
-       struct scatterlist      *sg;                    /* per-cmd SG list  */
-       struct scatterlist      *bad_sg;                /* assert statement */
-       int                     sg_count;               /* SG's to process  */
-       uint32_t                exp_datasn;             /* expected target's R2TSN/DataSN */
+       uint32_t                exp_datasn;     /* expected target's R2TSN/DataSN */
        int                     data_offset;
-       struct iscsi_r2t_info   *r2t;                   /* in progress R2T    */
-       struct iscsi_queue      r2tpool;
+       struct iscsi_r2t_info   *r2t;           /* in progress R2T    */
+       struct iscsi_pool       r2tpool;
        struct kfifo            *r2tqueue;
-       struct iscsi_r2t_info   **r2ts;
-       int                     digest_count;
-       uint32_t                immdigest;              /* for imm data */
-       struct iscsi_buf        immbuf;                 /* for imm data digest */
-       struct iscsi_data_task  unsol_dtask;    /* unsol data task */
+       struct iscsi_data_task  unsol_dtask;    /* Data-Out header buf */
 };
 
 #endif /* ISCSI_H */
index 8b57af5baaec7d41c215c645b437af4a725b2acd..553168ae44f1864c01a6f5cdc8508cc985fc7029 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/kfifo.h>
 #include <linux/delay.h>
+#include <linux/log2.h>
 #include <asm/unaligned.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
@@ -86,7 +87,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
                 * xmit thread
                 */
                if (!list_empty(&session->leadconn->xmitqueue) ||
-                   __kfifo_len(session->leadconn->mgmtqueue))
+                   !list_empty(&session->leadconn->mgmtqueue))
                        scsi_queue_work(session->host,
                                        &session->leadconn->xmitwork);
        }
@@ -122,6 +123,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
 }
 EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
 
+static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+{
+       unsigned exp_len = ctask->hdr_len + len;
+
+       if (exp_len > ctask->hdr_max) {
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
+       ctask->hdr_len = exp_len;
+       return 0;
+}
+
 /**
  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
  * @ctask: iscsi cmd task
@@ -129,27 +144,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
  * fields like dlength or final based on how much data it sends
  */
-static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 {
        struct iscsi_conn *conn = ctask->conn;
        struct iscsi_session *session = conn->session;
        struct iscsi_cmd *hdr = ctask->hdr;
        struct scsi_cmnd *sc = ctask->sc;
+       unsigned hdrlength;
+       int rc;
 
-        hdr->opcode = ISCSI_OP_SCSI_CMD;
-        hdr->flags = ISCSI_ATTR_SIMPLE;
-        int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
-        hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-        hdr->cmdsn = cpu_to_be32(session->cmdsn);
-        session->cmdsn++;
-        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-        memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
+       ctask->hdr_len = 0;
+       rc = iscsi_add_hdr(ctask, sizeof(*hdr));
+       if (rc)
+               return rc;
+       hdr->opcode = ISCSI_OP_SCSI_CMD;
+       hdr->flags = ISCSI_ATTR_SIMPLE;
+       int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+       hdr->itt = build_itt(ctask->itt, conn->id, session->age);
+       hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+       hdr->cmdsn = cpu_to_be32(session->cmdsn);
+       session->cmdsn++;
+       hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+       memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
        if (sc->cmd_len < MAX_COMMAND_SIZE)
                memset(&hdr->cdb[sc->cmd_len], 0,
                        MAX_COMMAND_SIZE - sc->cmd_len);
 
-       ctask->data_count = 0;
        ctask->imm_count = 0;
        if (sc->sc_data_direction == DMA_TO_DEVICE) {
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
@@ -178,9 +198,9 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                        else
                                ctask->imm_count = min(scsi_bufflen(sc),
                                                        conn->max_xmit_dlength);
-                       hton24(ctask->hdr->dlength, ctask->imm_count);
+                       hton24(hdr->dlength, ctask->imm_count);
                } else
-                       zero_data(ctask->hdr->dlength);
+                       zero_data(hdr->dlength);
 
                if (!session->initial_r2t_en) {
                        ctask->unsol_count = min((session->first_burst),
@@ -190,7 +210,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 
                if (!ctask->unsol_count)
                        /* No unsolicit Data-Out's */
-                       ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+                       hdr->flags |= ISCSI_FLAG_CMD_FINAL;
        } else {
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
                zero_data(hdr->dlength);
@@ -199,13 +219,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                        hdr->flags |= ISCSI_FLAG_CMD_READ;
        }
 
-       conn->scsicmd_pdus_cnt++;
+       /* calculate size of additional header segments (AHSs) */
+       hdrlength = ctask->hdr_len - sizeof(*hdr);
+
+       WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
+       hdrlength /= ISCSI_PAD_LEN;
+
+       WARN_ON(hdrlength >= 256);
+       hdr->hlength = hdrlength & 0xFF;
+
+       if (conn->session->tt->init_cmd_task(conn->ctask))
+               return EIO;
 
-        debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
+       conn->scsicmd_pdus_cnt++;
+       debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
                "cmdsn %d win %d]\n",
-                sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+               sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
                conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
-                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+               session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+       return 0;
 }
 
 /**
@@ -218,13 +250,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
  */
 static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
 {
-       struct iscsi_session *session = ctask->conn->session;
+       struct iscsi_conn *conn = ctask->conn;
+       struct iscsi_session *session = conn->session;
        struct scsi_cmnd *sc = ctask->sc;
 
        ctask->state = ISCSI_TASK_COMPLETED;
        ctask->sc = NULL;
        /* SCSI eh reuses commands to verify us */
        sc->SCp.ptr = NULL;
+       if (conn->ctask == ctask)
+               conn->ctask = NULL;
        list_del_init(&ctask->running);
        __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
        sc->scsi_done(sc);
@@ -241,6 +276,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
                iscsi_complete_command(ctask);
 }
 
+/*
+ * session lock must be held
+ */
+static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+                        int err)
+{
+       struct scsi_cmnd *sc;
+
+       sc = ctask->sc;
+       if (!sc)
+               return;
+
+       if (ctask->state == ISCSI_TASK_PENDING)
+               /*
+                * cmd never made it to the xmit thread, so we should not count
+                * the cmd in the sequencing
+                */
+               conn->session->queued_cmdsn--;
+       else
+               conn->session->tt->cleanup_cmd_task(conn, ctask);
+
+       sc->result = err;
+       scsi_set_resid(sc, scsi_bufflen(sc));
+       if (conn->ctask == ctask)
+               conn->ctask = NULL;
+       /* release ref from queuecommand */
+       __iscsi_put_ctask(ctask);
+}
+
+/**
+ * iscsi_free_mgmt_task - return mgmt task back to pool
+ * @conn: iscsi connection
+ * @mtask: mtask
+ *
+ * Must be called with session lock.
+ */
+void iscsi_free_mgmt_task(struct iscsi_conn *conn,
+                         struct iscsi_mgmt_task *mtask)
+{
+       list_del_init(&mtask->running);
+       if (conn->login_mtask == mtask)
+               return;
+
+       if (conn->ping_mtask == mtask)
+               conn->ping_mtask = NULL;
+       __kfifo_put(conn->session->mgmtpool.queue,
+                   (void*)&mtask, sizeof(void*));
+}
+EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
+
+static struct iscsi_mgmt_task *
+__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+                     char *data, uint32_t data_size)
+{
+       struct iscsi_session *session = conn->session;
+       struct iscsi_mgmt_task *mtask;
+
+       if (session->state == ISCSI_STATE_TERMINATE)
+               return NULL;
+
+       if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
+           hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+               /*
+                * Login and Text are sent serially, in
+                * request-followed-by-response sequence.
+                * Same mtask can be used. Same ITT must be used.
+                * Note that login_mtask is preallocated at conn_create().
+                */
+               mtask = conn->login_mtask;
+       else {
+               BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
+               BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+
+               if (!__kfifo_get(session->mgmtpool.queue,
+                                (void*)&mtask, sizeof(void*)))
+                       return NULL;
+       }
+
+       if (data_size) {
+               memcpy(mtask->data, data, data_size);
+               mtask->data_count = data_size;
+       } else
+               mtask->data_count = 0;
+
+       memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
+       INIT_LIST_HEAD(&mtask->running);
+       list_add_tail(&mtask->running, &conn->mgmtqueue);
+       return mtask;
+}
+
+int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
+                       char *data, uint32_t data_size)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct iscsi_session *session = conn->session;
+       int err = 0;
+
+       spin_lock_bh(&session->lock);
+       if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+               err = -EPERM;
+       spin_unlock_bh(&session->lock);
+       scsi_queue_work(session->host, &conn->xmitwork);
+       return err;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
+
 /**
  * iscsi_cmd_rsp - SCSI Command Response processing
  * @conn: iscsi connection
@@ -291,17 +432,19 @@ invalid_datalen:
                           min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
        }
 
-       if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
+       if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
+                          ISCSI_FLAG_CMD_OVERFLOW)) {
                int res_count = be32_to_cpu(rhdr->residual_count);
 
-               if (res_count > 0 && res_count <= scsi_bufflen(sc))
+               if (res_count > 0 &&
+                   (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+                    res_count <= scsi_bufflen(sc)))
                        scsi_set_resid(sc, res_count);
                else
                        sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-       } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
+       } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
+                                 ISCSI_FLAG_CMD_BIDI_OVERFLOW))
                sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-       else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
-               scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
 
 out:
        debug_scsi("done [sc %lx res %d itt 0x%x]\n",
@@ -318,18 +461,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
        conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
        conn->tmfrsp_pdus_cnt++;
 
-       if (conn->tmabort_state != TMABORT_INITIAL)
+       if (conn->tmf_state != TMF_QUEUED)
                return;
 
        if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
-               conn->tmabort_state = TMABORT_SUCCESS;
+               conn->tmf_state = TMF_SUCCESS;
        else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
-               conn->tmabort_state = TMABORT_NOT_FOUND;
+               conn->tmf_state = TMF_NOT_FOUND;
        else
-               conn->tmabort_state = TMABORT_FAILED;
+               conn->tmf_state = TMF_FAILED;
        wake_up(&conn->ehwait);
 }
 
+static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
+{
+        struct iscsi_nopout hdr;
+       struct iscsi_mgmt_task *mtask;
+
+       if (!rhdr && conn->ping_mtask)
+               return;
+
+       memset(&hdr, 0, sizeof(struct iscsi_nopout));
+       hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
+       hdr.flags = ISCSI_FLAG_CMD_FINAL;
+
+       if (rhdr) {
+               memcpy(hdr.lun, rhdr->lun, 8);
+               hdr.ttt = rhdr->ttt;
+               hdr.itt = RESERVED_ITT;
+       } else
+               hdr.ttt = RESERVED_ITT;
+
+       mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
+       if (!mtask) {
+               printk(KERN_ERR "Could not send nopout\n");
+               return;
+       }
+
+       /* only track our nops */
+       if (!rhdr) {
+               conn->ping_mtask = mtask;
+               conn->last_ping = jiffies;
+       }
+       scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+
 static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                               char *data, int datalen)
 {
@@ -374,6 +550,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        struct iscsi_mgmt_task *mtask;
        uint32_t itt;
 
+       conn->last_recv = jiffies;
        if (hdr->itt != RESERVED_ITT)
                itt = get_itt(hdr->itt);
        else
@@ -429,10 +606,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                         */
                        if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
                                rc = ISCSI_ERR_CONN_FAILED;
-                       list_del(&mtask->running);
-                       if (conn->login_mtask != mtask)
-                               __kfifo_put(session->mgmtpool.queue,
-                                           (void*)&mtask, sizeof(void*));
+                       iscsi_free_mgmt_task(conn, mtask);
                        break;
                case ISCSI_OP_SCSI_TMFUNC_RSP:
                        if (datalen) {
@@ -441,20 +615,26 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        }
 
                        iscsi_tmf_rsp(conn, hdr);
+                       iscsi_free_mgmt_task(conn, mtask);
                        break;
                case ISCSI_OP_NOOP_IN:
-                       if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
+                       if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) ||
+                           datalen) {
                                rc = ISCSI_ERR_PROTO;
                                break;
                        }
                        conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
 
-                       if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
-                               rc = ISCSI_ERR_CONN_FAILED;
-                       list_del(&mtask->running);
-                       if (conn->login_mtask != mtask)
-                               __kfifo_put(session->mgmtpool.queue,
-                                           (void*)&mtask, sizeof(void*));
+                       if (conn->ping_mtask != mtask) {
+                               /*
+                                * If this is not in response to one of our
+                                * nops then it must be from userspace.
+                                */
+                               if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
+                                                  datalen))
+                                       rc = ISCSI_ERR_CONN_FAILED;
+                       }
+                       iscsi_free_mgmt_task(conn, mtask);
                        break;
                default:
                        rc = ISCSI_ERR_BAD_OPCODE;
@@ -473,8 +653,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
                                break;
 
-                       if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
-                               rc = ISCSI_ERR_CONN_FAILED;
+                       iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
                        break;
                case ISCSI_OP_REJECT:
                        rc = iscsi_handle_reject(conn, hdr, data, datalen);
@@ -609,20 +788,19 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
                session->tt->init_mgmt_task(conn, mtask);
 
        debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
-                  hdr->opcode, hdr->itt, mtask->data_count);
+                  hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
+                  mtask->data_count);
 }
 
 static int iscsi_xmit_mtask(struct iscsi_conn *conn)
 {
        struct iscsi_hdr *hdr = conn->mtask->hdr;
-       int rc, was_logout = 0;
+       int rc;
 
+       if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
+               conn->session->state = ISCSI_STATE_LOGGING_OUT;
        spin_unlock_bh(&conn->session->lock);
-       if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
-               conn->session->state = ISCSI_STATE_IN_RECOVERY;
-               iscsi_block_session(session_to_cls(conn->session));
-               was_logout = 1;
-       }
+
        rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
        spin_lock_bh(&conn->session->lock);
        if (rc)
@@ -630,11 +808,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
 
        /* done with this in-progress mtask */
        conn->mtask = NULL;
-
-       if (was_logout) {
-               set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-               return -ENODATA;
-       }
        return 0;
 }
 
@@ -658,27 +831,35 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
 static int iscsi_xmit_ctask(struct iscsi_conn *conn)
 {
        struct iscsi_cmd_task *ctask = conn->ctask;
-       int rc = 0;
-
-       /*
-        * serialize with TMF AbortTask
-        */
-       if (ctask->state == ISCSI_TASK_ABORTING)
-               goto done;
+       int rc;
 
        __iscsi_get_ctask(ctask);
        spin_unlock_bh(&conn->session->lock);
        rc = conn->session->tt->xmit_cmd_task(conn, ctask);
        spin_lock_bh(&conn->session->lock);
        __iscsi_put_ctask(ctask);
-
-done:
        if (!rc)
                /* done with this ctask */
                conn->ctask = NULL;
        return rc;
 }
 
+/**
+ * iscsi_requeue_ctask - requeue ctask to run from session workqueue
+ * @ctask: ctask to requeue
+ *
+ * LLDs that need to run a ctask from the session workqueue should call
+ * this. The session lock must be held.
+ */
+void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
+{
+       struct iscsi_conn *conn = ctask->conn;
+
+       list_move_tail(&ctask->running, &conn->requeue);
+       scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+EXPORT_SYMBOL_GPL(iscsi_requeue_ctask);
+
 /**
  * iscsi_data_xmit - xmit any command into the scheduled connection
  * @conn: iscsi connection
@@ -717,36 +898,40 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
         * overflow us with nop-ins
         */
 check_mgmt:
-       while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
-                          sizeof(void*))) {
+       while (!list_empty(&conn->mgmtqueue)) {
+               conn->mtask = list_entry(conn->mgmtqueue.next,
+                                        struct iscsi_mgmt_task, running);
+               if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+                       iscsi_free_mgmt_task(conn, conn->mtask);
+                       conn->mtask = NULL;
+                       continue;
+               }
+
                iscsi_prep_mtask(conn, conn->mtask);
-               list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
+               list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
                rc = iscsi_xmit_mtask(conn);
                if (rc)
                        goto again;
        }
 
-       /* process command queue */
+       /* process pending command queue */
        while (!list_empty(&conn->xmitqueue)) {
-               /*
-                * iscsi tcp may readd the task to the xmitqueue to send
-                * write data
-                */
+               if (conn->tmf_state == TMF_QUEUED)
+                       break;
+
                conn->ctask = list_entry(conn->xmitqueue.next,
                                         struct iscsi_cmd_task, running);
-               switch (conn->ctask->state) {
-               case ISCSI_TASK_ABORTING:
-                       break;
-               case ISCSI_TASK_PENDING:
-                       iscsi_prep_scsi_cmd_pdu(conn->ctask);
-                       conn->session->tt->init_cmd_task(conn->ctask);
-                       /* fall through */
-               default:
-                       conn->ctask->state = ISCSI_TASK_RUNNING;
-                       break;
+               if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+                       fail_command(conn, conn->ctask, DID_IMM_RETRY << 16);
+                       continue;
+               }
+               if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
+                       fail_command(conn, conn->ctask, DID_ABORT << 16);
+                       continue;
                }
-               list_move_tail(conn->xmitqueue.next, &conn->run_list);
 
+               conn->ctask->state = ISCSI_TASK_RUNNING;
+               list_move_tail(conn->xmitqueue.next, &conn->run_list);
                rc = iscsi_xmit_ctask(conn);
                if (rc)
                        goto again;
@@ -755,7 +940,28 @@ check_mgmt:
                 * we need to check the mgmt queue for nops that need to
                 * be sent to aviod starvation
                 */
-               if (__kfifo_len(conn->mgmtqueue))
+               if (!list_empty(&conn->mgmtqueue))
+                       goto check_mgmt;
+       }
+
+       while (!list_empty(&conn->requeue)) {
+               if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
+                       break;
+
+               /*
+                * we always do fastlogout - conn stop code will clean up.
+                */
+               if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+                       break;
+
+               conn->ctask = list_entry(conn->requeue.next,
+                                        struct iscsi_cmd_task, running);
+               conn->ctask->state = ISCSI_TASK_RUNNING;
+               list_move_tail(conn->requeue.next, &conn->run_list);
+               rc = iscsi_xmit_ctask(conn);
+               if (rc)
+                       goto again;
+               if (!list_empty(&conn->mgmtqueue))
                        goto check_mgmt;
        }
        spin_unlock_bh(&conn->session->lock);
@@ -790,6 +996,7 @@ enum {
        FAILURE_SESSION_TERMINATE,
        FAILURE_SESSION_IN_RECOVERY,
        FAILURE_SESSION_RECOVERY_TIMEOUT,
+       FAILURE_SESSION_LOGGING_OUT,
 };
 
 int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -805,8 +1012,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        sc->SCp.ptr = NULL;
 
        host = sc->device->host;
-       session = iscsi_hostdata(host->hostdata);
+       spin_unlock(host->host_lock);
 
+       session = iscsi_hostdata(host->hostdata);
        spin_lock(&session->lock);
 
        /*
@@ -822,17 +1030,22 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                 * be entering our queuecommand while a block is starting
                 * up because the block code is not locked)
                 */
-               if (session->state == ISCSI_STATE_IN_RECOVERY) {
+               switch (session->state) {
+               case ISCSI_STATE_IN_RECOVERY:
                        reason = FAILURE_SESSION_IN_RECOVERY;
                        goto reject;
-               }
-
-               if (session->state == ISCSI_STATE_RECOVERY_FAILED)
+               case ISCSI_STATE_LOGGING_OUT:
+                       reason = FAILURE_SESSION_LOGGING_OUT;
+                       goto reject;
+               case ISCSI_STATE_RECOVERY_FAILED:
                        reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
-               else if (session->state == ISCSI_STATE_TERMINATE)
+                       break;
+               case ISCSI_STATE_TERMINATE:
                        reason = FAILURE_SESSION_TERMINATE;
-               else
+                       break;
+               default:
                        reason = FAILURE_SESSION_FREED;
+               }
                goto fault;
        }
 
@@ -859,7 +1072,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 
        atomic_set(&ctask->refcount, 1);
        ctask->state = ISCSI_TASK_PENDING;
-       ctask->mtask = NULL;
        ctask->conn = conn;
        ctask->sc = sc;
        INIT_LIST_HEAD(&ctask->running);
@@ -868,11 +1080,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        spin_unlock(&session->lock);
 
        scsi_queue_work(host, &conn->xmitwork);
+       spin_lock(host->host_lock);
        return 0;
 
 reject:
        spin_unlock(&session->lock);
        debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
+       spin_lock(host->host_lock);
        return SCSI_MLQUEUE_HOST_BUSY;
 
 fault:
@@ -882,6 +1096,7 @@ fault:
        sc->result = (DID_NO_CONNECT << 16);
        scsi_set_resid(sc, scsi_bufflen(sc));
        sc->scsi_done(sc);
+       spin_lock(host->host_lock);
        return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_queuecommand);
@@ -895,72 +1110,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
 }
 EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
 
-static struct iscsi_mgmt_task *
-__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-                     char *data, uint32_t data_size)
-{
-       struct iscsi_session *session = conn->session;
-       struct iscsi_mgmt_task *mtask;
-
-       if (session->state == ISCSI_STATE_TERMINATE)
-               return NULL;
-
-       if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
-           hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
-               /*
-                * Login and Text are sent serially, in
-                * request-followed-by-response sequence.
-                * Same mtask can be used. Same ITT must be used.
-                * Note that login_mtask is preallocated at conn_create().
-                */
-               mtask = conn->login_mtask;
-       else {
-               BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
-               BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-               if (!__kfifo_get(session->mgmtpool.queue,
-                                (void*)&mtask, sizeof(void*)))
-                       return NULL;
-       }
-
-       if (data_size) {
-               memcpy(mtask->data, data, data_size);
-               mtask->data_count = data_size;
-       } else
-               mtask->data_count = 0;
-
-       INIT_LIST_HEAD(&mtask->running);
-       memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
-       __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
-       return mtask;
-}
-
-int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
-                       char *data, uint32_t data_size)
-{
-       struct iscsi_conn *conn = cls_conn->dd_data;
-       struct iscsi_session *session = conn->session;
-       int err = 0;
-
-       spin_lock_bh(&session->lock);
-       if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
-               err = -EPERM;
-       spin_unlock_bh(&session->lock);
-       scsi_queue_work(session->host, &conn->xmitwork);
-       return err;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
-
 void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
 {
        struct iscsi_session *session = class_to_transport_session(cls_session);
-       struct iscsi_conn *conn = session->leadconn;
 
        spin_lock_bh(&session->lock);
        if (session->state != ISCSI_STATE_LOGGED_IN) {
                session->state = ISCSI_STATE_RECOVERY_FAILED;
-               if (conn)
-                       wake_up(&conn->ehwait);
+               if (session->leadconn)
+                       wake_up(&session->leadconn->ehwait);
        }
        spin_unlock_bh(&session->lock);
 }
@@ -971,30 +1129,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
        struct Scsi_Host *host = sc->device->host;
        struct iscsi_session *session = iscsi_hostdata(host->hostdata);
        struct iscsi_conn *conn = session->leadconn;
-       int fail_session = 0;
 
+       mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
        if (session->state == ISCSI_STATE_TERMINATE) {
 failed:
                debug_scsi("failing host reset: session terminated "
                           "[CID %d age %d]\n", conn->id, session->age);
                spin_unlock_bh(&session->lock);
+               mutex_unlock(&session->eh_mutex);
                return FAILED;
        }
 
-       if (sc->SCp.phase == session->age) {
-               debug_scsi("failing connection CID %d due to SCSI host reset\n",
-                          conn->id);
-               fail_session = 1;
-       }
        spin_unlock_bh(&session->lock);
-
+       mutex_unlock(&session->eh_mutex);
        /*
         * we drop the lock here but the leadconn cannot be destoyed while
         * we are in the scsi eh
         */
-       if (fail_session)
-               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+       iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 
        debug_scsi("iscsi_eh_host_reset wait for relogin\n");
        wait_event_interruptible(conn->ehwait,
@@ -1004,73 +1157,56 @@ failed:
        if (signal_pending(current))
                flush_signals(current);
 
+       mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
        if (session->state == ISCSI_STATE_LOGGED_IN)
                printk(KERN_INFO "iscsi: host reset succeeded\n");
        else
                goto failed;
        spin_unlock_bh(&session->lock);
-
+       mutex_unlock(&session->eh_mutex);
        return SUCCESS;
 }
 EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
 
-static void iscsi_tmabort_timedout(unsigned long data)
+static void iscsi_tmf_timedout(unsigned long data)
 {
-       struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data;
-       struct iscsi_conn *conn = ctask->conn;
+       struct iscsi_conn *conn = (struct iscsi_conn *)data;
        struct iscsi_session *session = conn->session;
 
        spin_lock(&session->lock);
-       if (conn->tmabort_state == TMABORT_INITIAL) {
-               conn->tmabort_state = TMABORT_TIMEDOUT;
-               debug_scsi("tmabort timedout [sc %p itt 0x%x]\n",
-                       ctask->sc, ctask->itt);
+       if (conn->tmf_state == TMF_QUEUED) {
+               conn->tmf_state = TMF_TIMEDOUT;
+               debug_scsi("tmf timedout\n");
                /* unblock eh_abort() */
                wake_up(&conn->ehwait);
        }
        spin_unlock(&session->lock);
 }
 
-static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
-                                struct iscsi_cmd_task *ctask)
+static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
+                                  struct iscsi_tm *hdr, int age,
+                                  int timeout)
 {
-       struct iscsi_conn *conn = ctask->conn;
        struct iscsi_session *session = conn->session;
-       struct iscsi_tm *hdr = &conn->tmhdr;
-
-       /*
-        * ctask timed out but session is OK requests must be serialized.
-        */
-       memset(hdr, 0, sizeof(struct iscsi_tm));
-       hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
-       hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
-       hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-       memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
-       hdr->rtt = ctask->hdr->itt;
-       hdr->refcmdsn = ctask->hdr->cmdsn;
+       struct iscsi_mgmt_task *mtask;
 
-       ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
-                                           NULL, 0);
-       if (!ctask->mtask) {
+       mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+                                     NULL, 0);
+       if (!mtask) {
                spin_unlock_bh(&session->lock);
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-               spin_lock_bh(&session->lock)
-               debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
+               spin_lock_bh(&session->lock);
+               debug_scsi("tmf exec failure\n");
                return -EPERM;
        }
-       ctask->state = ISCSI_TASK_ABORTING;
+       conn->tmfcmd_pdus_cnt++;
+       conn->tmf_timer.expires = timeout * HZ + jiffies;
+       conn->tmf_timer.function = iscsi_tmf_timedout;
+       conn->tmf_timer.data = (unsigned long)conn;
+       add_timer(&conn->tmf_timer);
+       debug_scsi("tmf set timeout\n");
 
-       debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
-
-       if (conn->tmabort_state == TMABORT_INITIAL) {
-               conn->tmfcmd_pdus_cnt++;
-               conn->tmabort_timer.expires = 20*HZ + jiffies;
-               conn->tmabort_timer.function = iscsi_tmabort_timedout;
-               conn->tmabort_timer.data = (unsigned long)ctask;
-               add_timer(&conn->tmabort_timer);
-               debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
-       }
        spin_unlock_bh(&session->lock);
        mutex_unlock(&session->eh_mutex);
        scsi_queue_work(session->host, &conn->xmitwork);
@@ -1078,113 +1214,197 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
        /*
         * block eh thread until:
         *
-        * 1) abort response
-        * 2) abort timeout
+        * 1) tmf response
+        * 2) tmf timeout
         * 3) session is terminated or restarted or userspace has
         * given up on recovery
         */
-       wait_event_interruptible(conn->ehwait,
-                                sc->SCp.phase != session->age ||
+       wait_event_interruptible(conn->ehwait, age != session->age ||
                                 session->state != ISCSI_STATE_LOGGED_IN ||
-                                conn->tmabort_state != TMABORT_INITIAL);
+                                conn->tmf_state != TMF_QUEUED);
        if (signal_pending(current))
                flush_signals(current);
-       del_timer_sync(&conn->tmabort_timer);
+       del_timer_sync(&conn->tmf_timer);
+
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
+       /* if the session drops it will clean up the mtask */
+       if (age != session->age ||
+           session->state != ISCSI_STATE_LOGGED_IN)
+               return -ENOTCONN;
        return 0;
 }
 
 /*
- * session lock must be held
+ * Fail commands. session lock held and recv side suspended and xmit
+ * thread flushed
  */
-static struct iscsi_mgmt_task *
-iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
 {
-       int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
-       struct iscsi_mgmt_task *task;
+       struct iscsi_cmd_task *ctask, *tmp;
 
-       debug_scsi("searching %d tasks\n", nr_tasks);
+       if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1))
+               conn->ctask = NULL;
 
-       for (i = 0; i < nr_tasks; i++) {
-               __kfifo_get(fifo, (void*)&task, sizeof(void*));
-               debug_scsi("check task %u\n", task->itt);
+       /* flush pending */
+       list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
+               if (lun == ctask->sc->device->lun || lun == -1) {
+                       debug_scsi("failing pending sc %p itt 0x%x\n",
+                                  ctask->sc, ctask->itt);
+                       fail_command(conn, ctask, DID_BUS_BUSY << 16);
+               }
+       }
 
-               if (task->itt == itt) {
-                       debug_scsi("matched task\n");
-                       return task;
+       list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) {
+               if (lun == ctask->sc->device->lun || lun == -1) {
+                       debug_scsi("failing requeued sc %p itt 0x%x\n",
+                                  ctask->sc, ctask->itt);
+                       fail_command(conn, ctask, DID_BUS_BUSY << 16);
                }
+       }
 
-               __kfifo_put(fifo, (void*)&task, sizeof(void*));
+       /* fail all other running */
+       list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
+               if (lun == ctask->sc->device->lun || lun == -1) {
+                       debug_scsi("failing in progress sc %p itt 0x%x\n",
+                                  ctask->sc, ctask->itt);
+                       fail_command(conn, ctask, DID_BUS_BUSY << 16);
+               }
        }
-       return NULL;
 }
 
-static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
+static void iscsi_suspend_tx(struct iscsi_conn *conn)
 {
-       struct iscsi_conn *conn = ctask->conn;
-       struct iscsi_session *session = conn->session;
-
-       if (!ctask->mtask)
-               return -EINVAL;
+       set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+       scsi_flush_work(conn->session->host);
+}
 
-       if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
-               list_del(&ctask->mtask->running);
-       __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
-                   sizeof(void*));
-       ctask->mtask = NULL;
-       return 0;
+static void iscsi_start_tx(struct iscsi_conn *conn)
+{
+       clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+       scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
-/*
- * session lock must be held
- */
-static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-                        int err)
+static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
 {
-       struct scsi_cmnd *sc;
+       struct iscsi_cls_session *cls_session;
+       struct iscsi_session *session;
+       struct iscsi_conn *conn;
+       enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
 
-       sc = ctask->sc;
-       if (!sc)
-               return;
+       cls_session = starget_to_session(scsi_target(scmd->device));
+       session = class_to_transport_session(cls_session);
 
-       if (ctask->state == ISCSI_TASK_PENDING)
+       debug_scsi("scsi cmd %p timedout\n", scmd);
+
+       spin_lock(&session->lock);
+       if (session->state != ISCSI_STATE_LOGGED_IN) {
                /*
-                * cmd never made it to the xmit thread, so we should not count
-                * the cmd in the sequencing
+                * We are probably in the middle of iscsi recovery so let
+                * that complete and handle the error.
                 */
-               conn->session->queued_cmdsn--;
-       else
-               conn->session->tt->cleanup_cmd_task(conn, ctask);
-       iscsi_ctask_mtask_cleanup(ctask);
+               rc = EH_RESET_TIMER;
+               goto done;
+       }
 
-       sc->result = err;
-       scsi_set_resid(sc, scsi_bufflen(sc));
-       if (conn->ctask == ctask)
-               conn->ctask = NULL;
-       /* release ref from queuecommand */
-       __iscsi_put_ctask(ctask);
+       conn = session->leadconn;
+       if (!conn) {
+               /* In the middle of shuting down */
+               rc = EH_RESET_TIMER;
+               goto done;
+       }
+
+       if (!conn->recv_timeout && !conn->ping_timeout)
+               goto done;
+       /*
+        * if the ping timedout then we are in the middle of cleaning up
+        * and can let the iscsi eh handle it
+        */
+       if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
+                           (conn->ping_timeout * HZ), jiffies))
+               rc = EH_RESET_TIMER;
+       /*
+        * if we are about to check the transport then give the command
+        * more time
+        */
+       if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
+                          jiffies))
+               rc = EH_RESET_TIMER;
+       /* if in the middle of checking the transport then give us more time */
+       if (conn->ping_mtask)
+               rc = EH_RESET_TIMER;
+done:
+       spin_unlock(&session->lock);
+       debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
+       return rc;
 }
 
-static void iscsi_suspend_tx(struct iscsi_conn *conn)
+static void iscsi_check_transport_timeouts(unsigned long data)
 {
-       set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-       scsi_flush_work(conn->session->host);
+       struct iscsi_conn *conn = (struct iscsi_conn *)data;
+       struct iscsi_session *session = conn->session;
+       unsigned long timeout, next_timeout = 0, last_recv;
+
+       spin_lock(&session->lock);
+       if (session->state != ISCSI_STATE_LOGGED_IN)
+               goto done;
+
+       timeout = conn->recv_timeout;
+       if (!timeout)
+               goto done;
+
+       timeout *= HZ;
+       last_recv = conn->last_recv;
+       if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
+                          jiffies)) {
+               printk(KERN_ERR "ping timeout of %d secs expired, "
+                      "last rx %lu, last ping %lu, now %lu\n",
+                      conn->ping_timeout, last_recv,
+                      conn->last_ping, jiffies);
+               spin_unlock(&session->lock);
+               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+               return;
+       }
+
+       if (time_before_eq(last_recv + timeout, jiffies)) {
+               if (time_before_eq(conn->last_ping, last_recv)) {
+                       /* send a ping to try to provoke some traffic */
+                       debug_scsi("Sending nopout as ping on conn %p\n", conn);
+                       iscsi_send_nopout(conn, NULL);
+               }
+               next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
+       } else {
+               next_timeout = last_recv + timeout;
+       }
+
+       if (next_timeout) {
+               debug_scsi("Setting next tmo %lu\n", next_timeout);
+               mod_timer(&conn->transport_timer, next_timeout);
+       }
+done:
+       spin_unlock(&session->lock);
 }
 
-static void iscsi_start_tx(struct iscsi_conn *conn)
+static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
+                                     struct iscsi_tm *hdr)
 {
-       clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-       scsi_queue_work(conn->session->host, &conn->xmitwork);
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+       hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
+       hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+       memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+       hdr->rtt = ctask->hdr->itt;
+       hdr->refcmdsn = ctask->hdr->cmdsn;
 }
 
 int iscsi_eh_abort(struct scsi_cmnd *sc)
 {
        struct Scsi_Host *host = sc->device->host;
        struct iscsi_session *session = iscsi_hostdata(host->hostdata);
-       struct iscsi_cmd_task *ctask;
        struct iscsi_conn *conn;
-       int rc;
+       struct iscsi_cmd_task *ctask;
+       struct iscsi_tm *hdr;
+       int rc, age;
 
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
@@ -1199,19 +1419,23 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                return SUCCESS;
        }
 
-       ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
-       conn = ctask->conn;
-
-       conn->eh_abort_cnt++;
-       debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
-
        /*
         * If we are not logged in or we have started a new session
         * then let the host reset code handle this
         */
-       if (session->state != ISCSI_STATE_LOGGED_IN ||
-           sc->SCp.phase != session->age)
-               goto failed;
+       if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
+           sc->SCp.phase != session->age) {
+               spin_unlock_bh(&session->lock);
+               mutex_unlock(&session->eh_mutex);
+               return FAILED;
+       }
+
+       conn = session->leadconn;
+       conn->eh_abort_cnt++;
+       age = session->age;
+
+       ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+       debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
 
        /* ctask completed before time out */
        if (!ctask->sc) {
@@ -1219,27 +1443,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                goto success;
        }
 
-       /* what should we do here ? */
-       if (conn->ctask == ctask) {
-               printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. "
-                      "Failing abort\n", sc, ctask->itt);
-               goto failed;
-       }
-
        if (ctask->state == ISCSI_TASK_PENDING) {
                fail_command(conn, ctask, DID_ABORT << 16);
                goto success;
        }
 
-       conn->tmabort_state = TMABORT_INITIAL;
-       rc = iscsi_exec_abort_task(sc, ctask);
-       if (rc || sc->SCp.phase != session->age ||
-           session->state != ISCSI_STATE_LOGGED_IN)
+       /* only have one tmf outstanding at a time */
+       if (conn->tmf_state != TMF_INITIAL)
+               goto failed;
+       conn->tmf_state = TMF_QUEUED;
+
+       hdr = &conn->tmhdr;
+       iscsi_prep_abort_task_pdu(ctask, hdr);
+
+       if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
+               rc = FAILED;
                goto failed;
-       iscsi_ctask_mtask_cleanup(ctask);
+       }
 
-       switch (conn->tmabort_state) {
-       case TMABORT_SUCCESS:
+       switch (conn->tmf_state) {
+       case TMF_SUCCESS:
                spin_unlock_bh(&session->lock);
                iscsi_suspend_tx(conn);
                /*
@@ -1248,22 +1471,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                write_lock_bh(conn->recv_lock);
                spin_lock(&session->lock);
                fail_command(conn, ctask, DID_ABORT << 16);
+               conn->tmf_state = TMF_INITIAL;
                spin_unlock(&session->lock);
                write_unlock_bh(conn->recv_lock);
                iscsi_start_tx(conn);
                goto success_unlocked;
-       case TMABORT_NOT_FOUND:
-               if (!ctask->sc) {
+       case TMF_TIMEDOUT:
+               spin_unlock_bh(&session->lock);
+               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+               goto failed_unlocked;
+       case TMF_NOT_FOUND:
+               if (!sc->SCp.ptr) {
+                       conn->tmf_state = TMF_INITIAL;
                        /* ctask completed before tmf abort response */
                        debug_scsi("sc completed while abort in progress\n");
                        goto success;
                }
                /* fall through */
        default:
-               /* timedout or failed */
-               spin_unlock_bh(&session->lock);
-               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-               goto failed_unlocked;
+               conn->tmf_state = TMF_INITIAL;
+               goto failed;
        }
 
 success:
@@ -1276,65 +1503,152 @@ success_unlocked:
 failed:
        spin_unlock_bh(&session->lock);
 failed_unlocked:
-       debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+       debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
+                   ctask ? ctask->itt : 0);
        mutex_unlock(&session->eh_mutex);
        return FAILED;
 }
 EXPORT_SYMBOL_GPL(iscsi_eh_abort);
 
+static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
+{
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+       hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
+       hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+       int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+       hdr->rtt = RESERVED_ITT;
+}
+
+int iscsi_eh_device_reset(struct scsi_cmnd *sc)
+{
+       struct Scsi_Host *host = sc->device->host;
+       struct iscsi_session *session = iscsi_hostdata(host->hostdata);
+       struct iscsi_conn *conn;
+       struct iscsi_tm *hdr;
+       int rc = FAILED;
+
+       debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
+
+       mutex_lock(&session->eh_mutex);
+       spin_lock_bh(&session->lock);
+       /*
+        * Just check if we are not logged in. We cannot check for
+        * the phase because the reset could come from a ioctl.
+        */
+       if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+               goto unlock;
+       conn = session->leadconn;
+
+       /* only have one tmf outstanding at a time */
+       if (conn->tmf_state != TMF_INITIAL)
+               goto unlock;
+       conn->tmf_state = TMF_QUEUED;
+
+       hdr = &conn->tmhdr;
+       iscsi_prep_lun_reset_pdu(sc, hdr);
+
+       if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
+                                   session->lu_reset_timeout)) {
+               rc = FAILED;
+               goto unlock;
+       }
+
+       switch (conn->tmf_state) {
+       case TMF_SUCCESS:
+               break;
+       case TMF_TIMEDOUT:
+               spin_unlock_bh(&session->lock);
+               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+               goto done;
+       default:
+               conn->tmf_state = TMF_INITIAL;
+               goto unlock;
+       }
+
+       rc = SUCCESS;
+       spin_unlock_bh(&session->lock);
+
+       iscsi_suspend_tx(conn);
+       /* need to grab the recv lock then session lock */
+       write_lock_bh(conn->recv_lock);
+       spin_lock(&session->lock);
+       fail_all_commands(conn, sc->device->lun);
+       conn->tmf_state = TMF_INITIAL;
+       spin_unlock(&session->lock);
+       write_unlock_bh(conn->recv_lock);
+
+       iscsi_start_tx(conn);
+       goto done;
+
+unlock:
+       spin_unlock_bh(&session->lock);
+done:
+       debug_scsi("iscsi_eh_device_reset %s\n",
+                 rc == SUCCESS ? "SUCCESS" : "FAILED");
+       mutex_unlock(&session->eh_mutex);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
+
+/*
+ * Pre-allocate a pool of @max items of @item_size. By default, the pool
+ * should be accessed via kfifo_{get,put} on q->queue.
+ * Optionally, the caller can obtain the array of object pointers
+ * by passing in a non-NULL @items pointer
+ */
 int
-iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
+iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
 {
-       int i;
+       int i, num_arrays = 1;
 
-       *items = kmalloc(max * sizeof(void*), GFP_KERNEL);
-       if (*items == NULL)
-               return -ENOMEM;
+       memset(q, 0, sizeof(*q));
 
        q->max = max;
-       q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL);
-       if (q->pool == NULL) {
-               kfree(*items);
-               return -ENOMEM;
-       }
+
+       /* If the user passed an items pointer, he wants a copy of
+        * the array. */
+       if (items)
+               num_arrays++;
+       q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
+       if (q->pool == NULL)
+               goto enomem;
 
        q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
                              GFP_KERNEL, NULL);
-       if (q->queue == ERR_PTR(-ENOMEM)) {
-               kfree(q->pool);
-               kfree(*items);
-               return -ENOMEM;
-       }
+       if (q->queue == ERR_PTR(-ENOMEM))
+               goto enomem;
 
        for (i = 0; i < max; i++) {
-               q->pool[i] = kmalloc(item_size, GFP_KERNEL);
+               q->pool[i] = kzalloc(item_size, GFP_KERNEL);
                if (q->pool[i] == NULL) {
-                       int j;
-
-                       for (j = 0; j < i; j++)
-                               kfree(q->pool[j]);
-
-                       kfifo_free(q->queue);
-                       kfree(q->pool);
-                       kfree(*items);
-                       return -ENOMEM;
+                       q->max = i;
+                       goto enomem;
                }
-               memset(q->pool[i], 0, item_size);
-               (*items)[i] = q->pool[i];
                __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
        }
+
+       if (items) {
+               *items = q->pool + max;
+               memcpy(*items, q->pool, max * sizeof(void *));
+       }
+
        return 0;
+
+enomem:
+       iscsi_pool_free(q);
+       return -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(iscsi_pool_init);
 
-void iscsi_pool_free(struct iscsi_queue *q, void **items)
+void iscsi_pool_free(struct iscsi_pool *q)
 {
        int i;
 
        for (i = 0; i < q->max; i++)
-               kfree(items[i]);
-       kfree(q->pool);
-       kfree(items);
+               kfree(q->pool[i]);
+       if (q->pool)
+               kfree(q->pool);
 }
 EXPORT_SYMBOL_GPL(iscsi_pool_free);
 
@@ -1387,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
                qdepth = ISCSI_DEF_CMD_PER_LUN;
        }
 
-       if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
+       if (!is_power_of_2(cmds_max) ||
            cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
                if (cmds_max != 0)
                        printk(KERN_ERR "iscsi: invalid can_queue of %d. "
@@ -1411,12 +1725,16 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
        shost->max_cmd_len = iscsit->max_cmd_len;
        shost->transportt = scsit;
        shost->transportt->create_work_queue = 1;
+       shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
        *hostno = shost->host_no;
 
        session = iscsi_hostdata(shost->hostdata);
        memset(session, 0, sizeof(struct iscsi_session));
        session->host = shost;
        session->state = ISCSI_STATE_FREE;
+       session->fast_abort = 1;
+       session->lu_reset_timeout = 15;
+       session->abort_timeout = 10;
        session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
        session->cmds_max = cmds_max;
        session->queued_cmdsn = session->cmdsn = initial_cmdsn;
@@ -1479,9 +1797,9 @@ module_put:
 cls_session_fail:
        scsi_remove_host(shost);
 add_host_fail:
-       iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
+       iscsi_pool_free(&session->mgmtpool);
 mgmtpool_alloc_fail:
-       iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+       iscsi_pool_free(&session->cmdpool);
 cmdpool_alloc_fail:
        scsi_host_put(shost);
        return NULL;
@@ -1501,11 +1819,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
        struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
        struct module *owner = cls_session->transport->owner;
 
-       iscsi_unblock_session(cls_session);
+       iscsi_remove_session(cls_session);
        scsi_remove_host(shost);
 
-       iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
-       iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+       iscsi_pool_free(&session->mgmtpool);
+       iscsi_pool_free(&session->cmdpool);
 
        kfree(session->password);
        kfree(session->password_in);
@@ -1516,7 +1834,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
        kfree(session->hwaddress);
        kfree(session->initiatorname);
 
-       iscsi_destroy_session(cls_session);
+       iscsi_free_session(cls_session);
        scsi_host_put(shost);
        module_put(owner);
 }
@@ -1546,17 +1864,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
        conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
        conn->id = conn_idx;
        conn->exp_statsn = 0;
-       conn->tmabort_state = TMABORT_INITIAL;
+       conn->tmf_state = TMF_INITIAL;
+
+       init_timer(&conn->transport_timer);
+       conn->transport_timer.data = (unsigned long)conn;
+       conn->transport_timer.function = iscsi_check_transport_timeouts;
+
        INIT_LIST_HEAD(&conn->run_list);
        INIT_LIST_HEAD(&conn->mgmt_run_list);
+       INIT_LIST_HEAD(&conn->mgmtqueue);
        INIT_LIST_HEAD(&conn->xmitqueue);
-
-       /* initialize general immediate & non-immediate PDU commands queue */
-       conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
-                                       GFP_KERNEL, NULL);
-       if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
-               goto mgmtqueue_alloc_fail;
-
+       INIT_LIST_HEAD(&conn->requeue);
        INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
        /* allocate login_mtask used for the login/text sequences */
@@ -1574,7 +1892,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
                goto login_mtask_data_alloc_fail;
        conn->login_mtask->data = conn->data = data;
 
-       init_timer(&conn->tmabort_timer);
+       init_timer(&conn->tmf_timer);
        init_waitqueue_head(&conn->ehwait);
 
        return cls_conn;
@@ -1583,8 +1901,6 @@ login_mtask_data_alloc_fail:
        __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
                    sizeof(void*));
 login_mtask_alloc_fail:
-       kfifo_free(conn->mgmtqueue);
-mgmtqueue_alloc_fail:
        iscsi_destroy_conn(cls_conn);
        return NULL;
 }
@@ -1603,8 +1919,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        struct iscsi_session *session = conn->session;
        unsigned long flags;
 
+       del_timer_sync(&conn->transport_timer);
+
        spin_lock_bh(&session->lock);
-       set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
        conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
        if (session->leadconn == conn) {
                /*
@@ -1637,7 +1954,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        }
 
        /* flush queued up work because we free the connection below */
-       scsi_flush_work(session->host);
+       iscsi_suspend_tx(conn);
 
        spin_lock_bh(&session->lock);
        kfree(conn->data);
@@ -1648,8 +1965,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
                session->leadconn = NULL;
        spin_unlock_bh(&session->lock);
 
-       kfifo_free(conn->mgmtqueue);
-
        iscsi_destroy_conn(cls_conn);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
@@ -1672,11 +1987,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
                return -EINVAL;
        }
 
+       if (conn->ping_timeout && !conn->recv_timeout) {
+               printk(KERN_ERR "iscsi: invalid recv timeout of zero "
+                     "Using 5 seconds\n.");
+               conn->recv_timeout = 5;
+       }
+
+       if (conn->recv_timeout && !conn->ping_timeout) {
+               printk(KERN_ERR "iscsi: invalid ping timeout of zero "
+                     "Using 5 seconds.\n");
+               conn->ping_timeout = 5;
+       }
+
        spin_lock_bh(&session->lock);
        conn->c_stage = ISCSI_CONN_STARTED;
        session->state = ISCSI_STATE_LOGGED_IN;
        session->queued_cmdsn = session->cmdsn;
 
+       conn->last_recv = jiffies;
+       conn->last_ping = jiffies;
+       if (conn->recv_timeout && conn->ping_timeout)
+               mod_timer(&conn->transport_timer,
+                         jiffies + (conn->recv_timeout * HZ));
+
        switch(conn->stop_stage) {
        case STOP_CONN_RECOVER:
                /*
@@ -1684,7 +2017,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
                 * commands after successful recovery
                 */
                conn->stop_stage = 0;
-               conn->tmabort_state = TMABORT_INITIAL;
+               conn->tmf_state = TMF_INITIAL;
                session->age++;
                spin_unlock_bh(&session->lock);
 
@@ -1709,55 +2042,27 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
        struct iscsi_mgmt_task *mtask, *tmp;
 
        /* handle pending */
-       while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
-               if (mtask == conn->login_mtask)
-                       continue;
+       list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
                debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
-               __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
-                           sizeof(void*));
+               iscsi_free_mgmt_task(conn, mtask);
        }
 
        /* handle running */
        list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
                debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
-               list_del(&mtask->running);
-
-               if (mtask == conn->login_mtask)
-                       continue;
-               __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
-                          sizeof(void*));
+               iscsi_free_mgmt_task(conn, mtask);
        }
 
        conn->mtask = NULL;
 }
 
-/* Fail commands. Mutex and session lock held and recv side suspended */
-static void fail_all_commands(struct iscsi_conn *conn)
-{
-       struct iscsi_cmd_task *ctask, *tmp;
-
-       /* flush pending */
-       list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
-               debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
-                          ctask->itt);
-               fail_command(conn, ctask, DID_BUS_BUSY << 16);
-       }
-
-       /* fail all other running */
-       list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
-               debug_scsi("failing in progress sc %p itt 0x%x\n",
-                          ctask->sc, ctask->itt);
-               fail_command(conn, ctask, DID_BUS_BUSY << 16);
-       }
-
-       conn->ctask = NULL;
-}
-
 static void iscsi_start_session_recovery(struct iscsi_session *session,
                                         struct iscsi_conn *conn, int flag)
 {
        int old_stop_stage;
 
+       del_timer_sync(&conn->transport_timer);
+
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
        if (conn->stop_stage == STOP_CONN_TERM) {
@@ -1818,7 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
         * flush queues.
         */
        spin_lock_bh(&session->lock);
-       fail_all_commands(conn);
+       fail_all_commands(conn, -1);
        flush_control_queues(session, conn);
        spin_unlock_bh(&session->lock);
        mutex_unlock(&session->eh_mutex);
@@ -1869,6 +2174,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
        uint32_t value;
 
        switch(param) {
+       case ISCSI_PARAM_FAST_ABORT:
+               sscanf(buf, "%d", &session->fast_abort);
+               break;
+       case ISCSI_PARAM_ABORT_TMO:
+               sscanf(buf, "%d", &session->abort_timeout);
+               break;
+       case ISCSI_PARAM_LU_RESET_TMO:
+               sscanf(buf, "%d", &session->lu_reset_timeout);
+               break;
+       case ISCSI_PARAM_PING_TMO:
+               sscanf(buf, "%d", &conn->ping_timeout);
+               break;
+       case ISCSI_PARAM_RECV_TMO:
+               sscanf(buf, "%d", &conn->recv_timeout);
+               break;
        case ISCSI_PARAM_MAX_RECV_DLENGTH:
                sscanf(buf, "%d", &conn->max_recv_dlength);
                break;
@@ -1983,6 +2303,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
        int len;
 
        switch(param) {
+       case ISCSI_PARAM_FAST_ABORT:
+               len = sprintf(buf, "%d\n", session->fast_abort);
+               break;
+       case ISCSI_PARAM_ABORT_TMO:
+               len = sprintf(buf, "%d\n", session->abort_timeout);
+               break;
+       case ISCSI_PARAM_LU_RESET_TMO:
+               len = sprintf(buf, "%d\n", session->lu_reset_timeout);
+               break;
        case ISCSI_PARAM_INITIAL_R2T_EN:
                len = sprintf(buf, "%d\n", session->initial_r2t_en);
                break;
@@ -2040,6 +2369,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
        int len;
 
        switch(param) {
+       case ISCSI_PARAM_PING_TMO:
+               len = sprintf(buf, "%u\n", conn->ping_timeout);
+               break;
+       case ISCSI_PARAM_RECV_TMO:
+               len = sprintf(buf, "%u\n", conn->recv_timeout);
+               break;
        case ISCSI_PARAM_MAX_RECV_DLENGTH:
                len = sprintf(buf, "%u\n", conn->max_recv_dlength);
                break;
index c01a40d321d43530b02e814b3cd335d7f0b54797..18f33cd54411c7cf2772fc57780d16f1b62be8aa 100644 (file)
@@ -38,6 +38,15 @@ config SCSI_SAS_ATA
                Builds in ATA support into libsas.  Will necessitate
                the loading of libata along with libsas.
 
+config SCSI_SAS_HOST_SMP
+       bool "Support for SMP interpretation for SAS hosts"
+       default y
+       depends on SCSI_SAS_LIBSAS
+       help
+               Allows sas hosts to receive SMP frames.  Selecting this
+               option builds an SMP interpreter into libsas.  Say
+               N here if you want to save the few kb this consumes.
+
 config SCSI_SAS_LIBSAS_DEBUG
        bool "Compile the SAS Domain Transport Attributes in debug mode"
        default y
index fd387b91856edf97c6a84b6106ab6329e4c599ab..1ad1323c60fa096966f982602b826cb749c601ad 100644 (file)
@@ -33,5 +33,7 @@ libsas-y +=  sas_init.o     \
                sas_dump.o     \
                sas_discover.o \
                sas_expander.o \
-               sas_scsi_host.o
+               sas_scsi_host.o \
+               sas_task.o
 libsas-$(CONFIG_SCSI_SAS_ATA) +=       sas_ata.o
+libsas-$(CONFIG_SCSI_SAS_HOST_SMP) +=  sas_host_smp.o
\ No newline at end of file
index 0829b55c64d23c90cf70b025a566447eed8635f0..0996f866f14c374bfa15ab69229af5cd14936d65 100644 (file)
@@ -158,8 +158,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
        struct Scsi_Host *host = sas_ha->core.shost;
        struct sas_internal *i = to_sas_internal(host->transportt);
        struct scatterlist *sg;
-       unsigned int num = 0;
        unsigned int xfer = 0;
+       unsigned int si;
 
        task = sas_alloc_task(GFP_ATOMIC);
        if (!task)
@@ -176,22 +176,20 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 
        ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
        task->uldd_task = qc;
-       if (is_atapi_taskfile(&qc->tf)) {
+       if (ata_is_atapi(qc->tf.protocol)) {
                memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
                task->total_xfer_len = qc->nbytes + qc->pad_len;
                task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
        } else {
-               ata_for_each_sg(sg, qc) {
-                       num++;
+               for_each_sg(qc->sg, sg, qc->n_elem, si)
                        xfer += sg->length;
-               }
 
                task->total_xfer_len = xfer;
-               task->num_scatter = num;
+               task->num_scatter = si;
        }
 
        task->data_dir = qc->dma_dir;
-       task->scatter = qc->__sg;
+       task->scatter = qc->sg;
        task->ata_task.retry_count = 1;
        task->task_state_flags = SAS_TASK_STATE_PENDING;
        qc->lldd_task = task;
@@ -200,7 +198,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
        case ATA_PROT_NCQ:
                task->ata_task.use_ncq = 1;
                /* fall through */
-       case ATA_PROT_ATAPI_DMA:
+       case ATAPI_PROT_DMA:
        case ATA_PROT_DMA:
                task->ata_task.dma_xfer = 1;
                break;
@@ -500,7 +498,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
                        goto ex_err;
                }
                wait_for_completion(&task->completion);
-               res = -ETASK;
+               res = -ECOMM;
                if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
                        int res2;
                        SAS_DPRINTK("task aborted, flags:0x%x\n",
index 5f3a0d7b18de9db796d4ada15df39d8ef29c1b61..31b9af224243d2e73c54bf2b4c8d19944eee0c30 100644 (file)
@@ -98,7 +98,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
                        dev->dev_type = SATA_PM;
                else
                        dev->dev_type = SATA_DEV;
-               dev->tproto = SATA_PROTO;
+               dev->tproto = SAS_PROTOCOL_SATA;
        } else {
                struct sas_identify_frame *id =
                        (struct sas_identify_frame *) dev->frame_rcvd;
index 8727436b222d340f269556d2b7054a31416700c6..aefd865a578862e3bf17b4a8d6a7f8a4a8aaffef 100644 (file)
@@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
                }
 
                wait_for_completion(&task->completion);
-               res = -ETASK;
+               res = -ECOMM;
                if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
                        SAS_DPRINTK("smp task timed out or aborted\n");
                        i->dft->lldd_abort_task(task);
@@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
                    task->task_status.stat == SAM_GOOD) {
                        res = 0;
                        break;
+               } if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                     task->task_status.stat == SAS_DATA_UNDERRUN) {
+                       /* no error, but return the number of bytes of
+                        * underrun */
+                       res = task->task_status.residual;
+                       break;
+               } if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                     task->task_status.stat == SAS_DATA_OVERRUN) {
+                       res = -EMSGSIZE;
+                       break;
                } else {
                        SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
                                    "status 0x%x\n", __FUNCTION__,
@@ -656,9 +666,9 @@ static struct domain_device *sas_ex_discover_end_dev(
        sas_ex_get_linkrate(parent, child, phy);
 
 #ifdef CONFIG_SCSI_SAS_ATA
-       if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
+       if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
                child->dev_type = SATA_DEV;
-               if (phy->attached_tproto & SAS_PROTO_STP)
+               if (phy->attached_tproto & SAS_PROTOCOL_STP)
                        child->tproto = phy->attached_tproto;
                if (phy->attached_sata_dev)
                        child->tproto |= SATA_DEV;
@@ -695,7 +705,7 @@ static struct domain_device *sas_ex_discover_end_dev(
                }
        } else
 #endif
-         if (phy->attached_tproto & SAS_PROTO_SSP) {
+         if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
                child->dev_type = SAS_END_DEV;
                rphy = sas_end_device_alloc(phy->port);
                /* FIXME: error handling */
@@ -1896,11 +1906,9 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        }
 
        /* no rphy means no smp target support (ie aic94xx host) */
-       if (!rphy) {
-               printk("%s: can we send a smp request to a host?\n",
-                      __FUNCTION__);
-               return -EINVAL;
-       }
+       if (!rphy)
+               return sas_smp_host_handler(shost, req, rsp);
+
        type = rphy->identify.device_type;
 
        if (type != SAS_EDGE_EXPANDER_DEVICE &&
@@ -1926,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
        ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
                               bio_data(rsp->bio), rsp->data_len);
+       if (ret > 0) {
+               /* positive number is the untransferred residual */
+               rsp->data_len = ret;
+               req->data_len = 0;
+               ret = 0;
+       } else if (ret == 0) {
+               rsp->data_len = 0;
+               req->data_len = 0;
+       }
 
        return ret;
 }
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
new file mode 100644 (file)
index 0000000..16f9312
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Serial Attached SCSI (SAS) Expander discovery and configuration
+ *
+ * Copyright (C) 2007 James E.J. Bottomley
+ *             <James.Bottomley@HansenPartnership.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; version 2 only.
+ */
+#include <linux/scatterlist.h>
+#include <linux/blkdev.h>
+
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data,
+                                 u8 phy_id)
+{
+       struct sas_phy *phy;
+       struct sas_rphy *rphy;
+
+       if (phy_id >= sas_ha->num_phys) {
+               resp_data[2] = SMP_RESP_NO_PHY;
+               return;
+       }
+       resp_data[2] = SMP_RESP_FUNC_ACC;
+
+       phy = sas_ha->sas_phy[phy_id]->phy;
+       resp_data[9] = phy_id;
+       resp_data[13] = phy->negotiated_linkrate;
+       memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE);
+       memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr,
+              SAS_ADDR_SIZE);
+       resp_data[40] = (phy->minimum_linkrate << 4) |
+               phy->minimum_linkrate_hw;
+       resp_data[41] = (phy->maximum_linkrate << 4) |
+               phy->maximum_linkrate_hw;
+
+       if (!sas_ha->sas_phy[phy_id]->port ||
+           !sas_ha->sas_phy[phy_id]->port->port_dev)
+               return;
+
+       rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
+       resp_data[12] = rphy->identify.device_type << 4;
+       resp_data[14] = rphy->identify.initiator_port_protocols;
+       resp_data[15] = rphy->identify.target_port_protocols;
+}
+
+static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data,
+                               u8 phy_id)
+{
+       struct sas_rphy *rphy;
+       struct dev_to_host_fis *fis;
+       int i;
+
+       if (phy_id >= sas_ha->num_phys) {
+               resp_data[2] = SMP_RESP_NO_PHY;
+               return;
+       }
+
+       resp_data[2] = SMP_RESP_PHY_NO_SATA;
+
+       if (!sas_ha->sas_phy[phy_id]->port)
+               return;
+
+       rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
+       fis = (struct dev_to_host_fis *)
+               sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd;
+       if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA)
+               return;
+
+       resp_data[2] = SMP_RESP_FUNC_ACC;
+       resp_data[9] = phy_id;
+       memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr,
+              SAS_ADDR_SIZE);
+
+       /* check to see if we have a valid d2h fis */
+       if (fis->fis_type != 0x34)
+               return;
+
+       /* the d2h fis is required by the standard to be in LE format */
+       for (i = 0; i < 20; i += 4) {
+               u8 *dst = resp_data + 24 + i, *src =
+                       &sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i];
+               dst[0] = src[3];
+               dst[1] = src[2];
+               dst[2] = src[1];
+               dst[3] = src[0];
+       }
+}
+
+static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
+                           u8 phy_op, enum sas_linkrate min,
+                           enum sas_linkrate max, u8 *resp_data)
+{
+       struct sas_internal *i =
+               to_sas_internal(sas_ha->core.shost->transportt);
+       struct sas_phy_linkrates rates;
+
+       if (phy_id >= sas_ha->num_phys) {
+               resp_data[2] = SMP_RESP_NO_PHY;
+               return;
+       }
+       switch (phy_op) {
+       case PHY_FUNC_NOP:
+       case PHY_FUNC_LINK_RESET:
+       case PHY_FUNC_HARD_RESET:
+       case PHY_FUNC_DISABLE:
+       case PHY_FUNC_CLEAR_ERROR_LOG:
+       case PHY_FUNC_CLEAR_AFFIL:
+       case PHY_FUNC_TX_SATA_PS_SIGNAL:
+               break;
+
+       default:
+               resp_data[2] = SMP_RESP_PHY_UNK_OP;
+               return;
+       }
+
+       rates.minimum_linkrate = min;
+       rates.maximum_linkrate = max;
+
+       if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
+               resp_data[2] = SMP_RESP_FUNC_FAILED;
+       else
+               resp_data[2] = SMP_RESP_FUNC_ACC;
+}
+
+int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
+                        struct request *rsp)
+{
+       u8 *req_data = NULL, *resp_data = NULL, *buf;
+       struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+       int error = -EINVAL, resp_data_len = rsp->data_len;
+
+       /* eight is the minimum size for request and response frames */
+       if (req->data_len < 8 || rsp->data_len < 8)
+               goto out;
+
+       if (bio_offset(req->bio) + req->data_len > PAGE_SIZE ||
+           bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) {
+               shost_printk(KERN_ERR, shost,
+                       "SMP request/response frame crosses page boundary");
+               goto out;
+       }
+
+       req_data = kzalloc(req->data_len, GFP_KERNEL);
+
+       /* make sure frame can always be built ... we copy
+        * back only the requested length */
+       resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL);
+
+       if (!req_data || !resp_data) {
+               error = -ENOMEM;
+               goto out;
+       }
+
+       local_irq_disable();
+       buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio);
+       memcpy(req_data, buf, req->data_len);
+       kunmap_atomic(buf - bio_offset(req->bio), KM_USER0);
+       local_irq_enable();
+
+       if (req_data[0] != SMP_REQUEST)
+               goto out;
+
+       /* always succeeds ... even if we can't process the request
+        * the result is in the response frame */
+       error = 0;
+
+       /* set up default don't know response */
+       resp_data[0] = SMP_RESPONSE;
+       resp_data[1] = req_data[1];
+       resp_data[2] = SMP_RESP_FUNC_UNK;
+
+       switch (req_data[1]) {
+       case SMP_REPORT_GENERAL:
+               req->data_len -= 8;
+               resp_data_len -= 32;
+               resp_data[2] = SMP_RESP_FUNC_ACC;
+               resp_data[9] = sas_ha->num_phys;
+               break;
+
+       case SMP_REPORT_MANUF_INFO:
+               req->data_len -= 8;
+               resp_data_len -= 64;
+               resp_data[2] = SMP_RESP_FUNC_ACC;
+               memcpy(resp_data + 12, shost->hostt->name,
+                      SAS_EXPANDER_VENDOR_ID_LEN);
+               memcpy(resp_data + 20, "libsas virt phy",
+                      SAS_EXPANDER_PRODUCT_ID_LEN);
+               break;
+
+       case SMP_READ_GPIO_REG:
+               /* FIXME: need GPIO support in the transport class */
+               break;
+
+       case SMP_DISCOVER:
+               req->data_len =- 16;
+               if (req->data_len < 0) {
+                       req->data_len = 0;
+                       error = -EINVAL;
+                       goto out;
+               }
+               resp_data_len -= 56;
+               sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
+               break;
+
+       case SMP_REPORT_PHY_ERR_LOG:
+               /* FIXME: could implement this with additional
+                * libsas callbacks providing the HW supports it */
+               break;
+
+       case SMP_REPORT_PHY_SATA:
+               req->data_len =- 16;
+               if (req->data_len < 0) {
+                       req->data_len = 0;
+                       error = -EINVAL;
+                       goto out;
+               }
+               resp_data_len -= 60;
+               sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
+               break;
+
+       case SMP_REPORT_ROUTE_INFO:
+               /* Can't implement; hosts have no routes */
+               break;
+
+       case SMP_WRITE_GPIO_REG:
+               /* FIXME: need GPIO support in the transport class */
+               break;
+
+       case SMP_CONF_ROUTE_INFO:
+               /* Can't implement; hosts have no routes */
+               break;
+
+       case SMP_PHY_CONTROL:
+               req->data_len =- 44;
+               if (req->data_len < 0) {
+                       req->data_len = 0;
+                       error = -EINVAL;
+                       goto out;
+               }
+               resp_data_len -= 8;
+               sas_phy_control(sas_ha, req_data[9], req_data[10],
+                               req_data[32] >> 4, req_data[33] >> 4,
+                               resp_data);
+               break;
+
+       case SMP_PHY_TEST_FUNCTION:
+               /* FIXME: should this be implemented? */
+               break;
+
+       default:
+               /* probably a 2.0 function */
+               break;
+       }
+
+       local_irq_disable();
+       buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio);
+       memcpy(buf, resp_data, rsp->data_len);
+       flush_kernel_dcache_page(bio_page(rsp->bio));
+       kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0);
+       local_irq_enable();
+       rsp->data_len = resp_data_len;
+
+ out:
+       kfree(req_data);
+       kfree(resp_data);
+       return error;
+}
index 2b8213b1832dae44a778a176063aee2286f626eb..b4f9368f116ac2002ac07741fd2f2ddc3b2ef33e 100644 (file)
@@ -45,7 +45,7 @@
 void sas_scsi_recover_host(struct Scsi_Host *shost);
 
 int sas_show_class(enum sas_class class, char *buf);
-int sas_show_proto(enum sas_proto proto, char *buf);
+int sas_show_proto(enum sas_protocol proto, char *buf);
 int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
 int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
 
@@ -80,6 +80,20 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
 
 void sas_hae_reset(struct work_struct *work);
 
+#ifdef CONFIG_SCSI_SAS_HOST_SMP
+extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
+                               struct request *rsp);
+#else
+static inline int sas_smp_host_handler(struct Scsi_Host *shost,
+                                      struct request *req,
+                                      struct request *rsp)
+{
+       shost_printk(KERN_ERR, shost,
+               "Cannot send SMP to a sas host (not enabled in CONFIG)\n");
+       return -EINVAL;
+}
+#endif
+
 static inline void sas_queue_event(int event, spinlock_t *lock,
                                   unsigned long *pending,
                                   struct work_struct *work,
index 7663841eb4cfe7af81a3ae186f332ffcf34531e4..f869fba8680721ed8365c0fed872fd4915ed7a84 100644 (file)
@@ -108,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task)
                        break;
                case SAM_CHECK_COND:
                        memcpy(sc->sense_buffer, ts->buf,
-                              max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+                              min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
                        stat = SAM_CHECK_COND;
                        break;
                default:
@@ -148,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
        if (!task)
                return NULL;
 
-       *(u32 *)cmd->sense_buffer = 0;
        task->uldd_task = cmd;
        ASSIGN_SAS_TASK(cmd, task);
 
@@ -200,6 +199,10 @@ int sas_queue_up(struct sas_task *task)
  */
 int sas_queuecommand(struct scsi_cmnd *cmd,
                     void (*scsi_done)(struct scsi_cmnd *))
+       __releases(host->host_lock)
+       __acquires(dev->sata_dev.ap->lock)
+       __releases(dev->sata_dev.ap->lock)
+       __acquires(host->host_lock)
 {
        int res = 0;
        struct domain_device *dev = cmd_to_domain_dev(cmd);
@@ -410,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev)
 }
 
 /* Find the sas_phy that's attached to this device */
-struct sas_phy *find_local_sas_phy(struct domain_device *dev)
+static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
 {
        struct domain_device *pdev = dev->parent;
        struct ex_phy *exphy = NULL;
@@ -464,7 +467,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
        res = sas_phy_reset(phy, 1);
        if (res)
                SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
-                           phy->dev.kobj.k_name,
+                           kobject_name(&phy->dev.kobj),
                            res);
        if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
                return SUCCESS;
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
new file mode 100644 (file)
index 0000000..594524d
--- /dev/null
@@ -0,0 +1,36 @@
+#include <linux/kernel.h>
+#include <scsi/sas.h>
+#include <scsi/libsas.h>
+
+/* fill task_status_struct based on SSP response frame */
+void sas_ssp_task_response(struct device *dev, struct sas_task *task,
+                          struct ssp_response_iu *iu)
+{
+       struct task_status_struct *tstat = &task->task_status;
+
+       tstat->resp = SAS_TASK_COMPLETE;
+
+       if (iu->datapres == 0)
+               tstat->stat = iu->status;
+       else if (iu->datapres == 1)
+               tstat->stat = iu->resp_data[3];
+       else if (iu->datapres == 2) {
+               tstat->stat = SAM_CHECK_COND;
+               tstat->buf_valid_size =
+                       min_t(int, SAS_STATUS_BUF_SIZE,
+                             be32_to_cpu(iu->sense_data_len));
+               memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
+
+               if (iu->status != SAM_CHECK_COND)
+                       dev_printk(KERN_WARNING, dev,
+                                  "dev %llx sent sense data, but "
+                                  "stat(%x) is not CHECK CONDITION\n",
+                                  SAS_ADDR(task->dev->sas_addr),
+                                  iu->status);
+       }
+       else
+               /* when datapres contains corrupt/unknown value... */
+               tstat->stat = SAM_CHECK_COND;
+}
+EXPORT_SYMBOL_GPL(sas_ssp_task_response);
+
index 2ad0a27dbaabf534718c67c7e9ef8ed5b93f70bb..5cff0204227dc8267ff6443cefa76eb248360f16 100644 (file)
@@ -192,18 +192,18 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
 
        if (dma_map) {
                iue = (struct iu_entry *) sc->SCp.ptr;
-               sg = sc->request_buffer;
+               sg = scsi_sglist(sc);
 
-               dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
-                       md->len, sc->use_sg);
+               dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
+                       md->len, scsi_sg_count(sc));
 
-               nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
+               nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
                                 DMA_BIDIRECTIONAL);
                if (!nsg) {
-                       printk("fail to map %p %d\n", iue, sc->use_sg);
+                       printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
                        return 0;
                }
-               len = min(sc->request_bufflen, md->len);
+               len = min(scsi_bufflen(sc), md->len);
        } else
                len = md->len;
 
@@ -229,10 +229,10 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
 
        if (dma_map || ext_desc) {
                iue = (struct iu_entry *) sc->SCp.ptr;
-               sg = sc->request_buffer;
+               sg = scsi_sglist(sc);
 
                dprintk("%p %u %u %d %d\n",
-                       iue, sc->request_bufflen, id->len,
+                       iue, scsi_bufflen(sc), id->len,
                        cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
        }
 
@@ -268,13 +268,14 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
 
 rdma:
        if (dma_map) {
-               nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
+               nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+                                DMA_BIDIRECTIONAL);
                if (!nsg) {
-                       eprintk("fail to map %p %d\n", iue, sc->use_sg);
+                       eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
                        err = -EIO;
                        goto free_mem;
                }
-               len = min(sc->request_bufflen, id->len);
+               len = min(scsi_bufflen(sc), id->len);
        } else
                len = id->len;
 
index ba3ecab9baf3857cca02ab670d059ad5ad877b6c..f26b9538affe232079d94cd4b9179815af441958 100644 (file)
@@ -29,7 +29,8 @@ struct lpfc_sli2_slim;
 #define LPFC_MAX_NS_RETRY      3       /* Number of retry attempts to contact
                                           the NameServer  before giving up. */
 #define LPFC_CMD_PER_LUN       3       /* max outstanding cmds per lun */
-#define LPFC_SG_SEG_CNT                64      /* sg element count per scsi cmnd */
+#define LPFC_DEFAULT_SG_SEG_CNT        64      /* sg element count per scsi cmnd */
+#define LPFC_MAX_SG_SEG_CNT    256     /* sg element count per scsi cmnd */
 #define LPFC_IOCB_LIST_CNT     2250    /* list of IOCBs for fast-path usage. */
 #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */
 
@@ -68,6 +69,7 @@ struct lpfc_dmabuf {
        struct list_head list;
        void *virt;             /* virtual address ptr */
        dma_addr_t phys;        /* mapped address */
+       uint32_t   buffer_tag;  /* used for tagged queue ring */
 };
 
 struct lpfc_dma_pool {
@@ -272,10 +274,16 @@ struct lpfc_vport {
 #define FC_ABORT_DISCOVERY      0x8000  /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000         /* NPort discovery active */
 #define FC_BYPASSED_MODE        0x20000         /* NPort is in bypassed mode */
-#define FC_RFF_NOT_SUPPORTED    0x40000         /* RFF_ID was rejected by switch */
 #define FC_VPORT_NEEDS_REG_VPI 0x80000  /* Needs to have its vpi registered */
 #define FC_RSCN_DEFERRED       0x100000 /* A deferred RSCN being processed */
 
+       uint32_t ct_flags;
+#define FC_CT_RFF_ID           0x1      /* RFF_ID accepted by switch */
+#define FC_CT_RNN_ID           0x2      /* RNN_ID accepted by switch */
+#define FC_CT_RSNN_NN          0x4      /* RSNN_NN accepted by switch */
+#define FC_CT_RSPN_ID          0x8      /* RSPN_ID accepted by switch */
+#define FC_CT_RFT_ID           0x10     /* RFT_ID accepted by switch */
+
        struct list_head fc_nodes;
 
        /* Keep counters for the number of entries in each list. */
@@ -344,6 +352,7 @@ struct lpfc_vport {
        uint32_t cfg_discovery_threads;
        uint32_t cfg_log_verbose;
        uint32_t cfg_max_luns;
+       uint32_t cfg_enable_da_id;
 
        uint32_t dev_loss_tmo_changed;
 
@@ -360,6 +369,7 @@ struct lpfc_vport {
 
 struct hbq_s {
        uint16_t entry_count;     /* Current number of HBQ slots */
+       uint16_t buffer_count;    /* Current number of buffers posted */
        uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
        uint32_t hbqPutIdx;       /* HBQ slot to use */
        uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
@@ -377,6 +387,11 @@ struct hbq_s {
 #define LPFC_ELS_HBQ   0
 #define LPFC_EXTRA_HBQ 1
 
+enum hba_temp_state {
+       HBA_NORMAL_TEMP,
+       HBA_OVER_TEMP
+};
+
 struct lpfc_hba {
        struct lpfc_sli sli;
        uint32_t sli_rev;               /* SLI2 or SLI3 */
@@ -457,7 +472,8 @@ struct lpfc_hba {
        uint64_t cfg_soft_wwnn;
        uint64_t cfg_soft_wwpn;
        uint32_t cfg_hba_queue_depth;
-
+       uint32_t cfg_enable_hba_reset;
+       uint32_t cfg_enable_hba_heartbeat;
 
        lpfc_vpd_t vpd;         /* vital product data */
 
@@ -544,8 +560,7 @@ struct lpfc_hba {
        struct list_head port_list;
        struct lpfc_vport *pport;       /* physical lpfc_vport pointer */
        uint16_t max_vpi;               /* Maximum virtual nports */
-#define LPFC_MAX_VPI 100               /* Max number of VPI supported */
-#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
+#define LPFC_MAX_VPI 0xFFFF            /* Max number of VPI supported */
        unsigned long *vpi_bmask;       /* vpi allocation table */
 
        /* Data structure used by fabric iocb scheduler */
@@ -563,16 +578,30 @@ struct lpfc_hba {
        struct dentry *hba_debugfs_root;
        atomic_t debugfs_vport_count;
        struct dentry *debug_hbqinfo;
-       struct dentry *debug_dumpslim;
+       struct dentry *debug_dumpHostSlim;
+       struct dentry *debug_dumpHBASlim;
        struct dentry *debug_slow_ring_trc;
        struct lpfc_debugfs_trc *slow_ring_trc;
        atomic_t slow_ring_trc_cnt;
 #endif
 
+       /* Used for deferred freeing of ELS data buffers */
+       struct list_head elsbuf;
+       int elsbuf_cnt;
+       int elsbuf_prev_cnt;
+
+       uint8_t temp_sensor_support;
        /* Fields used for heart beat. */
        unsigned long last_completion_time;
        struct timer_list hb_tmofunc;
        uint8_t hb_outstanding;
+       /*
+        * Following bit will be set for all buffer tags which are not
+        * associated with any HBQ.
+        */
+#define QUE_BUFTAG_BIT  (1<<31)
+       uint32_t buffer_tag_count;
+       enum hba_temp_state over_temp_state;
 };
 
 static inline struct Scsi_Host *
@@ -598,5 +627,15 @@ lpfc_is_link_up(struct lpfc_hba *phba)
                phba->link_state == LPFC_HBA_READY;
 }
 
-#define FC_REG_DUMP_EVENT      0x10    /* Register for Dump events */
+#define FC_REG_DUMP_EVENT              0x10    /* Register for Dump events */
+#define FC_REG_TEMPERATURE_EVENT       0x20    /* Register for temperature
+                                                  event */
 
+struct temp_event {
+       uint32_t event_type;
+       uint32_t event_code;
+       uint32_t data;
+};
+#define LPFC_CRIT_TEMP         0x1
+#define LPFC_THRESHOLD_TEMP    0x2
+#define LPFC_NORMAL_TEMP       0x3
index 80a11218b9bbe8ddafe5d44ce896ecd1115d9bc6..4bae4a2ed2f1e9218b627f279d513a847b5ce931 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #define LPFC_MIN_DEVLOSS_TMO 1
 #define LPFC_MAX_DEVLOSS_TMO 255
 
+#define LPFC_MAX_LINK_SPEED 8
+#define LPFC_LINK_SPEED_BITMAP 0x00000117
+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8"
+
 static void
 lpfc_jedec_to_ascii(int incr, char hdw[])
 {
@@ -85,6 +89,15 @@ lpfc_serialnum_show(struct class_device *cdev, char *buf)
        return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);
 }
 
+static ssize_t
+lpfc_temp_sensor_show(struct class_device *cdev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       struct lpfc_hba   *phba = vport->phba;
+       return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support);
+}
+
 static ssize_t
 lpfc_modeldesc_show(struct class_device *cdev, char *buf)
 {
@@ -178,12 +191,9 @@ lpfc_state_show(struct class_device *cdev, char *buf)
        case LPFC_LINK_UP:
        case LPFC_CLEAR_LA:
        case LPFC_HBA_READY:
-               len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n");
+               len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
 
                switch (vport->port_state) {
-                       len += snprintf(buf + len, PAGE_SIZE-len,
-                                       "initializing\n");
-                       break;
                case LPFC_LOCAL_CFG_LINK:
                        len += snprintf(buf + len, PAGE_SIZE-len,
                                        "Configuring Link\n");
@@ -252,8 +262,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
        int mbxstatus = MBXERR_ERROR;
 
        if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-           (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
-           (vport->port_state != LPFC_VPORT_READY))
+           (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
                return -EPERM;
 
        pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
@@ -305,12 +314,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
 
        psli = &phba->sli;
 
+       /* Wait a little for things to settle down, but not
+        * long enough for dev loss timeout to expire.
+        */
        for (i = 0; i < psli->num_rings; i++) {
                pring = &psli->ring[i];
-               /* The linkdown event takes 30 seconds to timeout. */
                while (pring->txcmplq_cnt) {
                        msleep(10);
-                       if (cnt++ > 3000) {
+                       if (cnt++ > 500) {  /* 5 secs */
                                lpfc_printf_log(phba,
                                        KERN_WARNING, LOG_INIT,
                                        "0466 Outstanding IO when "
@@ -336,6 +347,9 @@ lpfc_selective_reset(struct lpfc_hba *phba)
        struct completion online_compl;
        int status = 0;
 
+       if (!phba->cfg_enable_hba_reset)
+               return -EIO;
+
        status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
        if (status != 0)
@@ -409,6 +423,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
        struct completion online_compl;
        int status=0;
 
+       if (!phba->cfg_enable_hba_reset)
+               return -EACCES;
        init_completion(&online_compl);
 
        if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
@@ -908,6 +924,8 @@ static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL);
 static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
 static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
 static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
+static CLASS_DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show,
+                        NULL);
 
 
 static char *lpfc_soft_wwn_key = "C99G71SL8032A";
@@ -971,6 +989,14 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
        unsigned int i, j, cnt=count;
        u8 wwpn[8];
 
+       if (!phba->cfg_enable_hba_reset)
+               return -EACCES;
+       spin_lock_irq(&phba->hbalock);
+       if (phba->over_temp_state == HBA_OVER_TEMP) {
+               spin_unlock_irq(&phba->hbalock);
+               return -EACCES;
+       }
+       spin_unlock_irq(&phba->hbalock);
        /* count may include a LF at end of string */
        if (buf[cnt-1] == '\n')
                cnt--;
@@ -1102,7 +1128,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
                 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
                 " 3 - select SLI-3");
 
-LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
+int lpfc_enable_npiv = 0;
+module_param(lpfc_enable_npiv, int, 0);
+MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
+lpfc_param_show(enable_npiv);
+lpfc_param_init(enable_npiv, 0, 0, 1);
+static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
+                        lpfc_enable_npiv_show, NULL);
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1247,6 +1279,13 @@ static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
 LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
                       "Verbose logging bit-mask");
 
+/*
+# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters
+# objects that have been registered with the nameserver after login.
+*/
+LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1,
+                 "Deregister nameserver objects before LOGO");
+
 /*
 # lun_queue_depth:  This parameter is used to limit the number of outstanding
 # commands per FCP LUN. Value range is [1,128]. Default value is 30.
@@ -1369,7 +1408,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
 # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
 # Default value is 0.
 */
-LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
+static int
+lpfc_topology_set(struct lpfc_hba *phba, int val)
+{
+       int err;
+       uint32_t prev_val;
+       if (val >= 0 && val <= 6) {
+               prev_val = phba->cfg_topology;
+               phba->cfg_topology = val;
+               err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
+               if (err)
+                       phba->cfg_topology = prev_val;
+               return err;
+       }
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+               "%d:0467 lpfc_topology attribute cannot be set to %d, "
+               "allowed range is [0, 6]\n",
+               phba->brd_no, val);
+       return -EINVAL;
+}
+static int lpfc_topology = 0;
+module_param(lpfc_topology, int, 0);
+MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology");
+lpfc_param_show(topology)
+lpfc_param_init(topology, 0, 0, 6)
+lpfc_param_store(topology)
+static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
+               lpfc_topology_show, lpfc_topology_store);
 
 /*
 # lpfc_link_speed: Link speed selection for initializing the Fibre Channel
@@ -1381,7 +1446,59 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
 #       8  = 8 Gigabaud
 # Value range is [0,8]. Default value is 0.
 */
-LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
+static int
+lpfc_link_speed_set(struct lpfc_hba *phba, int val)
+{
+       int err;
+       uint32_t prev_val;
+
+       if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
+               ((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
+               ((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
+               ((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
+               ((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
+               return -EINVAL;
+
+       if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
+               && (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+               prev_val = phba->cfg_link_speed;
+               phba->cfg_link_speed = val;
+               err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
+               if (err)
+                       phba->cfg_link_speed = prev_val;
+               return err;
+       }
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+               "%d:0469 lpfc_link_speed attribute cannot be set to %d, "
+               "allowed range is [0, 8]\n",
+               phba->brd_no, val);
+       return -EINVAL;
+}
+
+static int lpfc_link_speed = 0;
+module_param(lpfc_link_speed, int, 0);
+MODULE_PARM_DESC(lpfc_link_speed, "Select link speed");
+lpfc_param_show(link_speed)
+static int
+lpfc_link_speed_init(struct lpfc_hba *phba, int val)
+{
+       if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
+               && (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+               phba->cfg_link_speed = val;
+               return 0;
+       }
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "0454 lpfc_link_speed attribute cannot "
+                       "be set to %d, allowed values are "
+                       "["LPFC_LINK_SPEED_STRING"]\n", val);
+       phba->cfg_link_speed = 0;
+       return -EINVAL;
+}
+
+lpfc_param_store(link_speed)
+static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
+               lpfc_link_speed_show, lpfc_link_speed_store);
 
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
@@ -1479,7 +1596,30 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
 */
 LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
 
+/*
+# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
+#       0  = HBA resets disabled
+#       1  = HBA resets enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
+
+/*
+# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
+#       0  = HBA Heartbeat disabled
+#       1  = HBA Heartbeat enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
 
+/*
+ * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count
+ * This value can be set to values between 64 and 256. The default value is
+ * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer
+ * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE).
+ */
+LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
+           LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
 
 struct class_device_attribute *lpfc_hba_attrs[] = {
        &class_device_attr_info,
@@ -1494,6 +1634,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
        &class_device_attr_state,
        &class_device_attr_num_discovered_ports,
        &class_device_attr_lpfc_drvr_version,
+       &class_device_attr_lpfc_temp_sensor,
        &class_device_attr_lpfc_log_verbose,
        &class_device_attr_lpfc_lun_queue_depth,
        &class_device_attr_lpfc_hba_queue_depth,
@@ -1530,6 +1671,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
        &class_device_attr_lpfc_soft_wwnn,
        &class_device_attr_lpfc_soft_wwpn,
        &class_device_attr_lpfc_soft_wwn_enable,
+       &class_device_attr_lpfc_enable_hba_reset,
+       &class_device_attr_lpfc_enable_hba_heartbeat,
+       &class_device_attr_lpfc_sg_seg_cnt,
        NULL,
 };
 
@@ -1552,6 +1696,7 @@ struct class_device_attribute *lpfc_vport_attrs[] = {
        &class_device_attr_lpfc_max_luns,
        &class_device_attr_nport_evt_cnt,
        &class_device_attr_npiv_info,
+       &class_device_attr_lpfc_enable_da_id,
        NULL,
 };
 
@@ -1727,13 +1872,18 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 
        spin_lock_irq(&phba->hbalock);
 
+       if (phba->over_temp_state == HBA_OVER_TEMP) {
+               sysfs_mbox_idle(phba);
+               spin_unlock_irq(&phba->hbalock);
+               return  -EACCES;
+       }
+
        if (off == 0 &&
            phba->sysfs_mbox.state  == SMBOX_WRITING &&
            phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
 
                switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
                        /* Offline only */
-               case MBX_WRITE_NV:
                case MBX_INIT_LINK:
                case MBX_DOWN_LINK:
                case MBX_CONFIG_LINK:
@@ -1744,9 +1894,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                case MBX_DUMP_CONTEXT:
                case MBX_RUN_DIAGS:
                case MBX_RESTART:
-               case MBX_FLASH_WR_ULA:
                case MBX_SET_MASK:
-               case MBX_SET_SLIM:
                case MBX_SET_DEBUG:
                        if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
                                printk(KERN_WARNING "mbox_read:Command 0x%x "
@@ -1756,6 +1904,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                                spin_unlock_irq(&phba->hbalock);
                                return -EPERM;
                        }
+               case MBX_WRITE_NV:
+               case MBX_WRITE_VPARMS:
                case MBX_LOAD_SM:
                case MBX_READ_NV:
                case MBX_READ_CONFIG:
@@ -1772,6 +1922,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                case MBX_LOAD_EXP_ROM:
                case MBX_BEACON:
                case MBX_DEL_LD_ENTRY:
+               case MBX_SET_VARIABLE:
+               case MBX_WRITE_WWN:
                        break;
                case MBX_READ_SPARM64:
                case MBX_READ_LA:
@@ -1793,6 +1945,17 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                        return -EPERM;
                }
 
+               /* If HBA encountered an error attention, allow only DUMP
+                * mailbox command until the HBA is restarted.
+                */
+               if ((phba->pport->stopped) &&
+                       (phba->sysfs_mbox.mbox->mb.mbxCommand
+                               != MBX_DUMP_MEMORY)) {
+                       sysfs_mbox_idle(phba);
+                       spin_unlock_irq(&phba->hbalock);
+                       return -EPERM;
+               }
+
                phba->sysfs_mbox.mbox->vport = vport;
 
                if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
@@ -1993,7 +2156,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
                                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                        break;
                }
-       }
+       } else
+               fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 
        spin_unlock_irq(shost->host_lock);
 }
@@ -2013,7 +2177,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
                node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
        else
                /* fabric is local port if there is no F/FL_Port */
-               node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
+               node_name = 0;
 
        spin_unlock_irq(shost->host_lock);
 
@@ -2337,8 +2501,6 @@ struct fc_function_template lpfc_transport_functions = {
        .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
        .terminate_rport_io = lpfc_terminate_rport_io,
 
-       .vport_create = lpfc_vport_create,
-       .vport_delete = lpfc_vport_delete,
        .dd_fcvport_size = sizeof(struct lpfc_vport *),
 };
 
@@ -2414,21 +2576,23 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
        lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
        lpfc_use_msi_init(phba, lpfc_use_msi);
+       lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
+       lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
        phba->cfg_poll = lpfc_poll;
        phba->cfg_soft_wwnn = 0L;
        phba->cfg_soft_wwpn = 0L;
-       /*
-        * The total number of segments is the configuration value plus 2
-        * since the IOCB need a command and response bde.
-        */
-       phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
+       lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
+       /* Also reinitialize the host templates with new values. */
+       lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+       lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
        /*
         * Since the sg_tablesize is module parameter, the sg_dma_buf_size
-        * used to create the sg_dma_buf_pool must be dynamically calculated
+        * used to create the sg_dma_buf_pool must be dynamically calculated.
+        * 2 segments are added since the IOCB needs a command and response bde.
         */
        phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
                        sizeof(struct fcp_rsp) +
-                       (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
+                       ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
        lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
        return;
 }
@@ -2448,5 +2612,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
        lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
        lpfc_max_luns_init(vport, lpfc_max_luns);
        lpfc_scan_down_init(vport, lpfc_scan_down);
+       lpfc_enable_da_id_init(vport, lpfc_enable_da_id);
        return;
 }
index a599e15107104071dd2315829923ea9311cb3bc1..50fcb7c930bcb5e6024ca1afc383dfea8111febc 100644 (file)
@@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
+
 void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
                 struct lpfc_dmabuf *mp);
@@ -43,9 +45,9 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
 struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
 void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
 int lpfc_linkdown(struct lpfc_hba *);
+void lpfc_port_link_failure(struct lpfc_vport *);
 void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
-void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -66,15 +68,15 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
 void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
 struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
 int  lpfc_nlp_put(struct lpfc_nodelist *);
+int  lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
 struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
 void lpfc_disc_list_loopmap(struct lpfc_vport *);
 void lpfc_disc_start(struct lpfc_vport *);
-void lpfc_disc_flush_list(struct lpfc_vport *);
 void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
+void lpfc_cleanup(struct lpfc_vport *);
 void lpfc_disc_timeout(unsigned long);
 
 struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
-struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
 
 void lpfc_worker_wake_up(struct lpfc_hba *);
 int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
@@ -82,17 +84,17 @@ int lpfc_do_work(void *);
 int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
                            uint32_t);
 
-void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
-                       struct lpfc_nodelist *);
 void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
 int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
                     struct serv_parm *, uint32_t);
 int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_more_plogi(struct lpfc_vport *);
+void lpfc_more_adisc(struct lpfc_vport *);
+void lpfc_end_rscn(struct lpfc_vport *);
 int lpfc_els_chk_latt(struct lpfc_vport *);
 int lpfc_els_abort_flogi(struct lpfc_hba *);
 int lpfc_initial_flogi(struct lpfc_vport *);
 int lpfc_initial_fdisc(struct lpfc_vport *);
-int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
 int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
@@ -112,7 +114,6 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
 void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
 void lpfc_els_retry_delay(unsigned long);
 void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
-void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
 void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
                          struct lpfc_iocbq *);
 int lpfc_els_handle_rscn(struct lpfc_vport *);
@@ -124,7 +125,6 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
 int lpfc_els_disc_plogi(struct lpfc_vport *);
 void lpfc_els_timeout(unsigned long);
 void lpfc_els_timeout_handler(struct lpfc_vport *);
-void lpfc_hb_timeout(unsigned long);
 void lpfc_hb_timeout_handler(struct lpfc_hba *);
 
 void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
@@ -142,7 +142,6 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
 int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
 void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
 int lpfc_online(struct lpfc_hba *);
-void lpfc_block_mgmt_io(struct lpfc_hba *);
 void lpfc_unblock_mgmt_io(struct lpfc_hba *);
 void lpfc_offline_prep(struct lpfc_hba *);
 void lpfc_offline(struct lpfc_hba *);
@@ -165,7 +164,6 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
 
 void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
        uint32_t , LPFC_MBOXQ_t *);
-struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
 struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
 void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
 
@@ -178,7 +176,6 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba);
 void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
 struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
 void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
-void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
 uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
 
 void lpfc_reset_barrier(struct lpfc_hba * phba);
@@ -204,11 +201,14 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
                                             struct lpfc_sli_ring *,
                                             dma_addr_t);
+
+uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
+struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
+                       struct lpfc_sli_ring *, uint32_t );
+
 int lpfc_sli_hbq_count(void);
-int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
 int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
 void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
-struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
 int lpfc_sli_hbq_size(void);
 int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
                               struct lpfc_iocbq *);
@@ -219,9 +219,6 @@ int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,
 void lpfc_mbox_timeout(unsigned long);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
 
-struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter,
-                                      void *);
-struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *);
 struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
 struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
                                         struct lpfc_name *);
@@ -260,6 +257,7 @@ extern struct scsi_host_template lpfc_vport_template;
 extern struct fc_function_template lpfc_transport_functions;
 extern struct fc_function_template lpfc_vport_transport_functions;
 extern int lpfc_sli_mode;
+extern int lpfc_enable_npiv;
 
 int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
 void lpfc_terminate_rport_io(struct fc_rport *);
@@ -281,11 +279,8 @@ extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
 extern struct lpfc_hbq_init *lpfc_hbq_defs[];
 
 /* Interface exported by fabric iocb scheduler */
-int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
-void lpfc_fabric_abort_vport(struct lpfc_vport *);
 void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
 void lpfc_fabric_abort_hba(struct lpfc_hba *);
-void lpfc_fabric_abort_flogi(struct lpfc_hba *);
 void lpfc_fabric_block_timeout(unsigned long);
 void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
 void lpfc_adjust_queue_depth(struct lpfc_hba *);
index c701e4d611a9a105e65566405047624900135d29..92441ce610ede4601dd113ee9175f7ef5ebc81e8 100644 (file)
@@ -19,7 +19,7 @@
  *******************************************************************/
 
 /*
- * Fibre Channel SCSI LAN Device Driver CT support
+ * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
  */
 
 #include <linux/blkdev.h>
 
 static char *lpfc_release_version = LPFC_DRIVER_VERSION;
 
-/*
- * lpfc_ct_unsol_event
- */
 static void
-lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-                    struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+                         struct lpfc_dmabuf *mp, uint32_t size)
 {
        if (!mp) {
-               printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
-                      "piocbq = %p, status = x%x, mp = %p, size = %d\n",
-                      __FUNCTION__, __LINE__,
-                      piocbq, piocbq->iocb.ulpStatus, mp, size);
+               lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                               "0146 Ignoring unsolicted CT No HBQ "
+                               "status = x%x\n",
+                               piocbq->iocb.ulpStatus);
        }
-
-       printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
-              "buffer = %p, size = %d, status = x%x\n",
-              __FUNCTION__, __LINE__,
-              piocbq, mp, size,
-              piocbq->iocb.ulpStatus);
-
+       lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                       "0145 Ignoring unsolicted CT HBQ Size:%d "
+                       "status = x%x\n",
+                       size, piocbq->iocb.ulpStatus);
 }
 
 static void
-lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-                         struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+                    struct lpfc_dmabuf *mp, uint32_t size)
 {
-       if (!mp) {
-               printk(KERN_ERR "%s (%d): Unsolited CT, no "
-                      "HBQ buffer, piocbq = %p, status = x%x\n",
-                      __FUNCTION__, __LINE__,
-                      piocbq, piocbq->iocb.ulpStatus);
-       } else {
-               lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
-               printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
-                      "piocbq = %p, buffer = %p, size = %d, "
-                      "status = x%x\n",
-                      __FUNCTION__, __LINE__,
-                      piocbq, mp, size, piocbq->iocb.ulpStatus);
-       }
+       lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
 }
 
 void
@@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        struct lpfc_iocbq *iocbq;
        dma_addr_t paddr;
        uint32_t size;
-       struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
-       struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
-
-       piocbq->context2 = NULL;
-       piocbq->context3 = NULL;
+       struct list_head head;
+       struct lpfc_dmabuf *bdeBuf;
 
        if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
                lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
@@ -122,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                /* Not enough posted buffers; Try posting more buffers */
                phba->fc_stat.NoRcvBuf++;
                if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
-                       lpfc_post_buffer(phba, pring, 0, 1);
+                       lpfc_post_buffer(phba, pring, 2, 1);
                return;
        }
 
@@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                return;
 
        if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-               list_for_each_entry(iocbq, &piocbq->list, list) {
+               INIT_LIST_HEAD(&head);
+               list_add_tail(&head, &piocbq->list);
+               list_for_each_entry(iocbq, &head, list) {
                        icmd = &iocbq->iocb;
-                       if (icmd->ulpBdeCount == 0) {
-                               printk(KERN_ERR "%s (%d): Unsolited CT, no "
-                                      "BDE, iocbq = %p, status = x%x\n",
-                                      __FUNCTION__, __LINE__,
-                                      iocbq, iocbq->iocb.ulpStatus);
+                       if (icmd->ulpBdeCount == 0)
                                continue;
-                       }
-
+                       bdeBuf = iocbq->context2;
+                       iocbq->context2 = NULL;
                        size  = icmd->un.cont64[0].tus.f.bdeSize;
-                       lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
-                       lpfc_in_buf_free(phba, bdeBuf1);
+                       lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
+                       lpfc_in_buf_free(phba, bdeBuf);
                        if (icmd->ulpBdeCount == 2) {
-                               lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
-                                                         size);
-                               lpfc_in_buf_free(phba, bdeBuf2);
+                               bdeBuf = iocbq->context3;
+                               iocbq->context3 = NULL;
+                               size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
+                               lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
+                                                    size);
+                               lpfc_in_buf_free(phba, bdeBuf);
                        }
                }
+               list_del(&head);
        } else {
                struct lpfc_iocbq  *next;
 
                list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
                        icmd = &iocbq->iocb;
-                       if (icmd->ulpBdeCount == 0) {
-                               printk(KERN_ERR "%s (%d): Unsolited CT, no "
-                                      "BDE, iocbq = %p, status = x%x\n",
-                                      __FUNCTION__, __LINE__,
-                                      iocbq, iocbq->iocb.ulpStatus);
-                               continue;
-                       }
-
+                       if (icmd->ulpBdeCount == 0)
+                               lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
                        for (i = 0; i < icmd->ulpBdeCount; i++) {
                                paddr = getPaddr(icmd->un.cont64[i].addrHigh,
                                                 icmd->un.cont64[i].addrLow);
@@ -176,6 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        }
                        list_del(&iocbq->list);
                        lpfc_sli_release_iocbq(phba, iocbq);
+                       lpfc_post_buffer(phba, pring, i, 1);
                }
        }
 }
@@ -203,7 +179,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
        struct lpfc_dmabuf *mp;
        int cnt, i = 0;
 
-       /* We get chucks of FCELSSIZE */
+       /* We get chunks of FCELSSIZE */
        cnt = size > FCELSSIZE ? FCELSSIZE: size;
 
        while (size) {
@@ -426,6 +402,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 
        lpfc_set_disctmo(vport);
        vport->num_disc_nodes = 0;
+       vport->fc_ns_retry = 0;
 
 
        list_add_tail(&head, &mp->list);
@@ -458,7 +435,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                            ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
                             vport->cfg_peer_port_login)) {
                                if ((vport->port_type != LPFC_NPIV_PORT) ||
-                                   (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
+                                   (!(vport->ct_flags & FC_CT_RFF_ID)) ||
                                    (!vport->cfg_restrict_login)) {
                                        ndlp = lpfc_setup_disc_node(vport, Did);
                                        if (ndlp) {
@@ -506,7 +483,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                                                Did, vport->fc_flag,
                                                vport->fc_rscn_id_cnt);
 
-                                               if (lpfc_ns_cmd(vport,
+                                               /* This NPortID was previously
+                                                * a FCP target, * Don't even
+                                                * bother to send GFF_ID.
+                                                */
+                                               ndlp = lpfc_findnode_did(vport,
+                                                       Did);
+                                               if (ndlp && (ndlp->nlp_type &
+                                                       NLP_FCP_TARGET))
+                                                       lpfc_setup_disc_node
+                                                               (vport, Did);
+                                               else if (lpfc_ns_cmd(vport,
                                                        SLI_CTNS_GFF_ID,
                                                        0, Did) == 0)
                                                        vport->num_disc_nodes++;
@@ -554,7 +541,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        struct lpfc_dmabuf *outp;
        struct lpfc_sli_ct_request *CTrsp;
        struct lpfc_nodelist *ndlp;
-       int rc;
+       int rc, retry;
 
        /* First save ndlp, before we overwrite it */
        ndlp = cmdiocb->context_un.ndlp;
@@ -574,7 +561,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (vport->load_flag & FC_UNLOADING)
                goto out;
 
-
        if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
                                 "0216 Link event during NS query\n");
@@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (irsp->ulpStatus) {
                /* Check for retry */
                if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
-                       if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
-                               (irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
+                       retry = 1;
+                       if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+                               switch (irsp->un.ulpWord[4]) {
+                               case IOERR_NO_RESOURCES:
+                                       /* We don't increment the retry
+                                        * count for this case.
+                                        */
+                                       break;
+                               case IOERR_LINK_DOWN:
+                               case IOERR_SLI_ABORTED:
+                               case IOERR_SLI_DOWN:
+                                       retry = 0;
+                                       break;
+                               default:
+                                       vport->fc_ns_retry++;
+                               }
+                       }
+                       else
                                vport->fc_ns_retry++;
-                       /* CT command is being retried */
-                       rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+
+                       if (retry) {
+                               /* CT command is being retried */
+                               rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
                                         vport->fc_ns_retry, 0);
-                       if (rc == 0)
-                               goto out;
+                               if (rc == 0) {
+                                       /* success */
+                                       goto out;
+                               }
+                       }
                }
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
                lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
        struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
        struct lpfc_sli_ct_request *CTrsp;
-       int did;
+       int did, rc, retry;
        uint8_t fbits;
        struct lpfc_nodelist *ndlp;
 
@@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
        }
        else {
+               /* Check for retry */
+               if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
+                       retry = 1;
+                       if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+                               switch (irsp->un.ulpWord[4]) {
+                               case IOERR_NO_RESOURCES:
+                                       /* We don't increment the retry
+                                        * count for this case.
+                                        */
+                                       break;
+                               case IOERR_LINK_DOWN:
+                               case IOERR_SLI_ABORTED:
+                               case IOERR_SLI_DOWN:
+                                       retry = 0;
+                                       break;
+                               default:
+                                       cmdiocb->retry++;
+                               }
+                       }
+                       else
+                               cmdiocb->retry++;
+
+                       if (retry) {
+                               /* CT command is being retried */
+                               rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
+                                        cmdiocb->retry, did);
+                               if (rc == 0) {
+                                       /* success */
+                                       lpfc_ct_free_iocb(phba, cmdiocb);
+                                       return;
+                               }
+                       }
+               }
                lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                                 "0267 NameServer GFF Rsp "
                                 "x%x Error (%d %d) Data: x%x x%x\n",
@@ -778,8 +818,8 @@ out:
 
 
 static void
-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-                       struct lpfc_iocbq *rspiocb)
+lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+            struct lpfc_iocbq *rspiocb)
 {
        struct lpfc_vport *vport = cmdiocb->vport;
        struct lpfc_dmabuf *inp;
@@ -809,7 +849,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        /* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                        "0209 RFT request completes, latt %d, "
+                        "0209 CT Request completes, latt %d, "
                         "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
                         latt, irsp->ulpStatus,
                         CTrsp->CommandResponse.bits.CmdRsp,
@@ -847,11 +887,45 @@ out:
        return;
 }
 
+static void
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                       struct lpfc_iocbq *rspiocb)
+{
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RFT_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+       return;
+}
+
 static void
 lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        struct lpfc_iocbq *rspiocb)
 {
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RNN_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
@@ -859,7 +933,20 @@ static void
 lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                         struct lpfc_iocbq *rspiocb)
 {
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RSPN_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
@@ -867,7 +954,32 @@ static void
 lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                         struct lpfc_iocbq *rspiocb)
 {
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RSNN_NN;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+       return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       /* even if it fails we will act as though it succeeded. */
+       vport->ct_flags = 0;
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
@@ -878,10 +990,17 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        IOCB_t *irsp = &rspiocb->iocb;
        struct lpfc_vport *vport = cmdiocb->vport;
 
-       if (irsp->ulpStatus != IOSTAT_SUCCESS)
-           vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
 
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RFF_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
@@ -1001,6 +1120,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RSNN_NN)
                bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+       else if (cmdcode == SLI_CTNS_DA_ID)
+               bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RFF_ID)
                bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
        else
@@ -1029,31 +1150,34 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
        case SLI_CTNS_GFF_ID:
                CtReq->CommandResponse.bits.CmdRsp =
                        be16_to_cpu(SLI_CTNS_GFF_ID);
-               CtReq->un.gff.PortId = be32_to_cpu(context);
+               CtReq->un.gff.PortId = cpu_to_be32(context);
                cmpl = lpfc_cmpl_ct_cmd_gff_id;
                break;
 
        case SLI_CTNS_RFT_ID:
+               vport->ct_flags &= ~FC_CT_RFT_ID;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RFT_ID);
-               CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
+               CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
                CtReq->un.rft.fcpReg = 1;
                cmpl = lpfc_cmpl_ct_cmd_rft_id;
                break;
 
        case SLI_CTNS_RNN_ID:
+               vport->ct_flags &= ~FC_CT_RNN_ID;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RNN_ID);
-               CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
+               CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
                memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
                       sizeof (struct lpfc_name));
                cmpl = lpfc_cmpl_ct_cmd_rnn_id;
                break;
 
        case SLI_CTNS_RSPN_ID:
+               vport->ct_flags &= ~FC_CT_RSPN_ID;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RSPN_ID);
-               CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
+               CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
                size = sizeof(CtReq->un.rspn.symbname);
                CtReq->un.rspn.len =
                        lpfc_vport_symbolic_port_name(vport,
@@ -1061,6 +1185,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                cmpl = lpfc_cmpl_ct_cmd_rspn_id;
                break;
        case SLI_CTNS_RSNN_NN:
+               vport->ct_flags &= ~FC_CT_RSNN_NN;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RSNN_NN);
                memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
@@ -1071,11 +1196,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                        CtReq->un.rsnn.symbname, size);
                cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
                break;
+       case SLI_CTNS_DA_ID:
+               /* Implement DA_ID Nameserver request */
+               CtReq->CommandResponse.bits.CmdRsp =
+                       be16_to_cpu(SLI_CTNS_DA_ID);
+               CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
+               cmpl = lpfc_cmpl_ct_cmd_da_id;
+               break;
        case SLI_CTNS_RFF_ID:
-               vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
+               vport->ct_flags &= ~FC_CT_RFF_ID;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RFF_ID);
-               CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
+               CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);;
                CtReq->un.rff.fbits = FC4_FEATURE_INIT;
                CtReq->un.rff.type_code = FC_FCP_DATA;
                cmpl = lpfc_cmpl_ct_cmd_rff_id;
index d6a98bc970ff7f81100f8cc112b7ae375d93e410..783d1eea13efdb4cfe01d9ca49429244b6d74912 100644 (file)
@@ -43,6 +43,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
+#include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
 
 #ifdef CONFIG_LPFC_DEBUG_FS
@@ -75,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
 
 /* This MUST be a power of 2 */
-static int lpfc_debugfs_max_disc_trc = 0;
+static int lpfc_debugfs_max_disc_trc;
 module_param(lpfc_debugfs_max_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
        "Set debugfs discovery trace depth");
 
 /* This MUST be a power of 2 */
-static int lpfc_debugfs_max_slow_ring_trc = 0;
+static int lpfc_debugfs_max_slow_ring_trc;
 module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
        "Set debugfs slow ring trace depth");
 
-static int lpfc_debugfs_mask_disc_trc = 0;
+int lpfc_debugfs_mask_disc_trc;
 module_param(lpfc_debugfs_mask_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
        "Set debugfs discovery trace mask");
@@ -100,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
 #define LPFC_NODELIST_SIZE 8192
 #define LPFC_NODELIST_ENTRY_SIZE 120
 
-/* dumpslim output buffer size */
-#define LPFC_DUMPSLIM_SIZE 4096
+/* dumpHBASlim output buffer size */
+#define LPFC_DUMPHBASLIM_SIZE 4096
+
+/* dumpHostSlim output buffer size */
+#define LPFC_DUMPHOSTSLIM_SIZE 4096
 
 /* hbqinfo output buffer size */
 #define LPFC_HBQINFO_SIZE 8192
@@ -243,16 +247,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
        raw_index = phba->hbq_get[i];
        getidx = le32_to_cpu(raw_index);
        len +=  snprintf(buf+len, size-len,
-               "entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
-               hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx,
-               hbqs->local_hbqGetIdx, getidx);
+               "entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
+               hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
+               hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
 
        hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
        for (j=0; j<hbqs->entry_count; j++) {
                len +=  snprintf(buf+len, size-len,
                        "%03d: %08x %04x %05x ", j,
-                       hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag);
-
+                       le32_to_cpu(hbqe->bde.addrLow),
+                       le32_to_cpu(hbqe->bde.tus.w),
+                       le32_to_cpu(hbqe->buffer_tag));
                i = 0;
                found = 0;
 
@@ -276,7 +281,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
                list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
                        hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
                        phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
-                       if (phys == hbqe->bde.addrLow) {
+                       if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
                                len +=  snprintf(buf+len, size-len,
                                        "Buf%d: %p %06x\n", i,
                                        hbq_buf->dbuf.virt, hbq_buf->tag);
@@ -297,18 +302,58 @@ skipit:
        return len;
 }
 
+static int lpfc_debugfs_last_hba_slim_off;
+
+static int
+lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
+{
+       int len = 0;
+       int i, off;
+       uint32_t *ptr;
+       char buffer[1024];
+
+       off = 0;
+       spin_lock_irq(&phba->hbalock);
+
+       len +=  snprintf(buf+len, size-len, "HBA SLIM\n");
+       lpfc_memcpy_from_slim(buffer,
+               ((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off,
+               1024);
+
+       ptr = (uint32_t *)&buffer[0];
+       off = lpfc_debugfs_last_hba_slim_off;
+
+       /* Set it up for the next time */
+       lpfc_debugfs_last_hba_slim_off += 1024;
+       if (lpfc_debugfs_last_hba_slim_off >= 4096)
+               lpfc_debugfs_last_hba_slim_off = 0;
+
+       i = 1024;
+       while (i > 0) {
+               len +=  snprintf(buf+len, size-len,
+               "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+               off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+               *(ptr+5), *(ptr+6), *(ptr+7));
+               ptr += 8;
+               i -= (8 * sizeof(uint32_t));
+               off += (8 * sizeof(uint32_t));
+       }
+
+       spin_unlock_irq(&phba->hbalock);
+       return len;
+}
+
 static int
-lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
+lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
 {
        int len = 0;
-       int cnt, i, off;
+       int i, off;
        uint32_t word0, word1, word2, word3;
        uint32_t *ptr;
        struct lpfc_pgp *pgpp;
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
 
-       cnt = LPFC_DUMPSLIM_SIZE;
        off = 0;
        spin_lock_irq(&phba->hbalock);
 
@@ -620,7 +665,34 @@ out:
 }
 
 static int
-lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
+lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
+{
+       struct lpfc_hba *phba = inode->i_private;
+       struct lpfc_debug *debug;
+       int rc = -ENOMEM;
+
+       debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+       if (!debug)
+               goto out;
+
+       /* Round to page boundry */
+       debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
+       if (!debug->buffer) {
+               kfree(debug);
+               goto out;
+       }
+
+       debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
+               LPFC_DUMPHBASLIM_SIZE);
+       file->private_data = debug;
+
+       rc = 0;
+out:
+       return rc;
+}
+
+static int
+lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
 {
        struct lpfc_hba *phba = inode->i_private;
        struct lpfc_debug *debug;
@@ -631,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
                goto out;
 
        /* Round to page boundry */
-       debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
+       debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
        if (!debug->buffer) {
                kfree(debug);
                goto out;
        }
 
-       debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
-               LPFC_DUMPSLIM_SIZE);
+       debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
+               LPFC_DUMPHOSTSLIM_SIZE);
        file->private_data = debug;
 
        rc = 0;
@@ -741,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = {
        .release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_dumpslim
-static struct file_operations lpfc_debugfs_op_dumpslim = {
+#undef lpfc_debugfs_op_dumpHBASlim
+static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpHBASlim_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHostSlim
+static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
        .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpslim_open,
+       .open =         lpfc_debugfs_dumpHostSlim_open,
        .llseek =       lpfc_debugfs_lseek,
        .read =         lpfc_debugfs_read,
        .release =      lpfc_debugfs_release,
@@ -812,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                        goto debug_failed;
                }
 
-               /* Setup dumpslim */
-               snprintf(name, sizeof(name), "dumpslim");
-               phba->debug_dumpslim =
+               /* Setup dumpHBASlim */
+               snprintf(name, sizeof(name), "dumpHBASlim");
+               phba->debug_dumpHBASlim =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                                phba->hba_debugfs_root,
+                                phba, &lpfc_debugfs_op_dumpHBASlim);
+               if (!phba->debug_dumpHBASlim) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                               "0409 Cannot create debugfs dumpHBASlim\n");
+                       goto debug_failed;
+               }
+
+               /* Setup dumpHostSlim */
+               snprintf(name, sizeof(name), "dumpHostSlim");
+               phba->debug_dumpHostSlim =
                        debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
                                 phba->hba_debugfs_root,
-                                phba, &lpfc_debugfs_op_dumpslim);
-               if (!phba->debug_dumpslim) {
+                                phba, &lpfc_debugfs_op_dumpHostSlim);
+               if (!phba->debug_dumpHostSlim) {
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-                               "0409 Cannot create debugfs dumpslim\n");
+                               "0409 Cannot create debugfs dumpHostSlim\n");
                        goto debug_failed;
                }
 
@@ -970,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                        debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
                        phba->debug_hbqinfo = NULL;
                }
-               if (phba->debug_dumpslim) {
-                       debugfs_remove(phba->debug_dumpslim); /* dumpslim */
-                       phba->debug_dumpslim = NULL;
+               if (phba->debug_dumpHBASlim) {
+                       debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
+                       phba->debug_dumpHBASlim = NULL;
+               }
+               if (phba->debug_dumpHostSlim) {
+                       debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
+                       phba->debug_dumpHostSlim = NULL;
                }
                if (phba->slow_ring_trc) {
                        kfree(phba->slow_ring_trc);
index aacac9ac538190a6e42afd29562d737d8664ed1e..cfe81c50529a502c9befdcb2104d235c9e78c42a 100644 (file)
@@ -36,7 +36,6 @@ enum lpfc_work_type {
        LPFC_EVT_WARM_START,
        LPFC_EVT_KILL,
        LPFC_EVT_ELS_RETRY,
-       LPFC_EVT_DEV_LOSS_DELAY,
        LPFC_EVT_DEV_LOSS,
 };
 
@@ -92,6 +91,7 @@ struct lpfc_nodelist {
 #define NLP_LOGO_SND       0x100       /* sent LOGO request for this entry */
 #define NLP_RNID_SND       0x400       /* sent RNID request for this entry */
 #define NLP_ELS_SND_MASK   0x7e0       /* sent ELS request for this entry */
+#define NLP_DEFER_RM       0x10000     /* Remove this ndlp if no longer used */
 #define NLP_DELAY_TMO      0x20000     /* delay timeout is running for node */
 #define NLP_NPR_2B_DISC    0x40000     /* node is included in num_disc_nodes */
 #define NLP_RCV_PLOGI      0x80000     /* Rcv'ed PLOGI from remote system */
index 8085900635d4876fd100b7930f41651af584abd1..c6b739dc6bc32c695e9721e32a5e4df79daa7900 100644 (file)
@@ -18,7 +18,7 @@
  * more details, a copy of which can be found in the file COPYING  *
  * included with this package.                                     *
  *******************************************************************/
-
+/* See Fibre Channel protocol T11 FC-LS for details */
 #include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
@@ -42,6 +42,14 @@ static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
                          struct lpfc_iocbq *);
 static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
                        struct lpfc_iocbq *);
+static void lpfc_fabric_abort_vport(struct lpfc_vport *vport);
+static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
+                               struct lpfc_nodelist *ndlp, uint8_t retry);
+static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
+                                 struct lpfc_iocbq *iocb);
+static void lpfc_register_new_vport(struct lpfc_hba *phba,
+                                   struct lpfc_vport *vport,
+                                   struct lpfc_nodelist *ndlp);
 
 static int lpfc_max_els_tries = 3;
 
@@ -109,14 +117,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 
        /* fill in BDEs for command */
        /* Allocate buffer for command payload */
-       if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
-           ((pcmd->virt = lpfc_mbuf_alloc(phba,
-                                          MEM_PRI, &(pcmd->phys))) == 0)) {
-               kfree(pcmd);
-
-               lpfc_sli_release_iocbq(phba, elsiocb);
-               return NULL;
-       }
+       pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (pcmd)
+               pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
+       if (!pcmd || !pcmd->virt)
+               goto els_iocb_free_pcmb_exit;
 
        INIT_LIST_HEAD(&pcmd->list);
 
@@ -126,13 +131,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                if (prsp)
                        prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                                     &prsp->phys);
-               if (prsp == 0 || prsp->virt == 0) {
-                       kfree(prsp);
-                       lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
-                       kfree(pcmd);
-                       lpfc_sli_release_iocbq(phba, elsiocb);
-                       return NULL;
-               }
+               if (!prsp || !prsp->virt)
+                       goto els_iocb_free_prsp_exit;
                INIT_LIST_HEAD(&prsp->list);
        } else {
                prsp = NULL;
@@ -143,15 +143,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
        if (pbuflist)
                pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                                 &pbuflist->phys);
-       if (pbuflist == 0 || pbuflist->virt == 0) {
-               lpfc_sli_release_iocbq(phba, elsiocb);
-               lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
-               lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
-               kfree(pcmd);
-               kfree(prsp);
-               kfree(pbuflist);
-               return NULL;
-       }
+       if (!pbuflist || !pbuflist->virt)
+               goto els_iocb_free_pbuf_exit;
 
        INIT_LIST_HEAD(&pbuflist->list);
 
@@ -196,7 +189,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                bpl->tus.w = le32_to_cpu(bpl->tus.w);
        }
 
+       /* prevent preparing iocb with NULL ndlp reference */
        elsiocb->context1 = lpfc_nlp_get(ndlp);
+       if (!elsiocb->context1)
+               goto els_iocb_free_pbuf_exit;
        elsiocb->context2 = pcmd;
        elsiocb->context3 = pbuflist;
        elsiocb->retry = retry;
@@ -222,8 +218,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                                 cmdSize);
        }
        return elsiocb;
-}
 
+els_iocb_free_pbuf_exit:
+       lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
+       kfree(pbuflist);
+
+els_iocb_free_prsp_exit:
+       lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+       kfree(prsp);
+
+els_iocb_free_pcmb_exit:
+       kfree(pcmd);
+       lpfc_sli_release_iocbq(phba, elsiocb);
+       return NULL;
+}
 
 static int
 lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
@@ -234,40 +242,53 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
        struct lpfc_nodelist *ndlp;
        struct serv_parm *sp;
        int rc;
+       int err = 0;
 
        sp = &phba->fc_fabparam;
        ndlp = lpfc_findnode_did(vport, Fabric_DID);
-       if (!ndlp)
+       if (!ndlp) {
+               err = 1;
                goto fail;
+       }
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mbox)
+       if (!mbox) {
+               err = 2;
                goto fail;
+       }
 
        vport->port_state = LPFC_FABRIC_CFG_LINK;
        lpfc_config_link(phba, mbox);
        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
        mbox->vport = vport;
 
-       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
-       if (rc == MBX_NOT_FINISHED)
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               err = 3;
                goto fail_free_mbox;
+       }
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mbox)
+       if (!mbox) {
+               err = 4;
                goto fail;
+       }
        rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
                            0);
-       if (rc)
+       if (rc) {
+               err = 5;
                goto fail_free_mbox;
+       }
 
        mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
        mbox->vport = vport;
        mbox->context2 = lpfc_nlp_get(ndlp);
 
-       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
-       if (rc == MBX_NOT_FINISHED)
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               err = 6;
                goto fail_issue_reg_login;
+       }
 
        return 0;
 
@@ -282,7 +303,7 @@ fail_free_mbox:
 fail:
        lpfc_vport_set_state(vport, FC_VPORT_FAILED);
        lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-               "0249 Cannot issue Register Fabric login\n");
+               "0249 Cannot issue Register Fabric login: Err %d\n", err);
        return -ENXIO;
 }
 
@@ -370,11 +391,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                }
                if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                        lpfc_mbx_unreg_vpi(vport);
+                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+                       spin_unlock_irq(shost->host_lock);
                }
        }
 
-       ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
 
        if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
@@ -429,8 +451,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox,
-                                        MBX_NOWAIT | MBX_STOP_IOCB);
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
                if (rc == MBX_NOT_FINISHED) {
                        mempool_free(mbox, phba->mbox_mem_pool);
                        goto fail;
@@ -463,6 +484,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                lpfc_nlp_put(ndlp);
        }
 
+       /* If we are pt2pt with another NPort, force NPIV off! */
+       phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
+
        spin_lock_irq(shost->host_lock);
        vport->fc_flag |= FC_PT2PT;
        spin_unlock_irq(shost->host_lock);
@@ -488,6 +512,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(vport)) {
+               /* One additional decrement on node reference count to
+                * trigger the release of the node
+                */
                lpfc_nlp_put(ndlp);
                goto out;
        }
@@ -562,8 +589,13 @@ flogifail:
 
                /* Start discovery */
                lpfc_disc_start(vport);
+       } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+                       ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
+                       (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
+                       (phba->link_state != LPFC_CLEAR_LA)) {
+               /* If FLOGI failed enable link interrupt. */
+               lpfc_issue_clear_la(phba, vport);
        }
-
 out:
        lpfc_els_free_iocb(phba, cmdiocb);
 }
@@ -685,6 +717,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
        struct lpfc_hba *phba = vport->phba;
        struct lpfc_nodelist *ndlp;
 
+       vport->port_state = LPFC_FLOGI;
+       lpfc_set_disctmo(vport);
+
        /* First look for the Fabric ndlp */
        ndlp = lpfc_findnode_did(vport, Fabric_DID);
        if (!ndlp) {
@@ -696,7 +731,11 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
        } else {
                lpfc_dequeue_node(vport, ndlp);
        }
+
        if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
+               /* This decrement of reference count to node shall kick off
+                * the release of the node.
+                */
                lpfc_nlp_put(ndlp);
        }
        return 1;
@@ -720,11 +759,16 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
                lpfc_dequeue_node(vport, ndlp);
        }
        if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
+               /* decrement node reference count to trigger the release of
+                * the node.
+                */
                lpfc_nlp_put(ndlp);
+               return 0;
        }
        return 1;
 }
-static void
+
+void
 lpfc_more_plogi(struct lpfc_vport *vport)
 {
        int sentplogi;
@@ -752,6 +796,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 {
        struct lpfc_vport    *vport = ndlp->vport;
        struct lpfc_nodelist *new_ndlp;
+       struct lpfc_rport_data *rdata;
+       struct fc_rport *rport;
        struct serv_parm *sp;
        uint8_t  name[sizeof(struct lpfc_name)];
        uint32_t rc;
@@ -788,11 +834,34 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
        lpfc_unreg_rpi(vport, new_ndlp);
        new_ndlp->nlp_DID = ndlp->nlp_DID;
        new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+
+       if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
+               new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+       ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+
        lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
 
        /* Move this back to NPR state */
-       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
+       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
+               /* The new_ndlp is replacing ndlp totally, so we need
+                * to put ndlp on UNUSED list and try to free it.
+                */
+
+               /* Fix up the rport accordingly */
+               rport =  ndlp->rport;
+               if (rport) {
+                       rdata = rport->dd_data;
+                       if (rdata->pnode == ndlp) {
+                               lpfc_nlp_put(ndlp);
+                               ndlp->rport = NULL;
+                               rdata->pnode = lpfc_nlp_get(new_ndlp);
+                               new_ndlp->rport = rport;
+                       }
+                       new_ndlp->nlp_type = ndlp->nlp_type;
+               }
+
                lpfc_drop_node(vport, ndlp);
+       }
        else {
                lpfc_unreg_rpi(vport, ndlp);
                ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
@@ -801,6 +870,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
        return new_ndlp;
 }
 
+void
+lpfc_end_rscn(struct lpfc_vport *vport)
+{
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+       if (vport->fc_flag & FC_RSCN_MODE) {
+               /*
+                * Check to see if more RSCNs came in while we were
+                * processing this one.
+                */
+               if (vport->fc_rscn_id_cnt ||
+                   (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+                       lpfc_els_handle_rscn(vport);
+               else {
+                       spin_lock_irq(shost->host_lock);
+                       vport->fc_flag &= ~FC_RSCN_MODE;
+                       spin_unlock_irq(shost->host_lock);
+               }
+       }
+}
+
 static void
 lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                    struct lpfc_iocbq *rspiocb)
@@ -871,13 +961,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        goto out;
                }
                /* PLOGI failed */
-               if (ndlp->nlp_DID == NameServer_DID) {
-                       lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-                       lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-                                        "0250 Nameserver login error: "
-                                        "0x%x / 0x%x\n",
-                                        irsp->ulpStatus, irsp->un.ulpWord[4]);
-               }
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
                if (lpfc_error_lost_link(irsp)) {
                        rc = NLP_STE_FREED_NODE;
@@ -905,20 +988,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        spin_unlock_irq(shost->host_lock);
 
                        lpfc_can_disctmo(vport);
-                       if (vport->fc_flag & FC_RSCN_MODE) {
-                               /*
-                                * Check to see if more RSCNs came in while
-                                * we were processing this one.
-                                */
-                               if ((vport->fc_rscn_id_cnt == 0) &&
-                                   (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
-                                       spin_lock_irq(shost->host_lock);
-                                       vport->fc_flag &= ~FC_RSCN_MODE;
-                                       spin_unlock_irq(shost->host_lock);
-                               } else {
-                                       lpfc_els_handle_rscn(vport);
-                               }
-                       }
+                       lpfc_end_rscn(vport);
                }
        }
 
@@ -933,6 +1003,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        struct lpfc_hba  *phba = vport->phba;
        struct serv_parm *sp;
        IOCB_t *icmd;
+       struct lpfc_nodelist *ndlp;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
@@ -943,8 +1014,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
+       ndlp = lpfc_findnode_did(vport, did);
+       /* If ndlp if not NULL, we will bump the reference count on it */
+
        cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
-       elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
+       elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
                                     ELS_CMD_PLOGI);
        if (!elsiocb)
                return 1;
@@ -1109,7 +1183,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        return 0;
 }
 
-static void
+void
 lpfc_more_adisc(struct lpfc_vport *vport)
 {
        int sentadisc;
@@ -1134,8 +1208,6 @@ lpfc_more_adisc(struct lpfc_vport *vport)
 static void
 lpfc_rscn_disc(struct lpfc_vport *vport)
 {
-       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
        lpfc_can_disctmo(vport);
 
        /* RSCN discovery */
@@ -1144,19 +1216,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
                if (lpfc_els_disc_plogi(vport))
                        return;
 
-       if (vport->fc_flag & FC_RSCN_MODE) {
-               /* Check to see if more RSCNs came in while we were
-                * processing this one.
-                */
-               if ((vport->fc_rscn_id_cnt == 0) &&
-                   (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
-                       spin_lock_irq(shost->host_lock);
-                       vport->fc_flag &= ~FC_RSCN_MODE;
-                       spin_unlock_irq(shost->host_lock);
-               } else {
-                       lpfc_els_handle_rscn(vport);
-               }
-       }
+       lpfc_end_rscn(vport);
 }
 
 static void
@@ -1413,6 +1473,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];
 
+       spin_lock_irq(shost->host_lock);
+       if (ndlp->nlp_flag & NLP_LOGO_SND) {
+               spin_unlock_irq(shost->host_lock);
+               return 0;
+       }
+       spin_unlock_irq(shost->host_lock);
+
        cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
        elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
                                     ndlp->nlp_DID, ELS_CMD_LOGO);
@@ -1499,6 +1566,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
                                     ndlp->nlp_DID, ELS_CMD_SCR);
 
        if (!elsiocb) {
+               /* This will trigger the release of the node just
+                * allocated
+                */
                lpfc_nlp_put(ndlp);
                return 1;
        }
@@ -1520,10 +1590,17 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        phba->fc_stat.elsXmitSCR++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+               /* The additional lpfc_nlp_put will cause the following
+                * lpfc_els_free_iocb routine to trigger the rlease of
+                * the node.
+                */
                lpfc_nlp_put(ndlp);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
+       /* This will cause the callback-function lpfc_cmpl_els_cmd to
+        * trigger the release of node.
+        */
        lpfc_nlp_put(ndlp);
        return 0;
 }
@@ -1555,6 +1632,9 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
                                     ndlp->nlp_DID, ELS_CMD_RNID);
        if (!elsiocb) {
+               /* This will trigger the release of the node just
+                * allocated
+                */
                lpfc_nlp_put(ndlp);
                return 1;
        }
@@ -1591,35 +1671,21 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        phba->fc_stat.elsXmitFARPR++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+               /* The additional lpfc_nlp_put will cause the following
+                * lpfc_els_free_iocb routine to trigger the release of
+                * the node.
+                */
                lpfc_nlp_put(ndlp);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
+       /* This will cause the callback-function lpfc_cmpl_els_cmd to
+        * trigger the release of the node.
+        */
        lpfc_nlp_put(ndlp);
        return 0;
 }
 
-static void
-lpfc_end_rscn(struct lpfc_vport *vport)
-{
-       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
-       if (vport->fc_flag & FC_RSCN_MODE) {
-               /*
-                * Check to see if more RSCNs came in while we were
-                * processing this one.
-                */
-               if (vport->fc_rscn_id_cnt ||
-                   (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
-                       lpfc_els_handle_rscn(vport);
-               else {
-                       spin_lock_irq(shost->host_lock);
-                       vport->fc_flag &= ~FC_RSCN_MODE;
-                       spin_unlock_irq(shost->host_lock);
-               }
-       }
-}
-
 void
 lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
 {
@@ -1675,7 +1741,10 @@ lpfc_els_retry_delay(unsigned long ptr)
                return;
        }
 
-       evtp->evt_arg1  = ndlp;
+       /* We need to hold the node by incrementing the reference
+        * count until the queued work is done
+        */
+       evtp->evt_arg1  = lpfc_nlp_get(ndlp);
        evtp->evt       = LPFC_EVT_ELS_RETRY;
        list_add_tail(&evtp->evt_listp, &phba->work_list);
        if (phba->work_wait)
@@ -1759,6 +1828,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        uint32_t *elscmd;
        struct ls_rjt stat;
        int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
+       int logerr = 0;
        uint32_t cmd = 0;
        uint32_t did;
 
@@ -1815,6 +1885,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        break;
 
                case IOERR_NO_RESOURCES:
+                       logerr = 1; /* HBA out of resources */
                        retry = 1;
                        if (cmdiocb->retry > 100)
                                delay = 100;
@@ -1843,6 +1914,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        case IOSTAT_NPORT_BSY:
        case IOSTAT_FABRIC_BSY:
+               logerr = 1; /* Fabric / Remote NPort out of resources */
                retry = 1;
                break;
 
@@ -1923,6 +1995,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (did == FDMI_DID)
                retry = 1;
 
+       if ((cmd == ELS_CMD_FLOGI) &&
+           (phba->fc_topology != TOPOLOGY_LOOP)) {
+               /* FLOGI retry policy */
+               retry = 1;
+               maxretry = 48;
+               if (cmdiocb->retry >= 32)
+                       delay = 1000;
+       }
+
        if ((++cmdiocb->retry) >= maxretry) {
                phba->fc_stat.elsRetryExceeded++;
                retry = 0;
@@ -2006,11 +2087,46 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
        }
        /* No retry ELS command <elsCmd> to remote NPORT <did> */
-       lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+       if (logerr) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                        "0137 No retry ELS command x%x to remote "
+                        "NPORT x%x: Out of Resources: Error:x%x/%x\n",
+                        cmd, did, irsp->ulpStatus,
+                        irsp->un.ulpWord[4]);
+       }
+       else {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "0108 No retry ELS command x%x to remote "
                         "NPORT x%x Retried:%d Error:x%x/%x\n",
                         cmd, did, cmdiocb->retry, irsp->ulpStatus,
                         irsp->un.ulpWord[4]);
+       }
+       return 0;
+}
+
+static int
+lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
+{
+       struct lpfc_dmabuf *buf_ptr;
+
+       /* Free the response before processing the command.  */
+       if (!list_empty(&buf_ptr1->list)) {
+               list_remove_head(&buf_ptr1->list, buf_ptr,
+                                struct lpfc_dmabuf,
+                                list);
+               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+               kfree(buf_ptr);
+       }
+       lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
+       kfree(buf_ptr1);
+       return 0;
+}
+
+static int
+lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
+{
+       lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+       kfree(buf_ptr);
        return 0;
 }
 
@@ -2018,30 +2134,63 @@ int
 lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 {
        struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
+       struct lpfc_nodelist *ndlp;
 
-       if (elsiocb->context1) {
-               lpfc_nlp_put(elsiocb->context1);
+       ndlp = (struct lpfc_nodelist *)elsiocb->context1;
+       if (ndlp) {
+               if (ndlp->nlp_flag & NLP_DEFER_RM) {
+                       lpfc_nlp_put(ndlp);
+
+                       /* If the ndlp is not being used by another discovery
+                        * thread, free it.
+                        */
+                       if (!lpfc_nlp_not_used(ndlp)) {
+                               /* If ndlp is being used by another discovery
+                                * thread, just clear NLP_DEFER_RM
+                                */
+                               ndlp->nlp_flag &= ~NLP_DEFER_RM;
+                       }
+               }
+               else
+                       lpfc_nlp_put(ndlp);
                elsiocb->context1 = NULL;
        }
        /* context2  = cmd,  context2->next = rsp, context3 = bpl */
        if (elsiocb->context2) {
-               buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
-               /* Free the response before processing the command.  */
-               if (!list_empty(&buf_ptr1->list)) {
-                       list_remove_head(&buf_ptr1->list, buf_ptr,
-                                        struct lpfc_dmabuf,
-                                        list);
-                       lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-                       kfree(buf_ptr);
+               if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) {
+                       /* Firmware could still be in progress of DMAing
+                        * payload, so don't free data buffer till after
+                        * a hbeat.
+                        */
+                       elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE;
+                       buf_ptr = elsiocb->context2;
+                       elsiocb->context2 = NULL;
+                       if (buf_ptr) {
+                               buf_ptr1 = NULL;
+                               spin_lock_irq(&phba->hbalock);
+                               if (!list_empty(&buf_ptr->list)) {
+                                       list_remove_head(&buf_ptr->list,
+                                               buf_ptr1, struct lpfc_dmabuf,
+                                               list);
+                                       INIT_LIST_HEAD(&buf_ptr1->list);
+                                       list_add_tail(&buf_ptr1->list,
+                                               &phba->elsbuf);
+                                       phba->elsbuf_cnt++;
+                               }
+                               INIT_LIST_HEAD(&buf_ptr->list);
+                               list_add_tail(&buf_ptr->list, &phba->elsbuf);
+                               phba->elsbuf_cnt++;
+                               spin_unlock_irq(&phba->hbalock);
+                       }
+               } else {
+                       buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
+                       lpfc_els_free_data(phba, buf_ptr1);
                }
-               lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-               kfree(buf_ptr1);
        }
 
        if (elsiocb->context3) {
                buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
-               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-               kfree(buf_ptr);
+               lpfc_els_free_bpl(phba, buf_ptr);
        }
        lpfc_sli_release_iocbq(phba, elsiocb);
        return 0;
@@ -2065,15 +2214,20 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                         "Data: x%x x%x x%x\n",
                         ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
                         ndlp->nlp_rpi);
-       switch (ndlp->nlp_state) {
-       case NLP_STE_UNUSED_NODE:       /* node is just allocated */
-               lpfc_drop_node(vport, ndlp);
-               break;
-       case NLP_STE_NPR_NODE:          /* NPort Recovery mode */
-               lpfc_unreg_rpi(vport, ndlp);
-               break;
-       default:
-               break;
+
+       if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+               /* NPort Recovery mode or node is just allocated */
+               if (!lpfc_nlp_not_used(ndlp)) {
+                       /* If the ndlp is being used by another discovery
+                        * thread, just unregister the RPI.
+                        */
+                       lpfc_unreg_rpi(vport, ndlp);
+               } else {
+                       /* Indicate the node has already released, should
+                        * not reference to it from within lpfc_els_free_iocb.
+                        */
+                       cmdiocb->context1 = NULL;
+               }
        }
        lpfc_els_free_iocb(phba, cmdiocb);
        return;
@@ -2089,7 +2243,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        mempool_free(pmb, phba->mbox_mem_pool);
-       lpfc_nlp_put(ndlp);
+       if (ndlp) {
+               lpfc_nlp_put(ndlp);
+               /* This is the end of the default RPI cleanup logic for this
+                * ndlp. If no other discovery threads are using this ndlp.
+                * we should free all resources associated with it.
+                */
+               lpfc_nlp_not_used(ndlp);
+       }
        return;
 }
 
@@ -2100,15 +2261,29 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
        struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
        struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
-       IOCB_t *irsp;
+       IOCB_t  *irsp;
+       uint8_t *pcmd;
        LPFC_MBOXQ_t *mbox = NULL;
        struct lpfc_dmabuf *mp = NULL;
+       uint32_t ls_rjt = 0;
 
        irsp = &rspiocb->iocb;
 
        if (cmdiocb->context_un.mbox)
                mbox = cmdiocb->context_un.mbox;
 
+       /* First determine if this is a LS_RJT cmpl. Note, this callback
+        * function can have cmdiocb->contest1 (ndlp) field set to NULL.
+        */
+       pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
+       if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
+               /* A LS_RJT associated with Default RPI cleanup has its own
+                * seperate code path.
+                */
+               if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
+                       ls_rjt = 1;
+       }
+
        /* Check to see if link went down during discovery */
        if (!ndlp || lpfc_els_chk_latt(vport)) {
                if (mbox) {
@@ -2119,6 +2294,15 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        }
                        mempool_free(mbox, phba->mbox_mem_pool);
                }
+               if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
+                       if (lpfc_nlp_not_used(ndlp)) {
+                               ndlp = NULL;
+                               /* Indicate the node has already released,
+                                * should not reference to it from within
+                                * the routine lpfc_els_free_iocb.
+                                */
+                               cmdiocb->context1 = NULL;
+                       }
                goto out;
        }
 
@@ -2150,20 +2334,39 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                lpfc_nlp_set_state(vport, ndlp,
                                           NLP_STE_REG_LOGIN_ISSUE);
                        }
-                       if (lpfc_sli_issue_mbox(phba, mbox,
-                                               (MBX_NOWAIT | MBX_STOP_IOCB))
+                       if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
                            != MBX_NOT_FINISHED) {
                                goto out;
                        }
-                       lpfc_nlp_put(ndlp);
-                       /* NOTE: we should have messages for unsuccessful
-                          reglogin */
+
+                       /* ELS rsp: Cannot issue reg_login for <NPortid> */
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                               "0138 ELS rsp: Cannot issue reg_login for x%x "
+                               "Data: x%x x%x x%x\n",
+                               ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+                               ndlp->nlp_rpi);
+
+                       if (lpfc_nlp_not_used(ndlp)) {
+                               ndlp = NULL;
+                               /* Indicate node has already been released,
+                                * should not reference to it from within
+                                * the routine lpfc_els_free_iocb.
+                                */
+                               cmdiocb->context1 = NULL;
+                       }
                } else {
                        /* Do not drop node for lpfc_els_abort'ed ELS cmds */
                        if (!lpfc_error_lost_link(irsp) &&
                            ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-                               lpfc_drop_node(vport, ndlp);
-                               ndlp = NULL;
+                               if (lpfc_nlp_not_used(ndlp)) {
+                                       ndlp = NULL;
+                                       /* Indicate node has already been
+                                        * released, should not reference
+                                        * to it from within the routine
+                                        * lpfc_els_free_iocb.
+                                        */
+                                       cmdiocb->context1 = NULL;
+                               }
                        }
                }
                mp = (struct lpfc_dmabuf *) mbox->context1;
@@ -2178,7 +2381,21 @@ out:
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
                spin_unlock_irq(shost->host_lock);
+
+               /* If the node is not being used by another discovery thread,
+                * and we are sending a reject, we are done with it.
+                * Release driver reference count here and free associated
+                * resources.
+                */
+               if (ls_rjt)
+                       if (lpfc_nlp_not_used(ndlp))
+                               /* Indicate node has already been released,
+                                * should not reference to it from within
+                                * the routine lpfc_els_free_iocb.
+                                */
+                               cmdiocb->context1 = NULL;
        }
+
        lpfc_els_free_iocb(phba, cmdiocb);
        return;
 }
@@ -2349,14 +2566,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
        rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
 
-       /* If the node is in the UNUSED state, and we are sending
-        * a reject, we are done with it.  Release driver reference
-        * count here.  The outstanding els will release its reference on
-        * completion and the node can be freed then.
-        */
-       if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-               lpfc_nlp_put(ndlp);
-
        if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
@@ -2642,7 +2851,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
                        }
                }
        }
-       if (sentplogi == 0) {
+       if (sentplogi) {
+               lpfc_set_disctmo(vport);
+       }
+       else {
                spin_lock_irq(shost->host_lock);
                vport->fc_flag &= ~FC_NLP_MORE;
                spin_unlock_irq(shost->host_lock);
@@ -2830,10 +3042,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                        "RCV RSCN defer:  did:x%x/ste:x%x flg:x%x",
                        ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
 
+               spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_RSCN_DEFERRED;
                if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
                    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
-                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_RSCN_MODE;
                        spin_unlock_irq(shost->host_lock);
                        if (rscn_cnt) {
@@ -2862,7 +3074,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                                         vport->fc_rscn_id_cnt, vport->fc_flag,
                                         vport->port_state);
                } else {
-                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_RSCN_DISCOVERY;
                        spin_unlock_irq(shost->host_lock);
                        /* ReDiscovery RSCN */
@@ -2877,7 +3088,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
                /* send RECOVERY event for ALL nodes that match RSCN payload */
                lpfc_rscn_recovery_check(vport);
+               spin_lock_irq(shost->host_lock);
                vport->fc_flag &= ~FC_RSCN_DEFERRED;
+               spin_unlock_irq(shost->host_lock);
                return 0;
        }
 
@@ -2929,6 +3142,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
 
        /* To process RSCN, first compare RSCN data with NameServer */
        vport->fc_ns_retry = 0;
+       vport->num_disc_nodes = 0;
+
        ndlp = lpfc_findnode_did(vport, NameServer_DID);
        if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                /* Good ndlp, issue CT Request to NameServer */
@@ -3022,8 +3237,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                        mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
                        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                        mbox->vport = vport;
-                       rc = lpfc_sli_issue_mbox
-                               (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
                        lpfc_set_loopback_flag(phba);
                        if (rc == MBX_NOT_FINISHED) {
                                mempool_free(mbox, phba->mbox_mem_pool);
@@ -3140,7 +3354,10 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
                                     lpfc_max_els_tries, ndlp,
                                     ndlp->nlp_DID, ELS_CMD_ACC);
+
+       /* Decrement the ndlp reference count from previous mbox command */
        lpfc_nlp_put(ndlp);
+
        if (!elsiocb)
                return;
 
@@ -3160,13 +3377,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                status |= 0x4;
 
        rps_rsp->rsvd1 = 0;
-       rps_rsp->portStatus = be16_to_cpu(status);
-       rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
-       rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
-       rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
-       rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
-       rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
-       rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
+       rps_rsp->portStatus = cpu_to_be16(status);
+       rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+       rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+       rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+       rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+       rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+       rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
        /* Xmit ELS RPS ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
                         "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
@@ -3223,11 +3440,13 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                        mbox->context2 = lpfc_nlp_get(ndlp);
                        mbox->vport = vport;
                        mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
-                       if (lpfc_sli_issue_mbox (phba, mbox,
-                           (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
+                       if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+                               != MBX_NOT_FINISHED)
                                /* Mbox completion will send ELS Response */
                                return 0;
-
+                       /* Decrement reference count used for the failed mbox
+                        * command.
+                        */
                        lpfc_nlp_put(ndlp);
                        mempool_free(mbox, phba->mbox_mem_pool);
                }
@@ -3461,6 +3680,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                                         * other NLP_FABRIC logins
                                         */
                                        lpfc_drop_node(vport, ndlp);
+
                                } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
                                        /* Fail outstanding I/O now since this
                                         * device is marked for PLOGI
@@ -3469,8 +3689,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                                }
                        }
 
-                       vport->port_state = LPFC_FLOGI;
-                       lpfc_set_disctmo(vport);
                        lpfc_initial_flogi(vport);
                        return 0;
                }
@@ -3711,6 +3929,7 @@ static void
 lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
 {
+       struct Scsi_Host  *shost;
        struct lpfc_nodelist *ndlp;
        struct ls_rjt stat;
        uint32_t *payload;
@@ -3750,11 +3969,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        goto dropit;
 
                lpfc_nlp_init(vport, ndlp, did);
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
                newnode = 1;
                if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
                        ndlp->nlp_type |= NLP_FABRIC;
                }
-               lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+       }
+       else {
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
+                       /* This is simular to the new node path */
+                       lpfc_nlp_get(ndlp);
+                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+                       newnode = 1;
+               }
        }
 
        phba->fc_stat.elsRcvFrame++;
@@ -3783,6 +4010,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        rjt_err = LSRJT_UNABLE_TPC;
                        break;
                }
+
+               shost = lpfc_shost_from_vport(vport);
+               spin_lock_irq(shost->host_lock);
+               ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
+               spin_unlock_irq(shost->host_lock);
+
                lpfc_disc_state_machine(vport, ndlp, elsiocb,
                                        NLP_EVT_RCV_PLOGI);
 
@@ -3795,7 +4028,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                phba->fc_stat.elsRcvFLOGI++;
                lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        case ELS_CMD_LOGO:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3825,7 +4058,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                phba->fc_stat.elsRcvRSCN++;
                lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        case ELS_CMD_ADISC:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3897,7 +4130,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                phba->fc_stat.elsRcvLIRR++;
                lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        case ELS_CMD_RPS:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3907,7 +4140,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                phba->fc_stat.elsRcvRPS++;
                lpfc_els_rcv_rps(vport, elsiocb, ndlp);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        case ELS_CMD_RPL:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3917,7 +4150,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                phba->fc_stat.elsRcvRPL++;
                lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        case ELS_CMD_RNID:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3927,7 +4160,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                phba->fc_stat.elsRcvRNID++;
                lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        default:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3942,7 +4175,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                 "0115 Unknown ELS command x%x "
                                 "received from NPORT x%x\n", cmd, did);
                if (newnode)
-                       lpfc_drop_node(vport, ndlp);
+                       lpfc_nlp_put(ndlp);
                break;
        }
 
@@ -3958,10 +4191,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return;
 
 dropit:
-       lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+       if (vport && !(vport->load_flag & FC_UNLOADING))
+               lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
                        "(%d):0111 Dropping received ELS cmd "
                        "Data: x%x x%x x%x\n",
-                       vport ? vport->vpi : 0xffff, icmd->ulpStatus,
+                       vport->vpi, icmd->ulpStatus,
                        icmd->un.ulpWord[4], icmd->ulpTimeout);
        phba->fc_stat.elsRcvDrop++;
 }
@@ -4114,8 +4348,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
        MAILBOX_t *mb = &pmb->mb;
 
+       spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
-       lpfc_nlp_put(ndlp);
+       spin_unlock_irq(shost->host_lock);
 
        if (mb->mbxStatus) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -4135,7 +4370,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                default:
                        /* Try to recover from this error */
                        lpfc_mbx_unreg_vpi(vport);
+                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+                       spin_unlock_irq(shost->host_lock);
                        lpfc_initial_fdisc(vport);
                        break;
                }
@@ -4146,14 +4383,21 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                else
                        lpfc_do_scr_ns_plogi(phba, vport);
        }
+
+       /* Now, we decrement the ndlp reference count held for this
+        * callback function
+        */
+       lpfc_nlp_put(ndlp);
+
        mempool_free(pmb, phba->mbox_mem_pool);
        return;
 }
 
-void
+static void
 lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
                        struct lpfc_nodelist *ndlp)
 {
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        LPFC_MBOXQ_t *mbox;
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -4162,25 +4406,31 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
                mbox->vport = vport;
                mbox->context2 = lpfc_nlp_get(ndlp);
                mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
-               if (lpfc_sli_issue_mbox(phba, mbox,
-                                       MBX_NOWAIT | MBX_STOP_IOCB)
+               if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
                    == MBX_NOT_FINISHED) {
+                       /* mailbox command not success, decrement ndlp
+                        * reference count for this command
+                        */
+                       lpfc_nlp_put(ndlp);
                        mempool_free(mbox, phba->mbox_mem_pool);
-                       vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
 
-                       lpfc_vport_set_state(vport, FC_VPORT_FAILED);
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
                                "0253 Register VPI: Can't send mbox\n");
+                       goto mbox_err_exit;
                }
        } else {
-               lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
                lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
                                 "0254 Register VPI: no memory\n");
-
-               vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
-               lpfc_nlp_put(ndlp);
+               goto mbox_err_exit;
        }
+       return;
+
+mbox_err_exit:
+       lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+       spin_lock_irq(shost->host_lock);
+       vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+       spin_unlock_irq(shost->host_lock);
+       return;
 }
 
 static void
@@ -4251,7 +4501,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                lpfc_unreg_rpi(vport, np);
                        }
                        lpfc_mbx_unreg_vpi(vport);
+                       spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+                       spin_unlock_irq(shost->host_lock);
                }
 
                if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
@@ -4259,14 +4511,15 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                else
                        lpfc_do_scr_ns_plogi(phba, vport);
 
-               lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
+               /* Unconditionaly kick off releasing fabric node for vports */
+               lpfc_nlp_put(ndlp);
        }
 
 out:
        lpfc_els_free_iocb(phba, cmdiocb);
 }
 
-int
+static int
 lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                     uint8_t retry)
 {
@@ -4539,7 +4792,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        }
 }
 
-int
+static int
 lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
 {
        unsigned long iflags;
@@ -4583,7 +4836,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
 }
 
 
-void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
+static void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
 {
        LIST_HEAD(completions);
        struct lpfc_hba  *phba = vport->phba;
@@ -4663,6 +4916,7 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
 }
 
 
+#if 0
 void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
 {
        LIST_HEAD(completions);
@@ -4693,5 +4947,6 @@ void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
                (piocb->iocb_cmpl) (phba, piocb, piocb);
        }
 }
+#endif  /*  0  */
 
 
index c81c2b3228d637c9047f56e5224e9014d182c281..dc042bd97baa62e3ebb2fcd09b322f85f921df2e 100644 (file)
@@ -57,6 +57,7 @@ static uint8_t lpfcAlpaArray[] = {
 };
 
 static void lpfc_disc_timeout_handler(struct lpfc_vport *);
+static void lpfc_disc_flush_list(struct lpfc_vport *vport);
 
 void
 lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -107,20 +108,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
        struct lpfc_nodelist * ndlp;
        struct lpfc_vport *vport;
        struct lpfc_hba   *phba;
-       struct completion devloss_compl;
        struct lpfc_work_evt *evtp;
+       int  put_node;
+       int  put_rport;
 
        rdata = rport->dd_data;
        ndlp = rdata->pnode;
-
-       if (!ndlp) {
-               if (rport->scsi_target_id != -1) {
-                       printk(KERN_ERR "Cannot find remote node"
-                               " for rport in dev_loss_tmo_callbk x%x\n",
-                               rport->port_id);
-               }
+       if (!ndlp)
                return;
-       }
 
        vport = ndlp->vport;
        phba  = vport->phba;
@@ -129,15 +124,35 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                "rport devlosscb: sid:x%x did:x%x flg:x%x",
                ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
 
-       init_completion(&devloss_compl);
+       /* Don't defer this if we are in the process of deleting the vport
+        * or unloading the driver. The unload will cleanup the node
+        * appropriately we just need to cleanup the ndlp rport info here.
+        */
+       if (vport->load_flag & FC_UNLOADING) {
+               put_node = rdata->pnode != NULL;
+               put_rport = ndlp->rport != NULL;
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
+               if (put_node)
+                       lpfc_nlp_put(ndlp);
+               if (put_rport)
+                       put_device(&rport->dev);
+               return;
+       }
+
+       if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+               return;
+
        evtp = &ndlp->dev_loss_evt;
 
        if (!list_empty(&evtp->evt_listp))
                return;
 
        spin_lock_irq(&phba->hbalock);
-       evtp->evt_arg1  = ndlp;
-       evtp->evt_arg2  = &devloss_compl;
+       /* We need to hold the node by incrementing the reference
+        * count until this queued work is done
+        */
+       evtp->evt_arg1  = lpfc_nlp_get(ndlp);
        evtp->evt       = LPFC_EVT_DEV_LOSS;
        list_add_tail(&evtp->evt_listp, &phba->work_list);
        if (phba->work_wait)
@@ -145,8 +160,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 
        spin_unlock_irq(&phba->hbalock);
 
-       wait_for_completion(&devloss_compl);
-
        return;
 }
 
@@ -154,7 +167,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
  * This function is called from the worker thread when dev_loss_tmo
  * expire.
  */
-void
+static void
 lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 {
        struct lpfc_rport_data *rdata;
@@ -162,6 +175,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
        struct lpfc_vport *vport;
        struct lpfc_hba   *phba;
        uint8_t *name;
+       int  put_node;
+       int  put_rport;
        int warn_on = 0;
 
        rport = ndlp->rport;
@@ -178,14 +193,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                "rport devlosstmo:did:x%x type:x%x id:x%x",
                ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
 
-       if (!(vport->load_flag & FC_UNLOADING) &&
-           ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+       /* Don't defer this if we are in the process of deleting the vport
+        * or unloading the driver. The unload will cleanup the node
+        * appropriately we just need to cleanup the ndlp rport info here.
+        */
+       if (vport->load_flag & FC_UNLOADING) {
+               if (ndlp->nlp_sid != NLP_NO_SID) {
+                       /* flush the target */
+                       lpfc_sli_abort_iocb(vport,
+                                       &phba->sli.ring[phba->sli.fcp_ring],
+                                       ndlp->nlp_sid, 0, LPFC_CTX_TGT);
+               }
+               put_node = rdata->pnode != NULL;
+               put_rport = ndlp->rport != NULL;
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
+               if (put_node)
+                       lpfc_nlp_put(ndlp);
+               if (put_rport)
+                       put_device(&rport->dev);
                return;
+       }
 
-       if (ndlp->nlp_type & NLP_FABRIC) {
-               int  put_node;
-               int  put_rport;
+       if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+               return;
 
+       if (ndlp->nlp_type & NLP_FABRIC) {
                /* We will clean up these Nodes in linkup */
                put_node = rdata->pnode != NULL;
                put_rport = ndlp->rport != NULL;
@@ -227,23 +260,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                                 ndlp->nlp_state, ndlp->nlp_rpi);
        }
 
+       put_node = rdata->pnode != NULL;
+       put_rport = ndlp->rport != NULL;
+       rdata->pnode = NULL;
+       ndlp->rport = NULL;
+       if (put_node)
+               lpfc_nlp_put(ndlp);
+       if (put_rport)
+               put_device(&rport->dev);
+
        if (!(vport->load_flag & FC_UNLOADING) &&
            !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
            !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
-           (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
+           (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) {
                lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
-       else {
-               int  put_node;
-               int  put_rport;
-
-               put_node = rdata->pnode != NULL;
-               put_rport = ndlp->rport != NULL;
-               rdata->pnode = NULL;
-               ndlp->rport = NULL;
-               if (put_node)
-                       lpfc_nlp_put(ndlp);
-               if (put_rport)
-                       put_device(&rport->dev);
        }
 }
 
@@ -260,7 +290,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
 {
        struct lpfc_work_evt  *evtp = NULL;
        struct lpfc_nodelist  *ndlp;
-       struct lpfc_vport     *vport;
        int free_evt;
 
        spin_lock_irq(&phba->hbalock);
@@ -270,35 +299,22 @@ lpfc_work_list_done(struct lpfc_hba *phba)
                spin_unlock_irq(&phba->hbalock);
                free_evt = 1;
                switch (evtp->evt) {
-               case LPFC_EVT_DEV_LOSS_DELAY:
-                       free_evt = 0; /* evt is part of ndlp */
-                       ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
-                       vport = ndlp->vport;
-                       if (!vport)
-                               break;
-
-                       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
-                               "rport devlossdly:did:x%x flg:x%x",
-                               ndlp->nlp_DID, ndlp->nlp_flag, 0);
-
-                       if (!(vport->load_flag & FC_UNLOADING) &&
-                           !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
-                           !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
-                               lpfc_disc_state_machine(vport, ndlp, NULL,
-                                       NLP_EVT_DEVICE_RM);
-                       }
-                       break;
                case LPFC_EVT_ELS_RETRY:
                        ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
                        lpfc_els_retry_delay_handler(ndlp);
                        free_evt = 0; /* evt is part of ndlp */
+                       /* decrement the node reference count held
+                        * for this queued work
+                        */
+                       lpfc_nlp_put(ndlp);
                        break;
                case LPFC_EVT_DEV_LOSS:
                        ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
-                       lpfc_nlp_get(ndlp);
                        lpfc_dev_loss_tmo_handler(ndlp);
                        free_evt = 0;
-                       complete((struct completion *)(evtp->evt_arg2));
+                       /* decrement the node reference count held for
+                        * this queued work
+                        */
                        lpfc_nlp_put(ndlp);
                        break;
                case LPFC_EVT_ONLINE:
@@ -373,7 +389,7 @@ lpfc_work_done(struct lpfc_hba *phba)
                lpfc_handle_latt(phba);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS; i++) {
+               for(i = 0; i <= phba->max_vpi; i++) {
                        /*
                         * We could have no vports in array if unloading, so if
                         * this happens then just use the pport
@@ -405,14 +421,14 @@ lpfc_work_done(struct lpfc_hba *phba)
                        vport->work_port_events &= ~work_port_events;
                        spin_unlock_irq(&vport->work_port_lock);
                }
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
 
        pring = &phba->sli.ring[LPFC_ELS_RING];
        status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
        status >>= (4*LPFC_ELS_RING);
        if ((status & HA_RXMASK)
                || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
-               if (pring->flag & LPFC_STOP_IOCB_MASK) {
+               if (pring->flag & LPFC_STOP_IOCB_EVENT) {
                        pring->flag |= LPFC_DEFERRED_RING_EVENT;
                } else {
                        lpfc_sli_handle_slow_ring_event(phba, pring,
@@ -544,6 +560,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
 void
 lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
 {
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        struct lpfc_hba  *phba = vport->phba;
        struct lpfc_nodelist *ndlp, *next_ndlp;
        int  rc;
@@ -552,7 +569,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
                if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
                        continue;
 
-               if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN)
+               if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
+                       ((vport->port_type == LPFC_NPIV_PORT) &&
+                       (ndlp->nlp_DID == NameServer_DID)))
                        lpfc_unreg_rpi(vport, ndlp);
 
                /* Leave Fabric nodes alone on link down */
@@ -565,14 +584,30 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
        }
        if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
                lpfc_mbx_unreg_vpi(vport);
+               spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+               spin_unlock_irq(shost->host_lock);
        }
 }
 
+void
+lpfc_port_link_failure(struct lpfc_vport *vport)
+{
+       /* Cleanup any outstanding RSCN activity */
+       lpfc_els_flush_rscn(vport);
+
+       /* Cleanup any outstanding ELS commands */
+       lpfc_els_flush_cmd(vport);
+
+       lpfc_cleanup_rpis(vport, 0);
+
+       /* Turn off discovery timer if its running */
+       lpfc_can_disctmo(vport);
+}
+
 static void
 lpfc_linkdown_port(struct lpfc_vport *vport)
 {
-       struct lpfc_nodelist *ndlp, *next_ndlp;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
        fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
@@ -581,21 +616,8 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
                "Link Down:       state:x%x rtry:x%x flg:x%x",
                vport->port_state, vport->fc_ns_retry, vport->fc_flag);
 
-       /* Cleanup any outstanding RSCN activity */
-       lpfc_els_flush_rscn(vport);
-
-       /* Cleanup any outstanding ELS commands */
-       lpfc_els_flush_cmd(vport);
+       lpfc_port_link_failure(vport);
 
-       lpfc_cleanup_rpis(vport, 0);
-
-       /* free any ndlp's on unused list */
-       list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-                       lpfc_drop_node(vport, ndlp);
-
-       /* Turn off discovery timer if its running */
-       lpfc_can_disctmo(vport);
 }
 
 int
@@ -618,18 +640,18 @@ lpfc_linkdown(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
                        /* Issue a LINK DOWN event to all nodes */
                        lpfc_linkdown_port(vports[i]);
                }
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
        /* Clean up any firmware default rpi's */
        mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mb) {
                lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
                mb->vport = vport;
                mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+               if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
                    == MBX_NOT_FINISHED) {
                        mempool_free(mb, phba->mbox_mem_pool);
                }
@@ -643,8 +665,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
                        lpfc_config_link(phba, mb);
                        mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                        mb->vport = vport;
-                       if (lpfc_sli_issue_mbox(phba, mb,
-                                               (MBX_NOWAIT | MBX_STOP_IOCB))
+                       if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
                            == MBX_NOT_FINISHED) {
                                mempool_free(mb, phba->mbox_mem_pool);
                        }
@@ -686,7 +707,6 @@ static void
 lpfc_linkup_port(struct lpfc_vport *vport)
 {
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-       struct lpfc_nodelist *ndlp, *next_ndlp;
        struct lpfc_hba  *phba = vport->phba;
 
        if ((vport->load_flag & FC_UNLOADING) != 0)
@@ -713,11 +733,6 @@ lpfc_linkup_port(struct lpfc_vport *vport)
        if (vport->fc_flag & FC_LBIT)
                lpfc_linkup_cleanup_nodes(vport);
 
-                               /* free any ndlp's in unused state */
-       list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
-                                nlp_listp)
-               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-                       lpfc_drop_node(vport, ndlp);
 }
 
 static int
@@ -734,9 +749,9 @@ lpfc_linkup(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
                        lpfc_linkup_port(vports[i]);
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
        if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
                lpfc_issue_clear_la(phba, phba->pport);
 
@@ -749,7 +764,7 @@ lpfc_linkup(struct lpfc_hba *phba)
  * as the completion routine when the command is
  * handed off to the SLI layer.
  */
-void
+static void
 lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
@@ -852,8 +867,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
         * LPFC_FLOGI while waiting for FLOGI cmpl
         */
        if (vport->port_state != LPFC_FLOGI) {
-               vport->port_state = LPFC_FLOGI;
-               lpfc_set_disctmo(vport);
                lpfc_initial_flogi(vport);
        }
        return;
@@ -1022,8 +1035,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                lpfc_read_sparam(phba, sparam_mbox, 0);
                sparam_mbox->vport = vport;
                sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
-               rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
-                                   (MBX_NOWAIT | MBX_STOP_IOCB));
+               rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
                if (rc == MBX_NOT_FINISHED) {
                        mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
                        lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -1040,8 +1052,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                lpfc_config_link(phba, cfglink_mbox);
                cfglink_mbox->vport = vport;
                cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
-               rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
-                                   (MBX_NOWAIT | MBX_STOP_IOCB));
+               rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
                if (rc != MBX_NOT_FINISHED)
                        return;
                mempool_free(cfglink_mbox, phba->mbox_mem_pool);
@@ -1174,6 +1185,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        mempool_free(pmb, phba->mbox_mem_pool);
+       /* decrement the node reference count held for this callback
+        * function.
+        */
        lpfc_nlp_put(ndlp);
 
        return;
@@ -1219,7 +1233,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
        lpfc_unreg_vpi(phba, vport->vpi, mbox);
        mbox->vport = vport;
        mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
-       rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
                                 "1800 Could not issue unreg_vpi\n");
@@ -1319,7 +1333,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                vports = lpfc_create_vport_work_array(phba);
                if (vports != NULL)
                        for(i = 0;
-                           i < LPFC_MAX_VPORTS && vports[i] != NULL;
+                           i <= phba->max_vpi && vports[i] != NULL;
                            i++) {
                                if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
                                        continue;
@@ -1335,7 +1349,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                                                        "Fabric support\n");
                                }
                        }
-               lpfc_destroy_vport_work_array(vports);
+               lpfc_destroy_vport_work_array(phba, vports);
                lpfc_do_scr_ns_plogi(phba, vport);
        }
 
@@ -1361,11 +1375,16 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
        if (mb->mbxStatus) {
 out:
+               /* decrement the node reference count held for this
+                * callback function.
+                */
                lpfc_nlp_put(ndlp);
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
                mempool_free(pmb, phba->mbox_mem_pool);
-               lpfc_drop_node(vport, ndlp);
+
+               /* If no other thread is using the ndlp, free it */
+               lpfc_nlp_not_used(ndlp);
 
                if (phba->fc_topology == TOPOLOGY_LOOP) {
                        /*
@@ -1410,6 +1429,9 @@ out:
                goto out;
        }
 
+       /* decrement the node reference count held for this
+        * callback function.
+        */
        lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -1656,8 +1678,18 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 void
 lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
+       /*
+        * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should
+        * be used if we wish to issue the "last" lpfc_nlp_put() to remove
+        * the ndlp from the vport. The ndlp marked as UNUSED on the list
+        * until ALL other outstanding threads have completed. We check
+        * that the ndlp not already in the UNUSED state before we proceed.
+        */
+       if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+               return;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
        lpfc_nlp_put(ndlp);
+       return;
 }
 
 /*
@@ -1868,8 +1900,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                        lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
                        mbox->vport = vport;
                        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-                       rc = lpfc_sli_issue_mbox(phba, mbox,
-                                                (MBX_NOWAIT | MBX_STOP_IOCB));
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
                        if (rc == MBX_NOT_FINISHED)
                                mempool_free(mbox, phba->mbox_mem_pool);
                }
@@ -1892,8 +1923,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
                lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               rc = lpfc_sli_issue_mbox(phba, mbox,
-                                        (MBX_NOWAIT | MBX_STOP_IOCB));
+               mbox->context1 = NULL;
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
                if (rc == MBX_NOT_FINISHED) {
                        mempool_free(mbox, phba->mbox_mem_pool);
                }
@@ -1912,8 +1943,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
                lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               rc = lpfc_sli_issue_mbox(phba, mbox,
-                                        (MBX_NOWAIT | MBX_STOP_IOCB));
+               mbox->context1 = NULL;
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
                if (rc == MBX_NOT_FINISHED) {
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
                                         "1815 Could not issue "
@@ -1981,11 +2012,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
                list_del_init(&ndlp->dev_loss_evt.evt_listp);
 
-       if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
-               list_del_init(&ndlp->dev_loss_evt.evt_listp);
-               complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
-       }
-
        lpfc_unreg_rpi(vport, ndlp);
 
        return 0;
@@ -1999,12 +2025,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 static void
 lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
+       struct lpfc_hba  *phba = vport->phba;
        struct lpfc_rport_data *rdata;
+       LPFC_MBOXQ_t *mbox;
+       int rc;
 
        if (ndlp->nlp_flag & NLP_DELAY_TMO) {
                lpfc_cancel_retry_delay_tmo(vport, ndlp);
        }
 
+       if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
+               /* For this case we need to cleanup the default rpi
+                * allocated by the firmware.
+                */
+               if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
+                       != NULL) {
+                       rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
+                           (uint8_t *) &vport->fc_sparam, mbox, 0);
+                       if (rc) {
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                       }
+                       else {
+                               mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
+                               mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+                               mbox->vport = vport;
+                               mbox->context2 = NULL;
+                               rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+                               if (rc == MBX_NOT_FINISHED) {
+                                       mempool_free(mbox, phba->mbox_mem_pool);
+                               }
+                       }
+               }
+       }
+
        lpfc_cleanup_node(vport, ndlp);
 
        /*
@@ -2132,6 +2185,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
        }
        if (vport->fc_flag & FC_RSCN_MODE) {
                if (lpfc_rscn_payload_check(vport, did)) {
+                       /* If we've already recieved a PLOGI from this NPort
+                        * we don't need to try to discover it again.
+                        */
+                       if (ndlp->nlp_flag & NLP_RCV_PLOGI)
+                               return NULL;
+
                        spin_lock_irq(shost->host_lock);
                        ndlp->nlp_flag |= NLP_NPR_2B_DISC;
                        spin_unlock_irq(shost->host_lock);
@@ -2144,8 +2203,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
                } else
                        ndlp = NULL;
        } else {
+               /* If we've already recieved a PLOGI from this NPort,
+                * or we are already in the process of discovery on it,
+                * we don't need to try to discover it again.
+                */
                if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
-                   ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
+                   ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+                   ndlp->nlp_flag & NLP_RCV_PLOGI)
                        return NULL;
                lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
                spin_lock_irq(shost->host_lock);
@@ -2220,8 +2284,7 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
                lpfc_clear_la(phba, mbox);
                mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
                mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT |
-                                                     MBX_STOP_IOCB));
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
                if (rc == MBX_NOT_FINISHED) {
                        mempool_free(mbox, phba->mbox_mem_pool);
                        lpfc_disc_flush_list(vport);
@@ -2244,8 +2307,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
                lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
                regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
                regvpimbox->vport = vport;
-               if (lpfc_sli_issue_mbox(phba, regvpimbox,
-                                       (MBX_NOWAIT | MBX_STOP_IOCB))
+               if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
                                        == MBX_NOT_FINISHED) {
                        mempool_free(regvpimbox, phba->mbox_mem_pool);
                }
@@ -2414,7 +2476,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
        }
 }
 
-void
+static void
 lpfc_disc_flush_list(struct lpfc_vport *vport)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
@@ -2426,7 +2488,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport)
                        if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
                            ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
                                lpfc_free_tx(phba, ndlp);
-                               lpfc_nlp_put(ndlp);
                        }
                }
        }
@@ -2516,6 +2577,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                        if (ndlp->nlp_type & NLP_FABRIC) {
                                /* Clean up the ndlp on Fabric connections */
                                lpfc_drop_node(vport, ndlp);
+
                        } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
                                /* Fail outstanding IO now since device
                                 * is marked for PLOGI.
@@ -2524,9 +2586,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                        }
                }
                if (vport->port_state != LPFC_FLOGI) {
-                       vport->port_state = LPFC_FLOGI;
-                       lpfc_set_disctmo(vport);
                        lpfc_initial_flogi(vport);
+                       return;
                }
                break;
 
@@ -2536,7 +2597,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                /* Initial FLOGI timeout */
                lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                                 "0222 Initial %s timeout\n",
-                                vport->vpi ? "FLOGI" : "FDISC");
+                                vport->vpi ? "FDISC" : "FLOGI");
 
                /* Assume no Fabric and go on with discovery.
                 * Check for outstanding ELS FLOGI to abort.
@@ -2558,10 +2619,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                /* Next look for NameServer ndlp */
                ndlp = lpfc_findnode_did(vport, NameServer_DID);
                if (ndlp)
-                       lpfc_nlp_put(ndlp);
-               /* Start discovery */
-               lpfc_disc_start(vport);
-               break;
+                       lpfc_els_abort(phba, ndlp);
+
+               /* ReStart discovery */
+               goto restart_disc;
 
        case LPFC_NS_QRY:
        /* Check for wait for NameServer Rsp timeout */
@@ -2580,6 +2641,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                }
                vport->fc_ns_retry = 0;
 
+restart_disc:
                /*
                 * Discovery is over.
                 * set port_state to PORT_READY if SLI2.
@@ -2608,8 +2670,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
                initlinkmbox->vport = vport;
                initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
-                                        (MBX_NOWAIT | MBX_STOP_IOCB));
+               rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
                lpfc_set_loopback_flag(phba);
                if (rc == MBX_NOT_FINISHED)
                        mempool_free(initlinkmbox, phba->mbox_mem_pool);
@@ -2664,12 +2725,14 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
                clrlaerr = 1;
                break;
 
+       case LPFC_LINK_UP:
+               lpfc_issue_clear_la(phba, vport);
+               /* Drop thru */
        case LPFC_LINK_UNKNOWN:
        case LPFC_WARM_START:
        case LPFC_INIT_START:
        case LPFC_INIT_MBX_CMDS:
        case LPFC_LINK_DOWN:
-       case LPFC_LINK_UP:
        case LPFC_HBA_ERROR:
                lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                                 "0230 Unexpected timeout, hba link "
@@ -2723,7 +2786,9 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        else
                mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
 
-                               /* Mailbox took a reference to the node */
+       /* decrement the node reference count held for this callback
+        * function.
+        */
        lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -2747,19 +2812,19 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
                      sizeof(ndlp->nlp_portname)) == 0;
 }
 
-struct lpfc_nodelist *
+static struct lpfc_nodelist *
 __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
 {
        struct lpfc_nodelist *ndlp;
 
        list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
-               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
-                   filter(ndlp, param))
+               if (filter(ndlp, param))
                        return ndlp;
        }
        return NULL;
 }
 
+#if 0
 /*
  * Search node lists for a remote port matching filter criteria
  * Caller needs to hold host_lock before calling this routine.
@@ -2775,6 +2840,7 @@ lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
        spin_unlock_irq(shost->host_lock);
        return ndlp;
 }
+#endif  /*  0  */
 
 /*
  * This routine looks up the ndlp lists for the given RPI. If rpi found it
@@ -2786,6 +2852,7 @@ __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
        return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
 }
 
+#if 0
 struct lpfc_nodelist *
 lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
 {
@@ -2797,6 +2864,7 @@ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
        spin_unlock_irq(shost->host_lock);
        return ndlp;
 }
+#endif  /*  0  */
 
 /*
  * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
@@ -2837,6 +2905,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        return;
 }
 
+/* This routine releases all resources associated with a specifc NPort's ndlp
+ * and mempool_free's the nodelist.
+ */
 static void
 lpfc_nlp_release(struct kref *kref)
 {
@@ -2851,16 +2922,57 @@ lpfc_nlp_release(struct kref *kref)
        mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
 }
 
+/* This routine bumps the reference count for a ndlp structure to ensure
+ * that one discovery thread won't free a ndlp while another discovery thread
+ * is using it.
+ */
 struct lpfc_nodelist *
 lpfc_nlp_get(struct lpfc_nodelist *ndlp)
 {
-       if (ndlp)
+       if (ndlp) {
+               lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+                       "node get:        did:x%x flg:x%x refcnt:x%x",
+                       ndlp->nlp_DID, ndlp->nlp_flag,
+                       atomic_read(&ndlp->kref.refcount));
                kref_get(&ndlp->kref);
+       }
        return ndlp;
 }
 
+
+/* This routine decrements the reference count for a ndlp structure. If the
+ * count goes to 0, this indicates the the associated nodelist should be freed.
+ */
 int
 lpfc_nlp_put(struct lpfc_nodelist *ndlp)
 {
+       if (ndlp) {
+               lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+               "node put:        did:x%x flg:x%x refcnt:x%x",
+                       ndlp->nlp_DID, ndlp->nlp_flag,
+                       atomic_read(&ndlp->kref.refcount));
+       }
        return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
 }
+
+/* This routine free's the specified nodelist if it is not in use
+ * by any other discovery thread. This routine returns 1 if the ndlp
+ * is not being used by anyone and has been freed. A return value of
+ * 0 indicates it is being used by another discovery thread and the
+ * refcount is left unchanged.
+ */
+int
+lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
+{
+       lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+               "node not used:   did:x%x flg:x%x refcnt:x%x",
+               ndlp->nlp_DID, ndlp->nlp_flag,
+               atomic_read(&ndlp->kref.refcount));
+
+       if (atomic_read(&ndlp->kref.refcount) == 1) {
+               lpfc_nlp_put(ndlp);
+               return 1;
+       }
+       return 0;
+}
+
index 451accd5564b23b3f72870d51895f7f2f7d7947e..041f83e7634ab626764092892f078cff28945d22 100644 (file)
@@ -139,6 +139,9 @@ struct lpfc_sli_ct_request {
                        uint8_t len;
                        uint8_t symbname[255];
                } rsnn;
+               struct da_id { /* For DA_ID requests */
+                       uint32_t port_id;
+               } da_id;
                struct rspn {   /* For RSPN_ID requests */
                        uint32_t PortId;
                        uint8_t len;
@@ -150,11 +153,7 @@ struct lpfc_sli_ct_request {
                struct gff_acc {
                        uint8_t fbits[128];
                } gff_acc;
-#ifdef __BIG_ENDIAN_BITFIELD
 #define FCP_TYPE_FEATURE_OFFSET 7
-#else  /*  __LITTLE_ENDIAN_BITFIELD */
-#define FCP_TYPE_FEATURE_OFFSET 4
-#endif
                struct rff {
                        uint32_t PortId;
                        uint8_t reserved[2];
@@ -177,6 +176,8 @@ struct lpfc_sli_ct_request {
                           sizeof(struct rnn))
 #define  RSNN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
                           sizeof(struct rsnn))
+#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+                         sizeof(struct da_id))
 #define  RSPN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
                           sizeof(struct rspn))
 
@@ -1228,7 +1229,8 @@ typedef struct {          /* FireFly BIU registers */
 #define HS_FFER3       0x20000000      /* Bit 29 */
 #define HS_FFER2       0x40000000      /* Bit 30 */
 #define HS_FFER1       0x80000000      /* Bit 31 */
-#define HS_FFERM       0xFF000000      /* Mask for error bits 31:24 */
+#define HS_CRIT_TEMP   0x00000100      /* Bit 8  */
+#define HS_FFERM       0xFF000100      /* Mask for error bits 31:24 and 8 */
 
 /* Host Control Register */
 
@@ -1277,12 +1279,14 @@ typedef struct {                /* FireFly BIU registers */
 #define MBX_DEL_LD_ENTRY    0x1D
 #define MBX_RUN_PROGRAM     0x1E
 #define MBX_SET_MASK        0x20
-#define MBX_SET_SLIM        0x21
+#define MBX_SET_VARIABLE    0x21
 #define MBX_UNREG_D_ID      0x23
 #define MBX_KILL_BOARD      0x24
 #define MBX_CONFIG_FARP     0x25
 #define MBX_BEACON          0x2A
 #define MBX_HEARTBEAT       0x31
+#define MBX_WRITE_VPARMS    0x32
+#define MBX_ASYNCEVT_ENABLE 0x33
 
 #define MBX_CONFIG_HBQ     0x7C
 #define MBX_LOAD_AREA       0x81
@@ -1297,7 +1301,7 @@ typedef struct {          /* FireFly BIU registers */
 #define MBX_REG_VNPID      0x96
 #define MBX_UNREG_VNPID            0x97
 
-#define MBX_FLASH_WR_ULA    0x98
+#define MBX_WRITE_WWN       0x98
 #define MBX_SET_DEBUG       0x99
 #define MBX_LOAD_EXP_ROM    0x9C
 
@@ -1344,6 +1348,7 @@ typedef struct {          /* FireFly BIU registers */
 
 /*  SLI_2 IOCB Command Set */
 
+#define CMD_ASYNC_STATUS        0x7C
 #define CMD_RCV_SEQUENCE64_CX   0x81
 #define CMD_XMIT_SEQUENCE64_CR  0x82
 #define CMD_XMIT_SEQUENCE64_CX  0x83
@@ -1368,6 +1373,7 @@ typedef struct {          /* FireFly BIU registers */
 #define CMD_FCP_TRECEIVE64_CX   0xA1
 #define CMD_FCP_TRSP64_CX       0xA3
 
+#define CMD_QUE_XRI64_CX       0xB3
 #define CMD_IOCB_RCV_SEQ64_CX  0xB5
 #define CMD_IOCB_RCV_ELS64_CX  0xB7
 #define CMD_IOCB_RCV_CONT64_CX 0xBB
@@ -1406,6 +1412,8 @@ typedef struct {          /* FireFly BIU registers */
 #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
 #define MBX_TIMEOUT                0xfffffe /* time-out expired waiting for */
 
+#define TEMPERATURE_OFFSET 0xB0        /* Slim offset for critical temperature event */
+
 /*
  *    Begin Structure Definitions for Mailbox Commands
  */
@@ -2606,6 +2614,18 @@ typedef struct {
        uint32_t IPAddress;
 } CONFIG_FARP_VAR;
 
+/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+       uint32_t rsvd:30;
+       uint32_t ring:2;        /* Ring for ASYNC_EVENT iocb Bits 0-1*/
+#else /*  __LITTLE_ENDIAN */
+       uint32_t ring:2;        /* Ring for ASYNC_EVENT iocb Bits 0-1*/
+       uint32_t rsvd:30;
+#endif
+} ASYNCEVT_ENABLE_VAR;
+
 /* Union of all Mailbox Command types */
 #define MAILBOX_CMD_WSIZE      32
 #define MAILBOX_CMD_SIZE       (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
@@ -2645,6 +2665,7 @@ typedef union {
        CONFIG_PORT_VAR varCfgPort;     /* cmd = 0x88 (CONFIG_PORT)  */
        REG_VPI_VAR varRegVpi;          /* cmd = 0x96 (REG_VPI) */
        UNREG_VPI_VAR varUnregVpi;      /* cmd = 0x97 (UNREG_VPI) */
+       ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
 } MAILVARIANTS;
 
 /*
@@ -2973,6 +2994,34 @@ typedef struct {
 #endif
 } RCV_ELS_REQ64;
 
+/* IOCB Command template for RCV_SEQ64 */
+struct rcv_seq64 {
+       struct ulp_bde64 elsReq;
+       uint32_t hbq_1;
+       uint32_t parmRo;
+#ifdef __BIG_ENDIAN_BITFIELD
+       uint32_t rctl:8;
+       uint32_t type:8;
+       uint32_t dfctl:8;
+       uint32_t ls:1;
+       uint32_t fs:1;
+       uint32_t rsvd2:3;
+       uint32_t si:1;
+       uint32_t bc:1;
+       uint32_t rsvd3:1;
+#else  /*  __LITTLE_ENDIAN_BITFIELD */
+       uint32_t rsvd3:1;
+       uint32_t bc:1;
+       uint32_t si:1;
+       uint32_t rsvd2:3;
+       uint32_t fs:1;
+       uint32_t ls:1;
+       uint32_t dfctl:8;
+       uint32_t type:8;
+       uint32_t rctl:8;
+#endif
+};
+
 /* IOCB Command template for all 64 bit FCP Initiator commands */
 typedef struct {
        ULP_BDL bdl;
@@ -2987,6 +3036,21 @@ typedef struct {
        uint32_t fcpt_Length;   /* transfer ready for IWRITE */
 } FCPT_FIELDS64;
 
+/* IOCB Command template for Async Status iocb commands */
+typedef struct {
+       uint32_t rsvd[4];
+       uint32_t param;
+#ifdef __BIG_ENDIAN_BITFIELD
+       uint16_t evt_code;              /* High order bits word 5 */
+       uint16_t sub_ctxt_tag;          /* Low  order bits word 5 */
+#else   /*  __LITTLE_ENDIAN_BITFIELD */
+       uint16_t sub_ctxt_tag;          /* High order bits word 5 */
+       uint16_t evt_code;              /* Low  order bits word 5 */
+#endif
+} ASYNCSTAT_FIELDS;
+#define ASYNC_TEMP_WARN                0x100
+#define ASYNC_TEMP_SAFE                0x101
+
 /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
    or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
 
@@ -3004,7 +3068,26 @@ struct rcv_sli3 {
        struct ulp_bde64 bde2;
 };
 
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+       struct ulp_bde64 bde;
+       uint32_t buffer_tag;
+};
 
+/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
+typedef struct {
+       struct lpfc_hbq_entry   buff;
+       uint32_t                rsvd;
+       uint32_t                rsvd1;
+} QUE_XRI64_CX_FIELDS;
+
+struct que_xri64cx_ext_fields {
+       uint32_t        iotag64_low;
+       uint32_t        iotag64_high;
+       uint32_t        ebde_count;
+       uint32_t        rsvd;
+       struct lpfc_hbq_entry   buff[5];
+};
 
 typedef struct _IOCB { /* IOCB structure */
        union {
@@ -3028,6 +3111,9 @@ typedef struct _IOCB {    /* IOCB structure */
                XMT_SEQ_FIELDS64 xseq64;        /* XMIT / BCAST cmd */
                FCPI_FIELDS64 fcpi64;   /* FCP 64 bit Initiator template */
                FCPT_FIELDS64 fcpt64;   /* FCP 64 bit target template */
+               ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
+               QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
+               struct rcv_seq64 rcvseq64;      /* RCV_SEQ64 and RCV_CONT64 */
 
                uint32_t ulpWord[IOCB_WORD_SZ - 2];     /* generic 6 'words' */
        } un;
@@ -3085,6 +3171,10 @@ typedef struct _IOCB {   /* IOCB structure */
 
        union {
                struct rcv_sli3 rcvsli3; /* words 8 - 15 */
+
+               /* words 8-31 used for que_xri_cx iocb */
+               struct que_xri64cx_ext_fields que_xri64cx_ext_words;
+
                uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
        } unsli3;
 
@@ -3124,12 +3214,6 @@ typedef struct _IOCB {   /* IOCB structure */
 
 } IOCB_t;
 
-/* Structure used for a single HBQ entry */
-struct lpfc_hbq_entry {
-       struct ulp_bde64 bde;
-       uint32_t buffer_tag;
-};
-
 
 #define SLI1_SLIM_SIZE   (4 * 1024)
 
@@ -3172,6 +3256,8 @@ lpfc_is_LC_HBA(unsigned short device)
            (device == PCI_DEVICE_ID_BSMB) ||
            (device == PCI_DEVICE_ID_ZMID) ||
            (device == PCI_DEVICE_ID_ZSMB) ||
+           (device == PCI_DEVICE_ID_SAT_MID) ||
+           (device == PCI_DEVICE_ID_SAT_SMB) ||
            (device == PCI_DEVICE_ID_RFLY))
                return 1;
        else
index ecebdfa0047007fd4385427eea0805522101093a..3205f7488d1c49b6f24b17391f77ccf6a25e5908 100644 (file)
@@ -212,6 +212,18 @@ out_free_mbox:
        return 0;
 }
 
+/* Completion handler for config async event mailbox command. */
+static void
+lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+{
+       if (pmboxq->mb.mbxStatus == MBX_SUCCESS)
+               phba->temp_sensor_support = 1;
+       else
+               phba->temp_sensor_support = 0;
+       mempool_free(pmboxq, phba->mbox_mem_pool);
+       return;
+}
+
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_config_port_post                                             */
@@ -234,6 +246,15 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        int i, j;
        int rc;
 
+       spin_lock_irq(&phba->hbalock);
+       /*
+        * If the Config port completed correctly the HBA is not
+        * over heated any more.
+        */
+       if (phba->over_temp_state == HBA_OVER_TEMP)
+               phba->over_temp_state = HBA_NORMAL_TEMP;
+       spin_unlock_irq(&phba->hbalock);
+
        pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmb) {
                phba->link_state = LPFC_HBA_ERROR;
@@ -343,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 
        phba->link_state = LPFC_LINK_DOWN;
 
-       /* Only process IOCBs on ring 0 till hba_state is READY */
+       /* Only process IOCBs on ELS ring till hba_state is READY */
        if (psli->ring[psli->extra_ring].cmdringaddr)
                psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT;
        if (psli->ring[psli->fcp_ring].cmdringaddr)
@@ -409,7 +430,21 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                return -EIO;
        }
        /* MBOX buffer will be freed in mbox compl */
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       lpfc_config_async(phba, pmb, LPFC_ELS_RING);
+       pmb->mbox_cmpl = lpfc_config_async_cmpl;
+       pmb->vport = phba->pport;
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
 
+       if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
+               lpfc_printf_log(phba,
+                               KERN_ERR,
+                               LOG_INIT,
+                               "0456 Adapter failed to issue "
+                               "ASYNCEVT_ENABLE mbox status x%x \n.",
+                               rc);
+               mempool_free(pmb, phba->mbox_mem_pool);
+       }
        return (0);
 }
 
@@ -449,6 +484,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
        struct lpfc_dmabuf *mp, *next_mp;
+       struct lpfc_iocbq *iocb;
+       IOCB_t *cmd = NULL;
+       LIST_HEAD(completions);
        int i;
 
        if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
@@ -464,16 +502,42 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
                }
        }
 
+       spin_lock_irq(&phba->hbalock);
        for (i = 0; i < psli->num_rings; i++) {
                pring = &psli->ring[i];
+
+               /* At this point in time the HBA is either reset or DOA. Either
+                * way, nothing should be on txcmplq as it will NEVER complete.
+                */
+               list_splice_init(&pring->txcmplq, &completions);
+               pring->txcmplq_cnt = 0;
+               spin_unlock_irq(&phba->hbalock);
+
+               while (!list_empty(&completions)) {
+                       iocb = list_get_first(&completions, struct lpfc_iocbq,
+                               list);
+                       cmd = &iocb->iocb;
+                       list_del_init(&iocb->list);
+
+                       if (!iocb->iocb_cmpl)
+                               lpfc_sli_release_iocbq(phba, iocb);
+                       else {
+                               cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                               cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                               (iocb->iocb_cmpl) (phba, iocb, iocb);
+                       }
+               }
+
                lpfc_sli_abort_iocb_ring(phba, pring);
+               spin_lock_irq(&phba->hbalock);
        }
+       spin_unlock_irq(&phba->hbalock);
 
        return 0;
 }
 
 /* HBA heart beat timeout handler */
-void
+static void
 lpfc_hb_timeout(unsigned long ptr)
 {
        struct lpfc_hba *phba;
@@ -512,8 +576,10 @@ void
 lpfc_hb_timeout_handler(struct lpfc_hba *phba)
 {
        LPFC_MBOXQ_t *pmboxq;
+       struct lpfc_dmabuf *buf_ptr;
        int retval;
        struct lpfc_sli *psli = &phba->sli;
+       LIST_HEAD(completions);
 
        if ((phba->link_state == LPFC_HBA_ERROR) ||
                (phba->pport->load_flag & FC_UNLOADING) ||
@@ -540,49 +606,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
        }
        spin_unlock_irq(&phba->pport->work_port_lock);
 
-       /* If there is no heart beat outstanding, issue a heartbeat command */
-       if (!phba->hb_outstanding) {
-               pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
-               if (!pmboxq) {
-                       mod_timer(&phba->hb_tmofunc,
-                               jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
-                       return;
+       if (phba->elsbuf_cnt &&
+               (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) {
+               spin_lock_irq(&phba->hbalock);
+               list_splice_init(&phba->elsbuf, &completions);
+               phba->elsbuf_cnt = 0;
+               phba->elsbuf_prev_cnt = 0;
+               spin_unlock_irq(&phba->hbalock);
+
+               while (!list_empty(&completions)) {
+                       list_remove_head(&completions, buf_ptr,
+                               struct lpfc_dmabuf, list);
+                       lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+                       kfree(buf_ptr);
                }
+       }
+       phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
 
-               lpfc_heart_beat(phba, pmboxq);
-               pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
-               pmboxq->vport = phba->pport;
-               retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+       /* If there is no heart beat outstanding, issue a heartbeat command */
+       if (phba->cfg_enable_hba_heartbeat) {
+               if (!phba->hb_outstanding) {
+                       pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+                       if (!pmboxq) {
+                               mod_timer(&phba->hb_tmofunc,
+                                         jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+                               return;
+                       }
 
-               if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
-                       mempool_free(pmboxq, phba->mbox_mem_pool);
+                       lpfc_heart_beat(phba, pmboxq);
+                       pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+                       pmboxq->vport = phba->pport;
+                       retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+
+                       if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+                               mempool_free(pmboxq, phba->mbox_mem_pool);
+                               mod_timer(&phba->hb_tmofunc,
+                                         jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+                               return;
+                       }
                        mod_timer(&phba->hb_tmofunc,
-                               jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+                                 jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+                       phba->hb_outstanding = 1;
                        return;
+               } else {
+                       /*
+                       * If heart beat timeout called with hb_outstanding set
+                       * we need to take the HBA offline.
+                       */
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0459 Adapter heartbeat failure, "
+                                       "taking this port offline.\n");
+
+                       spin_lock_irq(&phba->hbalock);
+                       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+                       spin_unlock_irq(&phba->hbalock);
+
+                       lpfc_offline_prep(phba);
+                       lpfc_offline(phba);
+                       lpfc_unblock_mgmt_io(phba);
+                       phba->link_state = LPFC_HBA_ERROR;
+                       lpfc_hba_down_post(phba);
                }
-               mod_timer(&phba->hb_tmofunc,
-                       jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
-               phba->hb_outstanding = 1;
-               return;
-       } else {
-               /*
-                * If heart beat timeout called with hb_outstanding set we
-                * need to take the HBA offline.
-                */
-               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0459 Adapter heartbeat failure, taking "
-                               "this port offline.\n");
+       }
+}
 
-               spin_lock_irq(&phba->hbalock);
-               psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-               spin_unlock_irq(&phba->hbalock);
+static void
+lpfc_offline_eratt(struct lpfc_hba *phba)
+{
+       struct lpfc_sli   *psli = &phba->sli;
 
-               lpfc_offline_prep(phba);
-               lpfc_offline(phba);
-               lpfc_unblock_mgmt_io(phba);
-               phba->link_state = LPFC_HBA_ERROR;
-               lpfc_hba_down_post(phba);
-       }
+       spin_lock_irq(&phba->hbalock);
+       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+       spin_unlock_irq(&phba->hbalock);
+       lpfc_offline_prep(phba);
+
+       lpfc_offline(phba);
+       lpfc_reset_barrier(phba);
+       lpfc_sli_brdreset(phba);
+       lpfc_hba_down_post(phba);
+       lpfc_sli_brdready(phba, HS_MBRDY);
+       lpfc_unblock_mgmt_io(phba);
+       phba->link_state = LPFC_HBA_ERROR;
+       return;
 }
 
 /************************************************************************/
@@ -601,6 +706,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
        struct lpfc_sli_ring  *pring;
        struct lpfc_vport **vports;
        uint32_t event_data;
+       unsigned long temperature;
+       struct temp_event temp_event_data;
        struct Scsi_Host  *shost;
        int i;
 
@@ -608,6 +715,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
         * since we cannot communicate with the pci card anyway. */
        if (pci_channel_offline(phba->pcidev))
                return;
+       /* If resets are disabled then leave the HBA alone and return */
+       if (!phba->cfg_enable_hba_reset)
+               return;
 
        if (phba->work_hs & HS_FFER6 ||
            phba->work_hs & HS_FFER5) {
@@ -620,14 +730,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
                vports = lpfc_create_vport_work_array(phba);
                if (vports != NULL)
                        for(i = 0;
-                           i < LPFC_MAX_VPORTS && vports[i] != NULL;
+                           i <= phba->max_vpi && vports[i] != NULL;
                            i++){
                                shost = lpfc_shost_from_vport(vports[i]);
                                spin_lock_irq(shost->host_lock);
                                vports[i]->fc_flag |= FC_ESTABLISH_LINK;
                                spin_unlock_irq(shost->host_lock);
                        }
-               lpfc_destroy_vport_work_array(vports);
+               lpfc_destroy_vport_work_array(phba, vports);
                spin_lock_irq(&phba->hbalock);
                psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
                spin_unlock_irq(&phba->hbalock);
@@ -655,6 +765,31 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
                        return;
                }
                lpfc_unblock_mgmt_io(phba);
+       } else if (phba->work_hs & HS_CRIT_TEMP) {
+               temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET);
+               temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
+               temp_event_data.event_code = LPFC_CRIT_TEMP;
+               temp_event_data.data = (uint32_t)temperature;
+
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0459 Adapter maximum temperature exceeded "
+                               "(%ld), taking this port offline "
+                               "Data: x%x x%x x%x\n",
+                               temperature, phba->work_hs,
+                               phba->work_status[0], phba->work_status[1]);
+
+               shost = lpfc_shost_from_vport(phba->pport);
+               fc_host_post_vendor_event(shost, fc_get_event_number(),
+                                         sizeof(temp_event_data),
+                                         (char *) &temp_event_data,
+                                         SCSI_NL_VID_TYPE_PCI
+                                         | PCI_VENDOR_ID_EMULEX);
+
+               spin_lock_irq(&phba->hbalock);
+               phba->over_temp_state = HBA_OVER_TEMP;
+               spin_unlock_irq(&phba->hbalock);
+               lpfc_offline_eratt(phba);
+
        } else {
                /* The if clause above forces this code path when the status
                 * failure is a value other than FFER6.  Do not call the offline
@@ -672,14 +807,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
                                sizeof(event_data), (char *) &event_data,
                                SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
-               spin_lock_irq(&phba->hbalock);
-               psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-               spin_unlock_irq(&phba->hbalock);
-               lpfc_offline_prep(phba);
-               lpfc_offline(phba);
-               lpfc_unblock_mgmt_io(phba);
-               phba->link_state = LPFC_HBA_ERROR;
-               lpfc_hba_down_post(phba);
+               lpfc_offline_eratt(phba);
        }
 }
 
@@ -699,21 +827,25 @@ lpfc_handle_latt(struct lpfc_hba *phba)
        LPFC_MBOXQ_t *pmb;
        volatile uint32_t control;
        struct lpfc_dmabuf *mp;
-       int rc = -ENOMEM;
+       int rc = 0;
 
        pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!pmb)
+       if (!pmb) {
+               rc = 1;
                goto lpfc_handle_latt_err_exit;
+       }
 
        mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-       if (!mp)
+       if (!mp) {
+               rc = 2;
                goto lpfc_handle_latt_free_pmb;
+       }
 
        mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-       if (!mp->virt)
+       if (!mp->virt) {
+               rc = 3;
                goto lpfc_handle_latt_free_mp;
-
-       rc = -EIO;
+       }
 
        /* Cleanup any outstanding ELS commands */
        lpfc_els_flush_all_cmd(phba);
@@ -722,9 +854,11 @@ lpfc_handle_latt(struct lpfc_hba *phba)
        lpfc_read_la(phba, pmb, mp);
        pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
        pmb->vport = vport;
-       rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
-       if (rc == MBX_NOT_FINISHED)
+       rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               rc = 4;
                goto lpfc_handle_latt_free_mbuf;
+       }
 
        /* Clear Link Attention in HA REG */
        spin_lock_irq(&phba->hbalock);
@@ -756,10 +890,8 @@ lpfc_handle_latt_err_exit:
        lpfc_linkdown(phba);
        phba->link_state = LPFC_HBA_ERROR;
 
-       /* The other case is an error from issue_mbox */
-       if (rc == -ENOMEM)
-               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
-                               "0300 READ_LA: no buffers\n");
+       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                    "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc);
 
        return;
 }
@@ -1088,9 +1220,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
                /* Allocate buffer to post */
                mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
                if (mp1)
-                   mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
-                                               &mp1->phys);
-               if (mp1 == 0 || mp1->virt == 0) {
+                   mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys);
+               if (!mp1 || !mp1->virt) {
                        kfree(mp1);
                        lpfc_sli_release_iocbq(phba, iocb);
                        pring->missbufcnt = cnt;
@@ -1104,7 +1235,7 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
                        if (mp2)
                                mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                                            &mp2->phys);
-                       if (mp2 == 0 || mp2->virt == 0) {
+                       if (!mp2 || !mp2->virt) {
                                kfree(mp2);
                                lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
                                kfree(mp1);
@@ -1280,15 +1411,39 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
        kfree(HashWorking);
 }
 
-static void
+void
 lpfc_cleanup(struct lpfc_vport *vport)
 {
+       struct lpfc_hba   *phba = vport->phba;
        struct lpfc_nodelist *ndlp, *next_ndlp;
+       int i = 0;
 
-       /* clean up phba - lpfc specific */
-       lpfc_can_disctmo(vport);
-       list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-               lpfc_nlp_put(ndlp);
+       if (phba->link_state > LPFC_LINK_DOWN)
+               lpfc_port_link_failure(vport);
+
+       list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_type & NLP_FABRIC)
+                       lpfc_disc_state_machine(vport, ndlp, NULL,
+                                       NLP_EVT_DEVICE_RECOVERY);
+               lpfc_disc_state_machine(vport, ndlp, NULL,
+                                            NLP_EVT_DEVICE_RM);
+       }
+
+       /* At this point, ALL ndlp's should be gone
+        * because of the previous NLP_EVT_DEVICE_RM.
+        * Lets wait for this to happen, if needed.
+        */
+       while (!list_empty(&vport->fc_nodes)) {
+
+               if (i++ > 3000) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+                               "0233 Nodelist not empty\n");
+                       break;
+               }
+
+               /* Wait for any activity on ndlps to settle */
+               msleep(10);
+       }
        return;
 }
 
@@ -1307,14 +1462,14 @@ lpfc_establish_link_tmo(unsigned long ptr)
                        phba->pport->fc_flag, phba->pport->port_state);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
                        struct Scsi_Host *shost;
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irqsave(shost->host_lock, iflag);
                        vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
                        spin_unlock_irqrestore(shost->host_lock, iflag);
                }
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
 }
 
 void
@@ -1339,6 +1494,16 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba)
        return;
 }
 
+static void
+lpfc_block_mgmt_io(struct lpfc_hba * phba)
+{
+       unsigned long iflag;
+
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
+}
+
 int
 lpfc_online(struct lpfc_hba *phba)
 {
@@ -1369,7 +1534,7 @@ lpfc_online(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
                        struct Scsi_Host *shost;
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
@@ -1378,22 +1543,12 @@ lpfc_online(struct lpfc_hba *phba)
                                vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
                        spin_unlock_irq(shost->host_lock);
                }
-               lpfc_destroy_vport_work_array(vports);
+               lpfc_destroy_vport_work_array(phba, vports);
 
        lpfc_unblock_mgmt_io(phba);
        return 0;
 }
 
-void
-lpfc_block_mgmt_io(struct lpfc_hba * phba)
-{
-       unsigned long iflag;
-
-       spin_lock_irqsave(&phba->hbalock, iflag);
-       phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
-       spin_unlock_irqrestore(&phba->hbalock, iflag);
-}
-
 void
 lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
 {
@@ -1409,6 +1564,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 {
        struct lpfc_vport *vport = phba->pport;
        struct lpfc_nodelist  *ndlp, *next_ndlp;
+       struct lpfc_vport **vports;
+       int i;
 
        if (vport->fc_flag & FC_OFFLINE_MODE)
                return;
@@ -1417,10 +1574,34 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 
        lpfc_linkdown(phba);
 
-       /* Issue an unreg_login to all nodes */
-       list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
-                       lpfc_unreg_rpi(vport, ndlp);
+       /* Issue an unreg_login to all nodes on all vports */
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports != NULL) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+                       struct Scsi_Host *shost;
+
+                       if (vports[i]->load_flag & FC_UNLOADING)
+                               continue;
+                       shost = lpfc_shost_from_vport(vports[i]);
+                       list_for_each_entry_safe(ndlp, next_ndlp,
+                                                &vports[i]->fc_nodes,
+                                                nlp_listp) {
+                               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+                                       continue;
+                               if (ndlp->nlp_type & NLP_FABRIC) {
+                                       lpfc_disc_state_machine(vports[i], ndlp,
+                                               NULL, NLP_EVT_DEVICE_RECOVERY);
+                                       lpfc_disc_state_machine(vports[i], ndlp,
+                                               NULL, NLP_EVT_DEVICE_RM);
+                               }
+                               spin_lock_irq(shost->host_lock);
+                               ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+                               spin_unlock_irq(shost->host_lock);
+                               lpfc_unreg_rpi(vports[i], ndlp);
+                       }
+               }
+       }
+       lpfc_destroy_vport_work_array(phba, vports);
 
        lpfc_sli_flush_mbox_queue(phba);
 }
@@ -1439,9 +1620,9 @@ lpfc_offline(struct lpfc_hba *phba)
        lpfc_stop_phba_timers(phba);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
                        lpfc_stop_vport_timers(vports[i]);
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
        lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
                        "0460 Bring Adapter offline\n");
        /* Bring down the SLI Layer and cleanup.  The HBA is offline
@@ -1452,15 +1633,14 @@ lpfc_offline(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
-                       lpfc_cleanup(vports[i]);
                        spin_lock_irq(shost->host_lock);
                        vports[i]->work_port_events = 0;
                        vports[i]->fc_flag |= FC_OFFLINE_MODE;
                        spin_unlock_irq(shost->host_lock);
                }
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
 }
 
 /******************************************************************************
@@ -1674,6 +1854,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
        fc_host_supported_speeds(shost) = 0;
        if (phba->lmt & LMT_10Gb)
                fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
+       if (phba->lmt & LMT_8Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT;
        if (phba->lmt & LMT_4Gb)
                fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
        if (phba->lmt & LMT_2Gb)
@@ -1707,13 +1889,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        struct Scsi_Host  *shost = NULL;
        void *ptr;
        unsigned long bar0map_len, bar2map_len;
-       int error = -ENODEV;
+       int error = -ENODEV, retval;
        int  i, hbq_count;
        uint16_t iotag;
+       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
-       if (pci_enable_device(pdev))
+       if (pci_enable_device_bars(pdev, bars))
                goto out;
-       if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
+       if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
                goto out_disable_device;
 
        phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
@@ -1823,9 +2006,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        lpfc_sli_setup(phba);
        lpfc_sli_queue_setup(phba);
 
-       error = lpfc_mem_alloc(phba);
-       if (error)
+       retval = lpfc_mem_alloc(phba);
+       if (retval) {
+               error = retval;
                goto out_free_hbqslimp;
+       }
 
        /* Initialize and populate the iocb list per host.  */
        INIT_LIST_HEAD(&phba->lpfc_iocb_list);
@@ -1880,6 +2065,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        /* Initialize list of fabric iocbs */
        INIT_LIST_HEAD(&phba->fabric_iocb_list);
 
+       /* Initialize list to save ELS buffers */
+       INIT_LIST_HEAD(&phba->elsbuf);
+
        vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
        if (!vport)
                goto out_kthread_stop;
@@ -1891,8 +2079,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        pci_set_drvdata(pdev, shost);
 
        if (phba->cfg_use_msi) {
-               error = pci_enable_msi(phba->pcidev);
-               if (!error)
+               retval = pci_enable_msi(phba->pcidev);
+               if (!retval)
                        phba->using_msi = 1;
                else
                        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -1900,11 +2088,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                                        "with IRQ\n");
        }
 
-       error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
+       retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
                            LPFC_DRIVER_NAME, phba);
-       if (error) {
+       if (retval) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "0451 Enable interrupt handler failed\n");
+               error = retval;
                goto out_disable_msi;
        }
 
@@ -1914,11 +2103,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
        phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
 
-       if (lpfc_alloc_sysfs_attr(vport))
+       if (lpfc_alloc_sysfs_attr(vport)) {
+               error = -ENOMEM;
                goto out_free_irq;
+       }
 
-       if (lpfc_sli_hba_setup(phba))
+       if (lpfc_sli_hba_setup(phba)) {
+               error = -ENODEV;
                goto out_remove_device;
+       }
 
        /*
         * hba setup may have changed the hba_queue_depth so we need to adjust
@@ -1975,7 +2168,7 @@ out_idr_remove:
 out_free_phba:
        kfree(phba);
 out_release_regions:
-       pci_release_regions(pdev);
+       pci_release_selected_regions(pdev, bars);
 out_disable_device:
        pci_disable_device(pdev);
 out:
@@ -1991,6 +2184,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
        struct Scsi_Host  *shost = pci_get_drvdata(pdev);
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba   *phba = vport->phba;
+       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
        spin_lock_irq(&phba->hbalock);
        vport->load_flag |= FC_UNLOADING;
        spin_unlock_irq(&phba->hbalock);
@@ -1998,8 +2193,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
        kfree(vport->vname);
        lpfc_free_sysfs_attr(vport);
 
+       kthread_stop(phba->worker_thread);
+
        fc_remove_host(shost);
        scsi_remove_host(shost);
+       lpfc_cleanup(vport);
+
        /*
         * Bring down the SLI Layer. This step disable all interrupts,
         * clears the rings, discards all mailbox commands, and resets
@@ -2014,9 +2213,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
        spin_unlock_irq(&phba->hbalock);
 
        lpfc_debugfs_terminate(vport);
-       lpfc_cleanup(vport);
-
-       kthread_stop(phba->worker_thread);
 
        /* Release the irq reservation */
        free_irq(phba->pcidev->irq, phba);
@@ -2048,7 +2244,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 
        kfree(phba);
 
-       pci_release_regions(pdev);
+       pci_release_selected_regions(pdev, bars);
        pci_disable_device(pdev);
 }
 
@@ -2239,12 +2435,22 @@ lpfc_init(void)
        printk(LPFC_MODULE_DESC "\n");
        printk(LPFC_COPYRIGHT "\n");
 
+       if (lpfc_enable_npiv) {
+               lpfc_transport_functions.vport_create = lpfc_vport_create;
+               lpfc_transport_functions.vport_delete = lpfc_vport_delete;
+       }
        lpfc_transport_template =
                                fc_attach_transport(&lpfc_transport_functions);
-       lpfc_vport_transport_template =
-                       fc_attach_transport(&lpfc_vport_transport_functions);
-       if (!lpfc_transport_template || !lpfc_vport_transport_template)
+       if (lpfc_transport_template == NULL)
                return -ENOMEM;
+       if (lpfc_enable_npiv) {
+               lpfc_vport_transport_template =
+                       fc_attach_transport(&lpfc_vport_transport_functions);
+               if (lpfc_vport_transport_template == NULL) {
+                       fc_release_transport(lpfc_transport_template);
+                       return -ENOMEM;
+               }
+       }
        error = pci_register_driver(&lpfc_driver);
        if (error) {
                fc_release_transport(lpfc_transport_template);
@@ -2259,7 +2465,8 @@ lpfc_exit(void)
 {
        pci_unregister_driver(&lpfc_driver);
        fc_release_transport(lpfc_transport_template);
-       fc_release_transport(lpfc_vport_transport_template);
+       if (lpfc_enable_npiv)
+               fc_release_transport(lpfc_vport_transport_template);
 }
 
 module_init(lpfc_init);
index 626e4d878725d48d6860025dff8587cae99c7a3c..c5841d7565f75def73fd180e10418433ff752d3b 100644 (file)
@@ -26,6 +26,7 @@
 #define LOG_IP                        0x20     /* IP traffic history */
 #define LOG_FCP                       0x40     /* FCP traffic history */
 #define LOG_NODE                      0x80     /* Node table events */
+#define LOG_TEMP                      0x100    /* Temperature sensor events */
 #define LOG_MISC                      0x400    /* Miscellaneous events */
 #define LOG_SLI                       0x800    /* SLI events */
 #define LOG_FCP_ERROR                 0x1000   /* log errors, not underruns */
index a592733664e9c14a183534602affa6f1c6d42cb4..dfc63f6ccd7bac89c8a98a41afa5e7042cea2250 100644 (file)
@@ -81,6 +81,24 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        return;
 }
 
+/**********************************************/
+/*  lpfc_config_async  Issue a                */
+/*  MBX_ASYNC_EVT_ENABLE mailbox command      */
+/**********************************************/
+void
+lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
+               uint32_t ring)
+{
+       MAILBOX_t *mb;
+
+       mb = &pmb->mb;
+       memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+       mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
+       mb->un.varCfgAsyncEvent.ring = ring;
+       mb->mbxOwner = OWN_HOST;
+       return;
+}
+
 /**********************************************/
 /*  lpfc_heart_beat  Issue a HEART_BEAT       */
 /*                mailbox command             */
@@ -270,8 +288,10 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
 
        /* Get a buffer to hold the HBAs Service Parameters */
 
-       if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
-           ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
+       mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+       if (mp)
+               mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+       if (!mp || !mp->virt) {
                kfree(mp);
                mb->mbxCommand = MBX_READ_SPARM64;
                /* READ_SPARAM: no buffers */
@@ -369,8 +389,10 @@ lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
        mb->mbxOwner = OWN_HOST;
 
        /* Get a buffer to hold NPorts Service Parameters */
-       if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
-           ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
+       mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+       if (mp)
+               mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+       if (!mp || !mp->virt) {
                kfree(mp);
                mb->mbxCommand = MBX_REG_LOGIN64;
                /* REG_LOGIN: no buffers */
@@ -874,7 +896,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
        case MBX_DOWN_LOAD:     /* 0x1C */
        case MBX_DEL_LD_ENTRY:  /* 0x1D */
        case MBX_LOAD_AREA:     /* 0x81 */
-       case MBX_FLASH_WR_ULA:  /* 0x98 */
+       case MBX_WRITE_WWN:     /* 0x98 */
        case MBX_LOAD_EXP_ROM:  /* 0x9C */
                return LPFC_MBOX_TMO_FLASH_CMD;
        }
index 43c3b8a0d76a5642418afbefc7e2209eef2e72bd..6dc5ab8d6716b3f8fd13e69dd3309afbe1cf8190 100644 (file)
@@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
 
  fail_free_hbq_pool:
        lpfc_sli_hbqbuf_free_all(phba);
+       pci_pool_destroy(phba->lpfc_hbq_pool);
  fail_free_nlp_mem_pool:
        mempool_destroy(phba->nlp_mem_pool);
        phba->nlp_mem_pool = NULL;
index 880af0cd463dbbe163c43ec379fa68e903a2242e..4a0e3406e37ab787060c8713cf56a2581bdcb256 100644 (file)
@@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+       if (wwn_to_u64(sp->portName.u.wwn) == 0) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "0140 PLOGI Reject: invalid nname\n");
+               stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+               stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME;
+               lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+                       NULL);
+               return 0;
+       }
+       if (wwn_to_u64(sp->nodeName.u.wwn) == 0) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "0141 PLOGI Reject: invalid pname\n");
+               stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+               stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME;
+               lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+                       NULL);
+               return 0;
+       }
        if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
                /* Reject this request because invalid parameters */
                stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
@@ -343,8 +361,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                lpfc_config_link(phba, mbox);
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox
-                       (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
                if (rc == MBX_NOT_FINISHED) {
                        mempool_free(mbox, phba->mbox_mem_pool);
                        goto out;
@@ -407,6 +424,61 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        ndlp, mbox);
                return 1;
        }
+
+       /* If the remote NPort logs into us, before we can initiate
+        * discovery to them, cleanup the NPort from discovery accordingly.
+        */
+       if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+               spin_lock_irq(shost->host_lock);
+               ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+               spin_unlock_irq(shost->host_lock);
+               del_timer_sync(&ndlp->nlp_delayfunc);
+               ndlp->nlp_last_elscmd = 0;
+
+               if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+                       list_del_init(&ndlp->els_retry_evt.evt_listp);
+
+               if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+                       spin_lock_irq(shost->host_lock);
+                       ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+                       spin_unlock_irq(shost->host_lock);
+
+                       if ((ndlp->nlp_flag & NLP_ADISC_SND) &&
+                               (vport->num_disc_nodes)) {
+                               /* Check to see if there are more
+                                * ADISCs to be sent
+                                */
+                               lpfc_more_adisc(vport);
+
+                               if ((vport->num_disc_nodes == 0) &&
+                                       (vport->fc_npr_cnt))
+                                       lpfc_els_disc_plogi(vport);
+
+                               if (vport->num_disc_nodes == 0) {
+                                       spin_lock_irq(shost->host_lock);
+                                       vport->fc_flag &= ~FC_NDISC_ACTIVE;
+                                       spin_unlock_irq(shost->host_lock);
+                                       lpfc_can_disctmo(vport);
+                                       lpfc_end_rscn(vport);
+                               }
+                       }
+                       else if (vport->num_disc_nodes) {
+                               /* Check to see if there are more
+                                * PLOGIs to be sent
+                                */
+                               lpfc_more_plogi(vport);
+
+                               if (vport->num_disc_nodes == 0) {
+                                       spin_lock_irq(shost->host_lock);
+                                       vport->fc_flag &= ~FC_NDISC_ACTIVE;
+                                       spin_unlock_irq(shost->host_lock);
+                                       lpfc_can_disctmo(vport);
+                                       lpfc_end_rscn(vport);
+                               }
+                       }
+               }
+       }
+
        lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
        return 1;
 
@@ -501,12 +573,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                spin_unlock_irq(shost->host_lock);
 
                ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
-               ndlp->nlp_prev_state = ndlp->nlp_state;
-               lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
-       } else {
-               ndlp->nlp_prev_state = ndlp->nlp_state;
-               lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
        }
+       ndlp->nlp_prev_state = ndlp->nlp_state;
+       lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -594,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        return ndlp->nlp_state;
 }
 
+static uint32_t
+lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+                 void *arg, uint32_t evt)
+{
+       /* This transition is only legal if we previously
+        * rcv'ed a PLOGI. Since we don't want 2 discovery threads
+        * working on the same NPortID, do nothing for this thread
+        * to stop it.
+        */
+       if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+                        "0253 Illegal State Transition: node x%x "
+                        "event x%x, state x%x Data: x%x x%x\n",
+                        ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
+                        ndlp->nlp_flag);
+       }
+       return ndlp->nlp_state;
+}
+
 /* Start of Discovery State Machine routines */
 
 static uint32_t
@@ -605,11 +693,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
-               ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-               lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
                return ndlp->nlp_state;
        }
-       lpfc_drop_node(vport, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -618,7 +703,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                         void *arg, uint32_t evt)
 {
        lpfc_issue_els_logo(vport, ndlp, 0);
-       lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
        return ndlp->nlp_state;
 }
 
@@ -633,7 +717,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        ndlp->nlp_flag |= NLP_LOGO_ACC;
        spin_unlock_irq(shost->host_lock);
        lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
-       lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 
        return ndlp->nlp_state;
 }
@@ -642,7 +725,6 @@ static uint32_t
 lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                           void *arg, uint32_t evt)
 {
-       lpfc_drop_node(vport, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -650,7 +732,6 @@ static uint32_t
 lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                           void *arg, uint32_t evt)
 {
-       lpfc_drop_node(vport, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -752,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
                            uint32_t evt)
 {
        struct lpfc_hba    *phba = vport->phba;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        struct lpfc_iocbq  *cmdiocb, *rspiocb;
        struct lpfc_dmabuf *pcmd, *prsp, *mp;
        uint32_t *lp;
@@ -778,6 +860,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 
        lp = (uint32_t *) prsp->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+       if (wwn_to_u64(sp->portName.u.wwn) == 0 ||
+           wwn_to_u64(sp->nodeName.u.wwn) == 0) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "0142 PLOGI RSP: Invalid WWN.\n");
+               goto out;
+       }
        if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
                goto out;
        /* PLOGI chkparm OK */
@@ -828,13 +916,15 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
                }
                mbox->context2 = lpfc_nlp_get(ndlp);
                mbox->vport = vport;
-               if (lpfc_sli_issue_mbox(phba, mbox,
-                                       (MBX_NOWAIT | MBX_STOP_IOCB))
+               if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
                    != MBX_NOT_FINISHED) {
                        lpfc_nlp_set_state(vport, ndlp,
                                           NLP_STE_REG_LOGIN_ISSUE);
                        return ndlp->nlp_state;
                }
+               /* decrement node reference count to the failed mbox
+                * command
+                */
                lpfc_nlp_put(ndlp);
                mp = (struct lpfc_dmabuf *) mbox->context1;
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -864,12 +954,26 @@ out:
                                 "0261 Cannot Register NameServer login\n");
        }
 
-       /* Free this node since the driver cannot login or has the wrong
-          sparm */
-       lpfc_drop_node(vport, ndlp);
+       spin_lock_irq(shost->host_lock);
+       ndlp->nlp_flag |= NLP_DEFER_RM;
+       spin_unlock_irq(shost->host_lock);
        return NLP_STE_FREED_NODE;
 }
 
+static uint32_t
+lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+                          void *arg, uint32_t evt)
+{
+       return ndlp->nlp_state;
+}
+
+static uint32_t
+lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
+       struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
+{
+       return ndlp->nlp_state;
+}
+
 static uint32_t
 lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                           void *arg, uint32_t evt)
@@ -1137,7 +1241,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
                   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
                        mp = (struct lpfc_dmabuf *) (mb->context1);
                        if (mp) {
-                               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                               __lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
                        }
                        lpfc_nlp_put(ndlp);
@@ -1197,8 +1301,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
                 * retry discovery.
                 */
                if (mb->mbxStatus == MBXERR_RPI_FULL) {
-                       ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+                       ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
+                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
                        return ndlp->nlp_state;
                }
 
@@ -1378,7 +1482,7 @@ out:
                lpfc_issue_els_logo(vport, ndlp, 0);
 
                ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-               lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
                return ndlp->nlp_state;
        }
 
@@ -1753,7 +1857,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus) {
-               lpfc_drop_node(vport, ndlp);
+               ndlp->nlp_flag |= NLP_DEFER_RM;
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1942,9 +2046,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
        lpfc_rcv_els_plogi_issue,       /* RCV_PRLO        */
        lpfc_cmpl_plogi_plogi_issue,    /* CMPL_PLOGI      */
        lpfc_disc_illegal,              /* CMPL_PRLI       */
-       lpfc_disc_illegal,              /* CMPL_LOGO       */
+       lpfc_cmpl_logo_plogi_issue,     /* CMPL_LOGO       */
        lpfc_disc_illegal,              /* CMPL_ADISC      */
-       lpfc_disc_illegal,              /* CMPL_REG_LOGIN  */
+       lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
        lpfc_device_rm_plogi_issue,     /* DEVICE_RM       */
        lpfc_device_recov_plogi_issue,  /* DEVICE_RECOVERY */
 
@@ -1968,7 +2072,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
        lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC       */
        lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC       */
        lpfc_rcv_prlo_reglogin_issue,   /* RCV_PRLO        */
-       lpfc_disc_illegal,              /* CMPL_PLOGI      */
+       lpfc_cmpl_plogi_illegal,        /* CMPL_PLOGI      */
        lpfc_disc_illegal,              /* CMPL_PRLI       */
        lpfc_disc_illegal,              /* CMPL_LOGO       */
        lpfc_disc_illegal,              /* CMPL_ADISC      */
@@ -1982,7 +2086,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
        lpfc_rcv_padisc_prli_issue,     /* RCV_ADISC       */
        lpfc_rcv_padisc_prli_issue,     /* RCV_PDISC       */
        lpfc_rcv_prlo_prli_issue,       /* RCV_PRLO        */
-       lpfc_disc_illegal,              /* CMPL_PLOGI      */
+       lpfc_cmpl_plogi_illegal,        /* CMPL_PLOGI      */
        lpfc_cmpl_prli_prli_issue,      /* CMPL_PRLI       */
        lpfc_disc_illegal,              /* CMPL_LOGO       */
        lpfc_disc_illegal,              /* CMPL_ADISC      */
index 4e46045dea6d4e3fe6c970ddb18cceec5e0a2ada..6483c62730b3b8b71c55b10389c881ce2c222d23 100644 (file)
@@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
                        shost_for_each_device(sdev, shost) {
                                new_queue_depth =
@@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
                                                        new_queue_depth);
                        }
                }
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
        atomic_set(&phba->num_rsrc_err, 0);
        atomic_set(&phba->num_cmd_success, 0);
 }
@@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
                        shost_for_each_device(sdev, shost) {
                                if (sdev->ordered_tags)
@@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
                                                        sdev->queue_depth+1);
                        }
                }
-       lpfc_destroy_vport_work_array(vports);
+       lpfc_destroy_vport_work_array(phba, vports);
        atomic_set(&phba->num_rsrc_err, 0);
        atomic_set(&phba->num_cmd_success, 0);
 }
@@ -380,7 +380,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
                (num_bde * sizeof (struct ulp_bde64));
        iocb_cmd->ulpBdeCount = 1;
        iocb_cmd->ulpLe = 1;
-       fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
+       fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
        return 0;
 }
 
@@ -542,6 +542,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        int result;
        struct scsi_device *sdev, *tmp_sdev;
        int depth = 0;
+       unsigned long flags;
 
        lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
        lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
@@ -608,6 +609,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        cmd->scsi_done(cmd);
 
        if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+               /*
+                * If there is a thread waiting for command completion
+                * wake up the thread.
+                */
+               spin_lock_irqsave(sdev->host->host_lock, flags);
+               lpfc_cmd->pCmd = NULL;
+               if (lpfc_cmd->waitq)
+                       wake_up(lpfc_cmd->waitq);
+               spin_unlock_irqrestore(sdev->host->host_lock, flags);
                lpfc_release_scsi_buf(phba, lpfc_cmd);
                return;
        }
@@ -669,6 +679,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                }
        }
 
+       /*
+        * If there is a thread waiting for command completion
+        * wake up the thread.
+        */
+       spin_lock_irqsave(sdev->host->host_lock, flags);
+       lpfc_cmd->pCmd = NULL;
+       if (lpfc_cmd->waitq)
+               wake_up(lpfc_cmd->waitq);
+       spin_unlock_irqrestore(sdev->host->host_lock, flags);
+
        lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
@@ -743,6 +763,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
        piocbq->iocb.ulpContext = pnode->nlp_rpi;
        if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
                piocbq->iocb.ulpFCP2Rcvy = 1;
+       else
+               piocbq->iocb.ulpFCP2Rcvy = 0;
 
        piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
        piocbq->context1  = lpfc_cmd;
@@ -1018,8 +1040,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
        struct lpfc_iocbq *abtsiocb;
        struct lpfc_scsi_buf *lpfc_cmd;
        IOCB_t *cmd, *icmd;
-       unsigned int loop_count = 0;
        int ret = SUCCESS;
+       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
 
        lpfc_block_error_handler(cmnd);
        lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
@@ -1074,17 +1096,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
        if (phba->cfg_poll & DISABLE_FCP_RING_INT)
                lpfc_sli_poll_fcp_ring (phba);
 
+       lpfc_cmd->waitq = &waitq;
        /* Wait for abort to complete */
-       while (lpfc_cmd->pCmd == cmnd)
-       {
-               if (phba->cfg_poll & DISABLE_FCP_RING_INT)
-                       lpfc_sli_poll_fcp_ring (phba);
+       wait_event_timeout(waitq,
+                         (lpfc_cmd->pCmd != cmnd),
+                          (2*vport->cfg_devloss_tmo*HZ));
 
-               schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
-               if (++loop_count
-                   > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
-                       break;
-       }
+       spin_lock_irq(shost->host_lock);
+       lpfc_cmd->waitq = NULL;
+       spin_unlock_irq(shost->host_lock);
 
        if (lpfc_cmd->pCmd == cmnd) {
                ret = FAILED;
@@ -1438,7 +1458,7 @@ struct scsi_host_template lpfc_template = {
        .slave_destroy          = lpfc_slave_destroy,
        .scan_finished          = lpfc_scan_finished,
        .this_id                = -1,
-       .sg_tablesize           = LPFC_SG_SEG_CNT,
+       .sg_tablesize           = LPFC_DEFAULT_SG_SEG_CNT,
        .use_sg_chaining        = ENABLE_SG_CHAINING,
        .cmd_per_lun            = LPFC_CMD_PER_LUN,
        .use_clustering         = ENABLE_CLUSTERING,
@@ -1459,7 +1479,7 @@ struct scsi_host_template lpfc_vport_template = {
        .slave_destroy          = lpfc_slave_destroy,
        .scan_finished          = lpfc_scan_finished,
        .this_id                = -1,
-       .sg_tablesize           = LPFC_SG_SEG_CNT,
+       .sg_tablesize           = LPFC_DEFAULT_SG_SEG_CNT,
        .cmd_per_lun            = LPFC_CMD_PER_LUN,
        .use_clustering         = ENABLE_CLUSTERING,
        .use_sg_chaining        = ENABLE_SG_CHAINING,
index 31787bb6d53ef1cd9e120dead2747f02ebe12f2a..daba92374985e584d38e7e20513f36d8355bd924 100644 (file)
@@ -138,6 +138,7 @@ struct lpfc_scsi_buf {
         * Iotag is in here
         */
        struct lpfc_iocbq cur_iocbq;
+       wait_queue_head_t *waitq;
 };
 
 #define LPFC_SCSI_DMA_EXT_SIZE 264
index ce348c5c706ce901f05cc72349804c63cc2b9935..fdd01e384e363d39b0ebf0114a1df68cbdf2dc56 100644 (file)
@@ -106,7 +106,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
        return iocbq;
 }
 
-void
+static void
 __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
        size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
@@ -199,6 +199,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_RCV_ELS_REQ_CX:
        case CMD_RCV_SEQUENCE64_CX:
        case CMD_RCV_ELS_REQ64_CX:
+       case CMD_ASYNC_STATUS:
        case CMD_IOCB_RCV_SEQ64_CX:
        case CMD_IOCB_RCV_ELS64_CX:
        case CMD_IOCB_RCV_CONT64_CX:
@@ -473,8 +474,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        if (pring->txq_cnt &&
            lpfc_is_link_up(phba) &&
            (pring->ringno != phba->sli.fcp_ring ||
-            phba->sli.sli_flag & LPFC_PROCESS_LA) &&
-           !(pring->flag & LPFC_STOP_IOCB_MBX)) {
+            phba->sli.sli_flag & LPFC_PROCESS_LA)) {
 
                while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
                       (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
@@ -489,32 +489,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return;
 }
 
-/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
-static void
-lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
-{
-       struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
-               &phba->slim2p->mbx.us.s3_pgp.port[ringno] :
-               &phba->slim2p->mbx.us.s2.port[ringno];
-       unsigned long iflags;
-
-       /* If the ring is active, flag it */
-       spin_lock_irqsave(&phba->hbalock, iflags);
-       if (phba->sli.ring[ringno].cmdringaddr) {
-               if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
-                       phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
-                       /*
-                        * Force update of the local copy of cmdGetInx
-                        */
-                       phba->sli.ring[ringno].local_getidx
-                               = le32_to_cpu(pgp->cmdGetInx);
-                       lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
-               }
-       }
-       spin_unlock_irqrestore(&phba->hbalock, iflags);
-}
-
-struct lpfc_hbq_entry *
+static struct lpfc_hbq_entry *
 lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
 {
        struct hbq_s *hbqp = &phba->hbqs[hbqno];
@@ -565,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
                        list_del(&hbq_buf->dbuf.list);
                        (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
                }
+               phba->hbqs[i].buffer_count = 0;
        }
 }
 
@@ -633,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
                return 0;
        }
 
-       start = lpfc_hbq_defs[hbqno]->buffer_count;
-       end = count + lpfc_hbq_defs[hbqno]->buffer_count;
+       start = phba->hbqs[hbqno].buffer_count;
+       end = count + start;
        if (end > lpfc_hbq_defs[hbqno]->entry_count) {
                end = lpfc_hbq_defs[hbqno]->entry_count;
        }
@@ -646,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
                        return 1;
                hbq_buffer->tag = (i | (hbqno << 16));
                if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
-                       lpfc_hbq_defs[hbqno]->buffer_count++;
+                       phba->hbqs[hbqno].buffer_count++;
                else
                        (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
        }
@@ -660,14 +636,14 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
                                         lpfc_hbq_defs[qno]->add_count));
 }
 
-int
+static int
 lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
 {
        return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
                                         lpfc_hbq_defs[qno]->init_count));
 }
 
-struct hbq_dmabuf *
+static struct hbq_dmabuf *
 lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
 {
        struct lpfc_dmabuf *d_buf;
@@ -686,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
        }
        lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
                        "1803 Bad hbq tag. Data: x%x x%x\n",
-                       tag, lpfc_hbq_defs[tag >> 16]->buffer_count);
+                       tag, phba->hbqs[tag >> 16].buffer_count);
        return NULL;
 }
 
@@ -712,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_LOAD_SM:
        case MBX_READ_NV:
        case MBX_WRITE_NV:
+       case MBX_WRITE_VPARMS:
        case MBX_RUN_BIU_DIAG:
        case MBX_INIT_LINK:
        case MBX_DOWN_LINK:
@@ -739,7 +716,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_DEL_LD_ENTRY:
        case MBX_RUN_PROGRAM:
        case MBX_SET_MASK:
-       case MBX_SET_SLIM:
+       case MBX_SET_VARIABLE:
        case MBX_UNREG_D_ID:
        case MBX_KILL_BOARD:
        case MBX_CONFIG_FARP:
@@ -751,9 +728,10 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_READ_RPI64:
        case MBX_REG_LOGIN64:
        case MBX_READ_LA64:
-       case MBX_FLASH_WR_ULA:
+       case MBX_WRITE_WWN:
        case MBX_SET_DEBUG:
        case MBX_LOAD_EXP_ROM:
+       case MBX_ASYNCEVT_ENABLE:
        case MBX_REG_VPI:
        case MBX_UNREG_VPI:
        case MBX_HEARTBEAT:
@@ -953,6 +931,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
        return &new_hbq_entry->dbuf;
 }
 
+static struct lpfc_dmabuf *
+lpfc_sli_get_buff(struct lpfc_hba *phba,
+                       struct lpfc_sli_ring *pring,
+                       uint32_t tag)
+{
+       if (tag & QUE_BUFTAG_BIT)
+               return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
+       else
+               return lpfc_sli_replace_hbqbuff(phba, tag);
+}
+
 static int
 lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                            struct lpfc_iocbq *saveq)
@@ -961,19 +950,112 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        WORD5            * w5p;
        uint32_t           Rctl, Type;
        uint32_t           match, i;
+       struct lpfc_iocbq *iocbq;
 
        match = 0;
        irsp = &(saveq->iocb);
-       if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
-           || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
-           || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
-           || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
+
+       if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
+               return 1;
+       if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
+               if (pring->lpfc_sli_rcv_async_status)
+                       pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
+               else
+                       lpfc_printf_log(phba,
+                                       KERN_WARNING,
+                                       LOG_SLI,
+                                       "0316 Ring %d handler: unexpected "
+                                       "ASYNC_STATUS iocb received evt_code "
+                                       "0x%x\n",
+                                       pring->ringno,
+                                       irsp->un.asyncstat.evt_code);
+               return 1;
+       }
+
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               if (irsp->ulpBdeCount != 0) {
+                       saveq->context2 = lpfc_sli_get_buff(phba, pring,
+                                               irsp->un.ulpWord[3]);
+                       if (!saveq->context2)
+                               lpfc_printf_log(phba,
+                                       KERN_ERR,
+                                       LOG_SLI,
+                                       "0341 Ring %d Cannot find buffer for "
+                                       "an unsolicited iocb. tag 0x%x\n",
+                                       pring->ringno,
+                                       irsp->un.ulpWord[3]);
+               }
+               if (irsp->ulpBdeCount == 2) {
+                       saveq->context3 = lpfc_sli_get_buff(phba, pring,
+                                               irsp->unsli3.sli3Words[7]);
+                       if (!saveq->context3)
+                               lpfc_printf_log(phba,
+                                       KERN_ERR,
+                                       LOG_SLI,
+                                       "0342 Ring %d Cannot find buffer for an"
+                                       " unsolicited iocb. tag 0x%x\n",
+                                       pring->ringno,
+                                       irsp->unsli3.sli3Words[7]);
+               }
+               list_for_each_entry(iocbq, &saveq->list, list) {
+                       irsp = &(iocbq->iocb);
+                       if (irsp->ulpBdeCount != 0) {
+                               iocbq->context2 = lpfc_sli_get_buff(phba, pring,
+                                                       irsp->un.ulpWord[3]);
+                               if (!iocbq->context2)
+                                       lpfc_printf_log(phba,
+                                               KERN_ERR,
+                                               LOG_SLI,
+                                               "0343 Ring %d Cannot find "
+                                               "buffer for an unsolicited iocb"
+                                               ". tag 0x%x\n", pring->ringno,
+                                               irsp->un.ulpWord[3]);
+                       }
+                       if (irsp->ulpBdeCount == 2) {
+                               iocbq->context3 = lpfc_sli_get_buff(phba, pring,
+                                               irsp->unsli3.sli3Words[7]);
+                               if (!iocbq->context3)
+                                       lpfc_printf_log(phba,
+                                               KERN_ERR,
+                                               LOG_SLI,
+                                               "0344 Ring %d Cannot find "
+                                               "buffer for an unsolicited "
+                                               "iocb. tag 0x%x\n",
+                                               pring->ringno,
+                                               irsp->unsli3.sli3Words[7]);
+                       }
+               }
+       }
+       if (irsp->ulpBdeCount != 0 &&
+           (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
+            irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
+               int found = 0;
+
+               /* search continue save q for same XRI */
+               list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
+                       if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
+                               list_add_tail(&saveq->list, &iocbq->list);
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       list_add_tail(&saveq->clist,
+                                     &pring->iocb_continue_saveq);
+               if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
+                       list_del_init(&iocbq->clist);
+                       saveq = iocbq;
+                       irsp = &(saveq->iocb);
+               } else
+                       return 0;
+       }
+       if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
+           (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
+           (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
                Rctl = FC_ELS_REQ;
                Type = FC_ELS_DATA;
        } else {
-               w5p =
-                   (WORD5 *) & (saveq->iocb.un.
-                                ulpWord[5]);
+               w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
                Rctl = w5p->hcsw.Rctl;
                Type = w5p->hcsw.Type;
 
@@ -988,15 +1070,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                }
        }
 
-       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-               if (irsp->ulpBdeCount != 0)
-                       saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
-                                               irsp->un.ulpWord[3]);
-               if (irsp->ulpBdeCount == 2)
-                       saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
-                                               irsp->unsli3.sli3Words[7]);
-       }
-
        /* unSolicited Responses */
        if (pring->prt[0].profile) {
                if (pring->prt[0].lpfc_sli_rcv_unsol_event)
@@ -1006,12 +1079,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        } else {
                /* We must search, based on rctl / type
                   for the right routine */
-               for (i = 0; i < pring->num_mask;
-                    i++) {
-                       if ((pring->prt[i].rctl ==
-                            Rctl)
-                           && (pring->prt[i].
-                               type == Type)) {
+               for (i = 0; i < pring->num_mask; i++) {
+                       if ((pring->prt[i].rctl == Rctl)
+                           && (pring->prt[i].type == Type)) {
                                if (pring->prt[i].lpfc_sli_rcv_unsol_event)
                                        (pring->prt[i].lpfc_sli_rcv_unsol_event)
                                                        (phba, pring, saveq);
@@ -1084,6 +1154,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                                IOSTAT_LOCAL_REJECT;
                                        saveq->iocb.un.ulpWord[4] =
                                                IOERR_SLI_ABORTED;
+
+                                       /* Firmware could still be in progress
+                                        * of DMAing payload, so don't free data
+                                        * buffer till after a hbeat.
+                                        */
+                                       saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
                                }
                        }
                        (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1572,12 +1648,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 
                writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
-               if (list_empty(&(pring->iocb_continueq))) {
-                       list_add(&rspiocbp->list, &(pring->iocb_continueq));
-               } else {
-                       list_add_tail(&rspiocbp->list,
-                                     &(pring->iocb_continueq));
-               }
+               list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
 
                pring->iocb_continueq_cnt++;
                if (irsp->ulpLe) {
@@ -1642,17 +1713,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
                        iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
                        type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
                        if (type == LPFC_SOL_IOCB) {
-                               spin_unlock_irqrestore(&phba->hbalock,
-                                                      iflag);
+                               spin_unlock_irqrestore(&phba->hbalock, iflag);
                                rc = lpfc_sli_process_sol_iocb(phba, pring,
                                                               saveq);
                                spin_lock_irqsave(&phba->hbalock, iflag);
                        } else if (type == LPFC_UNSOL_IOCB) {
-                               spin_unlock_irqrestore(&phba->hbalock,
-                                                      iflag);
+                               spin_unlock_irqrestore(&phba->hbalock, iflag);
                                rc = lpfc_sli_process_unsol_iocb(phba, pring,
                                                                 saveq);
                                spin_lock_irqsave(&phba->hbalock, iflag);
+                               if (!rc)
+                                       free_saveq = 0;
                        } else if (type == LPFC_ABORT_IOCB) {
                                if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
                                    ((cmdiocbp =
@@ -1921,8 +1992,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
                        "0329 Kill HBA Data: x%x x%x\n",
                        phba->pport->port_state, psli->sli_flag);
 
-       if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
-                                                 GFP_KERNEL)) == 0)
+       pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb)
                return 1;
 
        /* Disable the error attention */
@@ -2113,7 +2184,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
                           <status> */
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "0436 Adapter failed to init, "
-                                       "timeout, status reg x%x\n", status);
+                                       "timeout, status reg x%x, "
+                                       "FW Data: A8 x%x AC x%x\n", status,
+                                       readl(phba->MBslimaddr + 0xa8),
+                                       readl(phba->MBslimaddr + 0xac));
                        phba->link_state = LPFC_HBA_ERROR;
                        return -ETIMEDOUT;
                }
@@ -2125,7 +2199,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
                           <status> */
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "0437 Adapter failed to init, "
-                                       "chipset, status reg x%x\n", status);
+                                       "chipset, status reg x%x, "
+                                       "FW Data: A8 x%x AC x%x\n", status,
+                                       readl(phba->MBslimaddr + 0xa8),
+                                       readl(phba->MBslimaddr + 0xac));
                        phba->link_state = LPFC_HBA_ERROR;
                        return -EIO;
                }
@@ -2153,7 +2230,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
                /* Adapter failed to init, chipset, status reg <status> */
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "0438 Adapter failed to init, chipset, "
-                               "status reg x%x\n", status);
+                               "status reg x%x, "
+                               "FW Data: A8 x%x AC x%x\n", status,
+                               readl(phba->MBslimaddr + 0xa8),
+                               readl(phba->MBslimaddr + 0xac));
                phba->link_state = LPFC_HBA_ERROR;
                return -EIO;
        }
@@ -2485,11 +2565,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
        lpfc_sli_abort_iocb_ring(phba, pring);
 
        lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-                       "0316 Resetting board due to mailbox timeout\n");
+                       "0345 Resetting board due to mailbox timeout\n");
        /*
         * lpfc_offline calls lpfc_sli_hba_down which will clean up
         * on oustanding mailbox commands.
         */
+       /* If resets are disabled then set error state and return. */
+       if (!phba->cfg_enable_hba_reset) {
+               phba->link_state = LPFC_HBA_ERROR;
+               return;
+       }
        lpfc_offline_prep(phba);
        lpfc_offline(phba);
        lpfc_sli_brdrestart(phba);
@@ -2507,6 +2592,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
        uint32_t status, evtctr;
        uint32_t ha_copy;
        int i;
+       unsigned long timeout;
        unsigned long drvr_flag = 0;
        volatile uint32_t word0, ldata;
        void __iomem *to_slim;
@@ -2519,7 +2605,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                                        "1806 Mbox x%x failed. No vport\n",
                                        pmbox->mb.mbxCommand);
                        dump_stack();
-                       return MBXERR_ERROR;
+                       return MBX_NOT_FINISHED;
                }
        }
 
@@ -2571,21 +2657,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                        return MBX_NOT_FINISHED;
                }
 
-               /* Handle STOP IOCB processing flag. This is only meaningful
-                * if we are not polling for mbox completion.
-                */
-               if (flag & MBX_STOP_IOCB) {
-                       flag &= ~MBX_STOP_IOCB;
-                       /* Now flag each ring */
-                       for (i = 0; i < psli->num_rings; i++) {
-                               /* If the ring is active, flag it */
-                               if (psli->ring[i].cmdringaddr) {
-                                       psli->ring[i].flag |=
-                                           LPFC_STOP_IOCB_MBX;
-                               }
-                       }
-               }
-
                /* Another mailbox command is still being processed, queue this
                 * command to be processed later.
                 */
@@ -2620,23 +2691,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                return MBX_BUSY;
        }
 
-       /* Handle STOP IOCB processing flag. This is only meaningful
-        * if we are not polling for mbox completion.
-        */
-       if (flag & MBX_STOP_IOCB) {
-               flag &= ~MBX_STOP_IOCB;
-               if (flag == MBX_NOWAIT) {
-                       /* Now flag each ring */
-                       for (i = 0; i < psli->num_rings; i++) {
-                               /* If the ring is active, flag it */
-                               if (psli->ring[i].cmdringaddr) {
-                                       psli->ring[i].flag |=
-                                           LPFC_STOP_IOCB_MBX;
-                               }
-                       }
-               }
-       }
-
        psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
 
        /* If we are not polling, we MUST be in SLI2 mode */
@@ -2714,18 +2768,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
        }
 
        wmb();
-       /* interrupt board to doit right away */
-       writel(CA_MBATT, phba->CAregaddr);
-       readl(phba->CAregaddr); /* flush */
 
        switch (flag) {
        case MBX_NOWAIT:
-               /* Don't wait for it to finish, just return */
+               /* Set up reference to mailbox command */
                psli->mbox_active = pmbox;
+               /* Interrupt board to do it */
+               writel(CA_MBATT, phba->CAregaddr);
+               readl(phba->CAregaddr); /* flush */
+               /* Don't wait for it to finish, just return */
                break;
 
        case MBX_POLL:
+               /* Set up null reference to mailbox command */
                psli->mbox_active = NULL;
+               /* Interrupt board to do it */
+               writel(CA_MBATT, phba->CAregaddr);
+               readl(phba->CAregaddr); /* flush */
+
                if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                        /* First read mbox status word */
                        word0 = *((volatile uint32_t *)&phba->slim2p->mbx);
@@ -2737,15 +2797,15 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
                /* Read the HBA Host Attention Register */
                ha_copy = readl(phba->HAregaddr);
-
-               i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
-               i *= 1000; /* Convert to ms */
-
+               timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba,
+                                                            mb->mbxCommand) *
+                                          1000) + jiffies;
+               i = 0;
                /* Wait for command to complete */
                while (((word0 & OWN_CHIP) == OWN_CHIP) ||
                       (!(ha_copy & HA_MBATT) &&
                        (phba->link_state > LPFC_WARM_START))) {
-                       if (i-- <= 0) {
+                       if (time_after(jiffies, timeout)) {
                                psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
                                spin_unlock_irqrestore(&phba->hbalock,
                                                       drvr_flag);
@@ -2758,12 +2818,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                            && (evtctr != psli->slistat.mbox_event))
                                break;
 
-                       spin_unlock_irqrestore(&phba->hbalock,
-                                              drvr_flag);
-
-                       msleep(1);
-
-                       spin_lock_irqsave(&phba->hbalock, drvr_flag);
+                       if (i++ > 10) {
+                               spin_unlock_irqrestore(&phba->hbalock,
+                                                      drvr_flag);
+                               msleep(1);
+                               spin_lock_irqsave(&phba->hbalock, drvr_flag);
+                       }
 
                        if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                                /* First copy command data */
@@ -2848,7 +2908,7 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 /*
  * Lockless version of lpfc_sli_issue_iocb.
  */
-int
+static int
 __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                    struct lpfc_iocbq *piocb, uint32_t flag)
 {
@@ -2879,9 +2939,9 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        /*
         * Check to see if we are blocking IOCB processing because of a
-        * outstanding mbox command.
+        * outstanding event.
         */
-       if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
+       if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT))
                goto iocb_busy;
 
        if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
@@ -2993,6 +3053,61 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
        return 0;
 }
 
+static void
+lpfc_sli_async_event_handler(struct lpfc_hba * phba,
+       struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq)
+{
+       IOCB_t *icmd;
+       uint16_t evt_code;
+       uint16_t temp;
+       struct temp_event temp_event_data;
+       struct Scsi_Host *shost;
+
+       icmd = &iocbq->iocb;
+       evt_code = icmd->un.asyncstat.evt_code;
+       temp = icmd->ulpContext;
+
+       if ((evt_code != ASYNC_TEMP_WARN) &&
+               (evt_code != ASYNC_TEMP_SAFE)) {
+               lpfc_printf_log(phba,
+                       KERN_ERR,
+                       LOG_SLI,
+                       "0346 Ring %d handler: unexpected ASYNC_STATUS"
+                       " evt_code 0x%x\n",
+                       pring->ringno,
+                       icmd->un.asyncstat.evt_code);
+               return;
+       }
+       temp_event_data.data = (uint32_t)temp;
+       temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
+       if (evt_code == ASYNC_TEMP_WARN) {
+               temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
+               lpfc_printf_log(phba,
+                               KERN_ERR,
+                               LOG_TEMP,
+                               "0347 Adapter is very hot, please take "
+                               "corrective action. temperature : %d Celsius\n",
+                               temp);
+       }
+       if (evt_code == ASYNC_TEMP_SAFE) {
+               temp_event_data.event_code = LPFC_NORMAL_TEMP;
+               lpfc_printf_log(phba,
+                               KERN_ERR,
+                               LOG_TEMP,
+                               "0340 Adapter temperature is OK now. "
+                               "temperature : %d Celsius\n",
+                               temp);
+       }
+
+       /* Send temperature change event to applications */
+       shost = lpfc_shost_from_vport(phba->pport);
+       fc_host_post_vendor_event(shost, fc_get_event_number(),
+               sizeof(temp_event_data), (char *) &temp_event_data,
+               SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+
+}
+
+
 int
 lpfc_sli_setup(struct lpfc_hba *phba)
 {
@@ -3059,6 +3174,8 @@ lpfc_sli_setup(struct lpfc_hba *phba)
                        pring->fast_iotag = 0;
                        pring->iotag_ctr = 0;
                        pring->iotag_max = 4096;
+                       pring->lpfc_sli_rcv_async_status =
+                               lpfc_sli_async_event_handler;
                        pring->num_mask = 4;
                        pring->prt[0].profile = 0;      /* Mask 0 */
                        pring->prt[0].rctl = FC_ELS_REQ;
@@ -3123,6 +3240,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
                INIT_LIST_HEAD(&pring->txq);
                INIT_LIST_HEAD(&pring->txcmplq);
                INIT_LIST_HEAD(&pring->iocb_continueq);
+               INIT_LIST_HEAD(&pring->iocb_continue_saveq);
                INIT_LIST_HEAD(&pring->postbufq);
        }
        spin_unlock_irq(&phba->hbalock);
@@ -3193,6 +3311,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
        LIST_HEAD(completions);
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
+       struct lpfc_dmabuf *buf_ptr;
        LPFC_MBOXQ_t *pmb;
        struct lpfc_iocbq *iocb;
        IOCB_t *cmd = NULL;
@@ -3232,6 +3351,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
                }
        }
 
+       spin_lock_irqsave(&phba->hbalock, flags);
+       list_splice_init(&phba->elsbuf, &completions);
+       phba->elsbuf_cnt = 0;
+       phba->elsbuf_prev_cnt = 0;
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+
+       while (!list_empty(&completions)) {
+               list_remove_head(&completions, buf_ptr,
+                       struct lpfc_dmabuf, list);
+               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+               kfree(buf_ptr);
+       }
+
        /* Return any active mbox cmds */
        del_timer_sync(&psli->mbox_tmo);
        spin_lock_irqsave(&phba->hbalock, flags);
@@ -3294,6 +3426,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return 0;
 }
 
+uint32_t
+lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
+{
+       spin_lock_irq(&phba->hbalock);
+       phba->buffer_tag_count++;
+       /*
+        * Always set the QUE_BUFTAG_BIT to distiguish between
+        * a tag assigned by HBQ.
+        */
+       phba->buffer_tag_count |= QUE_BUFTAG_BIT;
+       spin_unlock_irq(&phba->hbalock);
+       return phba->buffer_tag_count;
+}
+
+struct lpfc_dmabuf *
+lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+                       uint32_t tag)
+{
+       struct lpfc_dmabuf *mp, *next_mp;
+       struct list_head *slp = &pring->postbufq;
+
+       /* Search postbufq, from the begining, looking for a match on tag */
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+               if (mp->buffer_tag == tag) {
+                       list_del_init(&mp->list);
+                       pring->postbufq_cnt--;
+                       spin_unlock_irq(&phba->hbalock);
+                       return mp;
+               }
+       }
+
+       spin_unlock_irq(&phba->hbalock);
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "0410 Cannot find virtual addr for buffer tag on "
+                       "ring %d Data x%lx x%p x%p x%x\n",
+                       pring->ringno, (unsigned long) tag,
+                       slp->next, slp->prev, pring->postbufq_cnt);
+
+       return NULL;
+}
 
 struct lpfc_dmabuf *
 lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
@@ -3361,6 +3534,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        pring->txcmplq_cnt--;
                        spin_unlock_irq(&phba->hbalock);
 
+                       /* Firmware could still be in progress of DMAing
+                        * payload, so don't free data buffer till after
+                        * a hbeat.
+                        */
+                       abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
+
                        abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
                        abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
                        abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
@@ -3699,7 +3878,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
        unsigned long flag;
 
        /* The caller must leave context1 empty. */
-       if (pmboxq->context1 != 0)
+       if (pmboxq->context1)
                return MBX_NOT_FINISHED;
 
        /* setup wake call as IOCB callback */
@@ -3771,7 +3950,6 @@ lpfc_intr_handler(int irq, void *dev_id)
        uint32_t ha_copy;
        uint32_t work_ha_copy;
        unsigned long status;
-       int i;
        uint32_t control;
 
        MAILBOX_t *mbox, *pmbox;
@@ -3888,7 +4066,6 @@ lpfc_intr_handler(int irq, void *dev_id)
                }
 
                if (work_ha_copy & HA_ERATT) {
-                       phba->link_state = LPFC_HBA_ERROR;
                        /*
                         * There was a link/board error.  Read the
                         * status register to retrieve the error event
@@ -3920,7 +4097,7 @@ lpfc_intr_handler(int irq, void *dev_id)
                                 * Stray Mailbox Interrupt, mbxCommand <cmd>
                                 * mbxStatus <status>
                                 */
-                               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
+                               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
                                                LOG_SLI,
                                                "(%d):0304 Stray Mailbox "
                                                "Interrupt mbxCommand x%x "
@@ -3928,51 +4105,60 @@ lpfc_intr_handler(int irq, void *dev_id)
                                                (vport ? vport->vpi : 0),
                                                pmbox->mbxCommand,
                                                pmbox->mbxStatus);
-                       }
-                       phba->last_completion_time = jiffies;
-                       del_timer_sync(&phba->sli.mbox_tmo);
-
-                       phba->sli.mbox_active = NULL;
-                       if (pmb->mbox_cmpl) {
-                               lpfc_sli_pcimem_bcopy(mbox, pmbox,
-                                                     MAILBOX_CMD_SIZE);
-                       }
-                       if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
-                               pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+                               /* clear mailbox attention bit */
+                               work_ha_copy &= ~HA_MBATT;
+                       } else {
+                               phba->last_completion_time = jiffies;
+                               del_timer(&phba->sli.mbox_tmo);
 
-                               lpfc_debugfs_disc_trc(vport,
-                                       LPFC_DISC_TRC_MBOX_VPORT,
-                                       "MBOX dflt rpi: : status:x%x rpi:x%x",
-                                       (uint32_t)pmbox->mbxStatus,
-                                       pmbox->un.varWords[0], 0);
-
-                               if ( !pmbox->mbxStatus) {
-                                       mp = (struct lpfc_dmabuf *)
-                                               (pmb->context1);
-                                       ndlp = (struct lpfc_nodelist *)
-                                               pmb->context2;
-
-                                       /* Reg_LOGIN of dflt RPI was successful.
-                                        * new lets get rid of the RPI using the
-                                        * same mbox buffer.
-                                        */
-                                       lpfc_unreg_login(phba, vport->vpi,
-                                               pmbox->un.varWords[0], pmb);
-                                       pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
-                                       pmb->context1 = mp;
-                                       pmb->context2 = ndlp;
-                                       pmb->vport = vport;
-                                       spin_lock(&phba->hbalock);
-                                       phba->sli.sli_flag &=
-                                               ~LPFC_SLI_MBOX_ACTIVE;
-                                       spin_unlock(&phba->hbalock);
-                                       goto send_current_mbox;
+                               phba->sli.mbox_active = NULL;
+                               if (pmb->mbox_cmpl) {
+                                       lpfc_sli_pcimem_bcopy(mbox, pmbox,
+                                                       MAILBOX_CMD_SIZE);
+                               }
+                               if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+                                       pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+
+                                       lpfc_debugfs_disc_trc(vport,
+                                               LPFC_DISC_TRC_MBOX_VPORT,
+                                               "MBOX dflt rpi: : "
+                                               "status:x%x rpi:x%x",
+                                               (uint32_t)pmbox->mbxStatus,
+                                               pmbox->un.varWords[0], 0);
+
+                                       if (!pmbox->mbxStatus) {
+                                               mp = (struct lpfc_dmabuf *)
+                                                       (pmb->context1);
+                                               ndlp = (struct lpfc_nodelist *)
+                                                       pmb->context2;
+
+                                               /* Reg_LOGIN of dflt RPI was
+                                                * successful. new lets get
+                                                * rid of the RPI using the
+                                                * same mbox buffer.
+                                                */
+                                               lpfc_unreg_login(phba,
+                                                       vport->vpi,
+                                                       pmbox->un.varWords[0],
+                                                       pmb);
+                                               pmb->mbox_cmpl =
+                                                       lpfc_mbx_cmpl_dflt_rpi;
+                                               pmb->context1 = mp;
+                                               pmb->context2 = ndlp;
+                                               pmb->vport = vport;
+                                               spin_lock(&phba->hbalock);
+                                               phba->sli.sli_flag &=
+                                                       ~LPFC_SLI_MBOX_ACTIVE;
+                                               spin_unlock(&phba->hbalock);
+                                               goto send_current_mbox;
+                                       }
                                }
+                               spin_lock(&phba->pport->work_port_lock);
+                               phba->pport->work_port_events &=
+                                       ~WORKER_MBOX_TMO;
+                               spin_unlock(&phba->pport->work_port_lock);
+                               lpfc_mbox_cmpl_put(phba, pmb);
                        }
-                       spin_lock(&phba->pport->work_port_lock);
-                       phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
-                       spin_unlock(&phba->pport->work_port_lock);
-                       lpfc_mbox_cmpl_put(phba, pmb);
                }
                if ((work_ha_copy & HA_MBATT) &&
                    (phba->sli.mbox_active == NULL)) {
@@ -3990,10 +4176,6 @@ send_current_mbox:
                                        lpfc_mbox_cmpl_put(phba, pmb);
                                        goto send_next_mbox;
                                }
-                       } else {
-                               /* Turn on IOCB processing */
-                               for (i = 0; i < phba->sli.num_rings; i++)
-                                       lpfc_sli_turn_on_ring(phba, i);
                        }
 
                }
index 51b2b6b949be498fa710b2cecee55a3be5b9b3f6..7249fd252cbbbd8a34a8a6a9da420c1aea78f222 100644 (file)
@@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd {
 struct lpfc_iocbq {
        /* lpfc_iocbqs are used in double linked lists */
        struct list_head list;
+       struct list_head clist;
        uint16_t iotag;         /* pre-assigned IO tag */
        uint16_t rsvd1;
 
@@ -44,6 +45,7 @@ struct lpfc_iocbq {
 #define LPFC_IO_FCP            4       /* FCP command -- iocbq in scsi_buf */
 #define LPFC_DRIVER_ABORTED    8       /* driver aborted this request */
 #define LPFC_IO_FABRIC         0x10    /* Iocb send using fabric scheduler */
+#define LPFC_DELAY_MEM_FREE    0x20    /* Defer free'ing of FC data */
 
        uint8_t abort_count;
        uint8_t rsvd2;
@@ -92,8 +94,6 @@ typedef struct lpfcMboxq {
 #define MBX_POLL        1      /* poll mailbox till command done, then
                                   return */
 #define MBX_NOWAIT      2      /* issue command then return immediately */
-#define MBX_STOP_IOCB   4      /* Stop iocb processing till mbox cmds
-                                  complete */
 
 #define LPFC_MAX_RING_MASK  4  /* max num of rctl/type masks allowed per
                                   ring */
@@ -129,9 +129,7 @@ struct lpfc_sli_ring {
        uint16_t flag;          /* ring flags */
 #define LPFC_DEFERRED_RING_EVENT 0x001 /* Deferred processing a ring event */
 #define LPFC_CALL_RING_AVAILABLE 0x002 /* indicates cmd was full */
-#define LPFC_STOP_IOCB_MBX       0x010 /* Stop processing IOCB cmds mbox */
 #define LPFC_STOP_IOCB_EVENT     0x020 /* Stop processing IOCB cmds event */
-#define LPFC_STOP_IOCB_MASK      0x030 /* Stop processing IOCB cmds mask */
        uint16_t abtsiotag;     /* tracks next iotag to use for ABTS */
 
        uint32_t local_getidx;   /* last available cmd index (from cmdGetInx) */
@@ -163,9 +161,12 @@ struct lpfc_sli_ring {
        struct list_head iocb_continueq;
        uint16_t iocb_continueq_cnt;    /* current length of queue */
        uint16_t iocb_continueq_max;    /* max length */
+       struct list_head iocb_continue_saveq;
 
        struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
        uint32_t num_mask;      /* number of mask entries in prt array */
+       void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *,
+               struct lpfc_sli_ring *, struct lpfc_iocbq *);
 
        struct lpfc_sli_ring_stat stats;        /* SLI statistical info */
 
@@ -199,9 +200,6 @@ struct lpfc_hbq_init {
        uint32_t add_count;     /* number to allocate when starved */
 } ;
 
-#define LPFC_MAX_HBQ 16
-
-
 /* Structure used to hold SLI statistical counters and info */
 struct lpfc_sli_stat {
        uint64_t mbox_stat_err;  /* Mbox cmds completed status error */
index 0081f49286bc131f5f358a12886b87091e1ff24d..4b633d39a82ae6b4c221b54cd13a781f3523201b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.2.2"
+#define LPFC_DRIVER_VERSION "8.2.4"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
                LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
+#define LPFC_COPYRIGHT "Copyright(c) 2004-2008 Emulex.  All rights reserved."
index dcb415e717c372230aefaf0ff384294d0edfe63d..9fad7663c1171020a370e48b2408d2d307b6236b 100644 (file)
@@ -125,15 +125,26 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
        pmb->vport = vport;
        rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
        if (rc != MBX_SUCCESS) {
-               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
-                                "1818 VPort failed init, mbxCmd x%x "
-                                "READ_SPARM mbxStatus x%x, rc = x%x\n",
-                                mb->mbxCommand, mb->mbxStatus, rc);
-               lpfc_mbuf_free(phba, mp->virt, mp->phys);
-               kfree(mp);
-               if (rc != MBX_TIMEOUT)
-                       mempool_free(pmb, phba->mbox_mem_pool);
-               return -EIO;
+               if (signal_pending(current)) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+                                        "1830 Signal aborted mbxCmd x%x\n",
+                                        mb->mbxCommand);
+                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                       kfree(mp);
+                       if (rc != MBX_TIMEOUT)
+                               mempool_free(pmb, phba->mbox_mem_pool);
+                       return -EINTR;
+               } else {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+                                        "1818 VPort failed init, mbxCmd x%x "
+                                        "READ_SPARM mbxStatus x%x, rc = x%x\n",
+                                        mb->mbxCommand, mb->mbxStatus, rc);
+                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                       kfree(mp);
+                       if (rc != MBX_TIMEOUT)
+                               mempool_free(pmb, phba->mbox_mem_pool);
+                       return -EIO;
+               }
        }
 
        memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
@@ -204,6 +215,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
        int instance;
        int vpi;
        int rc = VPORT_ERROR;
+       int status;
 
        if ((phba->sli_rev < 3) ||
                !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
@@ -248,13 +260,19 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
        vport->vpi = vpi;
        lpfc_debugfs_initialize(vport);
 
-       if (lpfc_vport_sparm(phba, vport)) {
-               lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
-                                "1813 Create VPORT failed. "
-                                "Cannot get sparam\n");
+       if ((status = lpfc_vport_sparm(phba, vport))) {
+               if (status == -EINTR) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+                                        "1831 Create VPORT Interrupted.\n");
+                       rc = VPORT_ERROR;
+               } else {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+                                        "1813 Create VPORT failed. "
+                                        "Cannot get sparam\n");
+                       rc = VPORT_NORESOURCES;
+               }
                lpfc_free_vpi(phba, vpi);
                destroy_port(vport);
-               rc = VPORT_NORESOURCES;
                goto error_out;
        }
 
@@ -427,7 +445,6 @@ int
 lpfc_vport_delete(struct fc_vport *fc_vport)
 {
        struct lpfc_nodelist *ndlp = NULL;
-       struct lpfc_nodelist *next_ndlp;
        struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
        struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
        struct lpfc_hba   *phba = vport->phba;
@@ -482,8 +499,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
 
        ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
        if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
-               phba->link_state >= LPFC_LINK_UP) {
-
+           phba->link_state >= LPFC_LINK_UP) {
+               if (vport->cfg_enable_da_id) {
+                       timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+                       if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
+                               while (vport->ct_flags && timeout)
+                                       timeout = schedule_timeout(timeout);
+                       else
+                               lpfc_printf_log(vport->phba, KERN_WARNING,
+                                               LOG_VPORT,
+                                               "1829 CT command failed to "
+                                               "delete objects on fabric. \n");
+               }
                /* First look for the Fabric ndlp */
                ndlp = lpfc_findnode_did(vport, Fabric_DID);
                if (!ndlp) {
@@ -503,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
        }
 
 skip_logo:
+       lpfc_cleanup(vport);
        lpfc_sli_host_down(vport);
 
-       list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
-               lpfc_disc_state_machine(vport, ndlp, NULL,
-                                            NLP_EVT_DEVICE_RECOVERY);
-               lpfc_disc_state_machine(vport, ndlp, NULL,
-                                            NLP_EVT_DEVICE_RM);
-       }
-
        lpfc_stop_vport_timers(vport);
        lpfc_unreg_all_rpis(vport);
-       lpfc_unreg_default_rpis(vport);
-       /*
-        * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
-        * scsi_host_put() to release the vport.
-        */
-       lpfc_mbx_unreg_vpi(vport);
+
+       if (!(phba->pport->load_flag & FC_UNLOADING)) {
+               lpfc_unreg_default_rpis(vport);
+               /*
+                * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
+                * does the scsi_host_put() to release the vport.
+                */
+               lpfc_mbx_unreg_vpi(vport);
+       }
 
        lpfc_free_vpi(phba, vport->vpi);
        vport->work_port_events = 0;
@@ -532,16 +556,13 @@ skip_logo:
        return VPORT_OK;
 }
 
-EXPORT_SYMBOL(lpfc_vport_create);
-EXPORT_SYMBOL(lpfc_vport_delete);
-
 struct lpfc_vport **
 lpfc_create_vport_work_array(struct lpfc_hba *phba)
 {
        struct lpfc_vport *port_iterator;
        struct lpfc_vport **vports;
        int index = 0;
-       vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
+       vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
                         GFP_KERNEL);
        if (vports == NULL)
                return NULL;
@@ -560,12 +581,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
 }
 
 void
-lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
+lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
 {
        int i;
        if (vports == NULL)
                return;
-       for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
+       for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
                scsi_host_put(lpfc_shost_from_vport(vports[i]));
        kfree(vports);
 }
index 91da17751a37273419ce5e95f09eef98daa07126..96c445333b69482d13499379bbd0ce38c6d43600 100644 (file)
@@ -89,7 +89,7 @@ int lpfc_vport_delete(struct fc_vport *);
 int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
 int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
 struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
-void lpfc_destroy_vport_work_array(struct lpfc_vport **);
+void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **);
 
 /*
  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.
index 66c652035730387e48d8532579a1986c2ffaa137..765c24d2bc3842d54da9ffcc214cff782d46eaaa 100644 (file)
@@ -4889,7 +4889,7 @@ __megaraid_shutdown(adapter_t *adapter)
                mdelay(1000);
 }
 
-static void
+static void __devexit
 megaraid_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
index c8923108183a5f6a976f33773266d0781170dfae..24e32e446e76048ed461c105539e730a9376ad98 100644 (file)
@@ -300,7 +300,7 @@ static struct pci_device_id pci_id_table_g[] =  {
 MODULE_DEVICE_TABLE(pci, pci_id_table_g);
 
 
-static struct pci_driver megaraid_pci_driver_g = {
+static struct pci_driver megaraid_pci_driver = {
        .name           = "megaraid",
        .id_table       = pci_id_table_g,
        .probe          = megaraid_probe_one,
@@ -394,7 +394,7 @@ megaraid_init(void)
 
 
        // register as a PCI hot-plug driver module
-       rval = pci_register_driver(&megaraid_pci_driver_g);
+       rval = pci_register_driver(&megaraid_pci_driver);
        if (rval < 0) {
                con_log(CL_ANN, (KERN_WARNING
                        "megaraid: could not register hotplug support.\n"));
@@ -415,7 +415,7 @@ megaraid_exit(void)
        con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
 
        // unregister as PCI hotplug driver
-       pci_unregister_driver(&megaraid_pci_driver_g);
+       pci_unregister_driver(&megaraid_pci_driver);
 
        return;
 }
index e3c5c52822030f42283b6c9baa357f1921238336..d7ec921865c4fdf4a911fd6c46f97e6b12ff9cd5 100644 (file)
@@ -2,7 +2,7 @@
  *
  *             Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Logic Corporation.
+ * Copyright (c) 2003-2005  LSI Corporation.
  *
  *        This program is free software; you can redistribute it and/or
  *        modify it under the terms of the GNU General Public License
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.03.10-rc5
+ * Version     : v00.00.03.16-rc1
  *
  * Authors:
  *     (email-id : megaraidlinux@lsi.com)
@@ -31,6 +31,7 @@
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/uio.h>
 #include <scsi/scsi_host.h>
 #include "megaraid_sas.h"
 
+/*
+ * poll_mode_io:1- schedule complete completion from q cmd
+ */
+static unsigned int poll_mode_io;
+module_param_named(poll_mode_io, poll_mode_io, int, 0);
+MODULE_PARM_DESC(poll_mode_io,
+       "Complete cmds from IO path, (default=0)");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux@lsi.com");
-MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
+MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
 
 /*
  * PCI ID table for all supported controllers
@@ -76,6 +85,10 @@ static DEFINE_MUTEX(megasas_async_queue_mutex);
 
 static u32 megasas_dbg_lvl;
 
+static void
+megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+                    u8 alt_status);
+
 /**
  * megasas_get_cmd -   Get a command from the free pool
  * @instance:          Adapter soft state
@@ -855,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
        atomic_inc(&instance->fw_outstanding);
 
        instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
+       /*
+        * Check if we have pend cmds to be completed
+        */
+       if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+               tasklet_schedule(&instance->isr_tasklet);
+
 
        return 0;
 
@@ -885,6 +904,64 @@ static int megasas_slave_configure(struct scsi_device *sdev)
        return 0;
 }
 
+/**
+ * megasas_complete_cmd_dpc     -      Returns FW's controller structure
+ * @instance_addr:                     Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+       u32 producer;
+       u32 consumer;
+       u32 context;
+       struct megasas_cmd *cmd;
+       struct megasas_instance *instance =
+                               (struct megasas_instance *)instance_addr;
+       unsigned long flags;
+
+       /* If we have already declared adapter dead, donot complete cmds */
+       if (instance->hw_crit_error)
+               return;
+
+       spin_lock_irqsave(&instance->completion_lock, flags);
+
+       producer = *instance->producer;
+       consumer = *instance->consumer;
+
+       while (consumer != producer) {
+               context = instance->reply_queue[consumer];
+
+               cmd = instance->cmd_list[context];
+
+               megasas_complete_cmd(instance, cmd, DID_OK);
+
+               consumer++;
+               if (consumer == (instance->max_fw_cmds + 1)) {
+                       consumer = 0;
+               }
+       }
+
+       *instance->consumer = producer;
+
+       spin_unlock_irqrestore(&instance->completion_lock, flags);
+
+       /*
+        * Check if we can restore can_queue
+        */
+       if (instance->flag & MEGASAS_FW_BUSY
+               && time_after(jiffies, instance->last_time + 5 * HZ)
+               && atomic_read(&instance->fw_outstanding) < 17) {
+
+               spin_lock_irqsave(instance->host->host_lock, flags);
+               instance->flag &= ~MEGASAS_FW_BUSY;
+               instance->host->can_queue =
+                               instance->max_fw_cmds - MEGASAS_INT_CMDS;
+
+               spin_unlock_irqrestore(instance->host->host_lock, flags);
+       }
+}
+
 /**
  * megasas_wait_for_outstanding -      Wait for all outstanding cmds
  * @instance:                          Adapter soft state
@@ -908,6 +985,11 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
                        printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
                               "commands to complete\n",i,outstanding);
+                       /*
+                        * Call cmd completion routine. Cmd to be
+                        * be completed directly without depending on isr.
+                        */
+                       megasas_complete_cmd_dpc((unsigned long)instance);
                }
 
                msleep(1000);
@@ -1100,7 +1182,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 static struct scsi_host_template megasas_template = {
 
        .module = THIS_MODULE,
-       .name = "LSI Logic SAS based MegaRAID driver",
+       .name = "LSI SAS based MegaRAID driver",
        .proc_name = "megaraid_sas",
        .slave_configure = megasas_slave_configure,
        .queuecommand = megasas_queue_command,
@@ -1749,57 +1831,119 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
 }
 
 /**
- * megasas_complete_cmd_dpc     -      Returns FW's controller structure
- * @instance_addr:                     Address of adapter soft state
+ * megasas_issue_init_mfi -    Initializes the FW
+ * @instance:          Adapter soft state
  *
- * Tasklet to complete cmds
+ * Issues the INIT MFI cmd
  */
-static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+static int
+megasas_issue_init_mfi(struct megasas_instance *instance)
 {
-       u32 producer;
-       u32 consumer;
        u32 context;
+
        struct megasas_cmd *cmd;
-       struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
-       unsigned long flags;
 
-       /* If we have already declared adapter dead, donot complete cmds */
-       if (instance->hw_crit_error)
-               return;
+       struct megasas_init_frame *init_frame;
+       struct megasas_init_queue_info *initq_info;
+       dma_addr_t init_frame_h;
+       dma_addr_t initq_info_h;
 
-       producer = *instance->producer;
-       consumer = *instance->consumer;
+       /*
+        * Prepare a init frame. Note the init frame points to queue info
+        * structure. Each frame has SGL allocated after first 64 bytes. For
+        * this frame - since we don't need any SGL - we use SGL's space as
+        * queue info structure
+        *
+        * We will not get a NULL command below. We just created the pool.
+        */
+       cmd = megasas_get_cmd(instance);
 
-       while (consumer != producer) {
-               context = instance->reply_queue[consumer];
+       init_frame = (struct megasas_init_frame *)cmd->frame;
+       initq_info = (struct megasas_init_queue_info *)
+               ((unsigned long)init_frame + 64);
 
-               cmd = instance->cmd_list[context];
+       init_frame_h = cmd->frame_phys_addr;
+       initq_info_h = init_frame_h + 64;
 
-               megasas_complete_cmd(instance, cmd, DID_OK);
+       context = init_frame->context;
+       memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+       memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
+       init_frame->context = context;
 
-               consumer++;
-               if (consumer == (instance->max_fw_cmds + 1)) {
-                       consumer = 0;
-               }
-       }
+       initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
+       initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
 
-       *instance->consumer = producer;
+       initq_info->producer_index_phys_addr_lo = instance->producer_h;
+       initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+
+       init_frame->cmd = MFI_CMD_INIT;
+       init_frame->cmd_status = 0xFF;
+       init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+
+       init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
 
        /*
-        * Check if we can restore can_queue
+        * disable the intr before firing the init frame to FW
         */
-       if (instance->flag & MEGASAS_FW_BUSY
-               && time_after(jiffies, instance->last_time + 5 * HZ)
-               && atomic_read(&instance->fw_outstanding) < 17) {
+       instance->instancet->disable_intr(instance->reg_set);
 
-               spin_lock_irqsave(instance->host->host_lock, flags);
-               instance->flag &= ~MEGASAS_FW_BUSY;
-               instance->host->can_queue =
-                               instance->max_fw_cmds - MEGASAS_INT_CMDS;
+       /*
+        * Issue the init frame in polled mode
+        */
 
-               spin_unlock_irqrestore(instance->host->host_lock, flags);
+       if (megasas_issue_polled(instance, cmd)) {
+               printk(KERN_ERR "megasas: Failed to init firmware\n");
+               megasas_return_cmd(instance, cmd);
+               goto fail_fw_init;
        }
 
+       megasas_return_cmd(instance, cmd);
+
+       return 0;
+
+fail_fw_init:
+       return -EINVAL;
+}
+
+/**
+ * megasas_start_timer - Initializes a timer object
+ * @instance:          Adapter soft state
+ * @timer:             timer object to be initialized
+ * @fn:                        timer function
+ * @interval:          time interval between timer function call
+ */
+static inline void
+megasas_start_timer(struct megasas_instance *instance,
+                       struct timer_list *timer,
+                       void *fn, unsigned long interval)
+{
+       init_timer(timer);
+       timer->expires = jiffies + interval;
+       timer->data = (unsigned long)instance;
+       timer->function = fn;
+       add_timer(timer);
+}
+
+/**
+ * megasas_io_completion_timer - Timer fn
+ * @instance_addr:     Address of adapter soft state
+ *
+ * Schedules tasklet for cmd completion
+ * if poll_mode_io is set
+ */
+static void
+megasas_io_completion_timer(unsigned long instance_addr)
+{
+       struct megasas_instance *instance =
+                       (struct megasas_instance *)instance_addr;
+
+       if (atomic_read(&instance->fw_outstanding))
+               tasklet_schedule(&instance->isr_tasklet);
+
+       /* Restart timer */
+       if (poll_mode_io)
+               mod_timer(&instance->io_completion_timer,
+                       jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
 }
 
 /**
@@ -1814,22 +1958,15 @@ static int megasas_init_mfi(struct megasas_instance *instance)
        u32 reply_q_sz;
        u32 max_sectors_1;
        u32 max_sectors_2;
+       u32 tmp_sectors;
        struct megasas_register_set __iomem *reg_set;
-
-       struct megasas_cmd *cmd;
        struct megasas_ctrl_info *ctrl_info;
-
-       struct megasas_init_frame *init_frame;
-       struct megasas_init_queue_info *initq_info;
-       dma_addr_t init_frame_h;
-       dma_addr_t initq_info_h;
-
        /*
         * Map the message registers
         */
        instance->base_addr = pci_resource_start(instance->pdev, 0);
 
-       if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {
+       if (pci_request_regions(instance->pdev, "megasas: LSI")) {
                printk(KERN_DEBUG "megasas: IO memory region busy!\n");
                return -EBUSY;
        }
@@ -1900,52 +2037,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
                goto fail_reply_queue;
        }
 
-       /*
-        * Prepare a init frame. Note the init frame points to queue info
-        * structure. Each frame has SGL allocated after first 64 bytes. For
-        * this frame - since we don't need any SGL - we use SGL's space as
-        * queue info structure
-        *
-        * We will not get a NULL command below. We just created the pool.
-        */
-       cmd = megasas_get_cmd(instance);
-
-       init_frame = (struct megasas_init_frame *)cmd->frame;
-       initq_info = (struct megasas_init_queue_info *)
-           ((unsigned long)init_frame + 64);
-
-       init_frame_h = cmd->frame_phys_addr;
-       initq_info_h = init_frame_h + 64;
-
-       memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
-       memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
-
-       initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
-       initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
-
-       initq_info->producer_index_phys_addr_lo = instance->producer_h;
-       initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
-
-       init_frame->cmd = MFI_CMD_INIT;
-       init_frame->cmd_status = 0xFF;
-       init_frame->queue_info_new_phys_addr_lo = initq_info_h;
-
-       init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
-
-       /*
-        * disable the intr before firing the init frame to FW
-        */
-       instance->instancet->disable_intr(instance->reg_set);
-
-       /*
-        * Issue the init frame in polled mode
-        */
-       if (megasas_issue_polled(instance, cmd)) {
-               printk(KERN_DEBUG "megasas: Failed to init firmware\n");
+       if (megasas_issue_init_mfi(instance))
                goto fail_fw_init;
-       }
-
-       megasas_return_cmd(instance, cmd);
 
        ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
 
@@ -1958,17 +2051,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
         * Note that older firmwares ( < FW ver 30) didn't report information
         * to calculate max_sectors_1. So the number ended up as zero always.
         */
+       tmp_sectors = 0;
        if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
 
                max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
                    ctrl_info->max_strips_per_io;
                max_sectors_2 = ctrl_info->max_request_size;
 
-               instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)
-                   ? max_sectors_1 : max_sectors_2;
-       } else
-               instance->max_sectors_per_req = instance->max_num_sge *
-                   PAGE_SIZE / 512;
+               tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
+       }
+
+       instance->max_sectors_per_req = instance->max_num_sge *
+                                               PAGE_SIZE / 512;
+       if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
+               instance->max_sectors_per_req = tmp_sectors;
 
        kfree(ctrl_info);
 
@@ -1976,12 +2072,17 @@ static int megasas_init_mfi(struct megasas_instance *instance)
        * Setup tasklet for cmd completion
        */
 
-        tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
-                        (unsigned long)instance);
+       tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+               (unsigned long)instance);
+
+       /* Initialize the cmd completion timer */
+       if (poll_mode_io)
+               megasas_start_timer(instance, &instance->io_completion_timer,
+                               megasas_io_completion_timer,
+                               MEGASAS_COMPLETION_TIMER_INTERVAL);
        return 0;
 
       fail_fw_init:
-       megasas_return_cmd(instance, cmd);
 
        pci_free_consistent(instance->pdev, reply_q_sz,
                            instance->reply_queue, instance->reply_queue_h);
@@ -2263,6 +2364,28 @@ static int megasas_io_attach(struct megasas_instance *instance)
        return 0;
 }
 
+static int
+megasas_set_dma_mask(struct pci_dev *pdev)
+{
+       /*
+        * All our contollers are capable of performing 64-bit DMA
+        */
+       if (IS_DMA64) {
+               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+
+                       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+                               goto fail_set_dma_mask;
+               }
+       } else {
+               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+                       goto fail_set_dma_mask;
+       }
+       return 0;
+
+fail_set_dma_mask:
+       return 1;
+}
+
 /**
  * megasas_probe_one - PCI hotplug entry point
  * @pdev:              PCI device structure
@@ -2296,19 +2419,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        pci_set_master(pdev);
 
-       /*
-        * All our contollers are capable of performing 64-bit DMA
-        */
-       if (IS_DMA64) {
-               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-
-                       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-                               goto fail_set_dma_mask;
-               }
-       } else {
-               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-                       goto fail_set_dma_mask;
-       }
+       if (megasas_set_dma_mask(pdev))
+               goto fail_set_dma_mask;
 
        host = scsi_host_alloc(&megasas_template,
                               sizeof(struct megasas_instance));
@@ -2357,8 +2469,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        init_waitqueue_head(&instance->abort_cmd_wait_q);
 
        spin_lock_init(&instance->cmd_pool_lock);
+       spin_lock_init(&instance->completion_lock);
 
-       sema_init(&instance->aen_mutex, 1);
+       mutex_init(&instance->aen_mutex);
        sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 
        /*
@@ -2490,8 +2603,10 @@ static void megasas_flush_cache(struct megasas_instance *instance)
 /**
  * megasas_shutdown_controller -       Instructs FW to shutdown the controller
  * @instance:                          Adapter soft state
+ * @opcode:                            Shutdown/Hibernate
  */
-static void megasas_shutdown_controller(struct megasas_instance *instance)
+static void megasas_shutdown_controller(struct megasas_instance *instance,
+                                       u32 opcode)
 {
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
@@ -2514,7 +2629,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
        dcmd->flags = MFI_FRAME_DIR_NONE;
        dcmd->timeout = 0;
        dcmd->data_xfer_len = 0;
-       dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;
+       dcmd->opcode = opcode;
 
        megasas_issue_blocked_cmd(instance, cmd);
 
@@ -2523,6 +2638,139 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
        return;
 }
 
+/**
+ * megasas_suspend -   driver suspend entry point
+ * @pdev:              PCI device structure
+ * @state:             PCI power state to suspend routine
+ */
+static int __devinit
+megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct Scsi_Host *host;
+       struct megasas_instance *instance;
+
+       instance = pci_get_drvdata(pdev);
+       host = instance->host;
+
+       if (poll_mode_io)
+               del_timer_sync(&instance->io_completion_timer);
+
+       megasas_flush_cache(instance);
+       megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+       tasklet_kill(&instance->isr_tasklet);
+
+       pci_set_drvdata(instance->pdev, instance);
+       instance->instancet->disable_intr(instance->reg_set);
+       free_irq(instance->pdev->irq, instance);
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+/**
+ * megasas_resume-      driver resume entry point
+ * @pdev:               PCI device structure
+ */
+static int __devinit
+megasas_resume(struct pci_dev *pdev)
+{
+       int rval;
+       struct Scsi_Host *host;
+       struct megasas_instance *instance;
+
+       instance = pci_get_drvdata(pdev);
+       host = instance->host;
+       pci_set_power_state(pdev, PCI_D0);
+       pci_enable_wake(pdev, PCI_D0, 0);
+       pci_restore_state(pdev);
+
+       /*
+        * PCI prepping: enable device set bus mastering and dma mask
+        */
+       rval = pci_enable_device(pdev);
+
+       if (rval) {
+               printk(KERN_ERR "megasas: Enable device failed\n");
+               return rval;
+       }
+
+       pci_set_master(pdev);
+
+       if (megasas_set_dma_mask(pdev))
+               goto fail_set_dma_mask;
+
+       /*
+        * Initialize MFI Firmware
+        */
+
+       *instance->producer = 0;
+       *instance->consumer = 0;
+
+       atomic_set(&instance->fw_outstanding, 0);
+
+       /*
+        * We expect the FW state to be READY
+        */
+       if (megasas_transition_to_ready(instance))
+               goto fail_ready_state;
+
+       if (megasas_issue_init_mfi(instance))
+               goto fail_init_mfi;
+
+       tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+                       (unsigned long)instance);
+
+       /*
+        * Register IRQ
+        */
+       if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
+               "megasas", instance)) {
+               printk(KERN_ERR "megasas: Failed to register IRQ\n");
+               goto fail_irq;
+       }
+
+       instance->instancet->enable_intr(instance->reg_set);
+
+       /*
+        * Initiate AEN (Asynchronous Event Notification)
+        */
+       if (megasas_start_aen(instance))
+               printk(KERN_ERR "megasas: Start AEN failed\n");
+
+       /* Initialize the cmd completion timer */
+       if (poll_mode_io)
+               megasas_start_timer(instance, &instance->io_completion_timer,
+                               megasas_io_completion_timer,
+                               MEGASAS_COMPLETION_TIMER_INTERVAL);
+       return 0;
+
+fail_irq:
+fail_init_mfi:
+       if (instance->evt_detail)
+               pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+                               instance->evt_detail,
+                               instance->evt_detail_h);
+
+       if (instance->producer)
+               pci_free_consistent(pdev, sizeof(u32), instance->producer,
+                               instance->producer_h);
+       if (instance->consumer)
+               pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+                               instance->consumer_h);
+       scsi_host_put(host);
+
+fail_set_dma_mask:
+fail_ready_state:
+
+       pci_disable_device(pdev);
+
+       return -ENODEV;
+}
+
 /**
  * megasas_detach_one -        PCI hot"un"plug entry point
  * @pdev:              PCI device structure
@@ -2536,9 +2784,12 @@ static void megasas_detach_one(struct pci_dev *pdev)
        instance = pci_get_drvdata(pdev);
        host = instance->host;
 
+       if (poll_mode_io)
+               del_timer_sync(&instance->io_completion_timer);
+
        scsi_remove_host(instance->host);
        megasas_flush_cache(instance);
-       megasas_shutdown_controller(instance);
+       megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
        tasklet_kill(&instance->isr_tasklet);
 
        /*
@@ -2660,6 +2911,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
        void *sense = NULL;
        dma_addr_t sense_handle;
        u32 *sense_ptr;
+       unsigned long *sense_buff;
 
        memset(kbuff_arr, 0, sizeof(kbuff_arr));
 
@@ -2764,14 +3016,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
         */
        if (ioc->sense_len) {
                /*
-                * sense_ptr points to the location that has the user
+                * sense_buff points to the location that has the user
                 * sense buffer address
                 */
-               sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
-                                    ioc->sense_off);
+               sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw +
+                                                               ioc->sense_off);
 
-               if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
-                                sense, ioc->sense_len)) {
+               if (copy_to_user((void __user *)(unsigned long)(*sense_buff),
+                               sense, ioc->sense_len)) {
+                       printk(KERN_ERR "megasas: Failed to copy out to user "
+                                       "sense data\n");
                        error = -EFAULT;
                        goto out;
                }
@@ -2874,10 +3128,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
        if (!instance)
                return -ENODEV;
 
-       down(&instance->aen_mutex);
+       mutex_lock(&instance->aen_mutex);
        error = megasas_register_aen(instance, aen.seq_num,
                                     aen.class_locale_word);
-       up(&instance->aen_mutex);
+       mutex_unlock(&instance->aen_mutex);
        return error;
 }
 
@@ -2977,6 +3231,8 @@ static struct pci_driver megasas_pci_driver = {
        .id_table = megasas_pci_table,
        .probe = megasas_probe_one,
        .remove = __devexit_p(megasas_detach_one),
+       .suspend = megasas_suspend,
+       .resume = megasas_resume,
        .shutdown = megasas_shutdown,
 };
 
@@ -3004,7 +3260,7 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
 static ssize_t
 megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
 {
-       return sprintf(buf,"%u",megasas_dbg_lvl);
+       return sprintf(buf, "%u\n", megasas_dbg_lvl);
 }
 
 static ssize_t
@@ -3019,7 +3275,65 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
 }
 
 static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
-                  megasas_sysfs_set_dbg_lvl);
+               megasas_sysfs_set_dbg_lvl);
+
+static ssize_t
+megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
+{
+       return sprintf(buf, "%u\n", poll_mode_io);
+}
+
+static ssize_t
+megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
+                               const char *buf, size_t count)
+{
+       int retval = count;
+       int tmp = poll_mode_io;
+       int i;
+       struct megasas_instance *instance;
+
+       if (sscanf(buf, "%u", &poll_mode_io) < 1) {
+               printk(KERN_ERR "megasas: could not set poll_mode_io\n");
+               retval = -EINVAL;
+       }
+
+       /*
+        * Check if poll_mode_io is already set or is same as previous value
+        */
+       if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
+               goto out;
+
+       if (poll_mode_io) {
+               /*
+                * Start timers for all adapters
+                */
+               for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+                       instance = megasas_mgmt_info.instance[i];
+                       if (instance) {
+                               megasas_start_timer(instance,
+                                       &instance->io_completion_timer,
+                                       megasas_io_completion_timer,
+                                       MEGASAS_COMPLETION_TIMER_INTERVAL);
+                       }
+               }
+       } else {
+               /*
+                * Delete timers for all adapters
+                */
+               for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+                       instance = megasas_mgmt_info.instance[i];
+                       if (instance)
+                               del_timer_sync(&instance->io_completion_timer);
+               }
+       }
+
+out:
+       return retval;
+}
+
+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
+               megasas_sysfs_show_poll_mode_io,
+               megasas_sysfs_set_poll_mode_io);
 
 /**
  * megasas_init - Driver load entry point
@@ -3070,8 +3384,16 @@ static int __init megasas_init(void)
                                  &driver_attr_dbg_lvl);
        if (rval)
                goto err_dcf_dbg_lvl;
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                                 &driver_attr_poll_mode_io);
+       if (rval)
+               goto err_dcf_poll_mode_io;
 
        return rval;
+
+err_dcf_poll_mode_io:
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_dbg_lvl);
 err_dcf_dbg_lvl:
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_release_date);
@@ -3089,6 +3411,8 @@ err_pcidrv:
  */
 static void __exit megasas_exit(void)
 {
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_poll_mode_io);
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_dbg_lvl);
        driver_remove_file(&megasas_pci_driver.driver,
index 4dffc918a414c3bf5c4254f0ceea06998127cc15..6466bdf548c2d8addce967c3b08f2fca7647d009 100644 (file)
@@ -2,7 +2,7 @@
  *
  *             Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Logic Corporation.
+ * Copyright (c) 2003-2005  LSI Corporation.
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -18,9 +18,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.03.10-rc5"
-#define MEGASAS_RELDATE                                "May 17, 2007"
-#define MEGASAS_EXT_VERSION                    "Thu May 17 10:09:32 PDT 2007"
+#define MEGASAS_VERSION                                "00.00.03.16-rc1"
+#define MEGASAS_RELDATE                                "Nov. 07, 2007"
+#define MEGASAS_EXT_VERSION                    "Thu. Nov. 07 10:09:32 PDT 2007"
 
 /*
  * Device IDs
 #define MR_FLUSH_DISK_CACHE                    0x02
 
 #define MR_DCMD_CTRL_SHUTDOWN                  0x01050000
+#define MR_DCMD_HIBERNATE_SHUTDOWN             0x01060000
 #define MR_ENABLE_DRIVE_SPINDOWN               0x01
 
 #define MR_DCMD_CTRL_EVENT_GET_INFO            0x01040100
@@ -570,7 +571,8 @@ struct megasas_ctrl_info {
 #define IS_DMA64                               (sizeof(dma_addr_t) == 8)
 
 #define MFI_OB_INTR_STATUS_MASK                        0x00000002
-#define MFI_POLL_TIMEOUT_SECS                  10
+#define MFI_POLL_TIMEOUT_SECS                  60
+#define MEGASAS_COMPLETION_TIMER_INTERVAL      (HZ/10)
 
 #define MFI_REPLY_1078_MESSAGE_INTERRUPT       0x80000000
 
@@ -1083,13 +1085,15 @@ struct megasas_instance {
        struct megasas_cmd **cmd_list;
        struct list_head cmd_pool;
        spinlock_t cmd_pool_lock;
+       /* used to synch producer, consumer ptrs in dpc */
+       spinlock_t completion_lock;
        struct dma_pool *frame_dma_pool;
        struct dma_pool *sense_dma_pool;
 
        struct megasas_evt_detail *evt_detail;
        dma_addr_t evt_detail_h;
        struct megasas_cmd *aen_cmd;
-       struct semaphore aen_mutex;
+       struct mutex aen_mutex;
        struct semaphore ioctl_sem;
 
        struct Scsi_Host *host;
@@ -1108,6 +1112,8 @@ struct megasas_instance {
 
        u8 flag;
        unsigned long last_time;
+
+       struct timer_list io_completion_timer;
 };
 
 #define MEGASAS_IS_LOGICAL(scp)                                                \
index 016c462bc771a80fddce05894445fc1cdb7dd384..c02771aa6c9b4d76d6abc52c509ec9c0327b83f3 100644 (file)
@@ -4963,7 +4963,8 @@ void ncr_complete (struct ncb *np, struct ccb *cp)
                **      Copy back sense data to caller's buffer.
                */
                memcpy(cmd->sense_buffer, cp->sense_buf,
-                      min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
+                      min_t(size_t, SCSI_SENSE_BUFFERSIZE,
+                            sizeof(cp->sense_buf)));
 
                if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
                        u_char * p = (u_char*) & cmd->sense_buffer;
index fa481b515ead0e745a74de03bb014724ec8b2a20..53857c6b6d4d3841aa08cc40ba8a361691cdf476 100644 (file)
@@ -6,7 +6,8 @@ menuconfig SCSI_LOWLEVEL_PCMCIA
        bool "PCMCIA SCSI adapter support"
        depends on SCSI!=n && PCMCIA!=n
 
-if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
+# drivers have problems when build in, so require modules
+if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m
 
 config PCMCIA_AHA152X
        tristate "Adaptec AHA152X PCMCIA support"
index a45d89b14147576fac94963774c4ec1241f15183..5082ca3c6876035df3818035873a47f1e6d181f9 100644 (file)
@@ -135,6 +135,11 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
 
 #define NSP_DEBUG_BUF_LEN              150
 
+static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
+{
+       scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
+}
+
 static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
 {
        va_list args;
@@ -192,8 +197,10 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
 #endif
        nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
 
-       nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
-                  SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
+       nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
+               "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
+               SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
+               scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
        //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
 
        SCpnt->scsi_done        = done;
@@ -225,7 +232,7 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
        SCpnt->SCp.have_data_in = IO_UNKNOWN;
        SCpnt->SCp.sent_command = 0;
        SCpnt->SCp.phase        = PH_UNDETERMINED;
-       SCpnt->resid            = SCpnt->request_bufflen;
+       scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
 
        /* setup scratch area
           SCp.ptr              : buffer pointer
@@ -233,14 +240,14 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
           SCp.buffer           : next buffer
           SCp.buffers_residual : left buffers in list
           SCp.phase            : current state of the command */
-       if (SCpnt->use_sg) {
-               SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
+       if (scsi_bufflen(SCpnt)) {
+               SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
                SCpnt->SCp.ptr              = BUFFER_ADDR;
                SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-               SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+               SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
        } else {
-               SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
-               SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+               SCpnt->SCp.ptr              = NULL;
+               SCpnt->SCp.this_residual    = 0;
                SCpnt->SCp.buffer           = NULL;
                SCpnt->SCp.buffers_residual = 0;
        }
@@ -721,7 +728,9 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
        ocount = data->FifoCount;
 
        nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
-               SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
+               SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
+               SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
+               SCpnt->SCp.buffers_residual);
 
        time_out = 1000;
 
@@ -771,7 +780,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
                        return;
                }
 
-               SCpnt->resid             -= res;
+               nsp_inc_resid(SCpnt, -res);
                SCpnt->SCp.ptr           += res;
                SCpnt->SCp.this_residual -= res;
                ocount                   += res;
@@ -795,10 +804,12 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
 
        if (time_out == 0) {
                nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
-                       SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
+                       scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
+                       SCpnt->SCp.buffers_residual);
        }
        nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
-       nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
+       nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
+                                                       scsi_get_resid(SCpnt));
 }
 
 /*
@@ -816,7 +827,9 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
        ocount   = data->FifoCount;
 
        nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
-               data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
+               data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
+               SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
+               scsi_get_resid(SCpnt));
 
        time_out = 1000;
 
@@ -830,7 +843,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
 
                        nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
                        /* Put back pointer */
-                       SCpnt->resid             += res;
+                       nsp_inc_resid(SCpnt, res);
                        SCpnt->SCp.ptr           -= res;
                        SCpnt->SCp.this_residual += res;
                        ocount                   -= res;
@@ -866,7 +879,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
                        break;
                }
 
-               SCpnt->resid             -= res;
+               nsp_inc_resid(SCpnt, -res);
                SCpnt->SCp.ptr           += res;
                SCpnt->SCp.this_residual -= res;
                ocount                   += res;
@@ -886,10 +899,12 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
        data->FifoCount = ocount;
 
        if (time_out == 0) {
-               nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
+               nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
+                                                       scsi_get_resid(SCpnt));
        }
        nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
-       nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
+       nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
+                                                       scsi_get_resid(SCpnt));
 }
 #undef RFIFO_CRIT
 #undef WFIFO_CRIT
@@ -911,9 +926,8 @@ static int nsp_nexus(struct scsi_cmnd *SCpnt)
        nsp_index_write(base, SYNCREG,  sync->SyncRegister);
        nsp_index_write(base, ACKWIDTH, sync->AckWidth);
 
-       if (SCpnt->use_sg    == 0        ||
-           SCpnt->resid % 4 != 0        ||
-           SCpnt->resid     <= PAGE_SIZE ) {
+       if (scsi_get_resid(SCpnt) % 4 != 0 ||
+           scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
                data->TransferMode = MODE_IO8;
        } else if (nsp_burst_mode == BURST_MEM32) {
                data->TransferMode = MODE_MEM32;
index 67ee51a3d7e14c2d328ac7510284ef3fe2e67bfa..f655ae320b483cfc418a30691b601f23a271b328 100644 (file)
@@ -750,18 +750,16 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                cmd->SCp.phase++;
 
        case 4:         /* Phase 4 - Setup scatter/gather buffers */
-               if (cmd->use_sg) {
-                       /* if many buffers are available, start filling the first */
-                       cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+               if (scsi_bufflen(cmd)) {
+                       cmd->SCp.buffer = scsi_sglist(cmd);
                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
                        cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                } else {
-                       /* else fill the only available buffer */
                        cmd->SCp.buffer = NULL;
-                       cmd->SCp.this_residual = cmd->request_bufflen;
-                       cmd->SCp.ptr = cmd->request_buffer;
+                       cmd->SCp.this_residual = 0;
+                       cmd->SCp.ptr = NULL;
                }
-               cmd->SCp.buffers_residual = cmd->use_sg - 1;
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.phase++;
 
        case 5:         /* Phase 5 - Data transfer stage */
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
deleted file mode 100644 (file)
index 899e89d..0000000
+++ /dev/null
@@ -1,689 +0,0 @@
-/*+M*************************************************************************
- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
- *
- * Copyright (c) 1997 Perceptive Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *     File Name:              psi240i.c
- *
- *     Description:    SCSI driver for the PSI240I EIDE interface card.
- *
- *-M*************************************************************************/
-
-#include <linux/module.h>
-
-#include <linux/blkdev.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-#include "psi240i.h"
-#include "psi_chip.h"
-
-//#define DEBUG 1
-
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
-
-#define MAXBOARDS 6    /* Increase this and the sizes of the arrays below, if you need more. */
-
-#define        PORT_DATA                               0
-#define        PORT_ERROR                              1
-#define        PORT_SECTOR_COUNT               2
-#define        PORT_LBA_0                              3
-#define        PORT_LBA_8                              4
-#define        PORT_LBA_16                             5
-#define        PORT_LBA_24                             6
-#define        PORT_STAT_CMD                   7
-#define        PORT_SEL_FAIL                   8
-#define        PORT_IRQ_STATUS                 9
-#define        PORT_ADDRESS                    10
-#define        PORT_FAIL                               11
-#define        PORT_ALT_STAT                   12
-
-typedef struct
-       {
-       UCHAR                   device;                         // device code
-       UCHAR                   byte6;                          // device select register image
-       UCHAR                   spigot;                         // spigot number
-       UCHAR                   expectingIRQ;           // flag for expecting and interrupt
-       USHORT                  sectors;                        // number of sectors per track
-       USHORT                  heads;                          // number of heads
-       USHORT                  cylinders;                      // number of cylinders for this device
-       USHORT                  spareword;                      // placeholder
-       ULONG                   blocks;                         // number of blocks on device
-       }       OUR_DEVICE, *POUR_DEVICE;
-
-typedef struct
-       {
-       USHORT           ports[13];
-       OUR_DEVICE       device[8];
-       struct scsi_cmnd *pSCmnd;
-       IDE_STRUCT       ide;
-       ULONG            startSector;
-       USHORT           sectorCount;
-       struct scsi_cmnd *SCpnt;
-       VOID            *buffer;
-       USHORT           expectingIRQ;
-       }       ADAPTER240I, *PADAPTER240I;
-
-#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
-
-static struct  Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
-static                 IDENTIFY_DATA   identifyData;
-static                 SETUP                   ChipSetup;
-
-static USHORT  portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
-
-/****************************************************************
- *     Name:   WriteData       :LOCAL
- *
- *     Description:    Write data to device.
- *
- *     Parameters:             padapter - Pointer adapter data structure.
- *
- *     Returns:                TRUE if drive does not assert DRQ in time.
- *
- ****************************************************************/
-static int WriteData (PADAPTER240I padapter)
-       {
-       ULONG   timer;
-       USHORT *pports = padapter->ports;
-
-       timer = jiffies + TIMEOUT_DRQ;                                                          // calculate the timeout value
-       do  {
-               if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
-                       {
-                       outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
-                       return 0;
-                       }
-               }       while ( time_after(timer, jiffies) );                                                                   // test for timeout
-
-       padapter->ide.ide.ides.cmd = 0;                                                                 // null out the command byte
-       return 1;
-       }
-/****************************************************************
- *     Name:   IdeCmd  :LOCAL
- *
- *     Description:    Process a queued command from the SCSI manager.
- *
- *     Parameters:             padapter - Pointer adapter data structure.
- *
- *     Returns:                Zero if no error or status register contents on error.
- *
- ****************************************************************/
-static UCHAR IdeCmd (PADAPTER240I padapter)
-       {
-       ULONG   timer;
-       USHORT *pports = padapter->ports;
-       UCHAR   status;
-
-       outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);  // select the spigot
-       outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);                 // select the drive
-       timer = jiffies + TIMEOUT_READY;                                                        // calculate the timeout value
-       do  {
-               status = inb_p (padapter->ports[PORT_STAT_CMD]);
-               if ( status & IDE_STATUS_DRDY )
-                       {
-                       outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
-                       outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
-                       outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
-                       outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
-                       padapter->expectingIRQ = 1;
-                       outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
-
-                       if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
-                               return (WriteData (padapter));
-
-                       return 0;
-                       }
-               }       while ( time_after(timer, jiffies) );                                                                   // test for timeout
-
-       padapter->ide.ide.ides.cmd = 0;                                                                 // null out the command byte
-       return status;
-       }
-/****************************************************************
- *     Name:   SetupTransfer   :LOCAL
- *
- *     Description:    Setup a data transfer command.
- *
- *     Parameters:             padapter - Pointer adapter data structure.
- *                                     drive    - Drive/head register upper nibble only.
- *
- *     Returns:                TRUE if no data to transfer.
- *
- ****************************************************************/
-static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
-       {
-       if ( padapter->sectorCount )
-               {
-               *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
-               padapter->ide.ide.ide[6] |= drive;
-               padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
-               padapter->sectorCount -= padapter->ide.ide.ides.sectors;        // bump the start and count for next xfer
-               padapter->startSector += padapter->ide.ide.ides.sectors;
-               return 0;
-               }
-       else
-               {
-               padapter->ide.ide.ides.cmd = 0;                                                         // null out the command byte
-               padapter->SCpnt = NULL;
-               return 1;
-               }
-       }
-/****************************************************************
- *     Name:   DecodeError     :LOCAL
- *
- *     Description:    Decode and process device errors.
- *
- *     Parameters:             pshost - Pointer to host data block.
- *                                     status - Status register code.
- *
- *     Returns:                The driver status code.
- *
- ****************************************************************/
-static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
-       {
-       PADAPTER240I    padapter = HOSTDATA(pshost);
-       UCHAR                   error;
-
-       padapter->expectingIRQ = 0;
-       padapter->SCpnt = NULL;
-       if ( status & IDE_STATUS_WRITE_FAULT )
-               {
-               return DID_PARITY << 16;
-               }
-       if ( status & IDE_STATUS_BUSY )
-               return DID_BUS_BUSY << 16;
-
-       error = inb_p (padapter->ports[PORT_ERROR]);
-       DEB(printk ("\npsi240i error register: %x", error));
-       switch ( error )
-               {
-               case IDE_ERROR_AMNF:
-               case IDE_ERROR_TKONF:
-               case IDE_ERROR_ABRT:
-               case IDE_ERROR_IDFN:
-               case IDE_ERROR_UNC:
-               case IDE_ERROR_BBK:
-               default:
-                       return DID_ERROR << 16;
-               }
-       return DID_ERROR << 16;
-       }
-/****************************************************************
- *     Name:   Irq_Handler     :LOCAL
- *
- *     Description:    Interrupt handler.
- *
- *     Parameters:             irq             - Hardware IRQ number.
- *                                     dev_id  -
- *
- *     Returns:                TRUE if drive is not ready in time.
- *
- ****************************************************************/
-static void Irq_Handler (int irq, void *dev_id)
-       {
-       struct Scsi_Host *shost;        // Pointer to host data block
-       PADAPTER240I padapter;          // Pointer to adapter control structure
-       USHORT *pports;                 // I/O port array
-       struct scsi_cmnd *SCpnt;
-       UCHAR status;
-       int z;
-
-       DEB(printk ("\npsi240i received interrupt\n"));
-
-       shost = PsiHost[irq - 10];
-       if ( !shost )
-               panic ("Splunge!");
-
-       padapter = HOSTDATA(shost);
-       pports = padapter->ports;
-       SCpnt = padapter->SCpnt;
-
-       if ( !padapter->expectingIRQ )
-               {
-               DEB(printk ("\npsi240i Unsolicited interrupt\n"));
-               return;
-               }
-       padapter->expectingIRQ = 0;
-
-       status = inb_p (padapter->ports[PORT_STAT_CMD]);                        // read the device status
-       if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
-               goto irqerror;
-
-       DEB(printk ("\npsi240i processing interrupt"));
-       switch ( padapter->ide.ide.ides.cmd )                                                   // decide how to handle the interrupt
-               {
-               case IDE_CMD_READ_MULTIPLE:
-                       if ( status & IDE_STATUS_DRQ )
-                               {
-                               insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
-                               padapter->buffer += padapter->ide.ide.ides.sectors * 512;
-                               if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
-                                       {
-                                       SCpnt->result = DID_OK << 16;
-                                       padapter->SCpnt = NULL;
-                                       SCpnt->scsi_done (SCpnt);
-                                       return;
-                                       }
-                               if ( !(status = IdeCmd (padapter)) )
-                                       return;
-                               }
-                       break;
-
-               case IDE_CMD_WRITE_MULTIPLE:
-                       padapter->buffer += padapter->ide.ide.ides.sectors * 512;
-                       if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
-                               {
-                               SCpnt->result = DID_OK << 16;
-                               padapter->SCpnt = NULL;
-                               SCpnt->scsi_done (SCpnt);
-                               return;
-                               }
-                       if ( !(status = IdeCmd (padapter)) )
-                               return;
-                       break;
-
-               case IDE_COMMAND_IDENTIFY:
-                       {
-                       PINQUIRYDATA    pinquiryData  = SCpnt->request_buffer;
-
-                       if ( status & IDE_STATUS_DRQ )
-                               {
-                               insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
-
-                               memset (pinquiryData, 0, SCpnt->request_bufflen);               // Zero INQUIRY data structure.
-                               pinquiryData->DeviceType = 0;
-                               pinquiryData->Versions = 2;
-                               pinquiryData->AdditionalLength = 35 - 4;
-
-                               // Fill in vendor identification fields.
-                               for ( z = 0;  z < 8;  z += 2 )
-                                       {
-                                       pinquiryData->VendorId[z]         = ((UCHAR *)identifyData.ModelNumber)[z + 1];
-                                       pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
-                                       }
-
-                               // Initialize unused portion of product id.
-                               for ( z = 0;  z < 4;  z++ )
-                                       pinquiryData->ProductId[12 + z] = ' ';
-
-                               // Move firmware revision from IDENTIFY data to
-                               // product revision in INQUIRY data.
-                               for ( z = 0;  z < 4;  z += 2 )
-                                       {
-                                       pinquiryData->ProductRevisionLevel[z]    = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
-                                       pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
-                                       }
-
-                               SCpnt->result = DID_OK << 16;
-                               padapter->SCpnt = NULL;
-                               SCpnt->scsi_done (SCpnt);
-                               return;
-                               }
-                       break;
-                       }
-
-               default:
-                       SCpnt->result = DID_OK << 16;
-                       padapter->SCpnt = NULL;
-                       SCpnt->scsi_done (SCpnt);
-                       return;
-               }
-
-irqerror:;
-       DEB(printk ("\npsi240i error  Device Status: %X\n", status));
-       SCpnt->result = DecodeError (shost, status);
-       SCpnt->scsi_done (SCpnt);
-       }
-
-static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
-{
-       unsigned long flags;
-       struct Scsi_Host *dev = dev_id;
-       
-       spin_lock_irqsave(dev->host_lock, flags);
-       Irq_Handler(irq, dev_id);
-       spin_unlock_irqrestore(dev->host_lock, flags);
-       return IRQ_HANDLED;
-}
-
-/****************************************************************
- *     Name:   Psi240i_QueueCommand
- *
- *     Description:    Process a queued command from the SCSI manager.
- *
- *     Parameters:             SCpnt - Pointer to SCSI command structure.
- *                                     done  - Pointer to done function to call.
- *
- *     Returns:                Status code.
- *
- ****************************************************************/
-static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
-                               void (*done)(struct scsi_cmnd *))
-       {
-       UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
-       // Pointer to SCSI CDB
-       PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
-       // Pointer to adapter control structure
-       POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
-       // Pointer to device information
-       UCHAR rc;
-       // command return code
-
-       SCpnt->scsi_done = done;
-       padapter->ide.ide.ides.spigot = pdev->spigot;
-       padapter->buffer = SCpnt->request_buffer;
-       if (done)
-               {
-               if ( !pdev->device )
-                       {
-                       SCpnt->result = DID_BAD_TARGET << 16;
-                       done (SCpnt);
-                       return 0;
-                       }
-               }
-       else
-               {
-               printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
-               return 0;
-               }
-
-       switch ( *cdb )
-               {
-               case SCSIOP_INQUIRY:                                    // inquiry CDB
-                       {
-                       padapter->ide.ide.ide[6] = pdev->byte6;
-                       padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
-                       break;
-                       }
-
-               case SCSIOP_TEST_UNIT_READY:                    // test unit ready CDB
-                       SCpnt->result = DID_OK << 16;
-                       done (SCpnt);
-                       return 0;
-
-               case SCSIOP_READ_CAPACITY:                              // read capctiy CDB
-                       {
-                       PREAD_CAPACITY_DATA     pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
-
-                       pdata->blksiz = 0x20000;
-                       XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
-                       SCpnt->result = DID_OK << 16;
-                       done (SCpnt);
-                       return 0;
-                       }
-
-               case SCSIOP_VERIFY:                                             // verify CDB
-                       *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
-                       padapter->ide.ide.ide[6] |= pdev->byte6;
-                       padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
-                       padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
-                       break;
-
-               case SCSIOP_READ:                                               // read10 CDB
-                       padapter->startSector = XSCSI2LONG (&cdb[2]);
-                       padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
-                       SetupTransfer (padapter, pdev->byte6);
-                       padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
-                       break;
-
-               case SCSIOP_READ6:                                              // read6  CDB
-                       padapter->startSector = SCSI2LONG (&cdb[1]);
-                       padapter->sectorCount = cdb[4];
-                       SetupTransfer (padapter, pdev->byte6);
-                       padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
-                       break;
-
-               case SCSIOP_WRITE:                                              // write10 CDB
-                       padapter->startSector = XSCSI2LONG (&cdb[2]);
-                       padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
-                       SetupTransfer (padapter, pdev->byte6);
-                       padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
-                       break;
-               case SCSIOP_WRITE6:                                             // write6  CDB
-                       padapter->startSector = SCSI2LONG (&cdb[1]);
-                       padapter->sectorCount = cdb[4];
-                       SetupTransfer (padapter, pdev->byte6);
-                       padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
-                       break;
-
-               default:
-                       DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
-                       SCpnt->result = DID_ERROR << 16;
-                       done (SCpnt);
-                       return 0;
-               }
-
-       padapter->SCpnt = SCpnt;                                                                        // Save this command data
-
-       rc = IdeCmd (padapter);
-       if ( rc )
-               {
-               padapter->expectingIRQ = 0;
-               DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
-               SCpnt->result = DID_ERROR << 16;
-               done (SCpnt);
-               return 0;
-               }
-       DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
-       return 0;
-       }
-
-/***************************************************************************
- *     Name:                   ReadChipMemory
- *
- *     Description:    Read information from controller memory.
- *
- *     Parameters:             psetup  - Pointer to memory image of setup information.
- *                                     base    - base address of memory.
- *                                     length  - lenght of data space in bytes.
- *                                     port    - I/O address of data port.
- *
- *     Returns:                Nothing.
- *
- **************************************************************************/
-static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
-       {
-       USHORT  z, zz;
-       UCHAR   *pd = (UCHAR *)pdata;
-       outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup data port
-       zz = 0;
-       while ( zz < length )
-               {
-               outw_p (base, port + REG_ADDRESS);                              // setup address
-
-               for ( z = 0;  z < 8;  z++ )
-                       {
-                       if ( (zz + z) < length )
-                       *pd++ = inb_p (port + z);       // read data byte
-                       }
-               zz += 8;
-               base += 8;
-               }
-       }
-/****************************************************************
- *     Name:   Psi240i_Detect
- *
- *     Description:    Detect and initialize our boards.
- *
- *     Parameters:             tpnt - Pointer to SCSI host template structure.
- *
- *     Returns:                Number of adapters found.
- *
- ****************************************************************/
-static int Psi240i_Detect (struct scsi_host_template *tpnt)
-       {
-       int                                     board;
-       int                                     count = 0;
-       int                                     unit;
-       int                                     z;
-       USHORT                          port, port_range = 16;
-       CHIP_CONFIG_N           chipConfig;
-       CHIP_DEVICE_N           chipDevice[8];
-       struct Scsi_Host   *pshost;
-
-       for ( board = 0;  board < MAXBOARDS;  board++ )                                 // scan for I/O ports
-               {
-               pshost = NULL;
-               port = portAddr[board];                                                         // get base address to test
-               if ( !request_region (port, port_range, "psi240i") )
-                       continue;
-               if ( inb_p (port + REG_FAIL) != CHIP_ID )                       // do the first test for likley hood that it is us
-                       goto host_init_failure;
-               outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup EEPROM/RAM access
-               outw (0, port + REG_ADDRESS);                                           // setup EEPROM address zero
-               if ( inb_p (port) != 0x55 )                                                     // test 1st byte
-                       goto host_init_failure;                                                                 //   nope
-               if ( inb_p (port + 1) != 0xAA )                                         // test 2nd byte
-                       goto host_init_failure;                                                         //   nope
-
-               // at this point our board is found and can be accessed.  Now we need to initialize
-               // our informatation and register with the kernel.
-
-
-               ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
-               ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
-               ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
-
-               if ( !chipConfig.numDrives )                                            // if no devices on this board
-                       goto host_init_failure;
-
-               pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
-               if(pshost == NULL)
-                       goto host_init_failure; 
-
-               PsiHost[chipConfig.irq - 10] = pshost;
-               pshost->unique_id = port;
-               pshost->io_port = port;
-               pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
-               pshost->irq = chipConfig.irq;
-
-               for ( z = 0;  z < 11;  z++ )                                            // build regester address array
-                       HOSTDATA(pshost)->ports[z] = port + z;
-               HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
-               HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
-               DEB (printk ("\nPorts ="));
-               DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
-
-               for ( z = 0;  z < chipConfig.numDrives;  ++z )
-                       {
-                       unit = chipDevice[z].channel & 0x0F;
-                       HOSTDATA(pshost)->device[unit].device    = ChipSetup.setupDevice[unit].device;
-                       HOSTDATA(pshost)->device[unit].byte6     = (UCHAR)(((unit & 1) << 4) | 0xE0);
-                       HOSTDATA(pshost)->device[unit].spigot    = (UCHAR)(1 << (unit >> 1));
-                       HOSTDATA(pshost)->device[unit].sectors   = ChipSetup.setupDevice[unit].sectors;
-                       HOSTDATA(pshost)->device[unit].heads     = ChipSetup.setupDevice[unit].heads;
-                       HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
-                       HOSTDATA(pshost)->device[unit].blocks    = ChipSetup.setupDevice[unit].blocks;
-                       DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
-                       DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
-                       DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
-                       DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
-                       DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
-                       DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
-                       DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
-                       }
-
-               if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
-                       {
-                       printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
-                       printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
-                       count++;
-                       continue;
-                       }
-
-               printk ("Unable to allocate IRQ for PSI-240I controller.\n");
-           
-host_init_failure:
-               
-               release_region (port, port_range);
-               if (pshost)
-                       scsi_unregister (pshost);
-
-               }
-       return count;
-       }
-
-static int Psi240i_Release(struct Scsi_Host *shost)
-{
-       if (shost->irq)
-               free_irq(shost->irq, NULL);
-       if (shost->io_port && shost->n_io_port)
-               release_region(shost->io_port, shost->n_io_port);
-       scsi_unregister(shost);
-       return 0;
-}
-
-/****************************************************************
- *     Name:   Psi240i_BiosParam
- *
- *     Description:    Process the biosparam request from the SCSI manager to
- *                                     return C/H/S data.
- *
- *     Parameters:             disk - Pointer to SCSI disk structure.
- *                                     dev      - Major/minor number from kernel.
- *                                     geom - Pointer to integer array to place geometry data.
- *
- *     Returns:                zero.
- *
- ****************************************************************/
-static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
-               sector_t capacity, int geom[])
-       {
-       POUR_DEVICE     pdev;
-
-       pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
-
-       geom[0] = pdev->heads;
-       geom[1] = pdev->sectors;
-       geom[2] = pdev->cylinders;
-       return 0;
-       }
-
-MODULE_LICENSE("GPL");
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "psi240i", 
-       .name                   = "PSI-240I EIDE Disk Controller",
-       .detect                 = Psi240i_Detect,
-       .release                = Psi240i_Release,
-       .queuecommand           = Psi240i_QueueCommand,
-       .bios_param             = Psi240i_BiosParam,
-       .can_queue              = 1,
-       .this_id                = -1,
-       .sg_tablesize           = SG_NONE,
-       .cmd_per_lun            = 1, 
-       .use_clustering         = DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
deleted file mode 100644 (file)
index 21ebb92..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*+M*************************************************************************
- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
- *
- * Copyright (c) 1997 Perceptive Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *     File Name:              psi240i.h
- *
- *     Description:    Header file for the SCSI driver for the PSI240I
- *                                     EIDE interface card.
- *
- *-M*************************************************************************/
-#ifndef _PSI240I_H
-#define _PSI240I_H
-
-#include <linux/types.h>
-
-#ifndef        PSI_EIDE_SCSIOP
-#define        PSI_EIDE_SCSIOP 1
-
-/************************************************/
-/*             Some defines that we like                               */
-/************************************************/
-#define        CHAR            char
-#define        UCHAR           unsigned char
-#define        SHORT           short
-#define        USHORT          unsigned short
-#define        BOOL            unsigned short
-#define        LONG            long
-#define        ULONG           unsigned long
-#define        VOID            void
-
-/************************************************/
-/*             Timeout konstants                                               */
-/************************************************/
-#define        TIMEOUT_READY                           10              // 100 mSec
-#define        TIMEOUT_DRQ                                     40              // 400 mSec
-
-/************************************************/
-/*             Misc. macros                                                    */
-/************************************************/
-#define ANY2SCSI(up, p)                                        \
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);        \
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up)                                  \
-( (((long)*(((UCHAR *)up))) << 16)             \
-+ (((long)(((UCHAR *)up)[1])) << 8)            \
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p)                               \
-((UCHAR *)up)[0] = ((long)(p)) >> 24;  \
-((UCHAR *)up)[1] = ((long)(p)) >> 16;  \
-((UCHAR *)up)[2] = ((long)(p)) >> 8;   \
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up)                                 \
-( (((long)(((UCHAR *)up)[0])) << 24)   \
-+ (((long)(((UCHAR *)up)[1])) << 16)   \
-+ (((long)(((UCHAR *)up)[2])) <<  8)   \
-+ ((long)(((UCHAR *)up)[3])) )
-
-/************************************************/
-/*             SCSI CDB operation codes                                */
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY         0x00
-#define SCSIOP_REZERO_UNIT                     0x01
-#define SCSIOP_REWIND                          0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR      0x02
-#define SCSIOP_REQUEST_SENSE           0x03
-#define SCSIOP_FORMAT_UNIT                     0x04
-#define SCSIOP_READ_BLOCK_LIMITS       0x05
-#define SCSIOP_REASSIGN_BLOCKS         0x07
-#define SCSIOP_READ6                           0x08
-#define SCSIOP_RECEIVE                         0x08
-#define SCSIOP_WRITE6                          0x0A
-#define SCSIOP_PRINT                           0x0A
-#define SCSIOP_SEND                                    0x0A
-#define SCSIOP_SEEK6                           0x0B
-#define SCSIOP_TRACK_SELECT                    0x0B
-#define SCSIOP_SLEW_PRINT                      0x0B
-#define SCSIOP_SEEK_BLOCK                      0x0C
-#define SCSIOP_PARTITION                       0x0D
-#define SCSIOP_READ_REVERSE                    0x0F
-#define SCSIOP_WRITE_FILEMARKS         0x10
-#define SCSIOP_FLUSH_BUFFER                    0x10
-#define SCSIOP_SPACE                           0x11
-#define SCSIOP_INQUIRY                         0x12
-#define SCSIOP_VERIFY6                         0x13
-#define SCSIOP_RECOVER_BUF_DATA                0x14
-#define SCSIOP_MODE_SELECT                     0x15
-#define SCSIOP_RESERVE_UNIT                    0x16
-#define SCSIOP_RELEASE_UNIT                    0x17
-#define SCSIOP_COPY                                    0x18
-#define SCSIOP_ERASE                           0x19
-#define SCSIOP_MODE_SENSE                      0x1A
-#define SCSIOP_START_STOP_UNIT         0x1B
-#define SCSIOP_STOP_PRINT                      0x1B
-#define SCSIOP_LOAD_UNLOAD                     0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC      0x1C
-#define SCSIOP_SEND_DIAGNOSTIC         0x1D
-#define SCSIOP_MEDIUM_REMOVAL          0x1E
-#define SCSIOP_READ_CAPACITY           0x25
-#define SCSIOP_READ                                    0x28
-#define SCSIOP_WRITE                           0x2A
-#define SCSIOP_SEEK                                    0x2B
-#define SCSIOP_LOCATE                          0x2B
-#define SCSIOP_WRITE_VERIFY                    0x2E
-#define SCSIOP_VERIFY                          0x2F
-#define SCSIOP_SEARCH_DATA_HIGH                0x30
-#define SCSIOP_SEARCH_DATA_EQUAL       0x31
-#define SCSIOP_SEARCH_DATA_LOW         0x32
-#define SCSIOP_SET_LIMITS                      0x33
-#define SCSIOP_READ_POSITION           0x34
-#define SCSIOP_SYNCHRONIZE_CACHE       0x35
-#define SCSIOP_COMPARE                         0x39
-#define SCSIOP_COPY_COMPARE                    0x3A
-#define SCSIOP_WRITE_DATA_BUFF         0x3B
-#define SCSIOP_READ_DATA_BUFF          0x3C
-#define SCSIOP_CHANGE_DEFINITION       0x40
-#define SCSIOP_READ_SUB_CHANNEL                0x42
-#define SCSIOP_READ_TOC                                0x43
-#define SCSIOP_READ_HEADER                     0x44
-#define SCSIOP_PLAY_AUDIO                      0x45
-#define SCSIOP_PLAY_AUDIO_MSF          0x47
-#define SCSIOP_PLAY_TRACK_INDEX                0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE     0x49
-#define SCSIOP_PAUSE_RESUME                    0x4B
-#define SCSIOP_LOG_SELECT                      0x4C
-#define SCSIOP_LOG_SENSE                       0x4D
-#define SCSIOP_MODE_SELECT10           0x55
-#define SCSIOP_MODE_SENSE10                    0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT                0xA6
-#define SCSIOP_MECHANISM_STATUS                0xBD
-#define SCSIOP_READ_CD                         0xBE
-
-// IDE command definitions
-#define IDE_COMMAND_ATAPI_RESET                0x08
-#define IDE_COMMAND_READ                       0x20
-#define IDE_COMMAND_WRITE                      0x30
-#define IDE_COMMAND_RECALIBRATE                0x10
-#define IDE_COMMAND_SEEK                       0x70
-#define IDE_COMMAND_SET_PARAMETERS     0x91
-#define IDE_COMMAND_VERIFY                     0x40
-#define IDE_COMMAND_ATAPI_PACKET       0xA0
-#define IDE_COMMAND_ATAPI_IDENTIFY     0xA1
-#define        IDE_CMD_READ_MULTIPLE           0xC4
-#define        IDE_CMD_WRITE_MULTIPLE          0xC5
-#define        IDE_CMD_SET_MULTIPLE            0xC6
-#define IDE_COMMAND_WRITE_DMA          0xCA
-#define IDE_COMMAND_READ_DMA           0xC8
-#define IDE_COMMAND_IDENTIFY           0xEC
-
-// IDE status definitions
-#define IDE_STATUS_ERROR                       0x01
-#define IDE_STATUS_INDEX                       0x02
-#define IDE_STATUS_CORRECTED_ERROR     0x04
-#define IDE_STATUS_DRQ                         0x08
-#define IDE_STATUS_DSC                         0x10
-#define        IDE_STATUS_WRITE_FAULT          0x20
-#define IDE_STATUS_DRDY                                0x40
-#define IDE_STATUS_BUSY                                0x80
-
-// IDE error definitions
-#define        IDE_ERROR_AMNF                          0x01
-#define        IDE_ERROR_TKONF                         0x02
-#define        IDE_ERROR_ABRT                          0x04
-#define        IDE_ERROR_MCR                           0x08
-#define        IDE_ERROR_IDFN                          0x10
-#define        IDE_ERROR_MC                            0x20
-#define        IDE_ERROR_UNC                           0x40
-#define        IDE_ERROR_BBK                           0x80
-
-//     IDE interface structure
-typedef struct _IDE_STRUCT
-       {
-       union
-               {
-               UCHAR   ide[9];
-               struct
-                       {
-                       USHORT  data;
-                       UCHAR   sectors;
-                       UCHAR   lba[4];
-                       UCHAR   cmd;
-                       UCHAR   spigot;
-                       }       ides;
-               } ide;
-       }       IDE_STRUCT;
-
-// SCSI read capacity structure
-typedef        struct _READ_CAPACITY_DATA
-       {
-       ULONG blks;                             /* total blocks (converted to little endian) */
-       ULONG blksiz;                   /* size of each (converted to little endian) */
-       }       READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-#ifndef HOSTS_C
-
-typedef struct _INQUIRYDATA
-       {
-       UCHAR DeviceType                        :5;
-       UCHAR DeviceTypeQualifier       :3;
-       UCHAR DeviceTypeModifier        :7;
-       UCHAR RemovableMedia            :1;
-    UCHAR Versions;
-    UCHAR ResponseDataFormat;
-    UCHAR AdditionalLength;
-    UCHAR Reserved[2];
-       UCHAR SoftReset                         :1;
-       UCHAR CommandQueue                      :1;
-       UCHAR Reserved2                         :1;
-       UCHAR LinkedCommands            :1;
-       UCHAR Synchronous                       :1;
-       UCHAR Wide16Bit                         :1;
-       UCHAR Wide32Bit                         :1;
-       UCHAR RelativeAddressing        :1;
-    UCHAR VendorId[8];
-    UCHAR ProductId[16];
-    UCHAR ProductRevisionLevel[4];
-    UCHAR VendorSpecific[20];
-    UCHAR Reserved3[40];
-       }       INQUIRYDATA, *PINQUIRYDATA;
-#endif
-
-// IDE IDENTIFY data
-typedef struct _IDENTIFY_DATA
-       {
-    USHORT GeneralConfiguration;            // 00
-    USHORT NumberOfCylinders;               // 02
-    USHORT Reserved1;                       // 04
-    USHORT NumberOfHeads;                   // 06
-    USHORT UnformattedBytesPerTrack;        // 08
-    USHORT UnformattedBytesPerSector;       // 0A
-    USHORT SectorsPerTrack;                 // 0C
-    USHORT VendorUnique1[3];                // 0E
-    USHORT SerialNumber[10];                // 14
-    USHORT BufferType;                      // 28
-    USHORT BufferSectorSize;                // 2A
-    USHORT NumberOfEccBytes;                // 2C
-    USHORT FirmwareRevision[4];             // 2E
-    USHORT ModelNumber[20];                 // 36
-    UCHAR  MaximumBlockTransfer;            // 5E
-    UCHAR  VendorUnique2;                   // 5F
-    USHORT DoubleWordIo;                    // 60
-    USHORT Capabilities;                    // 62
-    USHORT Reserved2;                       // 64
-    UCHAR  VendorUnique3;                   // 66
-    UCHAR  PioCycleTimingMode;              // 67
-    UCHAR  VendorUnique4;                   // 68
-    UCHAR  DmaCycleTimingMode;              // 69
-    USHORT TranslationFieldsValid:1;        // 6A
-    USHORT Reserved3:15;
-    USHORT NumberOfCurrentCylinders;        // 6C
-    USHORT NumberOfCurrentHeads;            // 6E
-    USHORT CurrentSectorsPerTrack;          // 70
-    ULONG  CurrentSectorCapacity;           // 72
-    USHORT Reserved4[197];                  // 76
-       }       IDENTIFY_DATA, *PIDENTIFY_DATA;
-
-// Identify data without the Reserved4.
-typedef struct _IDENTIFY_DATA2 {
-    USHORT GeneralConfiguration;            // 00
-    USHORT NumberOfCylinders;               // 02
-    USHORT Reserved1;                       // 04
-    USHORT NumberOfHeads;                   // 06
-    USHORT UnformattedBytesPerTrack;        // 08
-    USHORT UnformattedBytesPerSector;       // 0A
-    USHORT SectorsPerTrack;                 // 0C
-    USHORT VendorUnique1[3];                // 0E
-    USHORT SerialNumber[10];                // 14
-    USHORT BufferType;                      // 28
-    USHORT BufferSectorSize;                // 2A
-    USHORT NumberOfEccBytes;                // 2C
-    USHORT FirmwareRevision[4];             // 2E
-    USHORT ModelNumber[20];                 // 36
-    UCHAR  MaximumBlockTransfer;            // 5E
-    UCHAR  VendorUnique2;                   // 5F
-    USHORT DoubleWordIo;                    // 60
-    USHORT Capabilities;                    // 62
-    USHORT Reserved2;                       // 64
-    UCHAR  VendorUnique3;                   // 66
-    UCHAR  PioCycleTimingMode;              // 67
-    UCHAR  VendorUnique4;                   // 68
-    UCHAR  DmaCycleTimingMode;              // 69
-       USHORT TranslationFieldsValid:1;        // 6A
-    USHORT Reserved3:15;
-    USHORT NumberOfCurrentCylinders;        // 6C
-    USHORT NumberOfCurrentHeads;            // 6E
-    USHORT CurrentSectorsPerTrack;          // 70
-    ULONG  CurrentSectorCapacity;           // 72
-       }       IDENTIFY_DATA2, *PIDENTIFY_DATA2;
-
-#endif // PSI_EIDE_SCSIOP
-
-// function prototypes
-int Psi240i_Command(struct scsi_cmnd *SCpnt);
-int Psi240i_Abort(struct scsi_cmnd *SCpnt);
-int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags);
-#endif
diff --git a/drivers/scsi/psi_chip.h b/drivers/scsi/psi_chip.h
deleted file mode 100644 (file)
index 224cf8f..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*+M*************************************************************************
- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
- *
- * Copyright (c) 1997 Perceptive Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *     File Name:      psi_chip.h
- *
- *     Description:    This file contains the interface defines and
- *                                     error codes.
- *
- *-M*************************************************************************/
-#ifndef PSI_CHIP
-#define PSI_CHIP
-
-/************************************************/
-/*             Misc konstants                                                  */
-/************************************************/
-#define        CHIP_MAXDRIVES                  8
-
-/************************************************/
-/*             Chip I/O addresses                                              */
-/************************************************/
-#define        CHIP_ADRS_0                             0x0130
-#define        CHIP_ADRS_1                             0x0150
-#define        CHIP_ADRS_2                             0x0190
-#define        CHIP_ADRS_3                             0x0210
-#define        CHIP_ADRS_4                             0x0230
-#define        CHIP_ADRS_5                             0x0250
-
-/************************************************/
-/*             EEPROM locations                */
-/************************************************/
-#define        CHIP_EEPROM_BIOS                0x0000          // BIOS base address
-#define        CHIP_EEPROM_DATA                0x2000          // SETUP data base address
-#define        CHIP_EEPROM_FACTORY             0x2400          // FACTORY data base address
-#define        CHIP_EEPROM_SETUP               0x3000          // SETUP PROGRAM base address
-
-#define        CHIP_EEPROM_SIZE                32768U          // size of the entire EEPROM
-#define        CHIP_EEPROM_BIOS_SIZE   8192            // size of the BIOS in bytes
-#define        CHIP_EEPROM_DATA_SIZE   4096            // size of factory, setup, log data block in bytes
-#define        CHIP_EEPROM_SETUP_SIZE  20480U          // size of the setup program in bytes
-
-/************************************************/
-/*             Chip Interrupts                                                 */
-/************************************************/
-#define        CHIP_IRQ_10                             0x72
-#define        CHIP_IRQ_11                             0x73
-#define        CHIP_IRQ_12                             0x74
-
-/************************************************/
-/*             Chip Setup addresses            */
-/************************************************/
-#define        CHIP_SETUP_BASE                 0x0000C000L
-
-/************************************************/
-/*             Chip Register address offsets   */
-/************************************************/
-#define        REG_DATA                                0x00
-#define        REG_ERROR                               0x01
-#define        REG_SECTOR_COUNT                0x02
-#define        REG_LBA_0                               0x03
-#define        REG_LBA_8                               0x04
-#define        REG_LBA_16                              0x05
-#define        REG_LBA_24                              0x06
-#define        REG_STAT_CMD                    0x07
-#define        REG_SEL_FAIL                    0x08
-#define        REG_IRQ_STATUS                  0x09
-#define        REG_ADDRESS                             0x0A
-#define        REG_FAIL                                0x0C
-#define        REG_ALT_STAT                    0x0E
-#define        REG_DRIVE_ADRS                  0x0F
-
-/************************************************/
-/*             Chip RAM locations              */
-/************************************************/
-#define        CHIP_DEVICE                             0x8000
-#define        CHIP_DEVICE_0                   0x8000
-#define CHIP_DEVICE_1                  0x8008
-#define        CHIP_DEVICE_2                   0x8010
-#define        CHIP_DEVICE_3                   0x8018
-#define        CHIP_DEVICE_4                   0x8020
-#define        CHIP_DEVICE_5                   0x8028
-#define        CHIP_DEVICE_6                   0x8030
-#define        CHIP_DEVICE_7                   0x8038
-typedef struct
-       {
-       UCHAR   channel;                // channel of this device (0-8).
-       UCHAR   spt;                    // Sectors Per Track.
-       ULONG   spc;                    // Sectors Per Cylinder.
-       }       CHIP_DEVICE_N;
-
-#define        CHIP_CONFIG                             0x8100          // address of boards configuration.
-typedef struct
-       {
-       UCHAR           irq;                    // interrupt request channel number
-       UCHAR           numDrives;              // Number of accessible drives
-       UCHAR           fastFormat;             // Boolean for fast format enable
-       }       CHIP_CONFIG_N;
-
-#define        CHIP_MAP                                0x8108          // eight byte device type map.
-
-
-#define        CHIP_RAID                               0x8120          // array of RAID signature structures and LBA
-#define        CHIP_RAID_1                             0x8120
-#define CHIP_RAID_2                            0x8130
-#define        CHIP_RAID_3                             0x8140
-#define        CHIP_RAID_4                             0x8150
-
-/************************************************/
-/*             Chip Register Masks             */
-/************************************************/
-#define        CHIP_ID                                 0x7B
-#define        SEL_RAM                                 0x8000
-#define        MASK_FAIL                               0x80
-
-/************************************************/
-/*             Chip cable select bits          */
-/************************************************/
-#define        SECTORSXFER                             8
-
-/************************************************/
-/*             Chip cable select bits          */
-/************************************************/
-#define        SEL_NONE                                0x00
-#define        SEL_1                                   0x01
-#define        SEL_2                                   0x02
-#define        SEL_3                                   0x04
-#define        SEL_4                                   0x08
-
-/************************************************/
-/*             Programmable Interrupt Controller*/
-/************************************************/
-#define        PIC1                                    0x20            // first 8259 base port address
-#define        PIC2                                    0xA0            // second 8259 base port address
-#define        INT_OCW1                                1                       // Operation Control Word 1: IRQ mask
-#define        EOI                                             0x20            // non-specific end-of-interrupt
-
-/************************************************/
-/*             Device/Geometry controls                                */
-/************************************************/
-#define GEOMETRY_NONE                  0x0                     // No device
-#define GEOMETRY_AUTO                  0x1                     // Geometry set automatically
-#define GEOMETRY_USER                  0x2                     // User supplied geometry
-
-#define        DEVICE_NONE                             0x0                     // No device present
-#define        DEVICE_INACTIVE                 0x1                     // device present but not registered active
-#define        DEVICE_ATAPI                    0x2                     // ATAPI device (CD_ROM, Tape, Etc...)
-#define        DEVICE_DASD_NONLBA              0x3                     // Non LBA incompatible device
-#define        DEVICE_DASD_LBA                 0x4                     // LBA compatible device
-
-/************************************************/
-/*             Setup Structure Definitions     */
-/************************************************/
-typedef struct                                                 // device setup parameters
-       {
-       UCHAR                   geometryControl;        // geometry control flags
-       UCHAR                   device;                         // device code
-       USHORT                  sectors;                        // number of sectors per track
-       USHORT                  heads;                          // number of heads
-       USHORT                  cylinders;                      // number of cylinders for this device
-       ULONG                   blocks;                         // number of blocks on device
-       USHORT                  spare1;
-       USHORT                  spare2;
-       } SETUP_DEVICE, *PSETUP_DEVICE;
-
-typedef struct         // master setup structure
-       {
-       USHORT                  startupDelay;
-       USHORT                  promptBIOS;
-       USHORT                  fastFormat;
-       USHORT                  spare2;
-       USHORT                  spare3;
-       USHORT                  spare4;
-       USHORT                  spare5;
-       USHORT                  spare6;
-       SETUP_DEVICE    setupDevice[8];
-       }       SETUP, *PSETUP;
-
-#endif
-
index 146d540f6281fdd0917258fac03ae8c7eeef87e8..c94906abfee353137b4483dbcfcc2346cc4aeab9 100644 (file)
@@ -528,7 +528,7 @@ __setup("qla1280=", qla1280_setup);
 #define        CMD_CDBLEN(Cmnd)        Cmnd->cmd_len
 #define        CMD_CDBP(Cmnd)          Cmnd->cmnd
 #define        CMD_SNSP(Cmnd)          Cmnd->sense_buffer
-#define        CMD_SNSLEN(Cmnd)        sizeof(Cmnd->sense_buffer)
+#define        CMD_SNSLEN(Cmnd)        SCSI_SENSE_BUFFERSIZE
 #define        CMD_RESULT(Cmnd)        Cmnd->result
 #define        CMD_HANDLE(Cmnd)        Cmnd->host_scribble
 #define CMD_REQUEST(Cmnd)      Cmnd->request->cmd
@@ -3041,7 +3041,6 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
        int cnt;
        int req_cnt;
        int seg_cnt;
-       dma_addr_t dma_handle;
        u8 dir;
 
        ENTER("qla1280_32bit_start_scsi");
@@ -3050,6 +3049,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                cmd->cmnd[0]);
 
        /* Calculate number of entries and segments required. */
+       req_cnt = 1;
        seg_cnt = scsi_dma_map(cmd);
        if (seg_cnt) {
                /*
@@ -3715,7 +3715,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt,
                        } else
                                sense_sz = 0;
                        memset(cmd->sense_buffer + sense_sz, 0,
-                              sizeof(cmd->sense_buffer) - sense_sz);
+                              SCSI_SENSE_BUFFERSIZE - sense_sz);
 
                        dprintk(2, "qla1280_status_entry: Check "
                                "condition Sense data, b %i, t %i, "
index 71ddb5db4944e0321b1a89ce5960fe33db8a3ff8..c51fd1f86639a72c65d804ab0db7b726dc33ff0a 100644 (file)
@@ -1,4 +1,4 @@
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
-               qla_dbg.o qla_sup.o qla_attr.o qla_mid.o
+               qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
index fb388b8c07cf9edf614a63d9b35726ffbc1bb7a7..adf97320574bacd7b53f63a0be445805e379d8be 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/kthread.h>
 #include <linux/vmalloc.h>
 
-int qla24xx_vport_disable(struct fc_vport *, bool);
+static int qla24xx_vport_disable(struct fc_vport *, bool);
 
 /* SYSFS attributes --------------------------------------------------------- */
 
@@ -958,7 +958,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
 {
        scsi_qla_host_t *ha = shost_priv(shost);
 
-       set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
+       qla2x00_loop_reset(ha);
        return 0;
 }
 
@@ -967,35 +967,51 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 {
        scsi_qla_host_t *ha = shost_priv(shost);
        int rval;
-       uint16_t mb_stat[1];
-       link_stat_t stat_buf;
+       struct link_statistics *stats;
+       dma_addr_t stats_dma;
        struct fc_host_statistics *pfc_host_stat;
 
-       rval = QLA_FUNCTION_FAILED;
        pfc_host_stat = &ha->fc_host_stat;
        memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
 
+       stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
+       if (stats == NULL) {
+               DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
+                   __func__, ha->host_no));
+               goto done;
+       }
+       memset(stats, 0, DMA_POOL_SIZE);
+
+       rval = QLA_FUNCTION_FAILED;
        if (IS_FWI2_CAPABLE(ha)) {
-               rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
-                   sizeof(stat_buf) / 4, mb_stat);
+               rval = qla24xx_get_isp_stats(ha, stats, stats_dma);
        } else if (atomic_read(&ha->loop_state) == LOOP_READY &&
                    !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) &&
                    !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) &&
                    !ha->dpc_active) {
                /* Must be in a 'READY' state for statistics retrieval. */
-               rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
-                   mb_stat);
+               rval = qla2x00_get_link_status(ha, ha->loop_id, stats,
+                   stats_dma);
        }
 
        if (rval != QLA_SUCCESS)
-               goto done;
+               goto done_free;
+
+       pfc_host_stat->link_failure_count = stats->link_fail_cnt;
+       pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt;
+       pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt;
+       pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
+       pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
+       pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
+       if (IS_FWI2_CAPABLE(ha)) {
+               pfc_host_stat->tx_frames = stats->tx_frames;
+               pfc_host_stat->rx_frames = stats->rx_frames;
+               pfc_host_stat->dumped_frames = stats->dumped_frames;
+               pfc_host_stat->nos_count = stats->nos_rcvd;
+       }
 
-       pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
-       pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
-       pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt;
-       pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
-       pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
-       pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
+done_free:
+        dma_pool_free(ha->s_dma_pool, stats, stats_dma);
 done:
        return pfc_host_stat;
 }
@@ -1113,7 +1129,7 @@ vport_create_failed_2:
        return FC_VPORT_FAILED;
 }
 
-int
+static int
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 {
        scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
@@ -1124,7 +1140,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
        down(&ha->vport_sem);
        ha->cur_vport_count--;
-       clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+       clear_bit(vha->vp_idx, ha->vp_idx_map);
        up(&ha->vport_sem);
 
        kfree(vha->node_name);
@@ -1146,7 +1162,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
        return 0;
 }
 
-int
+static int
 qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
 {
        scsi_qla_host_t *vha = fc_vport->dd_data;
index eaa04dabcdf6b4fd331f6572e46691a727fe8fd4..d88e98c476b01c156e52c6d790be0d981056631a 100644 (file)
@@ -1051,6 +1051,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        struct qla25xx_fw_dump *fw;
        uint32_t        ext_mem_cnt;
        void            *nxt;
+       struct qla2xxx_fce_chain *fcec;
 
        risc_address = ext_mem_cnt = 0;
        flags = 0;
@@ -1321,10 +1322,31 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        if (rval != QLA_SUCCESS)
                goto qla25xx_fw_dump_failed_0;
 
+       /* Fibre Channel Trace Buffer. */
        nxt = qla2xxx_copy_queues(ha, nxt);
        if (ha->eft)
                memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
 
+       /* Fibre Channel Event Buffer. */
+       if (!ha->fce)
+               goto qla25xx_fw_dump_failed_0;
+
+       ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
+
+       fcec = nxt + ntohl(ha->fw_dump->eft_size);
+       fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST);
+       fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) +
+           fce_calc_size(ha->fce_bufs));
+       fcec->size = htonl(fce_calc_size(ha->fce_bufs));
+       fcec->addr_l = htonl(LSD(ha->fce_dma));
+       fcec->addr_h = htonl(MSD(ha->fce_dma));
+
+       iter_reg = fcec->eregs;
+       for (cnt = 0; cnt < 8; cnt++)
+               *iter_reg++ = htonl(ha->fce_mb[cnt]);
+
+       memcpy(iter_reg, ha->fce, ntohl(fcec->size));
+
 qla25xx_fw_dump_failed_0:
        if (rval != QLA_SUCCESS) {
                qla_printk(KERN_WARNING, ha,
@@ -1428,21 +1450,6 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
        printk("  sp flags=0x%x\n", sp->flags);
 }
 
-void
-qla2x00_dump_pkt(void *pkt)
-{
-       uint32_t i;
-       uint8_t *data = (uint8_t *) pkt;
-
-       for (i = 0; i < 64; i++) {
-               if (!(i % 4))
-                       printk("\n%02x: ", i);
-
-               printk("%02x ", data[i]);
-       }
-       printk("\n");
-}
-
 #if defined(QL_DEBUG_ROUTINES)
 /*
  * qla2x00_formatted_dump_buffer
index a50ecf0b7c8452b144b1459d247897a9bfef6b4f..524598afc81c2d561e8ef2542929bc64f320c290 100644 (file)
@@ -256,6 +256,25 @@ struct qla25xx_fw_dump {
 #define EFT_BYTES_PER_BUFFER   0x4000
 #define EFT_SIZE               ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
 
+#define FCE_NUM_BUFFERS                64
+#define FCE_BYTES_PER_BUFFER   0x400
+#define FCE_SIZE               ((FCE_BYTES_PER_BUFFER) * (FCE_NUM_BUFFERS))
+#define fce_calc_size(b)       ((FCE_BYTES_PER_BUFFER) * (b))
+
+struct qla2xxx_fce_chain {
+       uint32_t type;
+       uint32_t chain_size;
+
+       uint32_t size;
+       uint32_t addr_l;
+       uint32_t addr_h;
+       uint32_t eregs[8];
+};
+
+#define DUMP_CHAIN_VARIANT     0x80000000
+#define DUMP_CHAIN_FCE         0x7FFFFAF0
+#define DUMP_CHAIN_LAST                0x80000000
+
 struct qla2xxx_fw_dump {
        uint8_t signature[4];
        uint32_t version;
index 04e8cbca4c0d05221a8f6fdf3ece827a72a02fc4..6f129da3758942fec786136fecd4eed5a9b5e4d0 100644 (file)
@@ -623,9 +623,6 @@ typedef struct {
 #define MBC_GET_LINK_PRIV_STATS                0x6d    /* Get link & private data. */
 #define MBC_SET_VENDOR_ID              0x76    /* Set Vendor ID. */
 
-#define TC_ENABLE                      4
-#define TC_DISABLE                     5
-
 /* Firmware return data sizes */
 #define FCAL_MAP_SIZE  128
 
@@ -862,14 +859,20 @@ typedef struct {
 #define GLSO_SEND_RPS  BIT_0
 #define GLSO_USE_DID   BIT_3
 
-typedef struct {
-       uint32_t        link_fail_cnt;
-       uint32_t        loss_sync_cnt;
-       uint32_t        loss_sig_cnt;
-       uint32_t        prim_seq_err_cnt;
-       uint32_t        inval_xmit_word_cnt;
-       uint32_t        inval_crc_cnt;
-} link_stat_t;
+struct link_statistics {
+       uint32_t link_fail_cnt;
+       uint32_t loss_sync_cnt;
+       uint32_t loss_sig_cnt;
+       uint32_t prim_seq_err_cnt;
+       uint32_t inval_xmit_word_cnt;
+       uint32_t inval_crc_cnt;
+       uint32_t unused1[0x1b];
+       uint32_t tx_frames;
+       uint32_t rx_frames;
+       uint32_t dumped_frames;
+       uint32_t unused2[2];
+       uint32_t nos_rcvd;
+};
 
 /*
  * NVRAM Command values.
@@ -2116,14 +2119,6 @@ struct qla_msix_entry {
 
 #define        WATCH_INTERVAL          1       /* number of seconds */
 
-/* NPIV */
-#define MAX_MULTI_ID_LOOP                     126
-#define MAX_MULTI_ID_FABRIC                    64
-#define MAX_NUM_VPORT_LOOP                      (MAX_MULTI_ID_LOOP - 1)
-#define MAX_NUM_VPORT_FABRIC                    (MAX_MULTI_ID_FABRIC - 1)
-#define MAX_NUM_VHBA_LOOP                       (MAX_MULTI_ID_LOOP - 1)
-#define MAX_NUM_VHBA_FABRIC                     (MAX_MULTI_ID_FABRIC - 1)
-
 /*
  * Linux Host Adapter structure
  */
@@ -2161,6 +2156,7 @@ typedef struct scsi_qla_host {
                uint32_t        gpsc_supported          :1;
                uint32_t        vsan_enabled            :1;
                uint32_t        npiv_supported          :1;
+               uint32_t        fce_enabled             :1;
        } flags;
 
        atomic_t        loop_state;
@@ -2273,8 +2269,7 @@ typedef struct scsi_qla_host {
 
        int             bars;
        device_reg_t __iomem *iobase;           /* Base I/O address */
-       unsigned long   pio_address;
-       unsigned long   pio_length;
+       resource_size_t pio_address;
 #define MIN_IOBASE_LEN         0x100
 
        /* ISP ring lock, rings, and indexes */
@@ -2416,9 +2411,9 @@ typedef struct scsi_qla_host {
 #define MBX_INTR_WAIT  2
 #define MBX_UPDATE_FLASH_ACTIVE        3
 
-       struct semaphore mbx_cmd_sem;   /* Serialialize mbx access */
        struct semaphore vport_sem;     /* Virtual port synchronization */
-       struct semaphore mbx_intr_sem;  /* Used for completion notification */
+       struct completion mbx_cmd_comp; /* Serialize mbx access */
+       struct completion mbx_intr_comp;  /* Used for completion notification */
 
        uint32_t        mbx_flags;
 #define  MBX_IN_PROGRESS       BIT_0
@@ -2455,6 +2450,15 @@ typedef struct scsi_qla_host {
        dma_addr_t      eft_dma;
        void            *eft;
 
+       struct dentry *dfs_dir;
+       struct dentry *dfs_fce;
+       dma_addr_t      fce_dma;
+       void            *fce;
+       uint32_t        fce_bufs;
+       uint16_t        fce_mb[8];
+       uint64_t        fce_wr, fce_rd;
+       struct mutex    fce_mutex;
+
        uint8_t         host_str[16];
        uint32_t        pci_attr;
        uint16_t        chip_revision;
@@ -2507,7 +2511,7 @@ typedef struct scsi_qla_host {
 
        struct list_head        vp_list;        /* list of VP */
        struct fc_vport *fc_vport;      /* holds fc_vport * for each vport */
-       uint8_t         vp_idx_map[16];
+       unsigned long   vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)];
        uint16_t        num_vhosts;     /* number of vports created */
        uint16_t        num_vsans;      /* number of vsan created */
        uint16_t        vp_idx;         /* vport ID */
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
new file mode 100644 (file)
index 0000000..1479c60
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2005 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static struct dentry *qla2x00_dfs_root;
+static atomic_t qla2x00_dfs_root_count;
+
+static int
+qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
+{
+       scsi_qla_host_t *ha = s->private;
+       uint32_t cnt;
+       uint32_t *fce;
+       uint64_t fce_start;
+
+       mutex_lock(&ha->fce_mutex);
+
+       seq_printf(s, "FCE Trace Buffer\n");
+       seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr);
+       seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
+       seq_printf(s, "FCE Enable Registers\n");
+       seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
+           ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
+           ha->fce_mb[5], ha->fce_mb[6]);
+
+       fce = (uint32_t *) ha->fce;
+       fce_start = (unsigned long long) ha->fce_dma;
+       for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
+               if (cnt % 8 == 0)
+                       seq_printf(s, "\n%llx: ",
+                           (unsigned long long)((cnt * 4) + fce_start));
+               else
+                       seq_printf(s, " ");
+               seq_printf(s, "%08x", *fce++);
+       }
+
+       seq_printf(s, "\nEnd\n");
+
+       mutex_unlock(&ha->fce_mutex);
+
+       return 0;
+}
+
+static int
+qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
+{
+       scsi_qla_host_t *ha = inode->i_private;
+       int rval;
+
+       if (!ha->flags.fce_enabled)
+               goto out;
+
+       mutex_lock(&ha->fce_mutex);
+
+       /* Pause tracing to flush FCE buffers. */
+       rval = qla2x00_disable_fce_trace(ha, &ha->fce_wr, &ha->fce_rd);
+       if (rval)
+               qla_printk(KERN_WARNING, ha,
+                   "DebugFS: Unable to disable FCE (%d).\n", rval);
+
+       ha->flags.fce_enabled = 0;
+
+       mutex_unlock(&ha->fce_mutex);
+out:
+       return single_open(file, qla2x00_dfs_fce_show, ha);
+}
+
+static int
+qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
+{
+       scsi_qla_host_t *ha = inode->i_private;
+       int rval;
+
+       if (ha->flags.fce_enabled)
+               goto out;
+
+       mutex_lock(&ha->fce_mutex);
+
+       /* Re-enable FCE tracing. */
+       ha->flags.fce_enabled = 1;
+       memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
+       rval = qla2x00_enable_fce_trace(ha, ha->fce_dma, ha->fce_bufs,
+           ha->fce_mb, &ha->fce_bufs);
+       if (rval) {
+               qla_printk(KERN_WARNING, ha,
+                   "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
+               ha->flags.fce_enabled = 0;
+       }
+
+       mutex_unlock(&ha->fce_mutex);
+out:
+       return single_release(inode, file);
+}
+
+static const struct file_operations dfs_fce_ops = {
+       .open           = qla2x00_dfs_fce_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = qla2x00_dfs_fce_release,
+};
+
+int
+qla2x00_dfs_setup(scsi_qla_host_t *ha)
+{
+       if (!IS_QLA25XX(ha))
+               goto out;
+       if (!ha->fce)
+               goto out;
+
+       if (qla2x00_dfs_root)
+               goto create_dir;
+
+       atomic_set(&qla2x00_dfs_root_count, 0);
+       qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
+       if (!qla2x00_dfs_root) {
+               qla_printk(KERN_NOTICE, ha,
+                   "DebugFS: Unable to create root directory.\n");
+               goto out;
+       }
+
+create_dir:
+       if (ha->dfs_dir)
+               goto create_nodes;
+
+       mutex_init(&ha->fce_mutex);
+       ha->dfs_dir = debugfs_create_dir(ha->host_str, qla2x00_dfs_root);
+       if (!ha->dfs_dir) {
+               qla_printk(KERN_NOTICE, ha,
+                   "DebugFS: Unable to create ha directory.\n");
+               goto out;
+       }
+
+       atomic_inc(&qla2x00_dfs_root_count);
+
+create_nodes:
+       ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha,
+           &dfs_fce_ops);
+       if (!ha->dfs_fce) {
+               qla_printk(KERN_NOTICE, ha,
+                   "DebugFS: Unable to fce node.\n");
+               goto out;
+       }
+out:
+       return 0;
+}
+
+int
+qla2x00_dfs_remove(scsi_qla_host_t *ha)
+{
+       if (ha->dfs_fce) {
+               debugfs_remove(ha->dfs_fce);
+               ha->dfs_fce = NULL;
+       }
+
+       if (ha->dfs_dir) {
+               debugfs_remove(ha->dfs_dir);
+               ha->dfs_dir = NULL;
+               atomic_dec(&qla2x00_dfs_root_count);
+       }
+
+       if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
+           qla2x00_dfs_root) {
+               debugfs_remove(qla2x00_dfs_root);
+               qla2x00_dfs_root = NULL;
+       }
+
+       return 0;
+}
index 25364b1aaf12327daf2dac3e1ea34ce8286f147d..9337e138ed639ada65f29762140c9ef8f4ea4def 100644 (file)
@@ -952,9 +952,31 @@ struct device_reg_24xx {
        uint32_t iobase_sdata;
 };
 
+/* Trace Control *************************************************************/
+
+#define TC_AEN_DISABLE         0
+
+#define TC_EFT_ENABLE          4
+#define TC_EFT_DISABLE         5
+
+#define TC_FCE_ENABLE          8
+#define TC_FCE_OPTIONS         0
+#define TC_FCE_DEFAULT_RX_SIZE 2112
+#define TC_FCE_DEFAULT_TX_SIZE 2112
+#define TC_FCE_DISABLE         9
+#define TC_FCE_DISABLE_TRACE   BIT_0
+
 /* MID Support ***************************************************************/
 
-#define MAX_MID_VPS    125
+#define MIN_MULTI_ID_FABRIC    64      /* Must be power-of-2. */
+#define MAX_MULTI_ID_FABRIC    256     /* ... */
+
+#define for_each_mapped_vp_idx(_ha, _idx)              \
+       for (_idx = find_next_bit((_ha)->vp_idx_map,    \
+               (_ha)->max_npiv_vports + 1, 1);         \
+           _idx <= (_ha)->max_npiv_vports;             \
+           _idx = find_next_bit((_ha)->vp_idx_map,     \
+               (_ha)->max_npiv_vports + 1, _idx + 1))  \
 
 struct mid_conf_entry_24xx {
        uint16_t reserved_1;
@@ -982,7 +1004,7 @@ struct mid_init_cb_24xx {
        uint16_t count;
        uint16_t options;
 
-       struct mid_conf_entry_24xx entries[MAX_MID_VPS];
+       struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC];
 };
 
 
@@ -1002,10 +1024,6 @@ struct mid_db_entry_24xx {
        uint8_t reserved_1;
 };
 
-struct mid_db_24xx {
-       struct mid_db_entry_24xx entries[MAX_MID_VPS];
-};
-
  /*
  * Virtual Fabric ID type definition.
  */
index 09cb2a9080597afc6d28bb051b8f626fdd9985d1..ba35fc26ce6b8d0bf04f564d6de92137e35efa59 100644 (file)
@@ -65,33 +65,25 @@ extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
 extern int num_hosts;
 
+extern int qla2x00_loop_reset(scsi_qla_host_t *);
+
 /*
  * Global Functions in qla_mid.c source file.
  */
-extern struct scsi_host_template qla2x00_driver_template;
 extern struct scsi_host_template qla24xx_driver_template;
 extern struct scsi_transport_template *qla2xxx_transport_vport_template;
-extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
 extern void qla2x00_timer(scsi_qla_host_t *);
 extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
-extern void qla2x00_stop_timer(scsi_qla_host_t *);
-extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
 extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
 extern int qla24xx_disable_vp (scsi_qla_host_t *);
 extern int qla24xx_enable_vp (scsi_qla_host_t *);
-extern void qla2x00_mem_free(scsi_qla_host_t *);
 extern int qla24xx_control_vp(scsi_qla_host_t *, int );
 extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
 extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
 extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
 extern int qla24xx_configure_vhba (scsi_qla_host_t *);
-extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
-extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
-extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
 extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
     struct vp_rpt_id_entry_24xx *);
-extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
-    uint8_t *);
 extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
 extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
 extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
@@ -103,8 +95,6 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
 extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
 
-extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
-
 extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
 
 extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
@@ -113,7 +103,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
 extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
 extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
 extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
-extern int qla24xx_vport_delete(struct fc_vport *);
 
 /*
  * Global Function Prototypes in qla_iocb.c source file.
@@ -222,21 +211,16 @@ extern int
 qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
 
 extern int
-qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *,
-    uint16_t *);
+qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *,
+    dma_addr_t);
 
 extern int
-qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *);
+qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
+    dma_addr_t);
 
 extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *);
 extern int qla24xx_abort_target(fc_port_t *);
 
-extern int qla2x00_system_error(scsi_qla_host_t *);
-
-extern int
-qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *,
-    uint16_t *);
-
 extern int
 qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
 
@@ -244,13 +228,19 @@ extern int
 qla2x00_stop_firmware(scsi_qla_host_t *);
 
 extern int
-qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
+qla2x00_enable_eft_trace(scsi_qla_host_t *, dma_addr_t, uint16_t);
+extern int
+qla2x00_disable_eft_trace(scsi_qla_host_t *);
 
 extern int
-qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *,
+    uint32_t *);
 
 extern int
-qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
+qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
+
+extern int
+qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
 
 extern int
 qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
@@ -270,11 +260,7 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *);
 /*
  * Global Function Prototypes in qla_sup.c source file.
  */
-extern void qla2x00_lock_nvram_access(scsi_qla_host_t *);
-extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
 extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
-extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
-extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
 extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
     uint32_t, uint32_t);
 extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
@@ -321,7 +307,6 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
 extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
-extern void qla2x00_dump_pkt(void *);
 
 /*
  * Global Function Prototypes in qla_gs.c source file.
@@ -356,4 +341,10 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_init_host_attr(scsi_qla_host_t *);
 extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
+
+/*
+ * Global Function Prototypes in qla_dfs.c source file.
+ */
+extern int qla2x00_dfs_setup(scsi_qla_host_t *);
+extern int qla2x00_dfs_remove(scsi_qla_host_t *);
 #endif /* _QLA_GBL_H */
index 191dafd89be080763c520bfef2b41e62bba8d0f7..d0633ca894be7cfd06f622b78de4f2b2792486e4 100644 (file)
@@ -732,9 +732,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 {
        int rval;
        uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
-           eft_size;
-       dma_addr_t eft_dma;
-       void *eft;
+           eft_size, fce_size;
+       dma_addr_t tc_dma;
+       void *tc;
 
        if (ha->fw_dump) {
                qla_printk(KERN_WARNING, ha,
@@ -743,7 +743,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
        }
 
        ha->fw_dumped = 0;
-       fixed_size = mem_size = eft_size = 0;
+       fixed_size = mem_size = eft_size = fce_size = 0;
        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
                fixed_size = sizeof(struct qla2100_fw_dump);
        } else if (IS_QLA23XX(ha)) {
@@ -758,21 +758,21 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
                    sizeof(uint32_t);
 
                /* Allocate memory for Extended Trace Buffer. */
-               eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
+               tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
                    GFP_KERNEL);
-               if (!eft) {
+               if (!tc) {
                        qla_printk(KERN_WARNING, ha, "Unable to allocate "
                            "(%d KB) for EFT.\n", EFT_SIZE / 1024);
                        goto cont_alloc;
                }
 
-               rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
-                   EFT_NUM_BUFFERS);
+               memset(tc, 0, EFT_SIZE);
+               rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
                if (rval) {
                        qla_printk(KERN_WARNING, ha, "Unable to initialize "
                            "EFT (%d).\n", rval);
-                       dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
-                           eft_dma);
+                       dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+                           tc_dma);
                        goto cont_alloc;
                }
 
@@ -780,9 +780,40 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
                    EFT_SIZE / 1024);
 
                eft_size = EFT_SIZE;
-               memset(eft, 0, eft_size);
-               ha->eft_dma = eft_dma;
-               ha->eft = eft;
+               ha->eft_dma = tc_dma;
+               ha->eft = tc;
+
+               /* Allocate memory for Fibre Channel Event Buffer. */
+               if (!IS_QLA25XX(ha))
+                       goto cont_alloc;
+
+               tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
+                   GFP_KERNEL);
+               if (!tc) {
+                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
+                           "(%d KB) for FCE.\n", FCE_SIZE / 1024);
+                       goto cont_alloc;
+               }
+
+               memset(tc, 0, FCE_SIZE);
+               rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS,
+                   ha->fce_mb, &ha->fce_bufs);
+               if (rval) {
+                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
+                           "FCE (%d).\n", rval);
+                       dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
+                           tc_dma);
+                       ha->flags.fce_enabled = 0;
+                       goto cont_alloc;
+               }
+
+               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
+                   FCE_SIZE / 1024);
+
+               fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE;
+               ha->flags.fce_enabled = 1;
+               ha->fce_dma = tc_dma;
+               ha->fce = tc;
        }
 cont_alloc:
        req_q_size = ha->request_q_length * sizeof(request_t);
@@ -790,7 +821,7 @@ cont_alloc:
 
        dump_size = offsetof(struct qla2xxx_fw_dump, isp);
        dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
-           eft_size;
+           eft_size + fce_size;
 
        ha->fw_dump = vmalloc(dump_size);
        if (!ha->fw_dump) {
@@ -922,9 +953,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
                                        ha->flags.npiv_supported = 1;
                                        if ((!ha->max_npiv_vports) ||
                                            ((ha->max_npiv_vports + 1) %
-                                           MAX_MULTI_ID_FABRIC))
+                                           MIN_MULTI_ID_FABRIC))
                                                ha->max_npiv_vports =
-                                                   MAX_NUM_VPORT_FABRIC;
+                                                   MIN_MULTI_ID_FABRIC - 1;
                                }
 
                                if (ql2xallocfwdump)
@@ -1162,7 +1193,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
 
        DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
 
-       mid_init_cb->count = ha->max_npiv_vports;
+       if (ha->flags.npiv_supported)
+               mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
+
+       mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
 
        rval = qla2x00_init_firmware(ha, ha->init_cb_size);
        if (rval) {
@@ -2566,14 +2600,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 
                /* Bypass virtual ports of the same host. */
                if (pha->num_vhosts) {
-                       vp_index = find_next_bit(
-                           (unsigned long *)pha->vp_idx_map,
-                           MAX_MULTI_ID_FABRIC + 1, 1);
-
-                       for (;vp_index <= MAX_MULTI_ID_FABRIC;
-                           vp_index = find_next_bit(
-                           (unsigned long *)pha->vp_idx_map,
-                           MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+                       for_each_mapped_vp_idx(pha, vp_index) {
                                empty_vp_index = 1;
                                found_vp = 0;
                                list_for_each_entry(vha, &pha->vp_list,
@@ -2592,7 +2619,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                                    new_fcport->d_id.b24 == vha->d_id.b24)
                                        break;
                        }
-                       if (vp_index <= MAX_MULTI_ID_FABRIC)
+
+                       if (vp_index <= pha->max_npiv_vports)
                                continue;
                }
 
@@ -3245,7 +3273,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                        clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 
                        if (ha->eft) {
-                               rval = qla2x00_trace_control(ha, TC_ENABLE,
+                               rval = qla2x00_enable_eft_trace(ha,
                                    ha->eft_dma, EFT_NUM_BUFFERS);
                                if (rval) {
                                        qla_printk(KERN_WARNING, ha,
@@ -3253,6 +3281,21 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                                            "(%d).\n", rval);
                                }
                        }
+
+                       if (ha->fce) {
+                               ha->flags.fce_enabled = 1;
+                               memset(ha->fce, 0,
+                                   fce_calc_size(ha->fce_bufs));
+                               rval = qla2x00_enable_fce_trace(ha,
+                                   ha->fce_dma, ha->fce_bufs, ha->fce_mb,
+                                   &ha->fce_bufs);
+                               if (rval) {
+                                       qla_printk(KERN_WARNING, ha,
+                                           "Unable to reinitialize FCE "
+                                           "(%d).\n", rval);
+                                       ha->flags.fce_enabled = 0;
+                               }
+                       }
                } else {        /* failed the ISP abort */
                        ha->flags.online = 1;
                        if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
index 1104bd2eed405a0ce3432c702d8bdc804ad7edcc..642a0c3f09c6a6a11fb9d99d884b1334d64aa651 100644 (file)
@@ -104,7 +104,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return (IRQ_HANDLED);
@@ -216,7 +216,7 @@ qla2300_intr_handler(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return (IRQ_HANDLED);
@@ -347,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                break;
 
        case MBA_SYSTEM_ERR:            /* System Error */
-               mb[1] = RD_MAILBOX_REG(ha, reg, 1);
-               mb[2] = RD_MAILBOX_REG(ha, reg, 2);
-               mb[3] = RD_MAILBOX_REG(ha, reg, 3);
-
                qla_printk(KERN_INFO, ha,
                    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
                    mb[1], mb[2], mb[3]);
@@ -579,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                /* Check if the Vport has issued a SCR */
                if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
                        break;
+               /* Only handle SCNs for our Vport index. */
+               if (ha->flags.npiv_supported && ha->vp_idx != mb[3])
+                       break;
 
                DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
                    ha->host_no));
                DEBUG(printk(KERN_INFO
-                   "scsi(%ld): RSCN database changed -- %04x %04x.\n",
-                   ha->host_no, mb[1], mb[2]));
+                   "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
+                   ha->host_no, mb[1], mb[2], mb[3]));
 
                rscn_entry = (mb[1] << 16) | mb[2];
                host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
@@ -823,6 +822,35 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
        WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
 }
 
+static inline void
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
+{
+       struct scsi_cmnd *cp = sp->cmd;
+
+       if (sense_len >= SCSI_SENSE_BUFFERSIZE)
+               sense_len = SCSI_SENSE_BUFFERSIZE;
+
+       CMD_ACTUAL_SNSLEN(cp) = sense_len;
+       sp->request_sense_length = sense_len;
+       sp->request_sense_ptr = cp->sense_buffer;
+       if (sp->request_sense_length > 32)
+               sense_len = 32;
+
+       memcpy(cp->sense_buffer, sense_data, sense_len);
+
+       sp->request_sense_ptr += sense_len;
+       sp->request_sense_length -= sense_len;
+       if (sp->request_sense_length != 0)
+               sp->ha->status_srb = sp;
+
+       DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
+           "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel,
+           cp->device->id, cp->device->lun, cp, cp->serial_number));
+       if (sense_len)
+               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+                   CMD_ACTUAL_SNSLEN(cp)));
+}
+
 /**
  * qla2x00_status_entry() - Process a Status IOCB entry.
  * @ha: SCSI driver HA context
@@ -977,36 +1005,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                if (lscsi_status != SS_CHECK_CONDITION)
                        break;
 
-               /* Copy Sense Data into sense buffer. */
-               memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
-
+               memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
                if (!(scsi_status & SS_SENSE_LEN_VALID))
                        break;
 
-               if (sense_len >= sizeof(cp->sense_buffer))
-                       sense_len = sizeof(cp->sense_buffer);
-
-               CMD_ACTUAL_SNSLEN(cp) = sense_len;
-               sp->request_sense_length = sense_len;
-               sp->request_sense_ptr = cp->sense_buffer;
-
-               if (sp->request_sense_length > 32)
-                       sense_len = 32;
-
-               memcpy(cp->sense_buffer, sense_data, sense_len);
-
-               sp->request_sense_ptr += sense_len;
-               sp->request_sense_length -= sense_len;
-               if (sp->request_sense_length != 0)
-                       ha->status_srb = sp;
-
-               DEBUG5(printk("%s(): Check condition Sense data, "
-                   "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", __func__,
-                   ha->host_no, cp->device->channel, cp->device->id,
-                   cp->device->lun, cp, cp->serial_number));
-               if (sense_len)
-                       DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-                           CMD_ACTUAL_SNSLEN(cp)));
+               qla2x00_handle_sense(sp, sense_data, sense_len);
                break;
 
        case CS_DATA_UNDERRUN:
@@ -1061,34 +1064,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                        if (lscsi_status != SS_CHECK_CONDITION)
                                break;
 
-                       /* Copy Sense Data into sense buffer */
-                       memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
-
+                       memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
                        if (!(scsi_status & SS_SENSE_LEN_VALID))
                                break;
 
-                       if (sense_len >= sizeof(cp->sense_buffer))
-                               sense_len = sizeof(cp->sense_buffer);
-
-                       CMD_ACTUAL_SNSLEN(cp) = sense_len;
-                       sp->request_sense_length = sense_len;
-                       sp->request_sense_ptr = cp->sense_buffer;
-
-                       if (sp->request_sense_length > 32)
-                               sense_len = 32;
-
-                       memcpy(cp->sense_buffer, sense_data, sense_len);
-
-                       sp->request_sense_ptr += sense_len;
-                       sp->request_sense_length -= sense_len;
-                       if (sp->request_sense_length != 0)
-                               ha->status_srb = sp;
-
-                       DEBUG5(printk("%s(): Check condition Sense data, "
-                           "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
-                           __func__, ha->host_no, cp->device->channel,
-                           cp->device->id, cp->device->lun, cp,
-                           cp->serial_number));
+                       qla2x00_handle_sense(sp, sense_data, sense_len);
 
                        /*
                         * In case of a Underrun condition, set both the lscsi
@@ -1108,10 +1088,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 
                                cp->result = DID_ERROR << 16 | lscsi_status;
                        }
-
-                       if (sense_len)
-                               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-                                   CMD_ACTUAL_SNSLEN(cp)));
                } else {
                        /*
                         * If RISC reports underrun and target does not report
@@ -1621,7 +1597,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return IRQ_HANDLED;
@@ -1758,7 +1734,7 @@ qla24xx_msix_default(int irq, void *dev_id)
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
            (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               up(&ha->mbx_intr_sem);
+               complete(&ha->mbx_intr_comp);
        }
 
        return IRQ_HANDLED;
@@ -1853,6 +1829,18 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
                goto skip_msix;
        }
 
+       if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
+           (ha->pdev->subsystem_device == 0x7040 ||
+               ha->pdev->subsystem_device == 0x7041 ||
+               ha->pdev->subsystem_device == 0x1705)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
+                   ha->pdev->subsystem_vendor,
+                   ha->pdev->subsystem_device));
+
+               goto skip_msi;
+       }
+
        ret = qla24xx_enable_msix(ha);
        if (!ret) {
                DEBUG2(qla_printk(KERN_INFO, ha,
index ccd662a6f5dccbbfa23c97db60b574eff6356f42..0c10c0b0fb732602e5f0548be2e7be23a3ad1615 100644 (file)
@@ -8,19 +8,6 @@
 
 #include <linux/delay.h>
 
-static void
-qla2x00_mbx_sem_timeout(unsigned long data)
-{
-       struct semaphore        *sem_ptr = (struct semaphore *)data;
-
-       DEBUG11(printk("qla2x00_sem_timeout: entered.\n"));
-
-       if (sem_ptr != NULL) {
-               up(sem_ptr);
-       }
-
-       DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n"));
-}
 
 /*
  * qla2x00_mailbox_command
@@ -47,7 +34,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
        int             rval;
        unsigned long    flags = 0;
        device_reg_t __iomem *reg;
-       struct timer_list       tmp_intr_timer;
        uint8_t         abort_active;
        uint8_t         io_lock_on;
        uint16_t        command;
@@ -72,7 +58,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
         * non ISP abort time.
         */
        if (!abort_active) {
-               if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
+               if (!wait_for_completion_timeout(&ha->mbx_cmd_comp,
+                   mcp->tov * HZ)) {
                        /* Timeout occurred. Return error. */
                        DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
                            "Exiting.\n", __func__, ha->host_no));
@@ -135,22 +122,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
        /* Wait for mbx cmd completion until timeout */
 
        if (!abort_active && io_lock_on) {
-               /* sleep on completion semaphore */
-               DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n",
-                   __func__, ha->host_no));
-
-               init_timer(&tmp_intr_timer);
-               tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
-               tmp_intr_timer.expires = jiffies + mcp->tov * HZ;
-               tmp_intr_timer.function =
-                   (void (*)(unsigned long))qla2x00_mbx_sem_timeout;
-
-               DEBUG11(printk("%s(%ld): Adding timer.\n", __func__,
-                   ha->host_no));
-               add_timer(&tmp_intr_timer);
-
-               DEBUG11(printk("%s(%ld): going to unlock & sleep. "
-                   "time=0x%lx.\n", __func__, ha->host_no, jiffies));
 
                set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
@@ -160,17 +131,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
                        WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               /* Wait for either the timer to expire
-                * or the mbox completion interrupt
-                */
-               down(&ha->mbx_intr_sem);
+               wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
 
-               DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__,
-                   ha->host_no, jiffies));
                clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
-               /* delete the timer */
-               del_timer(&tmp_intr_timer);
        } else {
                DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
                    ha->host_no, command));
@@ -299,7 +263,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 
        /* Allow next mbx cmd to come in. */
        if (!abort_active)
-               up(&ha->mbx_cmd_sem);
+               complete(&ha->mbx_cmd_comp);
 
        if (rval) {
                DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
@@ -905,7 +869,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
 
        mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
        mcp->mb[9] = ha->vp_idx;
-       mcp->out_mb = MBX_0;
+       mcp->out_mb = MBX_9|MBX_0;
        mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->tov = 30;
        mcp->flags = 0;
@@ -1016,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
        DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
            ha->host_no));
 
-       if (ha->flags.npiv_supported)
+       if (ha->fw_attributes & BIT_2)
                mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
        else
                mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
@@ -2042,29 +2006,20 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
  */
 int
 qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
-    link_stat_t *ret_buf, uint16_t *status)
+    struct link_statistics *stats, dma_addr_t stats_dma)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
-       link_stat_t *stat_buf;
-       dma_addr_t stat_buf_dma;
+       uint32_t *siter, *diter, dwords;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
-       if (stat_buf == NULL) {
-               DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-                   __func__, ha->host_no));
-               return BIT_0;
-       }
-       memset(stat_buf, 0, sizeof(link_stat_t));
-
        mcp->mb[0] = MBC_GET_LINK_STATUS;
-       mcp->mb[2] = MSW(stat_buf_dma);
-       mcp->mb[3] = LSW(stat_buf_dma);
-       mcp->mb[6] = MSW(MSD(stat_buf_dma));
-       mcp->mb[7] = LSW(MSD(stat_buf_dma));
+       mcp->mb[2] = MSW(stats_dma);
+       mcp->mb[3] = LSW(stats_dma);
+       mcp->mb[6] = MSW(MSD(stats_dma));
+       mcp->mb[7] = LSW(MSD(stats_dma));
        mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
        mcp->in_mb = MBX_0;
        if (IS_FWI2_CAPABLE(ha)) {
@@ -2089,78 +2044,43 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
                if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
                        DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
                            __func__, ha->host_no, mcp->mb[0]));
-                       status[0] = mcp->mb[0];
-                       rval = BIT_1;
+                       rval = QLA_FUNCTION_FAILED;
                } else {
-                       /* copy over data -- firmware data is LE. */
-                       ret_buf->link_fail_cnt =
-                           le32_to_cpu(stat_buf->link_fail_cnt);
-                       ret_buf->loss_sync_cnt =
-                           le32_to_cpu(stat_buf->loss_sync_cnt);
-                       ret_buf->loss_sig_cnt =
-                           le32_to_cpu(stat_buf->loss_sig_cnt);
-                       ret_buf->prim_seq_err_cnt =
-                           le32_to_cpu(stat_buf->prim_seq_err_cnt);
-                       ret_buf->inval_xmit_word_cnt =
-                           le32_to_cpu(stat_buf->inval_xmit_word_cnt);
-                       ret_buf->inval_crc_cnt =
-                           le32_to_cpu(stat_buf->inval_crc_cnt);
-
-                       DEBUG11(printk("%s(%ld): stat dump: fail_cnt=%d "
-                           "loss_sync=%d loss_sig=%d seq_err=%d "
-                           "inval_xmt_word=%d inval_crc=%d.\n", __func__,
-                           ha->host_no, stat_buf->link_fail_cnt,
-                           stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
-                           stat_buf->prim_seq_err_cnt,
-                           stat_buf->inval_xmit_word_cnt,
-                           stat_buf->inval_crc_cnt));
+                       /* Copy over data -- firmware data is LE. */
+                       dwords = offsetof(struct link_statistics, unused1) / 4;
+                       siter = diter = &stats->link_fail_cnt;
+                       while (dwords--)
+                               *diter++ = le32_to_cpu(*siter++);
                }
        } else {
                /* Failed. */
                DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
                    ha->host_no, rval));
-               rval = BIT_1;
        }
 
-       dma_pool_free(ha->s_dma_pool, stat_buf, stat_buf_dma);
-
        return rval;
 }
 
 int
-qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
-    uint16_t *status)
+qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats,
+    dma_addr_t stats_dma)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
-       uint32_t *sbuf, *siter;
-       dma_addr_t sbuf_dma;
+       uint32_t *siter, *diter, dwords;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       if (dwords > (DMA_POOL_SIZE / 4)) {
-               DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs "
-                   "(max %d).\n", __func__, ha->host_no, dwords,
-                   DMA_POOL_SIZE / 4));
-               return BIT_0;
-       }
-       sbuf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &sbuf_dma);
-       if (sbuf == NULL) {
-               DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-                   __func__, ha->host_no));
-               return BIT_0;
-       }
-       memset(sbuf, 0, DMA_POOL_SIZE);
-
        mcp->mb[0] = MBC_GET_LINK_PRIV_STATS;
-       mcp->mb[2] = MSW(sbuf_dma);
-       mcp->mb[3] = LSW(sbuf_dma);
-       mcp->mb[6] = MSW(MSD(sbuf_dma));
-       mcp->mb[7] = LSW(MSD(sbuf_dma));
-       mcp->mb[8] = dwords;
+       mcp->mb[2] = MSW(stats_dma);
+       mcp->mb[3] = LSW(stats_dma);
+       mcp->mb[6] = MSW(MSD(stats_dma));
+       mcp->mb[7] = LSW(MSD(stats_dma));
+       mcp->mb[8] = sizeof(struct link_statistics) / 4;
+       mcp->mb[9] = ha->vp_idx;
        mcp->mb[10] = 0;
-       mcp->out_mb = MBX_10|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+       mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
        mcp->in_mb = MBX_2|MBX_1|MBX_0;
        mcp->tov = 30;
        mcp->flags = IOCTL_CMD;
@@ -2170,23 +2090,20 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
                if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
                        DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
                            __func__, ha->host_no, mcp->mb[0]));
-                       status[0] = mcp->mb[0];
-                       rval = BIT_1;
+                       rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Copy over data -- firmware data is LE. */
-                       siter = sbuf;
+                       dwords = sizeof(struct link_statistics) / 4;
+                       siter = diter = &stats->link_fail_cnt;
                        while (dwords--)
-                               *dwbuf++ = le32_to_cpu(*siter++);
+                               *diter++ = le32_to_cpu(*siter++);
                }
        } else {
                /* Failed. */
                DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
                    ha->host_no, rval));
-               rval = BIT_1;
        }
 
-       dma_pool_free(ha->s_dma_pool, sbuf, sbuf_dma);
-
        return rval;
 }
 
@@ -2331,6 +2248,8 @@ atarget_done:
        return rval;
 }
 
+#if 0
+
 int
 qla2x00_system_error(scsi_qla_host_t *ha)
 {
@@ -2360,47 +2279,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
        return rval;
 }
 
-/**
- * qla2x00_get_serdes_params() -
- * @ha: HA context
- *
- * Returns
- */
-int
-qla2x00_get_serdes_params(scsi_qla_host_t *ha, uint16_t *sw_em_1g,
-    uint16_t *sw_em_2g, uint16_t *sw_em_4g)
-{
-       int rval;
-       mbx_cmd_t mc;
-       mbx_cmd_t *mcp = &mc;
-
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
-
-       mcp->mb[0] = MBC_SERDES_PARAMS;
-       mcp->mb[1] = 0;
-       mcp->out_mb = MBX_1|MBX_0;
-       mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_0;
-       mcp->tov = 30;
-       mcp->flags = 0;
-       rval = qla2x00_mailbox_command(ha, mcp);
-
-       if (rval != QLA_SUCCESS) {
-               /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   ha->host_no, rval, mcp->mb[0]));
-       } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
-
-               if (sw_em_1g)
-                       *sw_em_1g = mcp->mb[2];
-               if (sw_em_2g)
-                       *sw_em_2g = mcp->mb[3];
-               if (sw_em_4g)
-                       *sw_em_4g = mcp->mb[4];
-       }
-
-       return rval;
-}
+#endif  /*  0  */
 
 /**
  * qla2x00_set_serdes_params() -
@@ -2471,7 +2350,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
 }
 
 int
-qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
+qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma,
     uint16_t buffers)
 {
        int rval;
@@ -2484,22 +2363,18 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
        mcp->mb[0] = MBC_TRACE_CONTROL;
-       mcp->mb[1] = ctrl;
-       mcp->out_mb = MBX_1|MBX_0;
+       mcp->mb[1] = TC_EFT_ENABLE;
+       mcp->mb[2] = LSW(eft_dma);
+       mcp->mb[3] = MSW(eft_dma);
+       mcp->mb[4] = LSW(MSD(eft_dma));
+       mcp->mb[5] = MSW(MSD(eft_dma));
+       mcp->mb[6] = buffers;
+       mcp->mb[7] = TC_AEN_DISABLE;
+       mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->in_mb = MBX_1|MBX_0;
-       if (ctrl == TC_ENABLE) {
-               mcp->mb[2] = LSW(eft_dma);
-               mcp->mb[3] = MSW(eft_dma);
-               mcp->mb[4] = LSW(MSD(eft_dma));
-               mcp->mb[5] = MSW(MSD(eft_dma));
-               mcp->mb[6] = buffers;
-               mcp->mb[7] = 0;
-               mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
-       }
        mcp->tov = 30;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
-
        if (rval != QLA_SUCCESS) {
                DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
                    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
@@ -2511,8 +2386,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
 }
 
 int
-qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
-    uint16_t off, uint16_t count)
+qla2x00_disable_eft_trace(scsi_qla_host_t *ha)
 {
        int rval;
        mbx_cmd_t mc;
@@ -2523,24 +2397,16 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       mcp->mb[0] = MBC_READ_SFP;
-       mcp->mb[1] = addr;
-       mcp->mb[2] = MSW(sfp_dma);
-       mcp->mb[3] = LSW(sfp_dma);
-       mcp->mb[6] = MSW(MSD(sfp_dma));
-       mcp->mb[7] = LSW(MSD(sfp_dma));
-       mcp->mb[8] = count;
-       mcp->mb[9] = off;
-       mcp->mb[10] = 0;
-       mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-       mcp->in_mb = MBX_0;
+       mcp->mb[0] = MBC_TRACE_CONTROL;
+       mcp->mb[1] = TC_EFT_DISABLE;
+       mcp->out_mb = MBX_1|MBX_0;
+       mcp->in_mb = MBX_1|MBX_0;
        mcp->tov = 30;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
-
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   ha->host_no, rval, mcp->mb[0]));
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+                   __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
        } else {
                DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
        }
@@ -2549,176 +2415,168 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
 }
 
 int
-qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
-    uint16_t *port_speed, uint16_t *mb)
+qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma,
+    uint16_t buffers, uint16_t *mb, uint32_t *dwords)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       if (!IS_IIDMA_CAPABLE(ha))
+       if (!IS_QLA25XX(ha))
                return QLA_FUNCTION_FAILED;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       mcp->mb[0] = MBC_PORT_PARAMS;
-       mcp->mb[1] = loop_id;
-       mcp->mb[2] = mcp->mb[3] = 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;
+       mcp->mb[0] = MBC_TRACE_CONTROL;
+       mcp->mb[1] = TC_FCE_ENABLE;
+       mcp->mb[2] = LSW(fce_dma);
+       mcp->mb[3] = MSW(fce_dma);
+       mcp->mb[4] = LSW(MSD(fce_dma));
+       mcp->mb[5] = MSW(MSD(fce_dma));
+       mcp->mb[6] = buffers;
+       mcp->mb[7] = TC_AEN_DISABLE;
+       mcp->mb[8] = 0;
+       mcp->mb[9] = TC_FCE_DEFAULT_RX_SIZE;
+       mcp->mb[10] = TC_FCE_DEFAULT_TX_SIZE;
+       mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
+           MBX_1|MBX_0;
+       mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->tov = 30;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
-
-       /* Return mailbox statuses. */
-       if (mb != NULL) {
-               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) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   ha->host_no, rval));
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+                   __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
        } else {
                DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
-               if (port_speed)
-                       *port_speed = mcp->mb[3];
+
+               if (mb)
+                       memcpy(mb, mcp->mb, 8 * sizeof(*mb));
+               if (dwords)
+                       *dwords = mcp->mb[6];
        }
 
        return rval;
 }
 
 int
-qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
-    uint16_t port_speed, uint16_t *mb)
+qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       if (!IS_IIDMA_CAPABLE(ha))
+       if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       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;
+       mcp->mb[0] = MBC_TRACE_CONTROL;
+       mcp->mb[1] = TC_FCE_DISABLE;
+       mcp->mb[2] = TC_FCE_DISABLE_TRACE;
+       mcp->out_mb = MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
+           MBX_1|MBX_0;
        mcp->tov = 30;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
-
-       /* Return mailbox statuses. */
-       if (mb != NULL) {
-               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) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   ha->host_no, rval));
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+                   __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
        } else {
                DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+
+               if (wr)
+                       *wr = (uint64_t) mcp->mb[5] << 48 |
+                           (uint64_t) mcp->mb[4] << 32 |
+                           (uint64_t) mcp->mb[3] << 16 |
+                           (uint64_t) mcp->mb[2];
+               if (rd)
+                       *rd = (uint64_t) mcp->mb[9] << 48 |
+                           (uint64_t) mcp->mb[8] << 32 |
+                           (uint64_t) mcp->mb[7] << 16 |
+                           (uint64_t) mcp->mb[6];
        }
 
        return rval;
 }
 
-/*
- * qla24xx_get_vp_database
- *     Get the VP's database for all configured ports.
- *
- * Input:
- *     ha = adapter block pointer.
- *     size = size of initialization control block.
- *
- * Returns:
- *     qla2x00 local function return status code.
- *
- * Context:
- *     Kernel context.
- */
 int
-qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
+qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
+    uint16_t off, uint16_t count)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("scsi(%ld):%s - entered.\n",
-           ha->host_no, __func__));
+       if (!IS_FWI2_CAPABLE(ha))
+               return QLA_FUNCTION_FAILED;
 
-       mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
-       mcp->mb[2] = MSW(ha->init_cb_dma);
-       mcp->mb[3] = LSW(ha->init_cb_dma);
-       mcp->mb[4] = 0;
-       mcp->mb[5] = 0;
-       mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
-       mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
-       mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
-       mcp->in_mb = MBX_1|MBX_0;
-       mcp->buf_size = size;
-       mcp->flags = MBX_DMA_OUT;
-       mcp->tov = MBX_TOV_SECONDS;
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+       mcp->mb[0] = MBC_READ_SFP;
+       mcp->mb[1] = addr;
+       mcp->mb[2] = MSW(sfp_dma);
+       mcp->mb[3] = LSW(sfp_dma);
+       mcp->mb[6] = MSW(MSD(sfp_dma));
+       mcp->mb[7] = LSW(MSD(sfp_dma));
+       mcp->mb[8] = count;
+       mcp->mb[9] = off;
+       mcp->mb[10] = 0;
+       mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x "
-                   "mb0=%x.\n",
-                   __func__, ha->host_no, rval, mcp->mb[0]));
+               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+                   ha->host_no, rval, mcp->mb[0]));
        } else {
-               /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n",
-                   __func__, ha->host_no));
+               DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
        }
 
        return rval;
 }
 
 int
-qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
+qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+    uint16_t port_speed, uint16_t *mb)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       if (!IS_IIDMA_CAPABLE(ha))
+               return QLA_FUNCTION_FAILED;
+
        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
-       mcp->mb[2] = MSW(ha->init_cb_dma);
-       mcp->mb[3] = LSW(ha->init_cb_dma);
-       mcp->mb[4] = 0;
-       mcp->mb[5] = 0;
-       mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
-       mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
-       mcp->mb[9] = vp_id;
-       mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
-       mcp->in_mb = MBX_0;
-       mcp->buf_size = size;
-       mcp->flags = MBX_DMA_OUT;
+       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;
        mcp->tov = 30;
+       mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
 
+       /* Return mailbox statuses. */
+       if (mb != NULL) {
+               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) {
-               /*EMPTY*/
-               DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
-                   "mb0=%x.\n",
-                   ha->host_no, rval, mcp->mb[0]));
+               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+                   ha->host_no, rval));
        } else {
-               /*EMPTY*/
-               DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
-                   ha->host_no));
+               DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
        }
 
        return rval;
@@ -2873,7 +2731,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
        DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
            ha->host_no, vp_index));
 
-       if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
+       if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
                return QLA_PARAMETER_ERROR;
 
        vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
index 821ee74aadc675ed4a7f3f5a1157000d76079413..cf784cdafb010c2b4ad3a3af374df991ea1c9283 100644 (file)
@@ -39,7 +39,7 @@ qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
        }
 }
 
-uint32_t
+static uint32_t
 qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
 {
        uint32_t vp_id;
@@ -47,16 +47,15 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
 
        /* Find an empty slot and assign an vp_id */
        down(&ha->vport_sem);
-       vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
-                               MAX_MULTI_ID_FABRIC);
-       if (vp_id > MAX_MULTI_ID_FABRIC) {
-               DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
-                   vp_id));
+       vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
+       if (vp_id > ha->max_npiv_vports) {
+               DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
+                   vp_id, ha->max_npiv_vports));
                up(&ha->vport_sem);
                return vp_id;
        }
 
-       set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+       set_bit(vp_id, ha->vp_idx_map);
        ha->num_vhosts++;
        vha->vp_idx = vp_id;
        list_add_tail(&vha->vp_list, &ha->vp_list);
@@ -73,12 +72,12 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
        down(&ha->vport_sem);
        vp_id = vha->vp_idx;
        ha->num_vhosts--;
-       clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+       clear_bit(vp_id, ha->vp_idx_map);
        list_del(&vha->vp_list);
        up(&ha->vport_sem);
 }
 
-scsi_qla_host_t *
+static scsi_qla_host_t *
 qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
 {
        scsi_qla_host_t *vha;
@@ -216,11 +215,7 @@ qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
        if (ha->parent)
                return;
 
-       i = find_next_bit((unsigned long *)ha->vp_idx_map,
-           MAX_MULTI_ID_FABRIC + 1, 1);
-       for (;i <= MAX_MULTI_ID_FABRIC;
-           i = find_next_bit((unsigned long *)ha->vp_idx_map,
-           MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+       for_each_mapped_vp_idx(ha, i) {
                vp_idx_matched = 0;
 
                list_for_each_entry(vha, &ha->vp_list, vp_list) {
@@ -270,7 +265,7 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
        qla24xx_enable_vp(vha);
 }
 
-int
+static int
 qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 {
        if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
@@ -311,11 +306,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
 
        clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
 
-       i = find_next_bit((unsigned long *)ha->vp_idx_map,
-           MAX_MULTI_ID_FABRIC + 1, 1);
-       for (;i <= MAX_MULTI_ID_FABRIC;
-           i = find_next_bit((unsigned long *)ha->vp_idx_map,
-           MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+       for_each_mapped_vp_idx(ha, i) {
                vp_idx_matched = 0;
 
                list_for_each_entry(vha, &ha->vp_list, vp_list) {
@@ -350,15 +341,17 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
 
        /* Check up unique WWPN */
        u64_to_wwn(fc_vport->port_name, port_name);
+       if (!memcmp(port_name, ha->port_name, WWN_SIZE))
+               return VPCERR_BAD_WWN;
        vha = qla24xx_find_vhost_by_name(ha, port_name);
        if (vha)
                return VPCERR_BAD_WWN;
 
        /* Check up max-npiv-supports */
        if (ha->num_vhosts > ha->max_npiv_vports) {
-               DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
-                   "max_npv_vports %d.\n", ha->host_no,
-                   (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
+               DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than "
+                   "max_npv_vports %ud.\n", ha->host_no,
+                   ha->num_vhosts, ha->max_npiv_vports));
                return VPCERR_UNSUPPORTED;
        }
        return 0;
@@ -412,8 +405,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        }
        vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
 
-       init_MUTEX(&vha->mbx_cmd_sem);
-       init_MUTEX_LOCKED(&vha->mbx_intr_sem);
+       init_completion(&vha->mbx_cmd_comp);
+       complete(&vha->mbx_cmd_comp);
+       init_completion(&vha->mbx_intr_comp);
 
        INIT_LIST_HEAD(&vha->list);
        INIT_LIST_HEAD(&vha->fcports);
@@ -450,7 +444,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        num_hosts++;
 
        down(&ha->vport_sem);
-       set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+       set_bit(vha->vp_idx, ha->vp_idx_map);
        ha->cur_vport_count++;
        up(&ha->vport_sem);
 
index a5bcf1f390b35162284dd13e5d181c4105a5cafe..aba1e6d480669ff6e9f932e55e6364f397d050df 100644 (file)
@@ -105,13 +105,12 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *);
 static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
 static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
 static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
-static int qla2x00_loop_reset(scsi_qla_host_t *ha);
 static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
 
 static int qla2x00_change_queue_depth(struct scsi_device *, int);
 static int qla2x00_change_queue_type(struct scsi_device *, int);
 
-struct scsi_host_template qla2x00_driver_template = {
+static struct scsi_host_template qla2x00_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = QLA2XXX_DRIVER_NAME,
        .queuecommand           = qla2x00_queuecommand,
@@ -179,13 +178,6 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
  * Timer routines
  */
 
-void qla2x00_timer(scsi_qla_host_t *);
-
-__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
-    void *, unsigned long);
-static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
-
 __inline__ void
 qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
 {
@@ -203,7 +195,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
        mod_timer(&ha->timer, jiffies + interval * HZ);
 }
 
-__inline__ void
+static __inline__ void
 qla2x00_stop_timer(scsi_qla_host_t *ha)
 {
        del_timer_sync(&ha->timer);
@@ -214,12 +206,11 @@ static int qla2x00_do_dpc(void *data);
 
 static void qla2x00_rst_aen(scsi_qla_host_t *);
 
-uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-void qla2x00_mem_free(scsi_qla_host_t *ha);
+static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+static void qla2x00_mem_free(scsi_qla_host_t *ha);
 static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
 static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
 static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
-void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);
 
 /* -------------------------------------------------------------------------- */
 
@@ -1060,7 +1051,7 @@ eh_host_reset_lock:
 * Returns:
 *      0 = success
 */
-static int
+int
 qla2x00_loop_reset(scsi_qla_host_t *ha)
 {
        int ret;
@@ -1479,8 +1470,7 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
 static int
 qla2x00_iospace_config(scsi_qla_host_t *ha)
 {
-       unsigned long   pio, pio_len, pio_flags;
-       unsigned long   mmio, mmio_len, mmio_flags;
+       resource_size_t pio;
 
        if (pci_request_selected_regions(ha->pdev, ha->bars,
            QLA2XXX_DRIVER_NAME)) {
@@ -1495,10 +1485,8 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
 
        /* We only need PIO for Flash operations on ISP2312 v2 chips. */
        pio = pci_resource_start(ha->pdev, 0);
-       pio_len = pci_resource_len(ha->pdev, 0);
-       pio_flags = pci_resource_flags(ha->pdev, 0);
-       if (pio_flags & IORESOURCE_IO) {
-               if (pio_len < MIN_IOBASE_LEN) {
+       if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
+               if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
                        qla_printk(KERN_WARNING, ha,
                            "Invalid PCI I/O region size (%s)...\n",
                                pci_name(ha->pdev));
@@ -1511,28 +1499,23 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
                pio = 0;
        }
        ha->pio_address = pio;
-       ha->pio_length = pio_len;
 
 skip_pio:
        /* Use MMIO operations for all accesses. */
-       mmio = pci_resource_start(ha->pdev, 1);
-       mmio_len = pci_resource_len(ha->pdev, 1);
-       mmio_flags = pci_resource_flags(ha->pdev, 1);
-
-       if (!(mmio_flags & IORESOURCE_MEM)) {
+       if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
                qla_printk(KERN_ERR, ha,
-                   "region #0 not an MMIO resource (%s), aborting\n",
+                   "region #1 not an MMIO resource (%s), aborting\n",
                    pci_name(ha->pdev));
                goto iospace_error_exit;
        }
-       if (mmio_len < MIN_IOBASE_LEN) {
+       if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
                qla_printk(KERN_ERR, ha,
                    "Invalid PCI mem region size (%s), aborting\n",
                        pci_name(ha->pdev));
                goto iospace_error_exit;
        }
 
-       ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
+       ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
        if (!ha->iobase) {
                qla_printk(KERN_ERR, ha,
                    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
@@ -1701,9 +1684,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /* load the F/W, read paramaters, and init the H/W */
        ha->instance = num_hosts;
 
-       init_MUTEX(&ha->mbx_cmd_sem);
        init_MUTEX(&ha->vport_sem);
-       init_MUTEX_LOCKED(&ha->mbx_intr_sem);
+       init_completion(&ha->mbx_cmd_comp);
+       complete(&ha->mbx_cmd_comp);
+       init_completion(&ha->mbx_intr_comp);
 
        INIT_LIST_HEAD(&ha->list);
        INIT_LIST_HEAD(&ha->fcports);
@@ -1807,6 +1791,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        qla2x00_init_host_attr(ha);
 
+       qla2x00_dfs_setup(ha);
+
        qla_printk(KERN_INFO, ha, "\n"
            " QLogic Fibre Channel HBA Driver: %s\n"
            "  QLogic %s - %s\n"
@@ -1831,13 +1817,15 @@ probe_out:
        return ret;
 }
 
-static void __devexit
+static void
 qla2x00_remove_one(struct pci_dev *pdev)
 {
        scsi_qla_host_t *ha;
 
        ha = pci_get_drvdata(pdev);
 
+       qla2x00_dfs_remove(ha);
+
        qla2x00_free_sysfs_attr(ha);
 
        fc_remove_host(ha->host);
@@ -1871,8 +1859,11 @@ qla2x00_free_device(scsi_qla_host_t *ha)
                kthread_stop(t);
        }
 
+       if (ha->flags.fce_enabled)
+               qla2x00_disable_fce_trace(ha, NULL, NULL);
+
        if (ha->eft)
-               qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
+               qla2x00_disable_eft_trace(ha);
 
        ha->flags.online = 0;
 
@@ -2016,7 +2007,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 *      0  = success.
 *      1  = failure.
 */
-uint8_t
+static uint8_t
 qla2x00_mem_alloc(scsi_qla_host_t *ha)
 {
        char    name[16];
@@ -2213,7 +2204,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 * Input:
 *      ha = adapter block pointer.
 */
-void
+static void
 qla2x00_mem_free(scsi_qla_host_t *ha)
 {
        struct list_head        *fcpl, *fcptemp;
@@ -2228,6 +2219,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
        /* free sp pool */
        qla2x00_free_sp_pool(ha);
 
+       if (ha->fce)
+               dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
+                   ha->fce_dma);
+
        if (ha->fw_dump) {
                if (ha->eft)
                        dma_free_coherent(&ha->pdev->dev,
@@ -2748,23 +2743,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
        qla2x00_restart_timer(ha, WATCH_INTERVAL);
 }
 
-/* XXX(hch): crude hack to emulate a down_timeout() */
-int
-qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
-{
-       const unsigned int step = 100; /* msecs */
-       unsigned int iterations = jiffies_to_msecs(timeout)/100;
-
-       do {
-               if (!down_trylock(sema))
-                       return 0;
-               if (msleep_interruptible(step))
-                       break;
-       } while (--iterations > 0);
-
-       return -ETIMEDOUT;
-}
-
 /* Firmware interface routines. */
 
 #define FW_BLOBS       6
@@ -2965,7 +2943,7 @@ static struct pci_driver qla2xxx_pci_driver = {
        },
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
-       .remove         = __devexit_p(qla2x00_remove_one),
+       .remove         = qla2x00_remove_one,
        .err_handler    = &qla2xxx_err_handler,
 };
 
index ad2fa01bd233115538e4a84f843b49fb7dd5a0e5..b68fb73613ed1a69ba6cb4774e0ea202bc27ab45 100644 (file)
@@ -22,7 +22,7 @@ static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
  * qla2x00_lock_nvram_access() -
  * @ha: HA context
  */
-void
+static void
 qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
 {
        uint16_t data;
@@ -55,7 +55,7 @@ qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
  * qla2x00_unlock_nvram_access() -
  * @ha: HA context
  */
-void
+static void
 qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
 {
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
@@ -74,7 +74,7 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
  *
  * Returns the word read from nvram @addr.
  */
-uint16_t
+static uint16_t
 qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
 {
        uint16_t        data;
@@ -93,7 +93,7 @@ qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
  * @addr: Address in NVRAM to write
  * @data: word to program
  */
-void
+static void
 qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
 {
        int count;
@@ -550,7 +550,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
        int ret;
        uint32_t liter, miter;
        uint32_t sec_mask, rest_addr, conf_addr;
-       uint32_t fdata, findex ;
+       uint32_t fdata, findex, cnt;
        uint8_t man_id, flash_id;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        dma_addr_t optrom_dma;
@@ -690,8 +690,14 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
                            0xff0000) | ((fdata >> 16) & 0xff));
        }
 
-       /* Enable flash write-protection. */
+       /* Enable flash write-protection and wait for completion. */
        qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
+       for (cnt = 300; cnt &&
+           qla24xx_read_flash_dword(ha,
+                   flash_conf_to_access_addr(0x005)) & BIT_0;
+           cnt--) {
+               udelay(10);
+       }
 
        /* Disable flash write. */
        WRT_REG_DWORD(&reg->ctrl_status,
index ae6f7a2fb19fed316e9cd5a08355f5d0ee8e154f..2c2f6b4697c7196127207638133ca0870bae4a7f 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.02.00-k5"
+#define QLA2XXX_VERSION      "8.02.00-k7"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   2
index d692c713416a54b385e486c3c02b3f90876b5fcf..cbe0a17ced5f9b97cde9e21e8c41640b41b16c3b 100644 (file)
@@ -5,6 +5,7 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
+#include <scsi/iscsi_if.h>
 #include "ql4_def.h"
 #include "ql4_glbl.h"
 #include "ql4_dbg.h"
@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
                atomic_set(&ddb_entry->relogin_timer, 0);
                clear_bit(DF_RELOGIN, &ddb_entry->flags);
                clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
-               iscsi_if_create_session_done(ddb_entry->conn);
+               iscsi_session_event(ddb_entry->sess,
+                                   ISCSI_KEVENT_CREATE_SESSION);
                /*
                 * Change the lun state to READY in case the lun TIMEOUT before
                 * the device came back.
index 4a154beb0d39ba90bf15e1b05b261fafe1bbec09..0f029d0d73150e17881cec0f98575134d22438e8 100644 (file)
@@ -123,15 +123,14 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                        break;
 
                /* Copy Sense Data into sense buffer. */
-               memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+               memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
                sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
                if (sensebytecnt == 0)
                        break;
 
                memcpy(cmd->sense_buffer, sts_entry->senseData,
-                      min(sensebytecnt,
-                          (uint16_t) sizeof(cmd->sense_buffer)));
+                      min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
 
                DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
                              "ASC/ASCQ = %02x/%02x\n", ha->host_no,
@@ -208,8 +207,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                                break;
 
                        /* Copy Sense Data into sense buffer. */
-                       memset(cmd->sense_buffer, 0,
-                              sizeof(cmd->sense_buffer));
+                       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
                        sensebytecnt =
                                le16_to_cpu(sts_entry->senseDataByteCnt);
@@ -217,8 +215,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                                break;
 
                        memcpy(cmd->sense_buffer, sts_entry->senseData,
-                              min(sensebytecnt,
-                                  (uint16_t) sizeof(cmd->sense_buffer)));
+                              min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
 
                        DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
                                      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
index 89460d27c68959225bc27bfb818f989a06426738..f55b9f7d93965ca46cc0516789f6e56f4fc938e6 100644 (file)
@@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
                return;
 
        if (ddb_entry->conn) {
-               iscsi_if_destroy_session_done(ddb_entry->conn);
-               iscsi_destroy_conn(ddb_entry->conn);
+               atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
                iscsi_remove_session(ddb_entry->sess);
        }
        iscsi_free_session(ddb_entry->sess);
@@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
 {
        int err;
 
+       ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
        err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
        if (err) {
                DEBUG2(printk(KERN_ERR "Could not add session.\n"));
@@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
                DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
                return -ENOMEM;
        }
-
-       ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
-       iscsi_if_create_session_done(ddb_entry->conn);
        return 0;
 }
 
index 7a2e7986b038f16185875fe95bc8e2a32acc80a4..65455ab1f3b94ffb8aaa2ed5c59b7dafcddc628e 100644 (file)
@@ -871,11 +871,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
        struct scatterlist *sg, *s;
        int i, n;
 
-       if (Cmnd->use_sg) {
+       if (scsi_bufflen(Cmnd)) {
                int sg_count;
 
-               sg = (struct scatterlist *) Cmnd->request_buffer;
-               sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
+               sg = scsi_sglist(Cmnd);
+               sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
+                                                     Cmnd->sc_data_direction);
 
                ds = cmd->dataseg;
                cmd->segment_cnt = sg_count;
@@ -914,16 +915,6 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
                        }
                        sg_count -= n;
                }
-       } else if (Cmnd->request_bufflen) {
-               Cmnd->SCp.ptr = (char *)(unsigned long)
-                       sbus_map_single(qpti->sdev,
-                                       Cmnd->request_buffer,
-                                       Cmnd->request_bufflen,
-                                       Cmnd->sc_data_direction);
-
-               cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
-               cmd->dataseg[0].d_count = Cmnd->request_bufflen;
-               cmd->segment_cnt = 1;
        } else {
                cmd->dataseg[0].d_base = 0;
                cmd->dataseg[0].d_count = 0;
@@ -1151,7 +1142,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
 
                if (sts->state_flags & SF_GOT_SENSE)
                        memcpy(Cmnd->sense_buffer, sts->req_sense_data,
-                              sizeof(Cmnd->sense_buffer));
+                              SCSI_SENSE_BUFFERSIZE);
 
                if (sts->hdr.entry_type == ENTRY_STATUS)
                        Cmnd->result =
@@ -1159,17 +1150,11 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
                else
                        Cmnd->result = DID_ERROR << 16;
 
-               if (Cmnd->use_sg) {
+               if (scsi_bufflen(Cmnd))
                        sbus_unmap_sg(qpti->sdev,
-                                     (struct scatterlist *)Cmnd->request_buffer,
-                                     Cmnd->use_sg,
+                                     scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
                                      Cmnd->sc_data_direction);
-               } else if (Cmnd->request_bufflen) {
-                       sbus_unmap_single(qpti->sdev,
-                                         (__u32)((unsigned long)Cmnd->SCp.ptr),
-                                         Cmnd->request_bufflen,
-                                         Cmnd->sc_data_direction);
-               }
+
                qpti->cmd_count[Cmnd->device->id]--;
                sbus_writew(out_ptr, qpti->qregs + MBOX5);
                Cmnd->host_scribble = (unsigned char *) done_queue;
index 0fb1709ce5e371649c0c90126a3a8558a1fd13a4..1a9fba6a9f92ac7ad60d05f1923f8fb45ccca574 100644 (file)
@@ -122,6 +122,11 @@ static const char *const scsi_device_types[] = {
        "Automation/Drive ",
 };
 
+/**
+ * scsi_device_type - Return 17 char string indicating device type.
+ * @type: type number to look up
+ */
+
 const char * scsi_device_type(unsigned type)
 {
        if (type == 0x1e)
@@ -136,32 +141,45 @@ const char * scsi_device_type(unsigned type)
 EXPORT_SYMBOL(scsi_device_type);
 
 struct scsi_host_cmd_pool {
-       struct kmem_cache       *slab;
-       unsigned int    users;
-       char            *name;
-       unsigned int    slab_flags;
-       gfp_t           gfp_mask;
+       struct kmem_cache       *cmd_slab;
+       struct kmem_cache       *sense_slab;
+       unsigned int            users;
+       char                    *cmd_name;
+       char                    *sense_name;
+       unsigned int            slab_flags;
+       gfp_t                   gfp_mask;
 };
 
 static struct scsi_host_cmd_pool scsi_cmd_pool = {
-       .name           = "scsi_cmd_cache",
+       .cmd_name       = "scsi_cmd_cache",
+       .sense_name     = "scsi_sense_cache",
        .slab_flags     = SLAB_HWCACHE_ALIGN,
 };
 
 static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
-       .name           = "scsi_cmd_cache(DMA)",
+       .cmd_name       = "scsi_cmd_cache(DMA)",
+       .sense_name     = "scsi_sense_cache(DMA)",
        .slab_flags     = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
        .gfp_mask       = __GFP_DMA,
 };
 
 static DEFINE_MUTEX(host_cmd_pool_mutex);
 
+/**
+ * __scsi_get_command - Allocate a struct scsi_cmnd
+ * @shost: host to transmit command
+ * @gfp_mask: allocation mask
+ *
+ * Description: allocate a struct scsi_cmd from host's slab, recycling from the
+ *              host's free_list if necessary.
+ */
 struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 {
        struct scsi_cmnd *cmd;
+       unsigned char *buf;
 
-       cmd = kmem_cache_alloc(shost->cmd_pool->slab,
-                       gfp_mask | shost->cmd_pool->gfp_mask);
+       cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
+                              gfp_mask | shost->cmd_pool->gfp_mask);
 
        if (unlikely(!cmd)) {
                unsigned long flags;
@@ -173,19 +191,32 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
                        list_del_init(&cmd->list);
                }
                spin_unlock_irqrestore(&shost->free_list_lock, flags);
+
+               if (cmd) {
+                       buf = cmd->sense_buffer;
+                       memset(cmd, 0, sizeof(*cmd));
+                       cmd->sense_buffer = buf;
+               }
+       } else {
+               buf = kmem_cache_alloc(shost->cmd_pool->sense_slab,
+                                      gfp_mask | shost->cmd_pool->gfp_mask);
+               if (likely(buf)) {
+                       memset(cmd, 0, sizeof(*cmd));
+                       cmd->sense_buffer = buf;
+               } else {
+                       kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+                       cmd = NULL;
+               }
        }
 
        return cmd;
 }
 EXPORT_SYMBOL_GPL(__scsi_get_command);
 
-/*
- * Function:   scsi_get_command()
- *
- * Purpose:    Allocate and setup a scsi command block
- *
- * Arguments:  dev     - parent scsi device
- *             gfp_mask- allocator flags
+/**
+ * scsi_get_command - Allocate and setup a scsi command block
+ * @dev: parent scsi device
+ * @gfp_mask: allocator flags
  *
  * Returns:    The allocated scsi command structure.
  */
@@ -202,7 +233,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
        if (likely(cmd != NULL)) {
                unsigned long flags;
 
-               memset(cmd, 0, sizeof(*cmd));
                cmd->device = dev;
                init_timer(&cmd->eh_timeout);
                INIT_LIST_HEAD(&cmd->list);
@@ -217,6 +247,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(scsi_get_command);
 
+/**
+ * __scsi_put_command - Free a struct scsi_cmnd
+ * @shost: dev->host
+ * @cmd: Command to free
+ * @dev: parent scsi device
+ */
 void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
                        struct device *dev)
 {
@@ -230,19 +266,19 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
        }
        spin_unlock_irqrestore(&shost->free_list_lock, flags);
 
-       if (likely(cmd != NULL))
-               kmem_cache_free(shost->cmd_pool->slab, cmd);
+       if (likely(cmd != NULL)) {
+               kmem_cache_free(shost->cmd_pool->sense_slab,
+                               cmd->sense_buffer);
+               kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+       }
 
        put_device(dev);
 }
 EXPORT_SYMBOL(__scsi_put_command);
 
-/*
- * Function:   scsi_put_command()
- *
- * Purpose:    Free a scsi command block
- *
- * Arguments:  cmd     - command block to free
+/**
+ * scsi_put_command - Free a scsi command block
+ * @cmd: command block to free
  *
  * Returns:    Nothing.
  *
@@ -263,12 +299,13 @@ void scsi_put_command(struct scsi_cmnd *cmd)
 }
 EXPORT_SYMBOL(scsi_put_command);
 
-/*
- * Function:   scsi_setup_command_freelist()
- *
- * Purpose:    Setup the command freelist for a scsi host.
+/**
+ * scsi_setup_command_freelist - Setup the command freelist for a scsi host.
+ * @shost: host to allocate the freelist for.
  *
- * Arguments:  shost   - host to allocate the freelist for.
+ * Description: The command freelist protects against system-wide out of memory
+ * deadlock by preallocating one SCSI command structure for each host, so the
+ * system can always write to a swap file on a device associated with that host.
  *
  * Returns:    Nothing.
  */
@@ -282,16 +319,24 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
 
        /*
         * Select a command slab for this host and create it if not
-        * yet existant.
+        * yet existent.
         */
        mutex_lock(&host_cmd_pool_mutex);
        pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
        if (!pool->users) {
-               pool->slab = kmem_cache_create(pool->name,
-                               sizeof(struct scsi_cmnd), 0,
-                               pool->slab_flags, NULL);
-               if (!pool->slab)
+               pool->cmd_slab = kmem_cache_create(pool->cmd_name,
+                                                  sizeof(struct scsi_cmnd), 0,
+                                                  pool->slab_flags, NULL);
+               if (!pool->cmd_slab)
+                       goto fail;
+
+               pool->sense_slab = kmem_cache_create(pool->sense_name,
+                                                    SCSI_SENSE_BUFFERSIZE, 0,
+                                                    pool->slab_flags, NULL);
+               if (!pool->sense_slab) {
+                       kmem_cache_destroy(pool->cmd_slab);
                        goto fail;
+               }
        }
 
        pool->users++;
@@ -301,29 +346,36 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
        /*
         * Get one backup command for this host.
         */
-       cmd = kmem_cache_alloc(shost->cmd_pool->slab,
-                       GFP_KERNEL | shost->cmd_pool->gfp_mask);
+       cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
+                              GFP_KERNEL | shost->cmd_pool->gfp_mask);
        if (!cmd)
                goto fail2;
-       list_add(&cmd->list, &shost->free_list);                
+
+       cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab,
+                                            GFP_KERNEL |
+                                            shost->cmd_pool->gfp_mask);
+       if (!cmd->sense_buffer)
+               goto fail2;
+
+       list_add(&cmd->list, &shost->free_list);
        return 0;
 
  fail2:
-       if (!--pool->users)
-               kmem_cache_destroy(pool->slab);
-       return -ENOMEM;
+       if (cmd)
+               kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+       mutex_lock(&host_cmd_pool_mutex);
+       if (!--pool->users) {
+               kmem_cache_destroy(pool->cmd_slab);
+               kmem_cache_destroy(pool->sense_slab);
+       }
  fail:
        mutex_unlock(&host_cmd_pool_mutex);
        return -ENOMEM;
-
 }
 
-/*
- * Function:   scsi_destroy_command_freelist()
- *
- * Purpose:    Release the command freelist for a scsi host.
- *
- * Arguments:  shost   - host that's freelist is going to be destroyed
+/**
+ * scsi_destroy_command_freelist - Release the command freelist for a scsi host.
+ * @shost: host whose freelist is going to be destroyed
  */
 void scsi_destroy_command_freelist(struct Scsi_Host *shost)
 {
@@ -332,12 +384,16 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
 
                cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
                list_del_init(&cmd->list);
-               kmem_cache_free(shost->cmd_pool->slab, cmd);
+               kmem_cache_free(shost->cmd_pool->sense_slab,
+                               cmd->sense_buffer);
+               kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
        }
 
        mutex_lock(&host_cmd_pool_mutex);
-       if (!--shost->cmd_pool->users)
-               kmem_cache_destroy(shost->cmd_pool->slab);
+       if (!--shost->cmd_pool->users) {
+               kmem_cache_destroy(shost->cmd_pool->cmd_slab);
+               kmem_cache_destroy(shost->cmd_pool->sense_slab);
+       }
        mutex_unlock(&host_cmd_pool_mutex);
 }
 
@@ -441,8 +497,12 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 }
 #endif
 
-/* 
- * Assign a serial number to the request for error recovery
+/**
+ * scsi_cmd_get_serial - Assign a serial number to a command
+ * @host: the scsi host
+ * @cmd: command to assign serial number to
+ *
+ * Description: a serial number identifies a request for error recovery
  * and debugging purposes.  Protected by the Host_Lock of host.
  */
 static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
@@ -452,14 +512,12 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
                cmd->serial_number = host->cmd_serial_number++;
 }
 
-/*
- * Function:    scsi_dispatch_command
- *
- * Purpose:     Dispatch a command to the low-level driver.
- *
- * Arguments:   cmd - command block we are dispatching.
+/**
+ * scsi_dispatch_command - Dispatch a command to the low-level driver.
+ * @cmd: command block we are dispatching.
  *
- * Notes:
+ * Return: nonzero return request was rejected and device's queue needs to be
+ * plugged.
  */
 int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 {
@@ -585,7 +643,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 
 /**
  * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
+ * @cmd: pointer to the SCSI command of interest
  *
  * This function requests that SCSI Core start recovery for the
  * command by deleting the timer and adding the command to the eh
@@ -606,9 +664,9 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
  * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
  *
- * This function is the mid-level's (SCSI Core) interrupt routine, which
- * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues
- * the command to the done queue for further processing.
+ * Description: This function is the mid-level's (SCSI Core) interrupt routine,
+ * which regains ownership of the SCSI command (de facto) from a LLDD, and
+ * enqueues the command to the done queue for further processing.
  *
  * This is the producer of the done queue who enqueues at the tail.
  *
@@ -617,7 +675,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
 static void scsi_done(struct scsi_cmnd *cmd)
 {
        /*
-        * We don't have to worry about this one timing out any more.
+        * We don't have to worry about this one timing out anymore.
         * If we are unable to remove the timer, then the command
         * has already timed out.  In which case, we have no choice but to
         * let the timeout function run, as we have no idea where in fact
@@ -660,10 +718,11 @@ static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
        return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
 }
 
-/*
- * Function:    scsi_finish_command
+/**
+ * scsi_finish_command - cleanup and pass command back to upper layer
+ * @cmd: the command
  *
- * Purpose:     Pass command off to upper layer for finishing of I/O
+ * Description: Pass command off to upper layer for finishing of I/O
  *              request, waking processes that are waiting on results,
  *              etc.
  */
@@ -708,18 +767,14 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
 }
 EXPORT_SYMBOL(scsi_finish_command);
 
-/*
- * Function:   scsi_adjust_queue_depth()
- *
- * Purpose:    Allow low level drivers to tell us to change the queue depth
- *             on a specific SCSI device
- *
- * Arguments:  sdev    - SCSI Device in question
- *             tagged  - Do we use tagged queueing (non-0) or do we treat
- *                       this device as an untagged device (0)
- *             tags    - Number of tags allowed if tagged queueing enabled,
- *                       or number of commands the low level driver can
- *                       queue up in non-tagged mode (as per cmd_per_lun).
+/**
+ * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth
+ * @sdev: SCSI Device in question
+ * @tagged: Do we use tagged queueing (non-0) or do we treat
+ *          this device as an untagged device (0)
+ * @tags: Number of tags allowed if tagged queueing enabled,
+ *        or number of commands the low level driver can
+ *        queue up in non-tagged mode (as per cmd_per_lun).
  *
  * Returns:    Nothing
  *
@@ -742,8 +797,8 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 
        spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 
-       /* Check to see if the queue is managed by the block layer
-        * if it is, and we fail to adjust the depth, exit */
+       /* Check to see if the queue is managed by the block layer.
+        * If it is, and we fail to adjust the depth, exit. */
        if (blk_queue_tagged(sdev->request_queue) &&
            blk_queue_resize_tags(sdev->request_queue, tags) != 0)
                goto out;
@@ -772,20 +827,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 }
 EXPORT_SYMBOL(scsi_adjust_queue_depth);
 
-/*
- * Function:   scsi_track_queue_full()
+/**
+ * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth
+ * @sdev: SCSI Device in question
+ * @depth: Current number of outstanding SCSI commands on this device,
+ *         not counting the one returned as QUEUE_FULL.
  *
- * Purpose:    This function will track successive QUEUE_FULL events on a
+ * Description:        This function will track successive QUEUE_FULL events on a
  *             specific SCSI device to determine if and when there is a
  *             need to adjust the queue depth on the device.
  *
- * Arguments:  sdev    - SCSI Device in question
- *             depth   - Current number of outstanding SCSI commands on
- *                       this device, not counting the one returned as
- *                       QUEUE_FULL.
- *
- * Returns:    0 - No change needed
- *             >0 - Adjust queue depth to this new depth
+ * Returns:    0 - No change needed, >0 - Adjust queue depth to this new depth,
  *             -1 - Drop back to untagged operation using host->cmd_per_lun
  *                     as the untagged command depth
  *
@@ -824,10 +876,10 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
 EXPORT_SYMBOL(scsi_track_queue_full);
 
 /**
- * scsi_device_get  -  get an addition reference to a scsi_device
+ * scsi_device_get  -  get an additional reference to a scsi_device
  * @sdev:      device to get a reference to
  *
- * Gets a reference to the scsi_device and increments the use count
+ * Description: Gets a reference to the scsi_device and increments the use count
  * of the underlying LLDD module.  You must hold host_lock of the
  * parent Scsi_Host or already have a reference when calling this.
  */
@@ -849,8 +901,8 @@ EXPORT_SYMBOL(scsi_device_get);
  * scsi_device_put  -  release a reference to a scsi_device
  * @sdev:      device to release a reference on.
  *
- * Release a reference to the scsi_device and decrements the use count
- * of the underlying LLDD module.  The device is freed once the last
+ * Description: Release a reference to the scsi_device and decrements the use
+ * count of the underlying LLDD module.  The device is freed once the last
  * user vanishes.
  */
 void scsi_device_put(struct scsi_device *sdev)
@@ -867,7 +919,7 @@ void scsi_device_put(struct scsi_device *sdev)
 }
 EXPORT_SYMBOL(scsi_device_put);
 
-/* helper for shost_for_each_device, thus not documented */
+/* helper for shost_for_each_device, see that for documentation */
 struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
                                           struct scsi_device *prev)
 {
@@ -895,6 +947,8 @@ EXPORT_SYMBOL(__scsi_iterate_devices);
 /**
  * starget_for_each_device  -  helper to walk all devices of a target
  * @starget:   target whose devices we want to iterate over.
+ * @data:      Opaque passed to each function call.
+ * @fn:                Function to call on each device
  *
  * This traverses over each device of @starget.  The devices have
  * a reference that must be released by scsi_host_put when breaking
@@ -946,13 +1000,13 @@ EXPORT_SYMBOL(__starget_for_each_device);
  * @starget:   SCSI target pointer
  * @lun:       SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @lun for a give
- * @starget. The returned scsi_device does not have an additional
+ * Description: Looks up the scsi_device with the specified @lun for a given
+ * @starget.  The returned scsi_device does not have an additional
  * reference.  You must hold the host's host_lock over this call and
  * any access to the returned scsi_device.
  *
- * Note:  The only reason why drivers would want to use this is because
- * they're need to access the device list in irq context.  Otherwise you
+ * Note:  The only reason why drivers should use this is because
+ * they need to access the device list in irq context.  Otherwise you
  * really want to use scsi_device_lookup_by_target instead.
  **/
 struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
@@ -974,9 +1028,9 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
  * @starget:   SCSI target pointer
  * @lun:       SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @channel, @id, @lun for a
- * give host.  The returned scsi_device has an additional reference that
- * needs to be release with scsi_host_put once you're done with it.
+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
+ * for a given host.  The returned scsi_device has an additional reference that
+ * needs to be released with scsi_device_put once you're done with it.
  **/
 struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
                                                 uint lun)
@@ -996,19 +1050,19 @@ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
 EXPORT_SYMBOL(scsi_device_lookup_by_target);
 
 /**
- * scsi_device_lookup - find a device given the host (UNLOCKED)
+ * __scsi_device_lookup - find a device given the host (UNLOCKED)
  * @shost:     SCSI host pointer
  * @channel:   SCSI channel (zero if only one channel)
- * @pun:       SCSI target number (physical unit number)
+ * @id:                SCSI target number (physical unit number)
  * @lun:       SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @channel, @id, @lun for a
- * give host. The returned scsi_device does not have an additional reference.
- * You must hold the host's host_lock over this call and any access to the
- * returned scsi_device.
+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
+ * for a given host. The returned scsi_device does not have an additional
+ * reference.  You must hold the host's host_lock over this call and any access
+ * to the returned scsi_device.
  *
  * Note:  The only reason why drivers would want to use this is because
- * they're need to access the device list in irq context.  Otherwise you
+ * they need to access the device list in irq context.  Otherwise you
  * really want to use scsi_device_lookup instead.
  **/
 struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost,
@@ -1033,9 +1087,9 @@ EXPORT_SYMBOL(__scsi_device_lookup);
  * @id:                SCSI target number (physical unit number)
  * @lun:       SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @channel, @id, @lun for a
- * give host.  The returned scsi_device has an additional reference that
- * needs to be release with scsi_host_put once you're done with it.
+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
+ * for a given host.  The returned scsi_device has an additional reference that
+ * needs to be released with scsi_device_put once you're done with it.
  **/
 struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
                uint channel, uint id, uint lun)
index 46cae5a212ded1df5e85b607119335065206dc98..82c06f0a9d0201ae42deb14bec2f2f0f4a239fa9 100644 (file)
@@ -329,7 +329,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
        if (done == NULL)
                return 0;       /* assume mid level reprocessing command */
 
-       SCpnt->resid = 0;
+       scsi_set_resid(SCpnt, 0);
        if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
                printk(KERN_INFO "scsi_debug: cmd ");
                for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
@@ -603,26 +603,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
        void * kaddr_off;
        struct scatterlist * sg;
 
-       if (0 == scp->request_bufflen)
+       if (0 == scsi_bufflen(scp))
                return 0;
-       if (NULL == scp->request_buffer)
+       if (NULL == scsi_sglist(scp))
                return (DID_ERROR << 16);
        if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
              (scp->sc_data_direction == DMA_FROM_DEVICE)))
                return (DID_ERROR << 16);
-       if (0 == scp->use_sg) {
-               req_len = scp->request_bufflen;
-               act_len = (req_len < arr_len) ? req_len : arr_len;
-               memcpy(scp->request_buffer, arr, act_len);
-               if (scp->resid)
-                       scp->resid -= act_len;
-               else
-                       scp->resid = req_len - act_len;
-               return 0;
-       }
        active = 1;
        req_len = act_len = 0;
-       scsi_for_each_sg(scp, sg, scp->use_sg, k) {
+       scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
                if (active) {
                        kaddr = (unsigned char *)
                                kmap_atomic(sg_page(sg), KM_USER0);
@@ -640,10 +630,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
                }
                req_len += sg->length;
        }
-       if (scp->resid)
-               scp->resid -= act_len;
+       if (scsi_get_resid(scp))
+               scsi_set_resid(scp, scsi_get_resid(scp) - act_len);
        else
-               scp->resid = req_len - act_len;
+               scsi_set_resid(scp, req_len - act_len);
        return 0;
 }
 
@@ -656,22 +646,15 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
        void * kaddr_off;
        struct scatterlist * sg;
 
-       if (0 == scp->request_bufflen)
+       if (0 == scsi_bufflen(scp))
                return 0;
-       if (NULL == scp->request_buffer)
+       if (NULL == scsi_sglist(scp))
                return -1;
        if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
              (scp->sc_data_direction == DMA_TO_DEVICE)))
                return -1;
-       if (0 == scp->use_sg) {
-               req_len = scp->request_bufflen;
-               len = (req_len < max_arr_len) ? req_len : max_arr_len;
-               memcpy(arr, scp->request_buffer, len);
-               return len;
-       }
-       sg = scsi_sglist(scp);
        req_len = fin = 0;
-       for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
+       scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
                kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
                if (NULL == kaddr)
                        return -1;
index 348cc5a6e3cdf002b091ea73762e16f0baf5b6d7..b8de041bc0ae8a2e894aeb723e67b98b9afe09a1 100644 (file)
@@ -276,11 +276,12 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
 }
 
 /**
- * scsi_dev_info_list_add: add one dev_info list entry.
+ * scsi_dev_info_list_add - 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
- * @flag     if strflags NULL, use this flag value
+ * @flags:     if strflags NULL, use this flag value
  *
  * Description:
  *     Create and add one dev_info entry for @vendor, @model, @strflags or
@@ -322,8 +323,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
 }
 
 /**
- * scsi_dev_info_list_add_str: parse dev_list and add to the
- * scsi_dev_info_list.
+ * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
  * @dev_list:  string of device flags to add
  *
  * Description:
@@ -374,15 +374,15 @@ static int scsi_dev_info_list_add_str(char *dev_list)
 }
 
 /**
- * get_device_flags - get device specific flags from the dynamic device
- * list. Called during scan time.
+ * get_device_flags - get device specific flags from the dynamic device list.
+ * @sdev:       &scsi_device to get flags for
  * @vendor:    vendor name
  * @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.
+ *     the host or global default settings.  Called during scan time.
  **/
 int scsi_get_device_flags(struct scsi_device *sdev,
                          const unsigned char *vendor,
@@ -483,13 +483,11 @@ stop_output:
 }
 
 /* 
- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
- * /proc.
+ * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc.
  *
- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
- *
- * To add a black/white list entry for vendor and model with an integer
- * value of flag to the scsi device info list.
+ * Description: Adds a black/white list entry for vendor and model with an
+ * integer value of flag to the scsi device info list.
+ * To use, echo "vendor:model:flag" > /proc/scsi/device_info
  */
 static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
                                   unsigned long length, void *data)
@@ -532,8 +530,7 @@ MODULE_PARM_DESC(default_dev_flags,
                 "scsi default device flag integer value");
 
 /**
- * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
- *     the scsi_dev_info_list.
+ * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list.
  **/
 void scsi_exit_devinfo(void)
 {
@@ -552,13 +549,12 @@ void scsi_exit_devinfo(void)
 }
 
 /**
- * scsi_dev_list_init: set up the dynamic device list.
- * @dev_list:  string of device flags to add
+ * scsi_init_devinfo - set up the dynamic device list.
  *
  * Description:
- *     Add command line @dev_list entries, then add
+ *     Add command line entries from scsi_dev_flags, then add
  *     scsi_static_device_list entries to the scsi device info list.
- **/
+ */
 int __init scsi_init_devinfo(void)
 {
 #ifdef CONFIG_SCSI_PROC_FS
index ebaca4ca4a135787a6ff3fa477a722dbc4b2ec45..547e85aa414f2b06a27a5b298e917c456e472f60 100644 (file)
@@ -62,7 +62,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
  * @shost:     SCSI host to invoke error handling on.
  *
  * Schedule SCSI EH without scmd.
- **/
+ */
 void scsi_schedule_eh(struct Scsi_Host *shost)
 {
        unsigned long flags;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
  *
  * Return value:
  *     0 on failure.
- **/
+ */
 int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
 {
        struct Scsi_Host *shost = scmd->device->host;
@@ -121,7 +121,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
  *    This should be turned into an inline function.  Each scsi command
  *    has its own timer, and as it is added to the queue, we set up the
  *    timer.  When the command completes, we cancel the timer.
- **/
+ */
 void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
                    void (*complete)(struct scsi_cmnd *))
 {
@@ -155,7 +155,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
  * Return value:
  *     1 if we were able to detach the timer.  0 if we blew it, and the
  *     timer function has already started to run.
- **/
+ */
 int scsi_delete_timer(struct scsi_cmnd *scmd)
 {
        int rtn;
@@ -181,7 +181,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
  *     only in that the normal completion handling might run, but if the
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
- **/
+ */
 void scsi_times_out(struct scsi_cmnd *scmd)
 {
        enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
@@ -224,7 +224,7 @@ void scsi_times_out(struct scsi_cmnd *scmd)
  *
  * Return value:
  *     0 when dev was taken offline by error recovery. 1 OK to proceed.
- **/
+ */
 int scsi_block_when_processing_errors(struct scsi_device *sdev)
 {
        int online;
@@ -245,7 +245,7 @@ EXPORT_SYMBOL(scsi_block_when_processing_errors);
  * scsi_eh_prt_fail_stats - Log info on failures.
  * @shost:     scsi host being recovered.
  * @work_q:    Queue of scsi cmds to process.
- **/
+ */
 static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
                                          struct list_head *work_q)
 {
@@ -295,7 +295,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
  * Notes:
  *     When a deferred error is detected the current command has
  *     not been executed and needs retrying.
- **/
+ */
 static int scsi_check_sense(struct scsi_cmnd *scmd)
 {
        struct scsi_sense_hdr sshdr;
@@ -398,7 +398,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
  *    queued during error recovery.  the main difference here is that we
  *    don't allow for the possibility of retries here, and we are a lot
  *    more restrictive about what we consider acceptable.
- **/
+ */
 static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
 {
        /*
@@ -452,7 +452,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
 /**
  * scsi_eh_done - Completion function for error handling.
  * @scmd:      Cmd that is done.
- **/
+ */
 static void scsi_eh_done(struct scsi_cmnd *scmd)
 {
        struct completion     *eh_action;
@@ -469,7 +469,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
 /**
  * scsi_try_host_reset - ask host adapter to reset itself
  * @scmd:      SCSI cmd to send hsot reset.
- **/
+ */
 static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
@@ -498,7 +498,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 /**
  * scsi_try_bus_reset - ask host to perform a bus reset
  * @scmd:      SCSI cmd to send bus reset.
- **/
+ */
 static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
@@ -533,7 +533,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
  *    unreliable for a given host, then the host itself needs to put a
  *    timer on it, and set the host back to a consistent state prior to
  *    returning.
- **/
+ */
 static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
 {
        int rtn;
@@ -568,7 +568,7 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
  *    author of the low-level driver wishes this operation to be timed,
  *    they can provide this facility themselves.  helper functions in
  *    scsi_error.c can be supplied to make this easier to do.
- **/
+ */
 static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
 {
        /*
@@ -601,7 +601,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
  * sent must be one that does not transfer any data.  If @sense_bytes != 0
  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
- **/
+ */
 void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
                        unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
 {
@@ -625,7 +625,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
 
        if (sense_bytes) {
                scmd->request_bufflen = min_t(unsigned,
-                                      sizeof(scmd->sense_buffer), sense_bytes);
+                                      SCSI_SENSE_BUFFERSIZE, sense_bytes);
                sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
                                                       scmd->request_bufflen);
                scmd->request_buffer = &ses->sense_sgl;
@@ -657,7 +657,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
         * Zero the sense buffer.  The scsi spec mandates that any
         * untransferred sense data should be interpreted as being zero.
         */
-       memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+       memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 }
 EXPORT_SYMBOL(scsi_eh_prep_cmnd);
 
@@ -667,7 +667,7 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
  * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
  *
  * Undo any damage done by above scsi_prep_eh_cmnd().
- **/
+ */
 void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 {
        /*
@@ -697,7 +697,7 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd);
  *
  * Return value:
  *    SUCCESS or FAILED or NEEDS_RETRY
- **/
+ */
 static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
                             int cmnd_size, int timeout, unsigned sense_bytes)
 {
@@ -765,7 +765,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
  *    Some hosts automatically obtain this information, others require
  *    that we obtain it on our own. This function will *not* return until
  *    the command either times out, or it completes.
- **/
+ */
 static int scsi_request_sense(struct scsi_cmnd *scmd)
 {
        return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
@@ -779,10 +779,10 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
  * Notes:
  *    We don't want to use the normal command completion while we are are
  *    still handling errors - it may cause other commands to be queued,
- *    and that would disturb what we are doing.  thus we really want to
+ *    and that would disturb what we are doing.  Thus we really want to
  *    keep a list of pending commands for final completion, and once we
  *    are ready to leave error handling we handle completion for real.
- **/
+ */
 void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
 {
        scmd->device->host->host_failed--;
@@ -794,7 +794,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
 /**
  * scsi_eh_get_sense - Get device sense data.
  * @work_q:    Queue of commands to process.
- * @done_q:    Queue of proccessed commands..
+ * @done_q:    Queue of processed commands.
  *
  * Description:
  *    See if we need to request sense information.  if so, then get it
@@ -802,7 +802,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
  *
  * Notes:
  *    This has the unfortunate side effect that if a shost adapter does
- *    not automatically request sense information, that we end up shutting
+ *    not automatically request sense information, we end up shutting
  *    it down before we request it.
  *
  *    All drivers should request sense information internally these days,
@@ -810,7 +810,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
  *
  *    XXX: Long term this code should go away, but that needs an audit of
  *         all LLDDs first.
- **/
+ */
 int scsi_eh_get_sense(struct list_head *work_q,
                      struct list_head *done_q)
 {
@@ -858,11 +858,11 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
 
 /**
  * scsi_eh_tur - Send TUR to device.
- * @scmd:      Scsi cmd to send TUR
+ * @scmd:      &scsi_cmnd to send TUR
  *
  * Return value:
  *    0 - Device is ready. 1 - Device NOT ready.
- **/
+ */
 static int scsi_eh_tur(struct scsi_cmnd *scmd)
 {
        static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
@@ -887,17 +887,17 @@ retry_tur:
 }
 
 /**
- * scsi_eh_abort_cmds - abort canceled commands.
- * @shost:     scsi host being recovered.
- * @eh_done_q: list_head for processed commands.
+ * scsi_eh_abort_cmds - abort pending commands.
+ * @work_q:    &list_head for pending commands.
+ * @done_q:    &list_head for processed commands.
  *
  * Decription:
  *    Try and see whether or not it makes sense to try and abort the
- *    running command.  this only works out to be the case if we have one
- *    command that has timed out.  if the command simply failed, it makes
+ *    running command.  This only works out to be the case if we have one
+ *    command that has timed out.  If the command simply failed, it makes
  *    no sense to try and abort the command, since as far as the shost
  *    adapter is concerned, it isn't running.
- **/
+ */
 static int scsi_eh_abort_cmds(struct list_head *work_q,
                              struct list_head *done_q)
 {
@@ -931,11 +931,11 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
 
 /**
  * scsi_eh_try_stu - Send START_UNIT to device.
- * @scmd:      Scsi cmd to send START_UNIT
+ * @scmd:      &scsi_cmnd to send START_UNIT
  *
  * Return value:
  *    0 - Device is ready. 1 - Device NOT ready.
- **/
+ */
 static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
 {
        static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
@@ -956,13 +956,14 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
 
  /**
  * scsi_eh_stu - send START_UNIT if needed
- * @shost:     scsi host being recovered.
- * @eh_done_q: list_head for processed commands.
+ * @shost:     &scsi host being recovered.
+ * @work_q:     &list_head for pending commands.
+ * @done_q:    &list_head for processed commands.
  *
  * Notes:
  *    If commands are failing due to not ready, initializing command required,
  *     try revalidating the device, which will end up sending a start unit. 
- **/
+ */
 static int scsi_eh_stu(struct Scsi_Host *shost,
                              struct list_head *work_q,
                              struct list_head *done_q)
@@ -1008,14 +1009,15 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
 /**
  * scsi_eh_bus_device_reset - send bdr if needed
  * @shost:     scsi host being recovered.
- * @eh_done_q: list_head for processed commands.
+ * @work_q:     &list_head for pending commands.
+ * @done_q:    &list_head for processed commands.
  *
  * Notes:
- *    Try a bus device reset.  still, look to see whether we have multiple
+ *    Try a bus device reset.  Still, look to see whether we have multiple
  *    devices that are jammed or not - if we have multiple devices, it
  *    makes no sense to try bus_device_reset - we really would need to try
  *    a bus_reset instead. 
- **/
+ */
 static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
                                    struct list_head *work_q,
                                    struct list_head *done_q)
@@ -1063,9 +1065,10 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
 
 /**
  * scsi_eh_bus_reset - send a bus reset 
- * @shost:     scsi host being recovered.
- * @eh_done_q: list_head for processed commands.
- **/
+ * @shost:     &scsi host being recovered.
+ * @work_q:     &list_head for pending commands.
+ * @done_q:    &list_head for processed commands.
+ */
 static int scsi_eh_bus_reset(struct Scsi_Host *shost,
                             struct list_head *work_q,
                             struct list_head *done_q)
@@ -1122,7 +1125,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
  * scsi_eh_host_reset - send a host reset 
  * @work_q:    list_head for processed commands.
  * @done_q:    list_head for processed commands.
- **/
+ */
 static int scsi_eh_host_reset(struct list_head *work_q,
                              struct list_head *done_q)
 {
@@ -1157,8 +1160,7 @@ static int scsi_eh_host_reset(struct list_head *work_q,
  * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
  * @work_q:    list_head for processed commands.
  * @done_q:    list_head for processed commands.
- *
- **/
+ */
 static void scsi_eh_offline_sdevs(struct list_head *work_q,
                                  struct list_head *done_q)
 {
@@ -1191,7 +1193,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
  *    is woken.  In cases where the error code indicates an error that
  *    doesn't require the error handler read (i.e. we don't need to
  *    abort/reset), this function should return SUCCESS.
- **/
+ */
 int scsi_decide_disposition(struct scsi_cmnd *scmd)
 {
        int rtn;
@@ -1372,7 +1374,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
  *
  *     If scsi_allocate_request() fails for what ever reason, we
  *     completely forget to lock the door.
- **/
+ */
 static void scsi_eh_lock_door(struct scsi_device *sdev)
 {
        unsigned char cmnd[MAX_COMMAND_SIZE];
@@ -1396,7 +1398,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
  * Notes:
  *    When we entered the error handler, we blocked all further i/o to
  *    this device.  we need to 'reverse' this process.
- **/
+ */
 static void scsi_restart_operations(struct Scsi_Host *shost)
 {
        struct scsi_device *sdev;
@@ -1440,9 +1442,9 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
 /**
  * scsi_eh_ready_devs - check device ready state and recover if not.
  * @shost:     host to be recovered.
- * @eh_done_q: list_head for processed commands.
- *
- **/
+ * @work_q:     &list_head for pending commands.
+ * @done_q:    &list_head for processed commands.
+ */
 void scsi_eh_ready_devs(struct Scsi_Host *shost,
                        struct list_head *work_q,
                        struct list_head *done_q)
@@ -1458,8 +1460,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
 /**
  * scsi_eh_flush_done_q - finish processed commands or retry them.
  * @done_q:    list_head of processed commands.
- *
- **/
+ */
 void scsi_eh_flush_done_q(struct list_head *done_q)
 {
        struct scsi_cmnd *scmd, *next;
@@ -1513,7 +1514,7 @@ EXPORT_SYMBOL(scsi_eh_flush_done_q);
  *    scsi_finish_cmd() called for it.  we do all of the retry stuff
  *    here, so when we restart the host after we return it should have an
  *    empty queue.
- **/
+ */
 static void scsi_unjam_host(struct Scsi_Host *shost)
 {
        unsigned long flags;
@@ -1540,7 +1541,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
  * Notes:
  *    This is the main error handling loop.  This is run as a kernel thread
  *    for every SCSI host and handles all error handling activity.
- **/
+ */
 int scsi_error_handler(void *data)
 {
        struct Scsi_Host *shost = data;
@@ -1769,7 +1770,7 @@ EXPORT_SYMBOL(scsi_reset_provider);
  *
  * Return value:
  *     1 if valid sense data information found, else 0;
- **/
+ */
 int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
                          struct scsi_sense_hdr *sshdr)
 {
@@ -1819,14 +1820,12 @@ int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
                                 struct scsi_sense_hdr *sshdr)
 {
        return scsi_normalize_sense(cmd->sense_buffer,
-                       sizeof(cmd->sense_buffer), sshdr);
+                       SCSI_SENSE_BUFFERSIZE, sshdr);
 }
 EXPORT_SYMBOL(scsi_command_normalize_sense);
 
 /**
- * scsi_sense_desc_find - search for a given descriptor type in
- *                     descriptor sense data format.
- *
+ * scsi_sense_desc_find - search for a given descriptor type in        descriptor sense data format.
  * @sense_buffer:      byte array of descriptor format sense data
  * @sb_len:            number of valid bytes in sense_buffer
  * @desc_type:         value of descriptor type to find
@@ -1837,7 +1836,7 @@ EXPORT_SYMBOL(scsi_command_normalize_sense);
  *
  * Return value:
  *     pointer to start of (first) descriptor if found else NULL
- **/
+ */
 const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
                                int desc_type)
 {
@@ -1865,9 +1864,7 @@ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
 EXPORT_SYMBOL(scsi_sense_desc_find);
 
 /**
- * scsi_get_sense_info_fld - attempts to get information field from
- *                     sense data (either fixed or descriptor format)
- *
+ * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
  * @sense_buffer:      byte array of sense data
  * @sb_len:            number of valid bytes in sense_buffer
  * @info_out:          pointer to 64 integer where 8 or 4 byte information
@@ -1875,7 +1872,7 @@ EXPORT_SYMBOL(scsi_sense_desc_find);
  *
  * Return value:
  *     1 if information field found, 0 if not found.
- **/
+ */
 int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
                            u64 * info_out)
 {
index 32293f4516694ae0d7bf237364a35892f2e53156..28b19ef26309f5c471104250c0683bea0caef3ab 100644 (file)
@@ -174,10 +174,15 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
 }
 
 
-/*
- * the scsi_ioctl() function differs from most ioctls in that it does
- * not take a major/minor number as the dev field.  Rather, it takes
- * a pointer to a scsi_devices[] element, a structure. 
+/**
+ * scsi_ioctl - Dispatch ioctl to scsi device
+ * @sdev: scsi device receiving ioctl
+ * @cmd: which ioctl is it
+ * @arg: data associated with ioctl
+ *
+ * Description: The scsi_ioctl() function differs from most ioctls in that it
+ * does not take a major/minor number as the dev field.  Rather, it takes
+ * a pointer to a &struct scsi_device.
  */
 int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 {
@@ -239,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
                return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
        case SCSI_IOCTL_TEST_UNIT_READY:
                return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
-                                           NORMAL_RETRIES);
+                                           NORMAL_RETRIES, NULL);
        case SCSI_IOCTL_START_UNIT:
                scsi_cmd[0] = START_STOP;
                scsi_cmd[1] = 0;
@@ -264,9 +269,12 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 }
 EXPORT_SYMBOL(scsi_ioctl);
 
-/*
- * the scsi_nonblock_ioctl() function is designed for ioctls which may
- * be executed even if the device is in recovery.
+/**
+ * scsi_nonblock_ioctl() - Handle SG_SCSI_RESET
+ * @sdev: scsi device receiving ioctl
+ * @cmd: Must be SC_SCSI_RESET
+ * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
+ * @filp: either NULL or a &struct file which must have the O_NONBLOCK flag.
  */
 int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
                            void __user *arg, struct file *filp)
@@ -276,7 +284,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
        /* The first set of iocts may be executed even if we're doing
         * error processing, as long as the device was opened
         * non-blocking */
-       if (filp && filp->f_flags & O_NONBLOCK) {
+       if (filp && (filp->f_flags & O_NONBLOCK)) {
                if (scsi_host_in_recovery(sdev->host))
                        return -ENODEV;
        } else if (!scsi_block_when_processing_errors(sdev))
index 0e81e4cf8876766a92cb43333d6883baadefdf03..4cf902efbdbf14aa26422226491463aa05a2f7cc 100644 (file)
@@ -175,7 +175,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
  *
  * returns the req->errors value which is the scsi_cmnd result
  * field.
- **/
+ */
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 int data_direction, void *buffer, unsigned bufflen,
                 unsigned char *sense, int timeout, int retries, int flags)
@@ -274,7 +274,7 @@ static void scsi_bi_endio(struct bio *bio, int error)
 /**
  * scsi_req_map_sg - map a scatterlist into a request
  * @rq:                request to fill
- * @sg:                scatterlist
+ * @sgl:       scatterlist
  * @nsegs:     number of elements
  * @bufflen:   len of buffer
  * @gfp:       memory allocation flags
@@ -365,14 +365,16 @@ free_bios:
  * @sdev:      scsi device
  * @cmd:       scsi command
  * @cmd_len:   length of scsi cdb
- * @data_direction: data direction
+ * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE
  * @buffer:    data buffer (this can be a kernel buffer or scatterlist)
  * @bufflen:   len of buffer
  * @use_sg:    if buffer is a scatterlist this is the number of elements
  * @timeout:   request timeout in seconds
  * @retries:   number of times to retry request
- * @flags:     or into request flags
- **/
+ * @privdata:  data passed to done()
+ * @done:      callback function when done
+ * @gfp:       memory allocation flags
+ */
 int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
                       int cmd_len, int data_direction, void *buffer, unsigned bufflen,
                       int use_sg, int timeout, int retries, void *privdata,
@@ -439,7 +441,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 {
        cmd->serial_number = 0;
        cmd->resid = 0;
-       memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
        if (cmd->cmd_len == 0)
                cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
 }
@@ -524,7 +526,7 @@ static void scsi_run_queue(struct request_queue *q)
        struct Scsi_Host *shost = sdev->host;
        unsigned long flags;
 
-       if (sdev->single_lun)
+       if (scsi_target(sdev)->single_lun)
                scsi_single_lun_run(sdev);
 
        spin_lock_irqsave(shost->host_lock, flags);
@@ -1102,7 +1104,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
  *
  * Returns:     0 on success
  *             BLKPREP_DEFER if the failure is retryable
- *             BLKPREP_KILL if the failure is fatal
  */
 static int scsi_init_io(struct scsi_cmnd *cmd)
 {
@@ -1136,17 +1137,9 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
         * each segment.
         */
        count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
-       if (likely(count <= cmd->use_sg)) {
-               cmd->use_sg = count;
-               return BLKPREP_OK;
-       }
-
-       printk(KERN_ERR "Incorrect number of segments after building list\n");
-       printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg);
-       printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
-                       req->current_nr_sectors);
-
-       return BLKPREP_KILL;
+       BUG_ON(count > cmd->use_sg);
+       cmd->use_sg = count;
+       return BLKPREP_OK;
 }
 
 static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
@@ -1332,7 +1325,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
 }
 EXPORT_SYMBOL(scsi_prep_return);
 
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
        struct scsi_device *sdev = q->queuedata;
        int ret = BLKPREP_KILL;
@@ -1557,7 +1550,7 @@ static void scsi_request_fn(struct request_queue *q)
 
                if (!scsi_host_queue_ready(q, shost, sdev))
                        goto not_ready;
-               if (sdev->single_lun) {
+               if (scsi_target(sdev)->single_lun) {
                        if (scsi_target(sdev)->starget_sdev_user &&
                            scsi_target(sdev)->starget_sdev_user != sdev)
                                goto not_ready;
@@ -1675,6 +1668,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
 
        if (!shost->use_clustering)
                clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+
+       /*
+        * set a reasonable default alignment on word boundaries: the
+        * host and device may alter it using
+        * blk_queue_update_dma_alignment() later.
+        */
+       blk_queue_dma_alignment(q, 0x03);
+
        return q;
 }
 EXPORT_SYMBOL(__scsi_alloc_queue);
@@ -1804,7 +1805,7 @@ void scsi_exit_queue(void)
  *     @timeout: command timeout
  *     @retries: number of retries before failing
  *     @data: returns a structure abstracting the mode header data
- *     @sense: place to put sense data (or NULL if no sense to be collected).
+ *     @sshdr: place to put sense data (or NULL if no sense to be collected).
  *             must be SCSI_SENSE_BUFFERSIZE big.
  *
  *     Returns zero if successful; negative error number or scsi
@@ -1871,8 +1872,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
 EXPORT_SYMBOL_GPL(scsi_mode_select);
 
 /**
- *     scsi_mode_sense - issue a mode sense, falling back from 10 to 
- *             six bytes if necessary.
+ *     scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
  *     @sdev:  SCSI device to be queried
  *     @dbd:   set if mode sense will allow block descriptors to be returned
  *     @modepage: mode page being requested
@@ -1881,13 +1881,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
  *     @timeout: command timeout
  *     @retries: number of retries before failing
  *     @data: returns a structure abstracting the mode header data
- *     @sense: place to put sense data (or NULL if no sense to be collected).
+ *     @sshdr: place to put sense data (or NULL if no sense to be collected).
  *             must be SCSI_SENSE_BUFFERSIZE big.
  *
  *     Returns zero if unsuccessful, or the header offset (either 4
  *     or 8 depending on whether a six or ten byte command was
  *     issued) if successful.
- **/
+ */
 int
 scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
                  unsigned char *buffer, int len, int timeout, int retries,
@@ -1981,40 +1981,69 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 }
 EXPORT_SYMBOL(scsi_mode_sense);
 
+/**
+ *     scsi_test_unit_ready - test if unit is ready
+ *     @sdev:  scsi device to change the state of.
+ *     @timeout: command timeout
+ *     @retries: number of retries before failing
+ *     @sshdr_external: Optional pointer to struct scsi_sense_hdr for
+ *             returning sense. Make sure that this is cleared before passing
+ *             in.
+ *
+ *     Returns zero if unsuccessful or an error if TUR failed.  For
+ *     removable media, a return of NOT_READY or UNIT_ATTENTION is
+ *     translated to success, with the ->changed flag updated.
+ **/
 int
-scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
+scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
+                    struct scsi_sense_hdr *sshdr_external)
 {
        char cmd[] = {
                TEST_UNIT_READY, 0, 0, 0, 0, 0,
        };
-       struct scsi_sense_hdr sshdr;
+       struct scsi_sense_hdr *sshdr;
        int result;
-       
-       result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
-                                 timeout, retries);
+
+       if (!sshdr_external)
+               sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
+       else
+               sshdr = sshdr_external;
+
+       /* try to eat the UNIT_ATTENTION if there are enough retries */
+       do {
+               result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
+                                         timeout, retries);
+       } while ((driver_byte(result) & DRIVER_SENSE) &&
+                sshdr && sshdr->sense_key == UNIT_ATTENTION &&
+                --retries);
+
+       if (!sshdr)
+               /* could not allocate sense buffer, so can't process it */
+               return result;
 
        if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
 
-               if ((scsi_sense_valid(&sshdr)) &&
-                   ((sshdr.sense_key == UNIT_ATTENTION) ||
-                    (sshdr.sense_key == NOT_READY))) {
+               if ((scsi_sense_valid(sshdr)) &&
+                   ((sshdr->sense_key == UNIT_ATTENTION) ||
+                    (sshdr->sense_key == NOT_READY))) {
                        sdev->changed = 1;
                        result = 0;
                }
        }
+       if (!sshdr_external)
+               kfree(sshdr);
        return result;
 }
 EXPORT_SYMBOL(scsi_test_unit_ready);
 
 /**
- *     scsi_device_set_state - Take the given device through the device
- *             state model.
+ *     scsi_device_set_state - Take the given device through the device state model.
  *     @sdev:  scsi device to change the state of.
  *     @state: state to change to.
  *
  *     Returns zero if unsuccessful or an error if the requested 
  *     transition is illegal.
- **/
+ */
 int
 scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 {
@@ -2264,7 +2293,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
  *     Must be called with user context, may sleep.
  *
  *     Returns zero if unsuccessful or an error if not.
- **/
+ */
 int
 scsi_device_quiesce(struct scsi_device *sdev)
 {
@@ -2289,7 +2318,7 @@ EXPORT_SYMBOL(scsi_device_quiesce);
  *     queues.
  *
  *     Must be called with user context, may sleep.
- **/
+ */
 void
 scsi_device_resume(struct scsi_device *sdev)
 {
@@ -2326,8 +2355,7 @@ scsi_target_resume(struct scsi_target *starget)
 EXPORT_SYMBOL(scsi_target_resume);
 
 /**
- * scsi_internal_device_block - internal function to put a device
- *                             temporarily into the SDEV_BLOCK state
+ * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state
  * @sdev:      device to block
  *
  * Block request made by scsi lld's to temporarily stop all
@@ -2342,7 +2370,7 @@ EXPORT_SYMBOL(scsi_target_resume);
  *     state, all commands are deferred until the scsi lld reenables
  *     the device with scsi_device_unblock or device_block_tmo fires.
  *     This routine assumes the host_lock is held on entry.
- **/
+ */
 int
 scsi_internal_device_block(struct scsi_device *sdev)
 {
@@ -2382,7 +2410,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
  *     (which must be a legal transition) allowing the midlayer to
  *     goose the queue for this device.  This routine assumes the 
  *     host_lock is held upon entry.
- **/
+ */
 int
 scsi_internal_device_unblock(struct scsi_device *sdev)
 {
@@ -2460,7 +2488,7 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock);
 
 /**
  * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
- * @sg:                scatter-gather list
+ * @sgl:       scatter-gather list
  * @sg_count:  number of segments in sg
  * @offset:    offset in bytes into sg, on return offset into the mapped area
  * @len:       bytes to map, on return number of bytes mapped
@@ -2509,8 +2537,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
 EXPORT_SYMBOL(scsi_kmap_atomic_sg);
 
 /**
- * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
- *                        mapped with scsi_kmap_atomic_sg
+ * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg
  * @virt:      virtual address to be unmapped
  */
 void scsi_kunmap_atomic_sg(void *virt)
index 40579edca101a465f997266343a5862ccebcb2c0..3e15918281719b5faddd5186314ab85ba8b52b05 100644 (file)
@@ -32,11 +32,12 @@ EXPORT_SYMBOL_GPL(scsi_nl_sock);
 
 
 /**
- * scsi_nl_rcv_msg -
- *    Receive message handler. Extracts message from a receive buffer.
+ * scsi_nl_rcv_msg - Receive message handler.
+ * @skb:               socket receive buffer
+ *
+ * Description: Extracts message from a receive buffer.
  *    Validates message header and calls appropriate transport message handler
  *
- * @skb:               socket receive buffer
  *
  **/
 static void
@@ -99,9 +100,7 @@ next_msg:
 
 
 /**
- * scsi_nl_rcv_event -
- *    Event handler for a netlink socket.
- *
+ * scsi_nl_rcv_event - Event handler for a netlink socket.
  * @this:              event notifier block
  * @event:             event type
  * @ptr:               event payload
@@ -129,9 +128,7 @@ static struct notifier_block scsi_netlink_notifier = {
 
 
 /**
- * scsi_netlink_init -
- *    Called by SCSI subsystem to intialize the SCSI transport netlink
- *    interface
+ * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
  *
  **/
 void
@@ -160,9 +157,7 @@ scsi_netlink_init(void)
 
 
 /**
- * scsi_netlink_exit -
- *    Called by SCSI subsystem to disable the SCSI transport netlink
- *    interface
+ * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface
  *
  **/
 void
index eff0059518954b26c62b116cd737f9e11e78da6a..3f34e9376b0aa148c8dafc58ee0c52c65849b1e1 100644 (file)
@@ -74,6 +74,9 @@ extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
 extern void scsi_free_queue(struct request_queue *q);
 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 *);
 
 /* scsi_proc.c */
 #ifdef CONFIG_SCSI_PROC_FS
index bb6f051beda82b569a611d330df99c7042be22f0..ed395154a5b189e4043c271da8fc9042178a043d 100644 (file)
@@ -45,6 +45,16 @@ static struct proc_dir_entry *proc_scsi;
 /* Protect sht->present and sht->proc_dir */
 static DEFINE_MUTEX(global_host_template_mutex);
 
+/**
+ * proc_scsi_read - handle read from /proc by calling host's proc_info() command
+ * @buffer: passed to proc_info
+ * @start: passed to proc_info
+ * @offset: passed to proc_info
+ * @length: passed to proc_info
+ * @eof: returns whether length read was less than requested
+ * @data: pointer to a &struct Scsi_Host
+ */
+
 static int proc_scsi_read(char *buffer, char **start, off_t offset,
                          int length, int *eof, void *data)
 {
@@ -57,6 +67,13 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset,
        return n;
 }
 
+/**
+ * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info()
+ * @file: not used
+ * @buf: source of data to write.
+ * @count: number of bytes (at most PROC_BLOCK_SIZE) to write.
+ * @data: pointer to &struct Scsi_Host
+ */
 static int proc_scsi_write_proc(struct file *file, const char __user *buf,
                            unsigned long count, void *data)
 {
@@ -80,6 +97,13 @@ out:
        return ret;
 }
 
+/**
+ * scsi_proc_hostdir_add - Create directory in /proc for a scsi host
+ * @sht: owner of this directory
+ *
+ * Sets sht->proc_dir to the new directory.
+ */
+
 void scsi_proc_hostdir_add(struct scsi_host_template *sht)
 {
        if (!sht->proc_info)
@@ -97,6 +121,10 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
        mutex_unlock(&global_host_template_mutex);
 }
 
+/**
+ * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host
+ * @sht: owner of directory
+ */
 void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
 {
        if (!sht->proc_info)
@@ -110,6 +138,11 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
        mutex_unlock(&global_host_template_mutex);
 }
 
+
+/**
+ * scsi_proc_host_add - Add entry for this host to appropriate /proc dir
+ * @shost: host to add
+ */
 void scsi_proc_host_add(struct Scsi_Host *shost)
 {
        struct scsi_host_template *sht = shost->hostt;
@@ -133,6 +166,10 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
        p->owner = sht->module;
 }
 
+/**
+ * scsi_proc_host_rm - remove this host's entry from /proc
+ * @shost: which host
+ */
 void scsi_proc_host_rm(struct Scsi_Host *shost)
 {
        char name[10];
@@ -143,7 +180,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
        sprintf(name,"%d", shost->host_no);
        remove_proc_entry(name, shost->hostt->proc_dir);
 }
-
+/**
+ * proc_print_scsidevice - return data about this host
+ * @dev: A scsi device
+ * @data: &struct seq_file to output to.
+ *
+ * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type,
+ * and revision.
+ */
 static int proc_print_scsidevice(struct device *dev, void *data)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
@@ -189,6 +233,21 @@ static int proc_print_scsidevice(struct device *dev, void *data)
        return 0;
 }
 
+/**
+ * scsi_add_single_device - Respond to user request to probe for/add device
+ * @host: user-supplied decimal integer
+ * @channel: user-supplied decimal integer
+ * @id: user-supplied decimal integer
+ * @lun: user-supplied decimal integer
+ *
+ * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi.
+ *
+ * does scsi_host_lookup() and either user_scan() if that transport
+ * type supports it, or else scsi_scan_host_selected()
+ *
+ * Note: this seems to be aimed exclusively at SCSI parallel busses.
+ */
+
 static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
 {
        struct Scsi_Host *shost;
@@ -206,6 +265,16 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
        return error;
 }
 
+/**
+ * scsi_remove_single_device - Respond to user request to remove a device
+ * @host: user-supplied decimal integer
+ * @channel: user-supplied decimal integer
+ * @id: user-supplied decimal integer
+ * @lun: user-supplied decimal integer
+ *
+ * Description: called by writing "scsi remove-single-device" to
+ * /proc/scsi/scsi.  Does a scsi_device_lookup() and scsi_remove_device()
+ */
 static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
 {
        struct scsi_device *sdev;
@@ -226,6 +295,25 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
        return error;
 }
 
+/**
+ * proc_scsi_write - handle writes to /proc/scsi/scsi
+ * @file: not used
+ * @buf: buffer to write
+ * @length: length of buf, at most PAGE_SIZE
+ * @ppos: not used
+ *
+ * Description: this provides a legacy mechanism to add or remove devices by
+ * Host, Channel, ID, and Lun.  To use,
+ * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or
+ * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with
+ * "0 1 2 3" replaced by the Host, Channel, Id, and Lun.
+ *
+ * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB,
+ * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to
+ * provide a unique identifier and nothing more.
+ */
+
+
 static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
                               size_t length, loff_t *ppos)
 {
@@ -291,6 +379,11 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
        return err;
 }
 
+/**
+ * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices)
+ * @s: output goes here
+ * @p: not used
+ */
 static int proc_scsi_show(struct seq_file *s, void *p)
 {
        seq_printf(s, "Attached devices:\n");
@@ -298,10 +391,17 @@ static int proc_scsi_show(struct seq_file *s, void *p)
        return 0;
 }
 
+/**
+ * proc_scsi_open - glue function
+ * @inode: not used
+ * @file: passed to single_open()
+ *
+ * Associates proc_scsi_show with this file
+ */
 static int proc_scsi_open(struct inode *inode, struct file *file)
 {
        /*
-        * We don't really needs this for the write case but it doesn't
+        * We don't really need this for the write case but it doesn't
         * harm either.
         */
        return single_open(file, proc_scsi_show, NULL);
@@ -315,6 +415,9 @@ static const struct file_operations proc_scsi_operations = {
        .release        = single_release,
 };
 
+/**
+ * scsi_init_procfs - create scsi and scsi/scsi in procfs
+ */
 int __init scsi_init_procfs(void)
 {
        struct proc_dir_entry *pde;
@@ -336,6 +439,9 @@ err1:
        return -ENOMEM;
 }
 
+/**
+ * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs
+ */
 void scsi_exit_procfs(void)
 {
        remove_proc_entry("scsi/scsi", NULL);
index 40ea71cd2ca6d5b9a7accefa25de353a98fd1b6d..1dc165ad17fb20edae98e80b408fbd8cfd0c4543 100644 (file)
@@ -221,6 +221,9 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
 
 /**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
+ * @starget: which target to allocate a &scsi_device for
+ * @lun: which lun
+ * @hostdata: usually NULL and set by ->slave_alloc instead
  *
  * Description:
  *     Allocate, initialize for io, and return a pointer to a scsi_Device.
@@ -472,7 +475,6 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
 
 /**
  * scsi_target_reap - check to see if target is in use and destroy if not
- *
  * @starget: target to be checked
  *
  * This is used after removing a LUN or doing a last put of the target
@@ -863,7 +865,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                sdev->no_start_on_add = 1;
 
        if (*bflags & BLIST_SINGLELUN)
-               sdev->single_lun = 1;
+               scsi_target(sdev)->single_lun = 1;
 
        sdev->use_10_for_rw = 1;
 
@@ -928,8 +930,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev)
 
 #ifdef CONFIG_SCSI_LOGGING
 /** 
- * scsi_inq_str - print INQUIRY data from min to max index,
- * strip trailing whitespace
+ * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
  * @buf:   Output buffer with at least end-first+1 bytes of space
  * @inq:   Inquiry buffer (input)
  * @first: Offset of string into inq
@@ -957,9 +958,10 @@ static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq,
  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
  * @starget:   pointer to target device structure
  * @lun:       LUN of target device
- * @sdevscan:  probe the LUN corresponding to this scsi_device
- * @sdevnew:   store the value of any new scsi_device allocated
  * @bflagsp:   store bflags here if not NULL
+ * @sdevp:     probe the LUN corresponding to this scsi_device
+ * @rescan:     if nonzero skip some code only needed on first scan
+ * @hostdata:  passed to scsi_alloc_sdev()
  *
  * Description:
  *     Call scsi_probe_lun, if a LUN with an attached device is found,
@@ -1110,6 +1112,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
  * scsi_sequential_lun_scan - sequentially scan a SCSI target
  * @starget:   pointer to target structure to scan
  * @bflags:    black/white list flag for LUN 0
+ * @scsi_level: Which version of the standard does this device adhere to
+ * @rescan:     passed to scsi_probe_add_lun()
  *
  * Description:
  *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
@@ -1220,7 +1224,7 @@ EXPORT_SYMBOL(scsilun_to_int);
 
 /**
  * int_to_scsilun: reverts an int into a scsi_lun
- * @int:        integer to be reverted
+ * @lun:        integer to be reverted
  * @scsilun:   struct scsi_lun to be set.
  *
  * Description:
@@ -1252,18 +1256,22 @@ EXPORT_SYMBOL(int_to_scsilun);
 
 /**
  * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
- * @sdevscan:  scan the host, channel, and id of this scsi_device
+ * @starget: which target
+ * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN
+ * @rescan: nonzero if we can skip code only needed on first scan
  *
  * Description:
- *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
- *     command, and scan the resulting list of LUNs by calling
- *     scsi_probe_and_add_lun.
+ *   Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command.
+ *   Scan the resulting list of LUNs by calling scsi_probe_and_add_lun.
  *
- *     Modifies sdevscan->lun.
+ *   If BLINK_REPORTLUN2 is set, scan a target that supports more than 8
+ *   LUNs even if it's older than SCSI-3.
+ *   If BLIST_NOREPORTLUN is set, return 1 always.
+ *   If BLIST_NOLUN is set, return 0 always.
  *
  * Return:
  *     0: scan completed (or no memory, so further scanning is futile)
- *     1: no report lun scan, or not configured
+ *     1: could not scan with REPORT LUN
  **/
 static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
                                int rescan)
@@ -1481,6 +1489,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
        if (scsi_host_scan_allowed(shost))
                scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
        mutex_unlock(&shost->scan_mutex);
+       transport_configure_device(&starget->dev);
        scsi_target_reap(starget);
        put_device(&starget->dev);
 
@@ -1561,6 +1570,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
  out_reap:
        /* now determine if the target has any children at all
         * and if not, nuke it */
+       transport_configure_device(&starget->dev);
        scsi_target_reap(starget);
 
        put_device(&starget->dev);
index f374fdcb6815981d3055f171c01e26fee89e0820..ed83cdb6e67dfbdb5c829238c91ed861b124a426 100644 (file)
@@ -373,12 +373,29 @@ 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,
 };
 
 int scsi_sysfs_register(void)
@@ -1001,6 +1018,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
        }
 
        transport_register_device(&shost->shost_gendev);
+       transport_configure_device(&shost->shost_gendev);
        return 0;
 }
 
index 9815a1a2db24a4c671ee769a670bfc3d6035fbbe..d2557dbc2dc156014b011609408b32d7dfcd70fc 100644 (file)
@@ -112,7 +112,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
        memset(&ev, 0, sizeof(ev));
        ev.p.cmd_req.host_no = shost->host_no;
        ev.p.cmd_req.itn_id = itn_id;
-       ev.p.cmd_req.data_len = cmd->request_bufflen;
+       ev.p.cmd_req.data_len = scsi_bufflen(cmd);
        memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
        memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
        ev.p.cmd_req.attribute = cmd->tag;
index a91761c3645f4d06b17237aa26deb5fb086a9e39..93ece8f4e5dea391c07c8a4241df9d180489c869 100644 (file)
@@ -180,7 +180,7 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
                container_of(work, struct scsi_tgt_cmd, work);
        struct scsi_cmnd *cmd = tcmd->rq->special;
 
-       dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
+       dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction,
                rq_data_dir(cmd->request));
        scsi_unmap_user_pages(tcmd);
        scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
@@ -327,11 +327,11 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
 {
        struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
 
-       dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+       dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
 
        scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
 
-       if (cmd->request_buffer)
+       if (scsi_sglist(cmd))
                scsi_free_sgtable(cmd);
 
        queue_work(scsi_tgtd, &tcmd->work);
@@ -342,7 +342,7 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
        int err;
 
-       dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+       dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
 
        err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
        switch (err) {
@@ -365,16 +365,12 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 
        cmd->request_bufflen = rq->data_len;
 
-       dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
-       count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
-       if (likely(count <= cmd->use_sg)) {
-               cmd->use_sg = count;
-               return 0;
-       }
-
-       eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
-       scsi_free_sgtable(cmd);
-       return -EINVAL;
+       dprintk("cmd %p cnt %d %lu\n", cmd, scsi_sg_count(cmd),
+               rq_data_dir(rq));
+       count = blk_rq_map_sg(rq->q, rq, scsi_sglist(cmd));
+       BUG_ON(count > cmd->use_sg);
+       cmd->use_sg = count;
+       return 0;
 }
 
 /* TODO: test this crap and replace bio_map_user with new interface maybe */
@@ -496,8 +492,8 @@ int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
        }
        cmd = rq->special;
 
-       dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
-               cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
+       dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n",
+               cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd),
                rq_data_dir(rq), cmd->cmnd[0]);
 
        if (result == TASK_ABORTED) {
@@ -617,7 +613,7 @@ int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
        struct Scsi_Host *shost;
        int err = -EINVAL;
 
-       dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+       dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
 
        shost = scsi_host_lookup(host_no);
        if (IS_ERR(shost)) {
index 7a7cfe583b2ab46171bb51929465aca2abad2ae5..b1119da6e88c902d9469c28690dc4101e1c42dc5 100644 (file)
@@ -481,9 +481,9 @@ MODULE_PARM_DESC(dev_loss_tmo,
                 " exceeded, the scsi target is removed. Value should be"
                 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
 
-/**
+/*
  * Netlink Infrastructure
- **/
+ */
 
 static atomic_t fc_event_seq;
 
@@ -491,10 +491,10 @@ static atomic_t fc_event_seq;
  * fc_get_event_number - Obtain the next sequential FC event number
  *
  * Notes:
- *   We could have inline'd this, but it would have required fc_event_seq to
+ *   We could have inlined this, but it would have required fc_event_seq to
  *   be exposed. For now, live with the subroutine call.
  *   Atomic used to avoid lock/unlock...
- **/
+ */
 u32
 fc_get_event_number(void)
 {
@@ -505,7 +505,6 @@ EXPORT_SYMBOL(fc_get_event_number);
 
 /**
  * fc_host_post_event - called to post an even on an fc_host.
- *
  * @shost:             host the event occurred on
  * @event_number:      fc event number obtained from get_fc_event_number()
  * @event_code:                fc_host event being posted
@@ -513,7 +512,7 @@ EXPORT_SYMBOL(fc_get_event_number);
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
                enum fc_host_event_code event_code, u32 event_data)
@@ -579,17 +578,16 @@ EXPORT_SYMBOL(fc_host_post_event);
 
 
 /**
- * fc_host_post_vendor_event - called to post a vendor unique event on
- *                             a fc_host
- *
+ * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host
  * @shost:             host the event occurred on
  * @event_number:      fc event number obtained from get_fc_event_number()
  * @data_len:          amount, in bytes, of vendor unique data
  * @data_buf:          pointer to vendor unique data
+ * @vendor_id:          Vendor id
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
                u32 data_len, char * data_buf, u64 vendor_id)
@@ -1900,7 +1898,6 @@ static int fc_vport_match(struct attribute_container *cont,
 
 /**
  * fc_timed_out - FC Transport I/O timeout intercept handler
- *
  * @scmd:      The SCSI command which timed out
  *
  * This routine protects against error handlers getting invoked while a
@@ -1920,7 +1917,7 @@ static int fc_vport_match(struct attribute_container *cont,
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 static enum scsi_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
@@ -2133,7 +2130,7 @@ EXPORT_SYMBOL(fc_release_transport);
  *     1 - work queued for execution
  *     0 - work is already queued
  *     -EINVAL - work queue doesn't exist
- **/
+ */
 static int
 fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
 {
@@ -2152,7 +2149,7 @@ fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
 /**
  * fc_flush_work - Flush a fc_host's workqueue.
  * @shost:     Pointer to Scsi_Host bound to fc_host.
- **/
+ */
 static void
 fc_flush_work(struct Scsi_Host *shost)
 {
@@ -2175,7 +2172,7 @@ fc_flush_work(struct Scsi_Host *shost)
  *
  * Return value:
  *     1 on success / 0 already queued / < 0 for error
- **/
+ */
 static int
 fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
                                unsigned long delay)
@@ -2195,7 +2192,7 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
 /**
  * fc_flush_devloss - Flush a fc_host's devloss workqueue.
  * @shost:     Pointer to Scsi_Host bound to fc_host.
- **/
+ */
 static void
 fc_flush_devloss(struct Scsi_Host *shost)
 {
@@ -2212,21 +2209,20 @@ fc_flush_devloss(struct Scsi_Host *shost)
 
 
 /**
- * fc_remove_host - called to terminate any fc_transport-related elements
- *                  for a scsi host.
- * @rport:     remote port to be unblocked.
+ * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host.
+ * @shost:     Which &Scsi_Host
  *
  * This routine is expected to be called immediately preceeding the
  * a driver's call to scsi_remove_host().
  *
  * WARNING: A driver utilizing the fc_transport, which fails to call
- *   this routine prior to scsi_remote_host(), will leave dangling
+ *   this routine prior to scsi_remove_host(), will leave dangling
  *   objects in /sys/class/fc_remote_ports. Access to any of these
  *   objects can result in a system crash !!!
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_remove_host(struct Scsi_Host *shost)
 {
@@ -2281,10 +2277,10 @@ EXPORT_SYMBOL(fc_remove_host);
 
 /**
  * fc_starget_delete - called to delete the scsi decendents of an rport
- *                  (target and all sdevs)
- *
  * @work:      remote port to be operated on.
- **/
+ *
+ * Deletes target and all sdevs.
+ */
 static void
 fc_starget_delete(struct work_struct *work)
 {
@@ -2303,9 +2299,8 @@ fc_starget_delete(struct work_struct *work)
 
 /**
  * fc_rport_final_delete - finish rport termination and delete it.
- *
  * @work:      remote port to be deleted.
- **/
+ */
 static void
 fc_rport_final_delete(struct work_struct *work)
 {
@@ -2375,7 +2370,7 @@ fc_rport_final_delete(struct work_struct *work)
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 static struct fc_rport *
 fc_rport_create(struct Scsi_Host *shost, int channel,
        struct fc_rport_identifiers  *ids)
@@ -2462,8 +2457,7 @@ delete_rport:
 }
 
 /**
- * fc_remote_port_add - notifies the fc transport of the existence
- *             of a remote FC port.
+ * fc_remote_port_add - notify fc transport of the existence of a remote FC port.
  * @shost:     scsi host the remote port is connected to.
  * @channel:   Channel on shost port connected to.
  * @ids:       The world wide names, fc address, and FC4 port
@@ -2499,7 +2493,7 @@ delete_rport:
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 struct fc_rport *
 fc_remote_port_add(struct Scsi_Host *shost, int channel,
        struct fc_rport_identifiers  *ids)
@@ -2683,19 +2677,18 @@ EXPORT_SYMBOL(fc_remote_port_add);
 
 
 /**
- * fc_remote_port_delete - notifies the fc transport that a remote
- *             port is no longer in existence.
+ * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence.
  * @rport:     The remote port that no longer exists
  *
  * The LLDD calls this routine to notify the transport that a remote
  * port is no longer part of the topology. Note: Although a port
  * may no longer be part of the topology, it may persist in the remote
  * ports displayed by the fc_host. We do this under 2 conditions:
- * - If the port was a scsi target, we delay its deletion by "blocking" it.
+ * 1) If the port was a scsi target, we delay its deletion by "blocking" it.
  *   This allows the port to temporarily disappear, then reappear without
  *   disrupting the SCSI device tree attached to it. During the "blocked"
  *   period the port will still exist.
- * - If the port was a scsi target and disappears for longer than we
+ * 2) If the port was a scsi target and disappears for longer than we
  *   expect, we'll delete the port and the tear down the SCSI device tree
  *   attached to it. However, we want to semi-persist the target id assigned
  *   to that port if it eventually does exist. The port structure will
@@ -2709,7 +2702,8 @@ EXPORT_SYMBOL(fc_remote_port_add);
  * temporary blocked state. From the LLDD's perspective, the rport no
  * longer exists. From the SCSI midlayer's perspective, the SCSI target
  * exists, but all sdevs on it are blocked from further I/O. The following
- * is then expected:
+ * is then expected.
+ *
  *   If the remote port does not return (signaled by a LLDD call to
  *   fc_remote_port_add()) within the dev_loss_tmo timeout, then the
  *   scsi target is removed - killing all outstanding i/o and removing the
@@ -2731,7 +2725,7 @@ EXPORT_SYMBOL(fc_remote_port_add);
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_remote_port_delete(struct fc_rport  *rport)
 {
@@ -2792,12 +2786,12 @@ fc_remote_port_delete(struct fc_rport  *rport)
 EXPORT_SYMBOL(fc_remote_port_delete);
 
 /**
- * fc_remote_port_rolechg - notifies the fc transport that the roles
- *             on a remote may have changed.
+ * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed.
  * @rport:     The remote port that changed.
+ * @roles:      New roles for this port.
  *
- * The LLDD calls this routine to notify the transport that the roles
- * on a remote port may have changed. The largest effect of this is
+ * Description: The LLDD calls this routine to notify the transport that the
+ * roles on a remote port may have changed. The largest effect of this is
  * if a port now becomes a FCP Target, it must be allocated a
  * scsi target id.  If the port is no longer a FCP target, any
  * scsi target id value assigned to it will persist in case the
@@ -2810,7 +2804,7 @@ EXPORT_SYMBOL(fc_remote_port_delete);
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 {
@@ -2875,12 +2869,12 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 EXPORT_SYMBOL(fc_remote_port_rolechg);
 
 /**
- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
- *                     which we blocked, and has now failed to return
- *                     in the allotted time.
- *
+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port.
  * @work:      rport target that failed to reappear in the allotted time.
- **/
+ *
+ * Description: An attempt to delete a remote port blocks, and if it fails
+ *              to return in the allotted time this gets called.
+ */
 static void
 fc_timeout_deleted_rport(struct work_struct *work)
 {
@@ -2984,14 +2978,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
 }
 
 /**
- * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
- *                       disconnected SCSI target.
- *
+ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target.
  * @work:      rport to terminate io on.
  *
  * Notes: Only requests the failure of the io, not that all are flushed
  *    prior to returning.
- **/
+ */
 static void
 fc_timeout_fail_rport_io(struct work_struct *work)
 {
@@ -3008,9 +3000,8 @@ fc_timeout_fail_rport_io(struct work_struct *work)
 
 /**
  * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
- *
  * @work:      remote port to be scanned.
- **/
+ */
 static void
 fc_scsi_scan_rport(struct work_struct *work)
 {
@@ -3047,7 +3038,7 @@ fc_scsi_scan_rport(struct work_struct *work)
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 static int
 fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
        struct fc_vport_identifiers  *ids, struct fc_vport **ret_vport)
@@ -3172,7 +3163,7 @@ delete_vport:
  *
  * Notes:
  *     This routine assumes no locks are held on entry.
- **/
+ */
 int
 fc_vport_terminate(struct fc_vport *vport)
 {
@@ -3232,9 +3223,8 @@ EXPORT_SYMBOL(fc_vport_terminate);
 
 /**
  * fc_vport_sched_delete - workq-based delete request for a vport
- *
  * @work:      vport to be deleted.
- **/
+ */
 static void
 fc_vport_sched_delete(struct work_struct *work)
 {
index 5428d15f23c617d5bfc579baea6391664c1c47c4..ef0e74264880625ffc78687e1603c1823ca0c6f3 100644 (file)
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/iscsi_if.h>
 
-#define ISCSI_SESSION_ATTRS 15
+#define ISCSI_SESSION_ATTRS 18
 #define ISCSI_CONN_ATTRS 11
 #define ISCSI_HOST_ATTRS 4
-#define ISCSI_TRANSPORT_VERSION "2.0-724"
+#define ISCSI_TRANSPORT_VERSION "2.0-867"
 
 struct iscsi_internal {
        int daemon_pid;
@@ -50,6 +50,7 @@ struct iscsi_internal {
 };
 
 static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
+static struct workqueue_struct *iscsi_eh_timer_workq;
 
 /*
  * list of registered transports and lock that must
@@ -115,6 +116,8 @@ static struct attribute_group iscsi_transport_group = {
        .attrs = iscsi_transport_attrs,
 };
 
+
+
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
                            struct class_device *cdev)
 {
@@ -124,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
        memset(ihost, 0, sizeof(*ihost));
        INIT_LIST_HEAD(&ihost->sessions);
        mutex_init(&ihost->mutex);
+
+       snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d",
+               shost->host_no);
+       ihost->unbind_workq = create_singlethread_workqueue(
+                                               ihost->unbind_workq_name);
+       if (!ihost->unbind_workq)
+               return -ENOMEM;
+       return 0;
+}
+
+static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
+                            struct class_device *cdev)
+{
+       struct Scsi_Host *shost = dev_to_shost(dev);
+       struct iscsi_host *ihost = shost->shost_data;
+
+       destroy_workqueue(ihost->unbind_workq);
        return 0;
 }
 
 static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
                               "iscsi_host",
                               iscsi_setup_host,
-                              NULL,
+                              iscsi_remove_host,
                               NULL);
 
 static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
@@ -252,7 +272,7 @@ static void session_recovery_timedout(struct work_struct *work)
 void iscsi_unblock_session(struct iscsi_cls_session *session)
 {
        if (!cancel_delayed_work(&session->recovery_work))
-               flush_scheduled_work();
+               flush_workqueue(iscsi_eh_timer_workq);
        scsi_target_unblock(&session->dev);
 }
 EXPORT_SYMBOL_GPL(iscsi_unblock_session);
@@ -260,11 +280,40 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session);
 void iscsi_block_session(struct iscsi_cls_session *session)
 {
        scsi_target_block(&session->dev);
-       schedule_delayed_work(&session->recovery_work,
-                            session->recovery_tmo * HZ);
+       queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
+                          session->recovery_tmo * HZ);
 }
 EXPORT_SYMBOL_GPL(iscsi_block_session);
 
+static void __iscsi_unbind_session(struct work_struct *work)
+{
+       struct iscsi_cls_session *session =
+                       container_of(work, struct iscsi_cls_session,
+                                    unbind_work);
+       struct Scsi_Host *shost = iscsi_session_to_shost(session);
+       struct iscsi_host *ihost = shost->shost_data;
+
+       /* Prevent new scans and make sure scanning is not in progress */
+       mutex_lock(&ihost->mutex);
+       if (list_empty(&session->host_list)) {
+               mutex_unlock(&ihost->mutex);
+               return;
+       }
+       list_del_init(&session->host_list);
+       mutex_unlock(&ihost->mutex);
+
+       scsi_remove_target(&session->dev);
+       iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
+}
+
+static int iscsi_unbind_session(struct iscsi_cls_session *session)
+{
+       struct Scsi_Host *shost = iscsi_session_to_shost(session);
+       struct iscsi_host *ihost = shost->shost_data;
+
+       return queue_work(ihost->unbind_workq, &session->unbind_work);
+}
+
 struct iscsi_cls_session *
 iscsi_alloc_session(struct Scsi_Host *shost,
                    struct iscsi_transport *transport)
@@ -281,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,
        INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
        INIT_LIST_HEAD(&session->host_list);
        INIT_LIST_HEAD(&session->sess_list);
+       INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
 
        /* this is released in the dev's release function */
        scsi_host_get(shost);
@@ -297,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 {
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
        struct iscsi_host *ihost;
+       unsigned long flags;
        int err;
 
        ihost = shost->shost_data;
@@ -313,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
        }
        transport_register_device(&session->dev);
 
+       spin_lock_irqsave(&sesslock, flags);
+       list_add(&session->sess_list, &sesslist);
+       spin_unlock_irqrestore(&sesslock, flags);
+
        mutex_lock(&ihost->mutex);
        list_add(&session->host_list, &ihost->sessions);
        mutex_unlock(&ihost->mutex);
+
+       iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
        return 0;
 
 release_host:
@@ -328,9 +385,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session);
  * iscsi_create_session - create iscsi class session
  * @shost: scsi host
  * @transport: iscsi transport
+ * @target_id: which target
  *
  * This can be called from a LLD or iscsi_transport.
- **/
+ */
 struct iscsi_cls_session *
 iscsi_create_session(struct Scsi_Host *shost,
                     struct iscsi_transport *transport,
@@ -350,19 +408,58 @@ iscsi_create_session(struct Scsi_Host *shost,
 }
 EXPORT_SYMBOL_GPL(iscsi_create_session);
 
+static void iscsi_conn_release(struct device *dev)
+{
+       struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+       struct device *parent = conn->dev.parent;
+
+       kfree(conn);
+       put_device(parent);
+}
+
+static int iscsi_is_conn_dev(const struct device *dev)
+{
+       return dev->release == iscsi_conn_release;
+}
+
+static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
+{
+       if (!iscsi_is_conn_dev(dev))
+               return 0;
+       return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
+}
+
 void iscsi_remove_session(struct iscsi_cls_session *session)
 {
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
        struct iscsi_host *ihost = shost->shost_data;
+       unsigned long flags;
+       int err;
 
-       if (!cancel_delayed_work(&session->recovery_work))
-               flush_scheduled_work();
+       spin_lock_irqsave(&sesslock, flags);
+       list_del(&session->sess_list);
+       spin_unlock_irqrestore(&sesslock, flags);
 
-       mutex_lock(&ihost->mutex);
-       list_del(&session->host_list);
-       mutex_unlock(&ihost->mutex);
+       /*
+        * If we are blocked let commands flow again. The lld or iscsi
+        * layer should set up the queuecommand to fail commands.
+        */
+       iscsi_unblock_session(session);
+       iscsi_unbind_session(session);
+       /*
+        * If the session dropped while removing devices then we need to make
+        * sure it is not blocked
+        */
+       if (!cancel_delayed_work(&session->recovery_work))
+               flush_workqueue(iscsi_eh_timer_workq);
+       flush_workqueue(ihost->unbind_workq);
 
-       scsi_remove_target(&session->dev);
+       /* hw iscsi may not have removed all connections from session */
+       err = device_for_each_child(&session->dev, NULL,
+                                   iscsi_iter_destroy_conn_fn);
+       if (err)
+               dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete "
+                          "all connections for session. Error %d.\n", err);
 
        transport_unregister_device(&session->dev);
        device_del(&session->dev);
@@ -371,9 +468,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session);
 
 void iscsi_free_session(struct iscsi_cls_session *session)
 {
+       iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
        put_device(&session->dev);
 }
-
 EXPORT_SYMBOL_GPL(iscsi_free_session);
 
 /**
@@ -382,7 +479,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session);
  *
  * Can be called by a LLD or iscsi_transport. There must not be
  * any running connections.
- **/
+ */
 int iscsi_destroy_session(struct iscsi_cls_session *session)
 {
        iscsi_remove_session(session);
@@ -391,20 +488,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
 }
 EXPORT_SYMBOL_GPL(iscsi_destroy_session);
 
-static void iscsi_conn_release(struct device *dev)
-{
-       struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
-       struct device *parent = conn->dev.parent;
-
-       kfree(conn);
-       put_device(parent);
-}
-
-static int iscsi_is_conn_dev(const struct device *dev)
-{
-       return dev->release == iscsi_conn_release;
-}
-
 /**
  * iscsi_create_conn - create iscsi class connection
  * @session: iscsi cls session
@@ -418,12 +501,13 @@ static int iscsi_is_conn_dev(const struct device *dev)
  * for software iscsi we could be trying to preallocate a connection struct
  * in which case there could be two connection structs and cid would be
  * non-zero.
- **/
+ */
 struct iscsi_cls_conn *
 iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
 {
        struct iscsi_transport *transport = session->transport;
        struct iscsi_cls_conn *conn;
+       unsigned long flags;
        int err;
 
        conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
@@ -452,6 +536,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
                goto release_parent_ref;
        }
        transport_register_device(&conn->dev);
+
+       spin_lock_irqsave(&connlock, flags);
+       list_add(&conn->conn_list, &connlist);
+       conn->active = 1;
+       spin_unlock_irqrestore(&connlock, flags);
        return conn;
 
 release_parent_ref:
@@ -465,17 +554,23 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn);
 
 /**
  * iscsi_destroy_conn - destroy iscsi class connection
- * @session: iscsi cls session
+ * @conn: iscsi cls session
  *
  * This can be called from a LLD or iscsi_transport.
- **/
+ */
 int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&connlock, flags);
+       conn->active = 0;
+       list_del(&conn->conn_list);
+       spin_unlock_irqrestore(&connlock, flags);
+
        transport_unregister_device(&conn->dev);
        device_unregister(&conn->dev);
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
 
 /*
@@ -685,132 +780,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 }
 
 /**
- * iscsi_if_destroy_session_done - send session destr. completion event
- * @conn: last connection for session
- *
- * This is called by HW iscsi LLDs to notify userpsace that its HW has
- * removed a session.
- **/
-int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
+ * iscsi_session_event - send session destr. completion event
+ * @session: iscsi class session
+ * @event: type of event
+ */
+int iscsi_session_event(struct iscsi_cls_session *session,
+                       enum iscsi_uevent_e event)
 {
        struct iscsi_internal *priv;
-       struct iscsi_cls_session *session;
        struct Scsi_Host *shost;
        struct iscsi_uevent *ev;
        struct sk_buff  *skb;
        struct nlmsghdr *nlh;
-       unsigned long flags;
        int rc, len = NLMSG_SPACE(sizeof(*ev));
 
-       priv = iscsi_if_transport_lookup(conn->transport);
+       priv = iscsi_if_transport_lookup(session->transport);
        if (!priv)
                return -EINVAL;
-
-       session = iscsi_dev_to_session(conn->dev.parent);
        shost = iscsi_session_to_shost(session);
 
        skb = alloc_skb(len, GFP_KERNEL);
        if (!skb) {
-               dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-                         "session creation event\n");
+               dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
+                         "of session event %u\n", event);
                return -ENOMEM;
        }
 
        nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
        ev = NLMSG_DATA(nlh);
-       ev->transport_handle = iscsi_handle(conn->transport);
-       ev->type = ISCSI_KEVENT_DESTROY_SESSION;
-       ev->r.d_session.host_no = shost->host_no;
-       ev->r.d_session.sid = session->sid;
-
-       /*
-        * this will occur if the daemon is not up, so we just warn
-        * the user and when the daemon is restarted it will handle it
-        */
-       rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
-       if (rc < 0)
-               dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-                         "session destruction event. Check iscsi daemon\n");
-
-       spin_lock_irqsave(&sesslock, flags);
-       list_del(&session->sess_list);
-       spin_unlock_irqrestore(&sesslock, flags);
+       ev->transport_handle = iscsi_handle(session->transport);
 
-       spin_lock_irqsave(&connlock, flags);
-       conn->active = 0;
-       list_del(&conn->conn_list);
-       spin_unlock_irqrestore(&connlock, flags);
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
-
-/**
- * iscsi_if_create_session_done - send session creation completion event
- * @conn: leading connection for session
- *
- * This is called by HW iscsi LLDs to notify userpsace that its HW has
- * created a session or a existing session is back in the logged in state.
- **/
-int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
-{
-       struct iscsi_internal *priv;
-       struct iscsi_cls_session *session;
-       struct Scsi_Host *shost;
-       struct iscsi_uevent *ev;
-       struct sk_buff  *skb;
-       struct nlmsghdr *nlh;
-       unsigned long flags;
-       int rc, len = NLMSG_SPACE(sizeof(*ev));
-
-       priv = iscsi_if_transport_lookup(conn->transport);
-       if (!priv)
+       ev->type = event;
+       switch (event) {
+       case ISCSI_KEVENT_DESTROY_SESSION:
+               ev->r.d_session.host_no = shost->host_no;
+               ev->r.d_session.sid = session->sid;
+               break;
+       case ISCSI_KEVENT_CREATE_SESSION:
+               ev->r.c_session_ret.host_no = shost->host_no;
+               ev->r.c_session_ret.sid = session->sid;
+               break;
+       case ISCSI_KEVENT_UNBIND_SESSION:
+               ev->r.unbind_session.host_no = shost->host_no;
+               ev->r.unbind_session.sid = session->sid;
+               break;
+       default:
+               dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n",
+                          event);
+               kfree_skb(skb);
                return -EINVAL;
-
-       session = iscsi_dev_to_session(conn->dev.parent);
-       shost = iscsi_session_to_shost(session);
-
-       skb = alloc_skb(len, GFP_KERNEL);
-       if (!skb) {
-               dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-                         "session creation event\n");
-               return -ENOMEM;
        }
 
-       nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
-       ev = NLMSG_DATA(nlh);
-       ev->transport_handle = iscsi_handle(conn->transport);
-       ev->type = ISCSI_UEVENT_CREATE_SESSION;
-       ev->r.c_session_ret.host_no = shost->host_no;
-       ev->r.c_session_ret.sid = session->sid;
-
        /*
         * this will occur if the daemon is not up, so we just warn
         * the user and when the daemon is restarted it will handle it
         */
        rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
        if (rc < 0)
-               dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-                         "session creation event. Check iscsi daemon\n");
-
-       spin_lock_irqsave(&sesslock, flags);
-       list_add(&session->sess_list, &sesslist);
-       spin_unlock_irqrestore(&sesslock, flags);
-
-       spin_lock_irqsave(&connlock, flags);
-       list_add(&conn->conn_list, &connlist);
-       conn->active = 1;
-       spin_unlock_irqrestore(&connlock, flags);
+               dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
+                         "of session event %u. Check iscsi daemon\n", event);
        return rc;
 }
-EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
+EXPORT_SYMBOL_GPL(iscsi_session_event);
 
 static int
 iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
 {
        struct iscsi_transport *transport = priv->iscsi_transport;
        struct iscsi_cls_session *session;
-       unsigned long flags;
        uint32_t hostno;
 
        session = transport->create_session(transport, &priv->t,
@@ -821,10 +858,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
        if (!session)
                return -ENOMEM;
 
-       spin_lock_irqsave(&sesslock, flags);
-       list_add(&session->sess_list, &sesslist);
-       spin_unlock_irqrestore(&sesslock, flags);
-
        ev->r.c_session_ret.host_no = hostno;
        ev->r.c_session_ret.sid = session->sid;
        return 0;
@@ -835,7 +868,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 {
        struct iscsi_cls_conn *conn;
        struct iscsi_cls_session *session;
-       unsigned long flags;
 
        session = iscsi_session_lookup(ev->u.c_conn.sid);
        if (!session) {
@@ -854,28 +886,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 
        ev->r.c_conn_ret.sid = session->sid;
        ev->r.c_conn_ret.cid = conn->cid;
-
-       spin_lock_irqsave(&connlock, flags);
-       list_add(&conn->conn_list, &connlist);
-       conn->active = 1;
-       spin_unlock_irqrestore(&connlock, flags);
-
        return 0;
 }
 
 static int
 iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 {
-       unsigned long flags;
        struct iscsi_cls_conn *conn;
 
        conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
        if (!conn)
                return -EINVAL;
-       spin_lock_irqsave(&connlock, flags);
-       conn->active = 0;
-       list_del(&conn->conn_list);
-       spin_unlock_irqrestore(&connlock, flags);
 
        if (transport->destroy_conn)
                transport->destroy_conn(conn);
@@ -1002,7 +1023,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct iscsi_internal *priv;
        struct iscsi_cls_session *session;
        struct iscsi_cls_conn *conn;
-       unsigned long flags;
 
        priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
        if (!priv)
@@ -1020,13 +1040,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                break;
        case ISCSI_UEVENT_DESTROY_SESSION:
                session = iscsi_session_lookup(ev->u.d_session.sid);
-               if (session) {
-                       spin_lock_irqsave(&sesslock, flags);
-                       list_del(&session->sess_list);
-                       spin_unlock_irqrestore(&sesslock, flags);
-
+               if (session)
                        transport->destroy_session(session);
-               } else
+               else
+                       err = -EINVAL;
+               break;
+       case ISCSI_UEVENT_UNBIND_SESSION:
+               session = iscsi_session_lookup(ev->u.d_session.sid);
+               if (session)
+                       iscsi_unbind_session(session);
+               else
                        err = -EINVAL;
                break;
        case ISCSI_UEVENT_CREATE_CONN:
@@ -1179,6 +1202,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
 iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
 iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
 iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
+iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
+iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
 
 #define iscsi_cdev_to_session(_cdev) \
        iscsi_dev_to_session(_cdev->dev)
@@ -1217,6 +1242,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
 iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
 iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
 iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
+iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
+iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
 
 #define iscsi_priv_session_attr_show(field, format)                    \
 static ssize_t                                                         \
@@ -1413,6 +1441,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
        SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
        SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
        SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
+       SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
+       SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
 
        BUG_ON(count > ISCSI_CONN_ATTRS);
        priv->conn_attrs[count] = NULL;
@@ -1438,6 +1468,9 @@ iscsi_register_transport(struct iscsi_transport *tt)
        SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
        SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
        SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
+       SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
+       SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
+       SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
        SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
 
        BUG_ON(count > ISCSI_SESSION_ATTRS);
@@ -1518,8 +1551,14 @@ static __init int iscsi_transport_init(void)
                goto unregister_session_class;
        }
 
+       iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
+       if (!iscsi_eh_timer_workq)
+               goto release_nls;
+
        return 0;
 
+release_nls:
+       sock_release(nls->sk_socket);
 unregister_session_class:
        transport_class_unregister(&iscsi_session_class);
 unregister_conn_class:
@@ -1533,6 +1572,7 @@ unregister_transport_class:
 
 static void __exit iscsi_transport_exit(void)
 {
+       destroy_workqueue(iscsi_eh_timer_workq);
        sock_release(nls->sk_socket);
        transport_class_unregister(&iscsi_connection_class);
        transport_class_unregister(&iscsi_session_class);
index 3120f4b3a11a806254a3eb3dcbf3f71cc4c6e40b..f2149d0bb9997a4caff68d9900eeb6da8de8832a 100644 (file)
@@ -173,6 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
 
                handler = to_sas_internal(shost->transportt)->f->smp_handler;
                ret = handler(shost, rphy, req);
+               req->errors = ret;
 
                spin_lock_irq(q->queue_lock);
 
@@ -323,7 +324,7 @@ static int do_sas_phy_delete(struct device *dev, void *data)
 }
 
 /**
- * sas_remove_children  --  tear down a devices SAS data structures
+ * sas_remove_children  -  tear down a devices SAS data structures
  * @dev:       device belonging to the sas object
  *
  * Removes all SAS PHYs and remote PHYs for a given object
@@ -336,7 +337,7 @@ void sas_remove_children(struct device *dev)
 EXPORT_SYMBOL(sas_remove_children);
 
 /**
- * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
+ * sas_remove_host  -  tear down a Scsi_Host's SAS data structures
  * @shost:     Scsi Host that is torn down
  *
  * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
@@ -577,7 +578,7 @@ static void sas_phy_release(struct device *dev)
 }
 
 /**
- * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
+ * sas_phy_alloc  -  allocates and initialize a SAS PHY structure
  * @parent:    Parent device
  * @number:    Phy index
  *
@@ -618,7 +619,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
 EXPORT_SYMBOL(sas_phy_alloc);
 
 /**
- * sas_phy_add  --  add a SAS PHY to the device hierarchy
+ * sas_phy_add  -  add a SAS PHY to the device hierarchy
  * @phy:       The PHY to be added
  *
  * Publishes a SAS PHY to the rest of the system.
@@ -638,7 +639,7 @@ int sas_phy_add(struct sas_phy *phy)
 EXPORT_SYMBOL(sas_phy_add);
 
 /**
- * sas_phy_free  --  free a SAS PHY
+ * sas_phy_free  -  free a SAS PHY
  * @phy:       SAS PHY to free
  *
  * Frees the specified SAS PHY.
@@ -655,7 +656,7 @@ void sas_phy_free(struct sas_phy *phy)
 EXPORT_SYMBOL(sas_phy_free);
 
 /**
- * sas_phy_delete  --  remove SAS PHY
+ * sas_phy_delete  -  remove SAS PHY
  * @phy:       SAS PHY to remove
  *
  * Removes the specified SAS PHY.  If the SAS PHY has an
@@ -677,7 +678,7 @@ sas_phy_delete(struct sas_phy *phy)
 EXPORT_SYMBOL(sas_phy_delete);
 
 /**
- * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
+ * scsi_is_sas_phy  -  check if a struct device represents a SAS PHY
  * @dev:       device to check
  *
  * Returns:
@@ -843,7 +844,6 @@ EXPORT_SYMBOL(sas_port_alloc_num);
 
 /**
  * sas_port_add - add a SAS port to the device hierarchy
- *
  * @port:      port to be added
  *
  * publishes a port to the rest of the system
@@ -868,7 +868,7 @@ int sas_port_add(struct sas_port *port)
 EXPORT_SYMBOL(sas_port_add);
 
 /**
- * sas_port_free  --  free a SAS PORT
+ * sas_port_free  -  free a SAS PORT
  * @port:      SAS PORT to free
  *
  * Frees the specified SAS PORT.
@@ -885,7 +885,7 @@ void sas_port_free(struct sas_port *port)
 EXPORT_SYMBOL(sas_port_free);
 
 /**
- * sas_port_delete  --  remove SAS PORT
+ * sas_port_delete  -  remove SAS PORT
  * @port:      SAS PORT to remove
  *
  * Removes the specified SAS PORT.  If the SAS PORT has an
@@ -924,7 +924,7 @@ void sas_port_delete(struct sas_port *port)
 EXPORT_SYMBOL(sas_port_delete);
 
 /**
- * scsi_is_sas_port --  check if a struct device represents a SAS port
+ * scsi_is_sas_port -  check if a struct device represents a SAS port
  * @dev:       device to check
  *
  * Returns:
@@ -1309,6 +1309,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
 
 /**
  * sas_end_device_alloc - allocate an rphy for an end device
+ * @parent: which port
  *
  * Allocates an SAS remote PHY structure, connected to @parent.
  *
@@ -1345,6 +1346,8 @@ EXPORT_SYMBOL(sas_end_device_alloc);
 
 /**
  * sas_expander_alloc - allocate an rphy for an end device
+ * @parent: which port
+ * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
  *
  * Allocates an SAS remote PHY structure, connected to @parent.
  *
@@ -1383,7 +1386,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
 EXPORT_SYMBOL(sas_expander_alloc);
 
 /**
- * sas_rphy_add  --  add a SAS remote PHY to the device hierarchy
+ * sas_rphy_add  -  add a SAS remote PHY to the device hierarchy
  * @rphy:      The remote PHY to be added
  *
  * Publishes a SAS remote PHY to the rest of the system.
@@ -1430,8 +1433,8 @@ int sas_rphy_add(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_add);
 
 /**
- * sas_rphy_free  --  free a SAS remote PHY
- * @rphy       SAS remote PHY to free
+ * sas_rphy_free  -  free a SAS remote PHY
+ * @rphy: SAS remote PHY to free
  *
  * Frees the specified SAS remote PHY.
  *
@@ -1459,7 +1462,7 @@ void sas_rphy_free(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_free);
 
 /**
- * sas_rphy_delete  --  remove and free SAS remote PHY
+ * sas_rphy_delete  -  remove and free SAS remote PHY
  * @rphy:      SAS remote PHY to remove and free
  *
  * Removes the specified SAS remote PHY and frees it.
@@ -1473,7 +1476,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_delete);
 
 /**
- * sas_rphy_remove  --  remove SAS remote PHY
+ * sas_rphy_remove  -  remove SAS remote PHY
  * @rphy:      SAS remote phy to remove
  *
  * Removes the specified SAS remote PHY.
@@ -1504,7 +1507,7 @@ sas_rphy_remove(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_remove);
 
 /**
- * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
+ * scsi_is_sas_rphy  -  check if a struct device represents a SAS remote PHY
  * @dev:       device to check
  *
  * Returns:
@@ -1604,7 +1607,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
        SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
 
 /**
- * sas_attach_transport  --  instantiate SAS transport template
+ * sas_attach_transport  -  instantiate SAS transport template
  * @ft:                SAS transport class function template
  */
 struct scsi_transport_template *
@@ -1715,7 +1718,7 @@ sas_attach_transport(struct sas_function_template *ft)
 EXPORT_SYMBOL(sas_attach_transport);
 
 /**
- * sas_release_transport  --  release SAS transport template instance
+ * sas_release_transport  -  release SAS transport template instance
  * @t:         transport template instance
  */
 void sas_release_transport(struct scsi_transport_template *t)
index 4df21c92ff1ede9931772f36ec7aa3ac77255bb9..1fb60313a516fcd971538b0ebf17271357d5ed48 100644 (file)
 struct spi_internal {
        struct scsi_transport_template t;
        struct spi_function_template *f;
-       /* The actual attributes */
-       struct class_device_attribute private_attrs[SPI_NUM_ATTRS];
-       /* The array of null terminated pointers to attributes 
-        * needed by scsi_sysfs.c */
-       struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1];
-       struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS];
-       struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1];
 };
 
 #define to_spi_internal(tmpl)  container_of(tmpl, struct spi_internal, t)
@@ -174,17 +167,20 @@ static int spi_host_setup(struct transport_container *tc, struct device *dev,
        return 0;
 }
 
+static int spi_host_configure(struct transport_container *tc,
+                             struct device *dev,
+                             struct class_device *cdev);
+
 static DECLARE_TRANSPORT_CLASS(spi_host_class,
                               "spi_host",
                               spi_host_setup,
                               NULL,
-                              NULL);
+                              spi_host_configure);
 
 static int spi_host_match(struct attribute_container *cont,
                          struct device *dev)
 {
        struct Scsi_Host *shost;
-       struct spi_internal *i;
 
        if (!scsi_is_host_device(dev))
                return 0;
@@ -194,11 +190,13 @@ static int spi_host_match(struct attribute_container *cont,
            != &spi_host_class.class)
                return 0;
 
-       i = to_spi_internal(shost->transportt);
-       
-       return &i->t.host_attrs.ac == cont;
+       return &shost->transportt->host_attrs.ac == cont;
 }
 
+static int spi_target_configure(struct transport_container *tc,
+                               struct device *dev,
+                               struct class_device *cdev);
+
 static int spi_device_configure(struct transport_container *tc,
                                struct device *dev,
                                struct class_device *cdev)
@@ -300,8 +298,10 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);    \
        struct spi_internal *i = to_spi_internal(shost->transportt);    \
                                                                        \
+       if (!i->f->set_##field)                                         \
+               return -EINVAL;                                         \
        val = simple_strtoul(buf, NULL, 0);                             \
-       i->f->set_##field(starget, val);                        \
+       i->f->set_##field(starget, val);                                \
        return count;                                                   \
 }
 
@@ -317,6 +317,8 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
        struct spi_transport_attrs *tp                                  \
                = (struct spi_transport_attrs *)&starget->starget_data; \
                                                                        \
+       if (i->f->set_##field)                                          \
+               return -EINVAL;                                         \
        val = simple_strtoul(buf, NULL, 0);                             \
        if (val > tp->max_##field)                                      \
                val = tp->max_##field;                                  \
@@ -327,14 +329,14 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
 #define spi_transport_rd_attr(field, format_string)                    \
        spi_transport_show_function(field, format_string)               \
        spi_transport_store_function(field, format_string)              \
-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,                     \
+static CLASS_DEVICE_ATTR(field, S_IRUGO,                               \
                         show_spi_transport_##field,                    \
                         store_spi_transport_##field);
 
 #define spi_transport_simple_attr(field, format_string)                        \
        spi_transport_show_simple(field, format_string)                 \
        spi_transport_store_simple(field, format_string)                \
-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,                     \
+static CLASS_DEVICE_ATTR(field, S_IRUGO,                               \
                         show_spi_transport_##field,                    \
                         store_spi_transport_##field);
 
@@ -342,7 +344,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,                  \
        spi_transport_show_function(field, format_string)               \
        spi_transport_store_max(field, format_string)                   \
        spi_transport_simple_attr(max_##field, format_string)           \
-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,                     \
+static CLASS_DEVICE_ATTR(field, S_IRUGO,                               \
                         show_spi_transport_##field,                    \
                         store_spi_transport_##field);
 
@@ -472,6 +474,9 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
                (struct spi_transport_attrs *)&starget->starget_data;
        int period, retval;
 
+       if (!i->f->set_period)
+               return -EINVAL;
+
        retval = store_spi_transport_period_helper(cdev, buf, count, &period);
 
        if (period < tp->min_period)
@@ -482,7 +487,7 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
        return retval;
 }
 
-static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
+static CLASS_DEVICE_ATTR(period, S_IRUGO,
                         show_spi_transport_period,
                         store_spi_transport_period);
 
@@ -490,9 +495,14 @@ static ssize_t
 show_spi_transport_min_period(struct class_device *cdev, char *buf)
 {
        struct scsi_target *starget = transport_class_to_starget(cdev);
+       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+       struct spi_internal *i = to_spi_internal(shost->transportt);
        struct spi_transport_attrs *tp =
                (struct spi_transport_attrs *)&starget->starget_data;
 
+       if (!i->f->set_period)
+               return -EINVAL;
+
        return show_spi_transport_period_helper(buf, tp->min_period);
 }
 
@@ -509,7 +519,7 @@ store_spi_transport_min_period(struct class_device *cdev, const char *buf,
 }
 
 
-static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 
+static CLASS_DEVICE_ATTR(min_period, S_IRUGO,
                         show_spi_transport_min_period,
                         store_spi_transport_min_period);
 
@@ -531,12 +541,15 @@ static ssize_t store_spi_host_signalling(struct class_device *cdev,
        struct spi_internal *i = to_spi_internal(shost->transportt);
        enum spi_signal_type type = spi_signal_to_value(buf);
 
+       if (!i->f->set_signalling)
+               return -EINVAL;
+
        if (type != SPI_SIGNAL_UNKNOWN)
                i->f->set_signalling(shost, type);
 
        return count;
 }
-static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
+static CLASS_DEVICE_ATTR(signalling, S_IRUGO,
                         show_spi_host_signalling,
                         store_spi_host_signalling);
 
@@ -1262,35 +1275,6 @@ int spi_print_msg(const unsigned char *msg)
 EXPORT_SYMBOL(spi_print_msg);
 #endif /* ! CONFIG_SCSI_CONSTANTS */
 
-#define SETUP_ATTRIBUTE(field)                                         \
-       i->private_attrs[count] = class_device_attr_##field;            \
-       if (!i->f->set_##field) {                                       \
-               i->private_attrs[count].attr.mode = S_IRUGO;            \
-               i->private_attrs[count].store = NULL;                   \
-       }                                                               \
-       i->attrs[count] = &i->private_attrs[count];                     \
-       if (i->f->show_##field)                                         \
-               count++
-
-#define SETUP_RELATED_ATTRIBUTE(field, rel_field)                      \
-       i->private_attrs[count] = class_device_attr_##field;            \
-       if (!i->f->set_##rel_field) {                                   \
-               i->private_attrs[count].attr.mode = S_IRUGO;            \
-               i->private_attrs[count].store = NULL;                   \
-       }                                                               \
-       i->attrs[count] = &i->private_attrs[count];                     \
-       if (i->f->show_##rel_field)                                     \
-               count++
-
-#define SETUP_HOST_ATTRIBUTE(field)                                    \
-       i->private_host_attrs[count] = class_device_attr_##field;       \
-       if (!i->f->set_##field) {                                       \
-               i->private_host_attrs[count].attr.mode = S_IRUGO;       \
-               i->private_host_attrs[count].store = NULL;              \
-       }                                                               \
-       i->host_attrs[count] = &i->private_host_attrs[count];           \
-       count++
-
 static int spi_device_match(struct attribute_container *cont,
                            struct device *dev)
 {
@@ -1343,16 +1327,156 @@ static DECLARE_TRANSPORT_CLASS(spi_transport_class,
                               "spi_transport",
                               spi_setup_transport_attrs,
                               NULL,
-                              NULL);
+                              spi_target_configure);
 
 static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
                                    spi_device_match,
                                    spi_device_configure);
 
+static struct attribute *host_attributes[] = {
+       &class_device_attr_signalling.attr,
+       NULL
+};
+
+static struct attribute_group host_attribute_group = {
+       .attrs = host_attributes,
+};
+
+static int spi_host_configure(struct transport_container *tc,
+                             struct device *dev,
+                             struct class_device *cdev)
+{
+       struct kobject *kobj = &cdev->kobj;
+       struct Scsi_Host *shost = transport_class_to_shost(cdev);
+       struct spi_internal *si = to_spi_internal(shost->transportt);
+       struct attribute *attr = &class_device_attr_signalling.attr;
+       int rc = 0;
+
+       if (si->f->set_signalling)
+               rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
+
+       return rc;
+}
+
+/* returns true if we should be showing the variable.  Also
+ * overloads the return by setting 1<<1 if the attribute should
+ * be writeable */
+#define TARGET_ATTRIBUTE_HELPER(name) \
+       (si->f->show_##name ? 1 : 0) + \
+       (si->f->set_##name ? 2 : 0)
+
+static int target_attribute_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int i)
+{
+       struct class_device *cdev =
+               container_of(kobj, struct class_device, kobj);
+       struct scsi_target *starget = transport_class_to_starget(cdev);
+       struct Scsi_Host *shost = transport_class_to_shost(cdev);
+       struct spi_internal *si = to_spi_internal(shost->transportt);
+
+       if (attr == &class_device_attr_period.attr &&
+           spi_support_sync(starget))
+               return TARGET_ATTRIBUTE_HELPER(period);
+       else if (attr == &class_device_attr_min_period.attr &&
+                spi_support_sync(starget))
+               return TARGET_ATTRIBUTE_HELPER(period);
+       else if (attr == &class_device_attr_offset.attr &&
+                spi_support_sync(starget))
+               return TARGET_ATTRIBUTE_HELPER(offset);
+       else if (attr == &class_device_attr_max_offset.attr &&
+                spi_support_sync(starget))
+               return TARGET_ATTRIBUTE_HELPER(offset);
+       else if (attr == &class_device_attr_width.attr &&
+                spi_support_wide(starget))
+               return TARGET_ATTRIBUTE_HELPER(width);
+       else if (attr == &class_device_attr_max_width.attr &&
+                spi_support_wide(starget))
+               return TARGET_ATTRIBUTE_HELPER(width);
+       else if (attr == &class_device_attr_iu.attr &&
+                spi_support_ius(starget))
+               return TARGET_ATTRIBUTE_HELPER(iu);
+       else if (attr == &class_device_attr_dt.attr &&
+                spi_support_dt(starget))
+               return TARGET_ATTRIBUTE_HELPER(dt);
+       else if (attr == &class_device_attr_qas.attr &&
+                spi_support_qas(starget))
+               return TARGET_ATTRIBUTE_HELPER(qas);
+       else if (attr == &class_device_attr_wr_flow.attr &&
+                spi_support_ius(starget))
+               return TARGET_ATTRIBUTE_HELPER(wr_flow);
+       else if (attr == &class_device_attr_rd_strm.attr &&
+                spi_support_ius(starget))
+               return TARGET_ATTRIBUTE_HELPER(rd_strm);
+       else if (attr == &class_device_attr_rti.attr &&
+                spi_support_ius(starget))
+               return TARGET_ATTRIBUTE_HELPER(rti);
+       else if (attr == &class_device_attr_pcomp_en.attr &&
+                spi_support_ius(starget))
+               return TARGET_ATTRIBUTE_HELPER(pcomp_en);
+       else if (attr == &class_device_attr_hold_mcs.attr &&
+                spi_support_ius(starget))
+               return TARGET_ATTRIBUTE_HELPER(hold_mcs);
+       else if (attr == &class_device_attr_revalidate.attr)
+               return 1;
+
+       return 0;
+}
+
+static struct attribute *target_attributes[] = {
+       &class_device_attr_period.attr,
+       &class_device_attr_min_period.attr,
+       &class_device_attr_offset.attr,
+       &class_device_attr_max_offset.attr,
+       &class_device_attr_width.attr,
+       &class_device_attr_max_width.attr,
+       &class_device_attr_iu.attr,
+       &class_device_attr_dt.attr,
+       &class_device_attr_qas.attr,
+       &class_device_attr_wr_flow.attr,
+       &class_device_attr_rd_strm.attr,
+       &class_device_attr_rti.attr,
+       &class_device_attr_pcomp_en.attr,
+       &class_device_attr_hold_mcs.attr,
+       &class_device_attr_revalidate.attr,
+       NULL
+};
+
+static struct attribute_group target_attribute_group = {
+       .attrs = target_attributes,
+       .is_visible = target_attribute_is_visible,
+};
+
+static int spi_target_configure(struct transport_container *tc,
+                               struct device *dev,
+                               struct class_device *cdev)
+{
+       struct kobject *kobj = &cdev->kobj;
+       int i;
+       struct attribute *attr;
+       int rc;
+
+       for (i = 0; (attr = target_attributes[i]) != NULL; i++) {
+               int j = target_attribute_group.is_visible(kobj, attr, i);
+
+               /* FIXME: as well as returning -EEXIST, which we'd like
+                * to ignore, sysfs also does a WARN_ON and dumps a trace,
+                * which is bad, so temporarily, skip attributes that are
+                * already visible (the revalidate one) */
+               if (j && attr != &class_device_attr_revalidate.attr)
+                       rc = sysfs_add_file_to_group(kobj, attr,
+                                               target_attribute_group.name);
+               /* and make the attribute writeable if we have a set
+                * function */
+               if ((j & 1))
+                       rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
+       }
+
+       return 0;
+}
+
 struct scsi_transport_template *
 spi_attach_transport(struct spi_function_template *ft)
 {
-       int count = 0;
        struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
                                         GFP_KERNEL);
 
@@ -1360,47 +1484,17 @@ spi_attach_transport(struct spi_function_template *ft)
                return NULL;
 
        i->t.target_attrs.ac.class = &spi_transport_class.class;
-       i->t.target_attrs.ac.attrs = &i->attrs[0];
+       i->t.target_attrs.ac.grp = &target_attribute_group;
        i->t.target_attrs.ac.match = spi_target_match;
        transport_container_register(&i->t.target_attrs);
        i->t.target_size = sizeof(struct spi_transport_attrs);
        i->t.host_attrs.ac.class = &spi_host_class.class;
-       i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+       i->t.host_attrs.ac.grp = &host_attribute_group;
        i->t.host_attrs.ac.match = spi_host_match;
        transport_container_register(&i->t.host_attrs);
        i->t.host_size = sizeof(struct spi_host_attrs);
        i->f = ft;
 
-       SETUP_ATTRIBUTE(period);
-       SETUP_RELATED_ATTRIBUTE(min_period, period);
-       SETUP_ATTRIBUTE(offset);
-       SETUP_RELATED_ATTRIBUTE(max_offset, offset);
-       SETUP_ATTRIBUTE(width);
-       SETUP_RELATED_ATTRIBUTE(max_width, width);
-       SETUP_ATTRIBUTE(iu);
-       SETUP_ATTRIBUTE(dt);
-       SETUP_ATTRIBUTE(qas);
-       SETUP_ATTRIBUTE(wr_flow);
-       SETUP_ATTRIBUTE(rd_strm);
-       SETUP_ATTRIBUTE(rti);
-       SETUP_ATTRIBUTE(pcomp_en);
-       SETUP_ATTRIBUTE(hold_mcs);
-
-       /* if you add an attribute but forget to increase SPI_NUM_ATTRS
-        * this bug will trigger */
-       BUG_ON(count > SPI_NUM_ATTRS);
-
-       i->attrs[count++] = &class_device_attr_revalidate;
-
-       i->attrs[count] = NULL;
-
-       count = 0;
-       SETUP_HOST_ATTRIBUTE(signalling);
-
-       BUG_ON(count > SPI_HOST_ATTRS);
-
-       i->host_attrs[count] = NULL;
-
        return &i->t;
 }
 EXPORT_SYMBOL(spi_attach_transport);
index 44a340bd937b9fb43752ccceb1427c25341f92bc..2445c98ae95e804e3c4b8e29d0fda4577cd1d7e8 100644 (file)
@@ -185,11 +185,10 @@ static int srp_host_match(struct attribute_container *cont, struct device *dev)
 
 /**
  * srp_rport_add - add a SRP remote port to the device hierarchy
- *
  * @shost:     scsi host the remote port is connected to.
  * @ids:       The port id for the remote port.
  *
- * publishes a port to the rest of the system
+ * Publishes a port to the rest of the system.
  */
 struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
                                struct srp_rport_identifiers *ids)
@@ -242,8 +241,8 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
 EXPORT_SYMBOL_GPL(srp_rport_add);
 
 /**
- * srp_rport_del  --  remove a SRP remote port
- * @port:      SRP remote port to remove
+ * srp_rport_del  -  remove a SRP remote port
+ * @rport:     SRP remote port to remove
  *
  * Removes the specified SRP remote port.
  */
@@ -265,12 +264,13 @@ EXPORT_SYMBOL_GPL(srp_rport_del);
 
 static int do_srp_rport_del(struct device *dev, void *data)
 {
-       srp_rport_del(dev_to_rport(dev));
+       if (scsi_is_srp_rport(dev))
+               srp_rport_del(dev_to_rport(dev));
        return 0;
 }
 
 /**
- * srp_remove_host  --  tear down a Scsi_Host's SRP data structures
+ * srp_remove_host  -  tear down a Scsi_Host's SRP data structures
  * @shost:     Scsi Host that is torn down
  *
  * Removes all SRP remote ports for a given Scsi_Host.
@@ -296,7 +296,7 @@ static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
 }
 
 /**
- * srp_attach_transport  --  instantiate SRP transport template
+ * srp_attach_transport  -  instantiate SRP transport template
  * @ft:                SRP transport class function template
  */
 struct scsi_transport_template *
@@ -336,7 +336,7 @@ srp_attach_transport(struct srp_function_template *ft)
 EXPORT_SYMBOL_GPL(srp_attach_transport);
 
 /**
- * srp_release_transport  --  release SRP transport template instance
+ * srp_release_transport  -  release SRP transport template instance
  * @t:         transport template instance
  */
 void srp_release_transport(struct scsi_transport_template *t)
index cd68a66c7bb3cef1d297d9fde33eadcfef967630..3f21bc65e8c66e6cbbb65d6a376de096a3cdfbee 100644 (file)
 static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
                   unsigned int *secs);
 
+/**
+ * scsi_bios_ptable - Read PC partition table out of first sector of device.
+ * @dev: from this device
+ *
+ * Description: Reads the first sector from the device and returns %0x42 bytes
+ *              starting at offset %0x1be.
+ * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error.
+ */
 unsigned char *scsi_bios_ptable(struct block_device *dev)
 {
        unsigned char *res = kmalloc(66, GFP_KERNEL);
@@ -43,15 +51,17 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
 }
 EXPORT_SYMBOL(scsi_bios_ptable);
 
-/*
- * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip)
+/**
+ * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
+ * @bdev: which device
+ * @capacity: size of the disk in sectors
+ * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
  *
- * Purpose : to determine the BIOS mapping used for a drive in a 
+ * Description : determine the BIOS mapping/geometry used for a drive in a
  *      SCSI-CAM system, storing the results in ip as required
  *      by the HDIO_GETGEO ioctl().
  *
  * Returns : -1 on failure, 0 on success.
- *
  */
 
 int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
@@ -98,15 +108,18 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
 }
 EXPORT_SYMBOL(scsicam_bios_param);
 
-/*
- * Function : static int scsi_partsize(unsigned char *buf, unsigned long 
- *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+/**
+ * scsi_partsize - Parse cylinders/heads/sectors from PC partition table
+ * @buf: partition table, see scsi_bios_ptable()
+ * @capacity: size of the disk in sectors
+ * @cyls: put cylinders here
+ * @hds: put heads here
+ * @secs: put sectors here
  *
- * Purpose : to determine the BIOS mapping used to create the partition
+ * Description: determine the BIOS mapping/geometry used to create the partition
  *      table, storing the results in *cyls, *hds, and *secs 
  *
- * Returns : -1 on failure, 0 on success.
- *
+ * Returns: -1 on failure, 0 on success.
  */
 
 int scsi_partsize(unsigned char *buf, unsigned long capacity,
@@ -194,7 +207,7 @@ EXPORT_SYMBOL(scsi_partsize);
  *
  * WORKING                                                    X3T9.2
  * DRAFT                                                        792D
- *
+ * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf
  *
  *                                                        Revision 6
  *                                                         10-MAR-94
index a69b155f39a2b2a1c4134b440e2cd5404d478e10..24eba3118b5a415e9b76c0d5a668a72fab58d303 100644 (file)
@@ -395,6 +395,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
                goto out;
        }
 
+       /*
+        * Some devices (some sdcards for one) don't like it if the
+        * last sector gets read in a larger then 1 sector read.
+        */
+       if (unlikely(sdp->last_sector_bug &&
+           rq->nr_sectors > sdp->sector_size / 512 &&
+           block + this_count == get_capacity(disk)))
+               this_count -= sdp->sector_size / 512;
+
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
                                        (unsigned long long)block));
 
@@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk)
 {
        struct scsi_disk *sdkp = scsi_disk(disk);
        struct scsi_device *sdp = sdkp->device;
+       struct scsi_sense_hdr *sshdr = NULL;
        int retval;
 
        SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
@@ -749,8 +759,11 @@ static int sd_media_changed(struct gendisk *disk)
         * can deal with it then.  It is only because of unrecoverable errors
         * that we would ever take a device offline in the first place.
         */
-       if (!scsi_device_online(sdp))
-               goto not_present;
+       if (!scsi_device_online(sdp)) {
+               set_media_not_present(sdkp);
+               retval = 1;
+               goto out;
+       }
 
        /*
         * Using TEST_UNIT_READY enables differentiation between drive with
@@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk)
         * sd_revalidate() is called.
         */
        retval = -ENODEV;
-       if (scsi_block_when_processing_errors(sdp))
-               retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
+
+       if (scsi_block_when_processing_errors(sdp)) {
+               sshdr  = kzalloc(sizeof(*sshdr), GFP_KERNEL);
+               retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
+                                             sshdr);
+       }
 
        /*
         * Unable to test, unit probably not ready.   This usually
@@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk)
         * and we will figure it out later once the drive is
         * available again.
         */
-       if (retval)
-                goto not_present;
+       if (retval || (scsi_sense_valid(sshdr) &&
+                      /* 0x3a is medium not present */
+                      sshdr->asc == 0x3a)) {
+               set_media_not_present(sdkp);
+               retval = 1;
+               goto out;
+       }
 
        /*
         * For removable scsi disk we have to recognise the presence
@@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk)
 
        retval = sdp->changed;
        sdp->changed = 0;
-
+out:
+       if (retval != sdkp->previous_state)
+               sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
+       sdkp->previous_state = retval;
+       kfree(sshdr);
        return retval;
-
-not_present:
-       set_media_not_present(sdkp);
-       return 1;
 }
 
 static int sd_sync_cache(struct scsi_disk *sdkp)
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
deleted file mode 100644 (file)
index b113244..0000000
+++ /dev/null
@@ -1,1667 +0,0 @@
-/*
- *    seagate.c Copyright (C) 1992, 1993 Drew Eckhardt
- *      low level scsi driver for ST01/ST02, Future Domain TMC-885,
- *      TMC-950 by Drew Eckhardt <drew@colorado.edu>
- *
- *      Note : TMC-880 boards don't work because they have two bits in
- *              the status register flipped, I'll fix this "RSN"
- *     [why do I have strong feeling that above message is from 1993? :-)
- *             pavel@ucw.cz]
- *
- *      This card does all the I/O via memory mapped I/O, so there is no need
- *      to check or allocate a region of the I/O address space.
- */
-
-/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt
- * macros, replaced assembler routines with C. There's probably a
- * performance hit, but I only have a cdrom and can't tell. Define
- * SEAGATE_USE_ASM if you want the old assembler code -- SJT
- *
- * 1998-jul-29 - created DPRINTK macros and made it work under 
- * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
- *
- * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
- * read the physical disk geometry, a bad mistake. Of course it doesn't
- * matter much what geometry one invents, but on large disks it
- * returned 256 (or more) heads, causing all kind of failures.
- * Of course this means that people might see a different geometry now,
- * so boot parameters may be necessary in some cases.
- */
-
-/*
- * Configuration :
- * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE
- * -DIRQ will override the default of 5.
- * Note: You can now set these options from the kernel's "command line".
- * The syntax is:
- *
- *     st0x=ADDRESS,IRQ                (for a Seagate controller)
- * or:
- *     tmc8xx=ADDRESS,IRQ              (for a TMC-8xx or TMC-950 controller)
- * eg:
- *     tmc8xx=0xC8000,15
- *
- * will configure the driver for a TMC-8xx style controller using IRQ 15
- * with a base address of 0xC8000.
- *
- * -DARBITRATE 
- *      Will cause the host adapter to arbitrate for the
- *      bus for better SCSI-II compatibility, rather than just
- *      waiting for BUS FREE and then doing its thing.  Should
- *      let us do one command per Lun when I integrate my
- *      reorganization changes into the distribution sources.
- *
- * -DDEBUG=65535
- *      Will activate debug code.
- *
- * -DFAST or -DFAST32 
- *      Will use blind transfers where possible
- *
- * -DPARITY  
- *      This will enable parity.
- *
- * -DSEAGATE_USE_ASM
- *      Will use older seagate assembly code. should be (very small amount)
- *      Faster.
- *
- * -DSLOW_RATE=50
- *      Will allow compatibility with broken devices that don't
- *      handshake fast enough (ie, some CD ROM's) for the Seagate
- *      code.
- *
- *      50 is some number, It will let you specify a default
- *      transfer rate if handshaking isn't working correctly.
- *
- * -DOLDCNTDATASCEME  There is a new sceme to set the CONTROL
- *                    and DATA reigsters which complies more closely
- *                    with the SCSI2 standard. This hopefully eliminates
- *                    the need to swap the order these registers are
- *                    'messed' with. It makes the following two options
- *                    obsolete. To reenable the old sceme define this.
- *
- * The following to options are patches from the SCSI.HOWTO
- *
- * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
- *
- * -DSWAPCNTDATA  This will swap the order that seagate.c messes with
- *                the CONTROL an DATA registers.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/signal.h>
-#include <linux/string.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi.h>
-
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_host.h>
-
-
-#ifdef DEBUG
-#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
-#else
-#define DPRINTK( when, msg... ) do { } while (0)
-#define DEBUG 0
-#endif
-#define DANY( msg... ) DPRINTK( 0xffff, msg );
-
-#ifndef IRQ
-#define IRQ 5
-#endif
-
-#ifdef FAST32
-#define FAST
-#endif
-
-#undef LINKED                  /* Linked commands are currently broken! */
-
-#if defined(OVERRIDE) && !defined(CONTROLLER)
-#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type
-#endif
-
-#ifndef __i386__
-#undef SEAGATE_USE_ASM
-#endif
-
-/*
-       Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
-               driver, and Mitsugu Suzuki for information on the ST-01
-               SCSI host.
-*/
-
-/*
-       CONTROL defines
-*/
-
-#define CMD_RST                0x01
-#define CMD_SEL                0x02
-#define CMD_BSY                0x04
-#define CMD_ATTN               0x08
-#define CMD_START_ARB          0x10
-#define CMD_EN_PARITY          0x20
-#define CMD_INTR               0x40
-#define CMD_DRVR_ENABLE                0x80
-
-/*
-       STATUS
-*/
-#ifdef SWAPSTAT
-#define STAT_MSG               0x08
-#define STAT_CD                        0x02
-#else
-#define STAT_MSG               0x02
-#define STAT_CD                        0x08
-#endif
-
-#define STAT_BSY               0x01
-#define STAT_IO                        0x04
-#define STAT_REQ               0x10
-#define STAT_SEL               0x20
-#define STAT_PARITY            0x40
-#define STAT_ARB_CMPL          0x80
-
-/* 
-       REQUESTS
-*/
-
-#define REQ_MASK (STAT_CD |  STAT_IO | STAT_MSG)
-#define REQ_DATAOUT 0
-#define REQ_DATAIN STAT_IO
-#define REQ_CMDOUT STAT_CD
-#define REQ_STATIN (STAT_CD | STAT_IO)
-#define REQ_MSGOUT (STAT_MSG | STAT_CD)
-#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
-
-extern volatile int seagate_st0x_timeout;
-
-#ifdef PARITY
-#define BASE_CMD CMD_EN_PARITY
-#else
-#define BASE_CMD  0
-#endif
-
-/*
-       Debugging code
-*/
-
-#define PHASE_BUS_FREE 1
-#define PHASE_ARBITRATION 2
-#define PHASE_SELECTION 4
-#define PHASE_DATAIN 8
-#define PHASE_DATAOUT 0x10
-#define PHASE_CMDOUT 0x20
-#define PHASE_MSGIN 0x40
-#define PHASE_MSGOUT 0x80
-#define PHASE_STATUSIN 0x100
-#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
-#define PRINT_COMMAND 0x200
-#define PHASE_EXIT 0x400
-#define PHASE_RESELECT 0x800
-#define DEBUG_FAST 0x1000
-#define DEBUG_SG   0x2000
-#define DEBUG_LINKED   0x4000
-#define DEBUG_BORKEN   0x8000
-
-/* 
- *     Control options - these are timeouts specified in .01 seconds.
- */
-
-/* 30, 20 work */
-#define ST0X_BUS_FREE_DELAY 25
-#define ST0X_SELECTION_DELAY 25
-
-#define SEAGATE 1              /* these determine the type of the controller */
-#define FD     2
-
-#define ST0X_ID_STR    "Seagate ST-01/ST-02"
-#define FD_ID_STR      "TMC-8XX/TMC-950"
-
-static int internal_command (unsigned char target, unsigned char lun,
-                            const void *cmnd,
-                            void *buff, int bufflen, int reselect);
-
-static int incommand;          /* set if arbitration has finished
-                                  and we are in some command phase. */
-
-static unsigned int base_address = 0;  /* Where the card ROM starts, used to 
-                                          calculate memory mapped register
-                                          location.  */
-
-static void __iomem *st0x_cr_sr;       /* control register write, status
-                                          register read.  256 bytes in
-                                          length.
-                                          Read is status of SCSI BUS, as per 
-                                          STAT masks.  */
-
-static void __iomem *st0x_dr;  /* data register, read write 256
-                                  bytes in length.  */
-
-static volatile int st0x_aborted = 0;  /* set when we are aborted, ie by a
-                                          time out, etc.  */
-
-static unsigned char controller_type = 0;      /* set to SEAGATE for ST0x
-                                                  boards or FD for TMC-8xx
-                                                  boards */
-static int irq = IRQ;
-
-module_param(base_address, uint, 0);
-module_param(controller_type, byte, 0);
-module_param(irq, int, 0);
-MODULE_LICENSE("GPL");
-
-
-#define retcode(result) (((result) << 16) | (message << 8) | status)
-#define STATUS ((u8) readb(st0x_cr_sr))
-#define DATA ((u8) readb(st0x_dr))
-#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); }
-#define WRITE_DATA(d) { writeb((d), st0x_dr); }
-
-#ifndef OVERRIDE
-static unsigned int seagate_bases[] = {
-       0xc8000, 0xca000, 0xcc000,
-       0xce000, 0xdc000, 0xde000
-};
-
-typedef struct {
-       const unsigned char *signature;
-       unsigned offset;
-       unsigned length;
-       unsigned char type;
-} Signature;
-
-static Signature __initdata signatures[] = {
-       {"ST01 v1.7  (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
-       {"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
-
-/*
- * The following two lines are NOT mistakes.  One detects ROM revision
- * 3.0.0, the other 3.2.  Since seagate has only one type of SCSI adapter,
- * and this is not going to change, the "SEAGATE" and "SCSI" together
- * are probably "good enough"
- */
-
-       {"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
-       {"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
-
-/*
- * However, future domain makes several incompatible SCSI boards, so specific
- * signatures must be used.
- */
-
-       {"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},
-       {"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
-       {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD},
-       {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD},
-       {"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
-       {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
-       {"IBM F1 BIOS V1.1004/30/92", 5, 25, FD},
-       {"FUTURE DOMAIN TMC-950", 5, 21, FD},
-       /* Added for 2.2.16 by Matthias_Heidbrink@b.maus.de */
-       {"IBM F1 V1.2009/22/93", 5, 25, FD},
-};
-
-#define NUM_SIGNATURES ARRAY_SIZE(signatures)
-#endif                         /* n OVERRIDE */
-
-/*
- * hostno stores the hostnumber, as told to us by the init routine.
- */
-
-static int hostno = -1;
-static void seagate_reconnect_intr (int, void *);
-static irqreturn_t do_seagate_reconnect_intr (int, void *);
-static int seagate_st0x_bus_reset(struct scsi_cmnd *);
-
-#ifdef FAST
-static int fast = 1;
-#else
-#define fast 0
-#endif
-
-#ifdef SLOW_RATE
-/*
- * Support for broken devices :
- * The Seagate board has a handshaking problem.  Namely, a lack
- * thereof for slow devices.  You can blast 600K/second through
- * it if you are polling for each byte, more if you do a blind
- * transfer.  In the first case, with a fast device, REQ will
- * transition high-low or high-low-high before your loop restarts
- * and you'll have no problems.  In the second case, the board
- * will insert wait states for up to 13.2 usecs for REQ to
- * transition low->high, and everything will work.
- *
- * However, there's nothing in the state machine that says
- * you *HAVE* to see a high-low-high set of transitions before
- * sending the next byte, and slow things like the Trantor CD ROMS
- * will break because of this.
- *
- * So, we need to slow things down, which isn't as simple as it
- * seems.  We can't slow things down period, because then people
- * who don't recompile their kernels will shoot me for ruining
- * their performance.  We need to do it on a case per case basis.
- *
- * The best for performance will be to, only for borken devices
- * (this is stored on a per-target basis in the scsi_devices array)
- *
- * Wait for a low->high transition before continuing with that
- * transfer.  If we timeout, continue anyways.  We don't need
- * a long timeout, because REQ should only be asserted until the
- * corresponding ACK is received and processed.
- *
- * Note that we can't use the system timer for this, because of
- * resolution, and we *really* can't use the timer chip since
- * gettimeofday() and the beeper routines use that.  So,
- * the best thing for us to do will be to calibrate a timing
- * loop in the initialization code using the timer chip before
- * gettimeofday() can screw with it.
- *
- * FIXME: this is broken (not borken :-). Empty loop costs less than
- * loop with ISA access in it! -- pavel@ucw.cz
- */
-
-static int borken_calibration = 0;
-
-static void __init borken_init (void)
-{
-       register int count = 0, start = jiffies + 1, stop = start + 25;
-
-       /* FIXME: There may be a better approach, this is a straight port for
-          now */
-       preempt_disable();
-       while (time_before (jiffies, start))
-               cpu_relax();
-       for (; time_before (jiffies, stop); ++count)
-               cpu_relax();
-       preempt_enable();
-
-/*
- * Ok, we now have a count for .25 seconds.  Convert to a
- * count per second and divide by transfer rate in K.  */
-
-       borken_calibration = (count * 4) / (SLOW_RATE * 1024);
-
-       if (borken_calibration < 1)
-               borken_calibration = 1;
-}
-
-static inline void borken_wait (void)
-{
-       register int count;
-
-       for (count = borken_calibration; count && (STATUS & STAT_REQ); --count)
-               cpu_relax();
-               
-#if (DEBUG & DEBUG_BORKEN)
-       if (count)
-               printk ("scsi%d : borken timeout\n", hostno);
-#endif
-}
-
-#endif                         /* def SLOW_RATE */
-
-/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP()
- * contains at least one ISA access, which takes more than 0.125
- * usec. So if we loop 8 times time in usec, we are safe.
- */
-
-#define ULOOP( i ) for (clock = i*8;;)
-#define TIMEOUT (!(clock--))
-
-static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
-{
-       struct Scsi_Host *instance;
-       int i, j;
-       unsigned long cr, dr;
-
-       tpnt->proc_name = "seagate";
-/*
- *     First, we try for the manual override.
- */
-       DANY ("Autodetecting ST0x / TMC-8xx\n");
-
-       if (hostno != -1) {
-               printk (KERN_ERR "seagate_st0x_detect() called twice?!\n");
-               return 0;
-       }
-
-/* If the user specified the controller type from the command line,
-   controller_type will be non-zero, so don't try to detect one */
-
-       if (!controller_type) {
-#ifdef OVERRIDE
-               base_address = OVERRIDE;
-               controller_type = CONTROLLER;
-
-               DANY ("Base address overridden to %x, controller type is %s\n",
-                     base_address,
-                     controller_type == SEAGATE ? "SEAGATE" : "FD");
-#else                          /* OVERRIDE */
-/*
- *     To detect this card, we simply look for the signature
- *      from the BIOS version notice in all the possible locations
- *      of the ROM's.  This has a nice side effect of not trashing
- *      any register locations that might be used by something else.
- *
- * XXX - note that we probably should be probing the address
- * space for the on-board RAM instead.
- */
-
-               for (i = 0; i < ARRAY_SIZE(seagate_bases); ++i) {
-                       void __iomem *p = ioremap(seagate_bases[i], 0x2000);
-                       if (!p)
-                               continue;
-                       for (j = 0; j < NUM_SIGNATURES; ++j)
-                               if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) {
-                                       base_address = seagate_bases[i];
-                                       controller_type = signatures[j].type;
-                                       break;
-                               }
-                       iounmap(p);
-               }
-#endif                         /* OVERRIDE */
-       }
-       /* (! controller_type) */
-       tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;
-       tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
-
-       if (!base_address) {
-               printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n");
-               return 0;
-       }
-
-       cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
-       dr = cr + 0x200;
-       st0x_cr_sr = ioremap(cr, 0x100);
-       st0x_dr = ioremap(dr, 0x100);
-
-       DANY("%s detected. Base address = %x, cr = %x, dr = %x\n",
-             tpnt->name, base_address, cr, dr);
-
-       /*
-        *      At all times, we will use IRQ 5.  Should also check for IRQ3
-        *      if we lose our first interrupt.
-        */
-       instance = scsi_register (tpnt, 0);
-       if (instance == NULL)
-               return 0;
-
-       hostno = instance->host_no;
-       if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
-               printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
-               return 0;
-       }
-       instance->irq = irq;
-       instance->io_port = base_address;
-#ifdef SLOW_RATE
-       printk(KERN_INFO "Calibrating borken timer... ");
-       borken_init();
-       printk(" %d cycles per transfer\n", borken_calibration);
-#endif
-       printk (KERN_INFO "This is one second... ");
-       {
-               int clock;
-               ULOOP (1 * 1000 * 1000) {
-                       STATUS;
-                       if (TIMEOUT)
-                               break;
-               }
-       }
-
-       printk ("done, %s options:"
-#ifdef ARBITRATE
-               " ARBITRATE"
-#endif
-#if DEBUG
-               " DEBUG"
-#endif
-#ifdef FAST
-               " FAST"
-#ifdef FAST32
-               "32"
-#endif
-#endif
-#ifdef LINKED
-               " LINKED"
-#endif
-#ifdef PARITY
-               " PARITY"
-#endif
-#ifdef SEAGATE_USE_ASM
-               " SEAGATE_USE_ASM"
-#endif
-#ifdef SLOW_RATE
-               " SLOW_RATE"
-#endif
-#ifdef SWAPSTAT
-               " SWAPSTAT"
-#endif
-#ifdef SWAPCNTDATA
-               " SWAPCNTDATA"
-#endif
-               "\n", tpnt->name);
-       return 1;
-}
-
-static const char *seagate_st0x_info (struct Scsi_Host *shpnt)
-{
-       static char buffer[64];
-
-       snprintf(buffer, 64, "%s at irq %d, address 0x%05X",
-                (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
-                irq, base_address);
-       return buffer;
-}
-
-/*
- * These are our saved pointers for the outstanding command that is
- * waiting for a reconnect
- */
-
-static unsigned char current_target, current_lun;
-static unsigned char *current_cmnd, *current_data;
-static int current_nobuffs;
-static struct scatterlist *current_buffer;
-static int current_bufflen;
-
-#ifdef LINKED
-/*
- * linked_connected indicates whether or not we are currently connected to
- * linked_target, linked_lun and in an INFORMATION TRANSFER phase,
- * using linked commands.
- */
-
-static int linked_connected = 0;
-static unsigned char linked_target, linked_lun;
-#endif
-
-static void (*done_fn) (struct scsi_cmnd *) = NULL;
-static struct scsi_cmnd *SCint = NULL;
-
-/*
- * These control whether or not disconnect / reconnect will be attempted,
- * or are being attempted.
- */
-
-#define NO_RECONNECT    0
-#define RECONNECT_NOW   1
-#define CAN_RECONNECT   2
-
-/*
- * LINKED_RIGHT indicates that we are currently connected to the correct target
- * for this command, LINKED_WRONG indicates that we are connected to the wrong
- * target. Note that these imply CAN_RECONNECT and require defined(LINKED).
- */
-
-#define LINKED_RIGHT    3
-#define LINKED_WRONG    4
-
-/*
- * This determines if we are expecting to reconnect or not.
- */
-
-static int should_reconnect = 0;
-
-/*
- * The seagate_reconnect_intr routine is called when a target reselects the
- * host adapter.  This occurs on the interrupt triggered by the target
- * asserting SEL.
- */
-
-static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
-{
-       unsigned long flags;
-       struct Scsi_Host *dev = dev_id;
-       
-       spin_lock_irqsave (dev->host_lock, flags);
-       seagate_reconnect_intr (irq, dev_id);
-       spin_unlock_irqrestore (dev->host_lock, flags);
-       return IRQ_HANDLED;
-}
-
-static void seagate_reconnect_intr (int irq, void *dev_id)
-{
-       int temp;
-       struct scsi_cmnd *SCtmp;
-
-       DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
-
-       if (!should_reconnect)
-               printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno);
-       else {
-               should_reconnect = 0;
-
-               DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", 
-                       hostno, current_target, current_data, current_bufflen);
-
-               temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW);
-
-               if (msg_byte(temp) != DISCONNECT) {
-                       if (done_fn) {
-                               DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);
-                               if (!SCint)
-                                       panic ("SCint == NULL in seagate");
-                               SCtmp = SCint;
-                               SCint = NULL;
-                               SCtmp->result = temp;
-                               done_fn(SCtmp);
-                       } else
-                               printk(KERN_ERR "done_fn() not defined.\n");
-               }
-       }
-}
-
-/*
- * The seagate_st0x_queue_command() function provides a queued interface
- * to the seagate SCSI driver.  Basically, it just passes control onto the
- * seagate_command() function, after fixing it so that the done_fn()
- * is set to the one passed to the function.  We have to be very careful,
- * because there are some commands on some devices that do not disconnect,
- * and if we simply call the done_fn when the command is done then another
- * command is started and queue_command is called again...  We end up
- * overflowing the kernel stack, and this tends not to be such a good idea.
- */
-
-static int recursion_depth = 0;
-
-static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
-                                     void (*done) (struct scsi_cmnd *))
-{
-       int result, reconnect;
-       struct scsi_cmnd *SCtmp;
-
-       DANY ("seagate: que_command");
-       done_fn = done;
-       current_target = SCpnt->device->id;
-       current_lun = SCpnt->device->lun;
-       current_cmnd = SCpnt->cmnd;
-       current_data = (unsigned char *) SCpnt->request_buffer;
-       current_bufflen = SCpnt->request_bufflen;
-       SCint = SCpnt;
-       if (recursion_depth)
-               return 1;
-       recursion_depth++;
-       do {
-#ifdef LINKED
-               /*
-                * Set linked command bit in control field of SCSI command.
-                */
-
-               current_cmnd[SCpnt->cmd_len] |= 0x01;
-               if (linked_connected) {
-                       DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno);
-                       if (linked_target == current_target && linked_lun == current_lun) 
-                       {
-                               DPRINTK(DEBUG_LINKED, "correct\n");
-                               reconnect = LINKED_RIGHT;
-                       } else {
-                               DPRINTK(DEBUG_LINKED, "incorrect\n");
-                               reconnect = LINKED_WRONG;
-                       }
-               } else
-#endif                         /* LINKED */
-                       reconnect = CAN_RECONNECT;
-
-               result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd,
-                                     SCint->request_buffer, SCint->request_bufflen, reconnect);
-               if (msg_byte(result) == DISCONNECT)
-                       break;
-               SCtmp = SCint;
-               SCint = NULL;
-               SCtmp->result = result;
-               done_fn(SCtmp);
-       }
-       while (SCint);
-       recursion_depth--;
-       return 0;
-}
-
-static int internal_command (unsigned char target, unsigned char lun,
-                 const void *cmnd, void *buff, int bufflen, int reselect)
-{
-       unsigned char *data = NULL;
-       struct scatterlist *buffer = NULL;
-       int clock, temp, nobuffs = 0, done = 0, len = 0;
-#if DEBUG
-       int transfered = 0, phase = 0, newphase;
-#endif
-       register unsigned char status_read;
-       unsigned char tmp_data, tmp_control, status = 0, message = 0;
-       unsigned transfersize = 0, underflow = 0;
-#ifdef SLOW_RATE
-       int borken = (int) SCint->device->borken;       /* Does the current target require
-                                                          Very Slow I/O ?  */
-#endif
-
-       incommand = 0;
-       st0x_aborted = 0;
-
-#if (DEBUG & PRINT_COMMAND)
-       printk("scsi%d : target = %d, command = ", hostno, target);
-       __scsi_print_command((unsigned char *) cmnd);
-#endif
-
-#if (DEBUG & PHASE_RESELECT)
-       switch (reselect) {
-       case RECONNECT_NOW:
-               printk("scsi%d : reconnecting\n", hostno);
-               break;
-#ifdef LINKED
-       case LINKED_RIGHT:
-               printk("scsi%d : connected, can reconnect\n", hostno);
-               break;
-       case LINKED_WRONG:
-               printk("scsi%d : connected to wrong target, can reconnect\n",
-                       hostno);
-               break;
-#endif
-       case CAN_RECONNECT:
-               printk("scsi%d : allowed to reconnect\n", hostno);
-               break;
-       default:
-               printk("scsi%d : not allowed to reconnect\n", hostno);
-       }
-#endif
-
-       if (target == (controller_type == SEAGATE ? 7 : 6))
-               return DID_BAD_TARGET;
-
-       /*
-        *      We work it differently depending on if this is is "the first time,"
-        *      or a reconnect.  If this is a reselect phase, then SEL will
-        *      be asserted, and we must skip selection / arbitration phases.
-        */
-
-       switch (reselect) {
-       case RECONNECT_NOW:
-               DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);
-               /*
-                *      At this point, we should find the logical or of our ID
-                *      and the original target's ID on the BUS, with BSY, SEL,
-                *      and I/O signals asserted.
-                *
-                *      After ARBITRATION phase is completed, only SEL, BSY,
-                *      and the target ID are asserted.  A valid initiator ID
-                *      is not on the bus until IO is asserted, so we must wait
-                *      for that.
-                */
-               ULOOP (100 * 1000) {
-                       temp = STATUS;
-                       if ((temp & STAT_IO) && !(temp & STAT_BSY))
-                               break;
-                       if (TIMEOUT) {
-                               DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);
-                               return (DID_BAD_INTR << 16);
-                       }
-               }
-
-               /*
-                *      After I/O is asserted by the target, we can read our ID
-                *      and its ID off of the BUS.
-                */
-
-               if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
-                       DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp);
-                       return (DID_BAD_INTR << 16);
-               }
-
-               if (!(temp & (1 << current_target))) {
-                       printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt.  Data bus = %d\n", hostno, temp);
-                       return (DID_BAD_INTR << 16);
-               }
-
-               buffer = current_buffer;
-               cmnd = current_cmnd;    /* WDE add */
-               data = current_data;    /* WDE add */
-               len = current_bufflen;  /* WDE add */
-               nobuffs = current_nobuffs;
-
-               /*
-                *      We have determined that we have been selected.  At this
-                *      point, we must respond to the reselection by asserting
-                *      BSY ourselves
-                */
-
-#if 1
-               WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
-#else
-               WRITE_CONTROL (BASE_CMD | CMD_BSY);
-#endif
-
-               /*
-                *      The target will drop SEL, and raise BSY, at which time
-                *      we must drop BSY.
-                */
-
-               ULOOP (100 * 1000) {
-                       if (!(STATUS & STAT_SEL))
-                               break;
-                       if (TIMEOUT) {
-                               WRITE_CONTROL (BASE_CMD | CMD_INTR);
-                               DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);
-                               return (DID_BAD_INTR << 16);
-                       }
-               }
-               WRITE_CONTROL (BASE_CMD);
-               /*
-                *      At this point, we have connected with the target
-                *      and can get on with our lives.
-                */
-               break;
-       case CAN_RECONNECT:
-#ifdef LINKED
-               /*
-                * This is a bletcherous hack, just as bad as the Unix #!
-                * interpreter stuff. If it turns out we are using the wrong
-                * I_T_L nexus, the easiest way to deal with it is to go into
-                *  our INFORMATION TRANSFER PHASE code, send a ABORT
-                * message on MESSAGE OUT phase, and then loop back to here.
-                */
-connect_loop:
-#endif
-               DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);
-
-               /*
-                *    BUS FREE PHASE
-                *
-                *      On entry, we make sure that the BUS is in a BUS FREE
-                *      phase, by insuring that both BSY and SEL are low for
-                *      at least one bus settle delay.  Several reads help
-                *      eliminate wire glitch.
-                */
-
-#ifndef ARBITRATE
-#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.
-               clock = jiffies + ST0X_BUS_FREE_DELAY;
-
-               while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock))
-                       cpu_relax();
-
-               if (time_after (jiffies, clock))
-                       return retcode (DID_BUS_BUSY);
-               else if (st0x_aborted)
-                       return retcode (st0x_aborted);
-#endif
-               DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno);
-
-               clock = jiffies + ST0X_SELECTION_DELAY;
-
-               /*
-                * Arbitration/selection procedure :
-                * 1.  Disable drivers
-                * 2.  Write HOST adapter address bit
-                * 3.  Set start arbitration.
-                * 4.  We get either ARBITRATION COMPLETE or SELECT at this
-                *     point.
-                * 5.  OR our ID and targets on bus.
-                * 6.  Enable SCSI drivers and asserted SEL and ATTN
-                */
-
-#ifdef ARBITRATE
-               /* FIXME: verify host lock is always held here */
-               WRITE_CONTROL(0);
-               WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40);
-               WRITE_CONTROL(CMD_START_ARB);
-
-               ULOOP (ST0X_SELECTION_DELAY * 10000) {
-                       status_read = STATUS;
-                       if (status_read & STAT_ARB_CMPL)
-                               break;
-                       if (st0x_aborted)       /* FIXME: What? We are going to do something even after abort? */
-                               break;
-                       if (TIMEOUT || (status_read & STAT_SEL)) {
-                               printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno);
-                               WRITE_CONTROL (BASE_CMD);
-                               return retcode (DID_NO_CONNECT);
-                       }
-               }
-               DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);
-#endif
-
-               /*
-                *    When the SCSI device decides that we're gawking at it, 
-                *    it will respond by asserting BUSY on the bus.
-                *
-                *    Note : the Seagate ST-01/02 product manual says that we
-                *    should twiddle the DATA register before the control
-                *    register. However, this does not work reliably so we do
-                *    it the other way around.
-                *
-                *    Probably could be a problem with arbitration too, we
-                *    really should try this with a SCSI protocol or logic 
-                *    analyzer to see what is going on.
-                */
-               tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
-               tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0);
-
-               /* FIXME: verify host lock is always held here */
-#ifdef OLDCNTDATASCEME
-#ifdef SWAPCNTDATA
-               WRITE_CONTROL (tmp_control);
-               WRITE_DATA (tmp_data);
-#else
-               WRITE_DATA (tmp_data);
-               WRITE_CONTROL (tmp_control);
-#endif
-#else
-               tmp_control ^= CMD_BSY; /* This is guesswork. What used to be in driver    */
-               WRITE_CONTROL (tmp_control);    /* could never work: it sent data into control     */
-               WRITE_DATA (tmp_data);  /* register and control info into data. Hopefully  */
-               tmp_control ^= CMD_BSY; /* fixed, but order of first two may be wrong.     */
-               WRITE_CONTROL (tmp_control);    /* -- pavel@ucw.cz   */
-#endif
-
-               ULOOP (250 * 1000) {
-                       if (st0x_aborted) {
-                               /*
-                                *      If we have been aborted, and we have a
-                                *      command in progress, IE the target 
-                                *      still has BSY asserted, then we will
-                                *      reset the bus, and notify the midlevel
-                                *      driver to expect sense.
-                                */
-
-                               WRITE_CONTROL (BASE_CMD);
-                               if (STATUS & STAT_BSY) {
-                                       printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno);
-                                       seagate_st0x_bus_reset(NULL);
-                                       return retcode (DID_RESET);
-                               }
-                               return retcode (st0x_aborted);
-                       }
-                       if (STATUS & STAT_BSY)
-                               break;
-                       if (TIMEOUT) {
-                               DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS);
-                               return retcode (DID_NO_CONNECT);
-                       }
-               }
-
-               /* Establish current pointers.  Take into account scatter / gather */
-
-               if ((nobuffs = SCint->use_sg)) {
-#if (DEBUG & DEBUG_SG)
-                       {
-                               int i;
-                               printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs);
-                               for (i = 0; i < nobuffs; ++i)
-                                       printk("scsi%d : buffer %d address = %p length = %d\n",
-                                            hostno, i,
-                                            sg_virt(&buffer[i]),
-                                            buffer[i].length);
-                       }
-#endif
-
-                       buffer = (struct scatterlist *) SCint->request_buffer;
-                       len = buffer->length;
-                       data = sg_virt(buffer);
-               } else {
-                       DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
-                       buffer = NULL;
-                       len = SCint->request_bufflen;
-                       data = (unsigned char *) SCint->request_buffer;
-               }
-
-               DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n",
-                        hostno, len);
-
-               break;
-#ifdef LINKED
-       case LINKED_RIGHT:
-               break;
-       case LINKED_WRONG:
-               break;
-#endif
-       }                       /* end of switch(reselect) */
-
-       /*
-        *    There are several conditions under which we wish to send a message :
-        *      1.  When we are allowing disconnect / reconnect, and need to
-        *      establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit
-        *      set.
-        *
-        *      2.  When we are doing linked commands, are have the wrong I_T_L
-        *      nexus established and want to send an ABORT message.
-        */
-
-       /* GCC does not like an ifdef inside a macro, so do it the hard way. */
-#ifdef LINKED
-       WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0));
-#else
-       WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0));
-#endif
-
-       /*
-        *    INFORMATION TRANSFER PHASE
-        *
-        *      The nasty looking read / write inline assembler loops we use for
-        *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
-        *      the 'C' versions - since we're moving 1024 bytes of data, this
-        *      really adds up.
-        *
-        *      SJT: The nasty-looking assembler is gone, so it's slower.
-        *
-        */
-
-       DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno);
-
-       incommand = 1;
-       transfersize = SCint->transfersize;
-       underflow = SCint->underflow;
-
-       /*
-        *      Now, we poll the device for status information,
-        *      and handle any requests it makes.  Note that since we are unsure
-        *      of how much data will be flowing across the system, etc and
-        *      cannot make reasonable timeouts, that we will instead have the
-        *      midlevel driver handle any timeouts that occur in this phase.
-        */
-
-       while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) {
-#ifdef PARITY
-               if (status_read & STAT_PARITY) {
-                       printk(KERN_ERR "scsi%d : got parity error\n", hostno);
-                       st0x_aborted = DID_PARITY;
-               }
-#endif
-               if (status_read & STAT_REQ) {
-#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
-                       if ((newphase = (status_read & REQ_MASK)) != phase) {
-                               phase = newphase;
-                               switch (phase) {
-                               case REQ_DATAOUT:
-                                       printk ("scsi%d : phase = DATA OUT\n", hostno);
-                                       break;
-                               case REQ_DATAIN:
-                                       printk ("scsi%d : phase = DATA IN\n", hostno);
-                                       break;
-                               case REQ_CMDOUT:
-                                       printk
-                                           ("scsi%d : phase = COMMAND OUT\n", hostno);
-                                       break;
-                               case REQ_STATIN:
-                                       printk ("scsi%d : phase = STATUS IN\n", hostno);
-                                       break;
-                               case REQ_MSGOUT:
-                                       printk
-                                           ("scsi%d : phase = MESSAGE OUT\n", hostno);
-                                       break;
-                               case REQ_MSGIN:
-                                       printk ("scsi%d : phase = MESSAGE IN\n", hostno);
-                                       break;
-                               default:
-                                       printk ("scsi%d : phase = UNKNOWN\n", hostno);
-                                       st0x_aborted = DID_ERROR;
-                               }
-                       }
-#endif
-                       switch (status_read & REQ_MASK) {
-                       case REQ_DATAOUT:
-                               /*
-                                * If we are in fast mode, then we simply splat
-                                * the data out in word-sized chunks as fast as
-                                * we can.
-                                */
-
-                               if (!len) {
-#if 0
-                                       printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun);
-                                       st0x_aborted = DID_ERROR;
-                                       fast = 0;
-#endif
-                                       break;
-                               }
-
-                               if (fast && transfersize
-                                   && !(len % transfersize)
-                                   && (len >= transfersize)
-#ifdef FAST32
-                                   && !(transfersize % 4)
-#endif
-                                   ) {
-                                       DPRINTK (DEBUG_FAST,
-                                                "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
-                                                "         len = %d, data = %08x\n",
-                                                hostno, SCint->underflow,
-                                                SCint->transfersize, len,
-                                                data);
-
-                       /* SJT: Start. Fast Write */
-#ifdef SEAGATE_USE_ASM
-                                       __asm__ ("cld\n\t"
-#ifdef FAST32
-                                                "shr $2, %%ecx\n\t"
-                                                "1:\t"
-                                                "lodsl\n\t"
-                                                "movl %%eax, (%%edi)\n\t"
-#else
-                                                "1:\t"
-                                                "lodsb\n\t"
-                                                "movb %%al, (%%edi)\n\t"
-#endif
-                                                "loop 1b;"
-                                     /* output */ :
-                                     /* input */ :"D" (st0x_dr),
-                                                "S"
-                                                (data),
-                                                "c" (SCint->transfersize)
-/* clobbered */
-                                     :  "eax", "ecx",
-                                                "esi");
-#else                          /* SEAGATE_USE_ASM */
-                                       memcpy_toio(st0x_dr, data, transfersize);
-#endif                         /* SEAGATE_USE_ASM */
-/* SJT: End */
-                                       len -= transfersize;
-                                       data += transfersize;
-                                       DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
-                               } else {
-                                       /*
-                                        *    We loop as long as we are in a 
-                                        *    data out phase, there is data to
-                                        *    send, and BSY is still active.
-                                        */
-
-/* SJT: Start. Slow Write. */
-#ifdef SEAGATE_USE_ASM
-
-                                       int __dummy_1, __dummy_2;
-
-/*
- *      We loop as long as we are in a data out phase, there is data to send, 
- *      and BSY is still active.
- */
-/* Local variables : len = ecx , data = esi, 
-                     st0x_cr_sr = ebx, st0x_dr =  edi
-*/
-                                       __asm__ (
-                                                       /* Test for any data here at all. */
-                                                       "orl %%ecx, %%ecx\n\t"
-                                                       "jz 2f\n\t" "cld\n\t"
-/*                    "movl st0x_cr_sr, %%ebx\n\t"  */
-/*                    "movl st0x_dr, %%edi\n\t"  */
-                                                       "1:\t"
-                                                       "movb (%%ebx), %%al\n\t"
-                                                       /* Test for BSY */
-                                                       "test $1, %%al\n\t"
-                                                       "jz 2f\n\t"
-                                                       /* Test for data out phase - STATUS & REQ_MASK should be 
-                                                          REQ_DATAOUT, which is 0. */
-                                                       "test $0xe, %%al\n\t"
-                                                       "jnz 2f\n\t"
-                                                       /* Test for REQ */
-                                                       "test $0x10, %%al\n\t"
-                                                       "jz 1b\n\t"
-                                                       "lodsb\n\t"
-                                                       "movb %%al, (%%edi)\n\t"
-                                                       "loop 1b\n\t" "2:\n"
-                                     /* output */ :"=S" (data), "=c" (len),
-                                                       "=b"
-                                                       (__dummy_1),
-                                                       "=D" (__dummy_2)
-/* input */
-                                     :         "0" (data), "1" (len),
-                                                       "2" (st0x_cr_sr),
-                                                       "3" (st0x_dr)
-/* clobbered */
-                                     :         "eax");
-#else                          /* SEAGATE_USE_ASM */
-                                       while (len) {
-                                               unsigned char stat;
-
-                                               stat = STATUS;
-                                               if (!(stat & STAT_BSY)
-                                                   || ((stat & REQ_MASK) !=
-                                                       REQ_DATAOUT))
-                                                       break;
-                                               if (stat & STAT_REQ) {
-                                                       WRITE_DATA (*data++);
-                                                       --len;
-                                               }
-                                       }
-#endif                         /* SEAGATE_USE_ASM */
-/* SJT: End. */
-                               }
-
-                               if (!len && nobuffs) {
-                                       --nobuffs;
-                                       ++buffer;
-                                       len = buffer->length;
-                                       data = sg_virt(buffer);
-                                       DPRINTK (DEBUG_SG,
-                                                "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
-                                                hostno, len, data);
-                               }
-                               break;
-
-                       case REQ_DATAIN:
-#ifdef SLOW_RATE
-                               if (borken) {
-#if (DEBUG & (PHASE_DATAIN))
-                                       transfered += len;
-#endif
-                                       for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) {
-                                               *data++ = DATA;
-                                               borken_wait();
-                                       }
-#if (DEBUG & (PHASE_DATAIN))
-                                       transfered -= len;
-#endif
-                               } else
-#endif
-
-                                       if (fast && transfersize
-                                           && !(len % transfersize)
-                                           && (len >= transfersize)
-#ifdef FAST32
-                                           && !(transfersize % 4)
-#endif
-                                   ) {
-                                       DPRINTK (DEBUG_FAST,
-                                                "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
-                                                "         len = %d, data = %08x\n",
-                                                hostno, SCint->underflow,
-                                                SCint->transfersize, len,
-                                                data);
-
-/* SJT: Start. Fast Read */
-#ifdef SEAGATE_USE_ASM
-                                       __asm__ ("cld\n\t"
-#ifdef FAST32
-                                                "shr $2, %%ecx\n\t"
-                                                "1:\t"
-                                                "movl (%%esi), %%eax\n\t"
-                                                "stosl\n\t"
-#else
-                                                "1:\t"
-                                                "movb (%%esi), %%al\n\t"
-                                                "stosb\n\t"
-#endif
-                                                "loop 1b\n\t"
-                                     /* output */ :
-                                     /* input */ :"S" (st0x_dr),
-                                                "D"
-                                                (data),
-                                                "c" (SCint->transfersize)
-/* clobbered */
-                                     :  "eax", "ecx",
-                                                "edi");
-#else                          /* SEAGATE_USE_ASM */
-                                       memcpy_fromio(data, st0x_dr, len);
-#endif                         /* SEAGATE_USE_ASM */
-/* SJT: End */
-                                       len -= transfersize;
-                                       data += transfersize;
-#if (DEBUG & PHASE_DATAIN)
-                                       printk ("scsi%d: transfered += %d\n", hostno, transfersize);
-                                       transfered += transfersize;
-#endif
-
-                                       DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
-                               } else {
-
-#if (DEBUG & PHASE_DATAIN)
-                                       printk ("scsi%d: transfered += %d\n", hostno, len);
-                                       transfered += len;      /* Assume we'll transfer it all, then
-                                                                  subtract what we *didn't* transfer */
-#endif
-
-/*
- *     We loop as long as we are in a data in phase, there is room to read,
- *      and BSY is still active
- */
-
-/* SJT: Start. */
-#ifdef SEAGATE_USE_ASM
-
-                                       int __dummy_3, __dummy_4;
-
-/* Dummy clobbering variables for the new gcc-2.95 */
-
-/*
- *      We loop as long as we are in a data in phase, there is room to read, 
- *      and BSY is still active
- */
-                                       /* Local variables : ecx = len, edi = data
-                                          esi = st0x_cr_sr, ebx = st0x_dr */
-                                       __asm__ (
-                                                       /* Test for room to read */
-                                                       "orl %%ecx, %%ecx\n\t"
-                                                       "jz 2f\n\t" "cld\n\t"
-/*                "movl st0x_cr_sr, %%esi\n\t"  */
-/*                "movl st0x_dr, %%ebx\n\t"  */
-                                                       "1:\t"
-                                                       "movb (%%esi), %%al\n\t"
-                                                       /* Test for BSY */
-                                                       "test $1, %%al\n\t"
-                                                       "jz 2f\n\t"
-                                                       /* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, 
-                                                          = STAT_IO, which is 4. */
-                                                       "movb $0xe, %%ah\n\t"
-                                                       "andb %%al, %%ah\n\t"
-                                                       "cmpb $0x04, %%ah\n\t"
-                                                       "jne 2f\n\t"
-                                                       /* Test for REQ */
-                                                       "test $0x10, %%al\n\t"
-                                                       "jz 1b\n\t"
-                                                       "movb (%%ebx), %%al\n\t"
-                                                       "stosb\n\t"
-                                                       "loop 1b\n\t" "2:\n"
-                                     /* output */ :"=D" (data), "=c" (len),
-                                                       "=S"
-                                                       (__dummy_3),
-                                                       "=b" (__dummy_4)
-/* input */
-                                     :         "0" (data), "1" (len),
-                                                       "2" (st0x_cr_sr),
-                                                       "3" (st0x_dr)
-/* clobbered */
-                                     :         "eax");
-#else                          /* SEAGATE_USE_ASM */
-                                       while (len) {
-                                               unsigned char stat;
-
-                                               stat = STATUS;
-                                               if (!(stat & STAT_BSY)
-                                                   || ((stat & REQ_MASK) !=
-                                                       REQ_DATAIN))
-                                                       break;
-                                               if (stat & STAT_REQ) {
-                                                       *data++ = DATA;
-                                                       --len;
-                                               }
-                                       }
-#endif                         /* SEAGATE_USE_ASM */
-/* SJT: End. */
-#if (DEBUG & PHASE_DATAIN)
-                                       printk ("scsi%d: transfered -= %d\n", hostno, len);
-                                       transfered -= len;      /* Since we assumed all of Len got  *
-                                                                  transfered, correct our mistake */
-#endif
-                               }
-
-                               if (!len && nobuffs) {
-                                       --nobuffs;
-                                       ++buffer;
-                                       len = buffer->length;
-                                       data = sg_virt(buffer);
-                                       DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
-                               }
-                               break;
-
-                       case REQ_CMDOUT:
-                               while (((status_read = STATUS) & STAT_BSY) &&
-                                      ((status_read & REQ_MASK) == REQ_CMDOUT))
-                                       if (status_read & STAT_REQ) {
-                                               WRITE_DATA (*(const unsigned char *) cmnd);
-                                               cmnd = 1 + (const unsigned char *)cmnd;
-#ifdef SLOW_RATE
-                                               if (borken)
-                                                       borken_wait ();
-#endif
-                                       }
-                               break;
-
-                       case REQ_STATIN:
-                               status = DATA;
-                               break;
-
-                       case REQ_MSGOUT:
-                               /*
-                                *      We can only have sent a MSG OUT if we
-                                *      requested to do this by raising ATTN.
-                                *      So, we must drop ATTN.
-                                */
-                               WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);
-                               /*
-                                *      If we are reconnecting, then we must 
-                                *      send an IDENTIFY message in response
-                                *      to MSGOUT.
-                                */
-                               switch (reselect) {
-                               case CAN_RECONNECT:
-                                       WRITE_DATA (IDENTIFY (1, lun));
-                                       DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);
-                                       break;
-#ifdef LINKED
-                               case LINKED_WRONG:
-                                       WRITE_DATA (ABORT);
-                                       linked_connected = 0;
-                                       reselect = CAN_RECONNECT;
-                                       goto connect_loop;
-                                       DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
-#endif                                 /* LINKED */
-                                       DPRINTK (DEBUG_LINKED, "correct\n");
-                               default:
-                                       WRITE_DATA (NOP);
-                                       printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);
-                               }
-                               break;
-
-                       case REQ_MSGIN:
-                               switch (message = DATA) {
-                               case DISCONNECT:
-                                       DANY("seagate: deciding to disconnect\n");
-                                       should_reconnect = 1;
-                                       current_data = data;    /* WDE add */
-                                       current_buffer = buffer;
-                                       current_bufflen = len;  /* WDE add */
-                                       current_nobuffs = nobuffs;
-#ifdef LINKED
-                                       linked_connected = 0;
-#endif
-                                       done = 1;
-                                       DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);
-                                       break;
-
-#ifdef LINKED
-                               case LINKED_CMD_COMPLETE:
-                               case LINKED_FLG_CMD_COMPLETE:
-#endif
-                               case COMMAND_COMPLETE:
-                                       /*
-                                        * Note : we should check for underflow here.
-                                        */
-                                       DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno);
-                                       done = 1;
-                                       break;
-                               case ABORT:
-                                       DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno);
-                                       done = 1;
-                                       break;
-                               case SAVE_POINTERS:
-                                       current_buffer = buffer;
-                                       current_bufflen = len;  /* WDE add */
-                                       current_data = data;    /* WDE mod */
-                                       current_nobuffs = nobuffs;
-                                       DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);
-                                       break;
-                               case RESTORE_POINTERS:
-                                       buffer = current_buffer;
-                                       cmnd = current_cmnd;
-                                       data = current_data;    /* WDE mod */
-                                       len = current_bufflen;
-                                       nobuffs = current_nobuffs;
-                                       DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);
-                                       break;
-                               default:
-
-                                       /*
-                                        *      IDENTIFY distinguishes itself
-                                        *      from the other messages by 
-                                        *      setting the high bit.
-                                        *
-                                        *      Note : we need to handle at 
-                                        *      least one outstanding command
-                                        *      per LUN, and need to hash the 
-                                        *      SCSI command for that I_T_L
-                                        *      nexus based on the known ID 
-                                        *      (at this point) and LUN.
-                                        */
-
-                                       if (message & 0x80) {
-                                               DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);
-                                       } else {
-                                               /*
-                                                *      We should go into a
-                                                *      MESSAGE OUT phase, and
-                                                *      send  a MESSAGE_REJECT
-                                                *      if we run into a message 
-                                                *      that we don't like.  The
-                                                *      seagate driver needs 
-                                                *      some serious 
-                                                *      restructuring first
-                                                *      though.
-                                                */
-                                               DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target);
-                                       }
-                               }
-                               break;
-                       default:
-                               printk(KERN_ERR "scsi%d : unknown phase.\n", hostno);
-                               st0x_aborted = DID_ERROR;
-                       }       /* end of switch (status_read &  REQ_MASK) */
-#ifdef SLOW_RATE
-                       /*
-                        * I really don't care to deal with borken devices in
-                        * each single byte transfer case (ie, message in,
-                        * message out, status), so I'll do the wait here if 
-                        * necessary.
-                        */
-                       if(borken)
-                               borken_wait();
-#endif
-
-               }               /* if(status_read & STAT_REQ) ends */
-       }                       /* while(((status_read = STATUS)...) ends */
-
-       DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);
-
-#if (DEBUG & PHASE_EXIT)
-#if 0                          /* Doesn't work for scatter/gather */
-       printk("Buffer : \n");
-       for(i = 0; i < 20; ++i)
-               printk("%02x  ", ((unsigned char *) data)[i]);  /* WDE mod */
-       printk("\n");
-#endif
-       printk("scsi%d : status = ", hostno);
-       scsi_print_status(status);
-       printk(" message = %02x\n", message);
-#endif
-
-       /* We shouldn't reach this until *after* BSY has been deasserted */
-
-#ifdef LINKED
-       else
-       {
-               /*
-                * Fix the message byte so that unsuspecting high level drivers
-                * don't puke when they see a LINKED COMMAND message in place of
-                * the COMMAND COMPLETE they may be expecting.  Shouldn't be
-                * necessary, but it's better to be on the safe side.
-                *
-                * A non LINKED* message byte will indicate that the command
-                * completed, and we are now disconnected.
-                */
-
-               switch (message) {
-               case LINKED_CMD_COMPLETE:
-               case LINKED_FLG_CMD_COMPLETE:
-                       message = COMMAND_COMPLETE;
-                       linked_target = current_target;
-                       linked_lun = current_lun;
-                       linked_connected = 1;
-                       DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);
-                       /* We also will need to adjust status to accommodate intermediate
-                          conditions. */
-                       if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD))
-                               status = GOOD;
-                       break;
-                       /*
-                        * We should also handle what are "normal" termination
-                        * messages here (ABORT, BUS_DEVICE_RESET?, and
-                        * COMMAND_COMPLETE individually, and flake if things
-                        * aren't right.
-                        */
-               default:
-                       DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);
-                       linked_connected = 0;
-               }
-       }
-#endif /* LINKED */
-
-       if (should_reconnect) {
-               DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);
-               WRITE_CONTROL (BASE_CMD | CMD_INTR);
-       } else
-               WRITE_CONTROL (BASE_CMD);
-
-       return retcode (st0x_aborted);
-}                              /* end of internal_command */
-
-static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
-{
-       st0x_aborted = DID_ABORT;
-       return SUCCESS;
-}
-
-#undef ULOOP
-#undef TIMEOUT
-
-/*
- * the seagate_st0x_reset function resets the SCSI bus 
- *
- * May be called with SCpnt = NULL
- */
-
-static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
-{
-       /* No timeouts - this command is going to fail because it was reset. */
-       DANY ("scsi%d: Reseting bus... ", hostno);
-
-       /* assert  RESET signal on SCSI bus.  */
-       WRITE_CONTROL (BASE_CMD | CMD_RST);
-
-       mdelay (20);
-
-       WRITE_CONTROL (BASE_CMD);
-       st0x_aborted = DID_RESET;
-
-       DANY ("done.\n");
-       return SUCCESS;
-}
-
-static int seagate_st0x_release(struct Scsi_Host *shost)
-{
-       if (shost->irq)
-               free_irq(shost->irq, shost);
-       release_region(shost->io_port, shost->n_io_port);
-       return 0;
-}
-
-static struct scsi_host_template driver_template = {
-       .detect                 = seagate_st0x_detect,
-       .release                = seagate_st0x_release,
-       .info                   = seagate_st0x_info,
-       .queuecommand           = seagate_st0x_queue_command,
-       .eh_abort_handler       = seagate_st0x_abort,
-       .eh_bus_reset_handler   = seagate_st0x_bus_reset,
-       .can_queue              = 1,
-       .this_id                = 7,
-       .sg_tablesize           = SG_ALL,
-       .cmd_per_lun            = 1,
-       .use_clustering         = DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
index f1871ea0404573e610ef439e8d377d0b4a7a1419..17216b76efdcbd72a0b5c141e3245c09e992d17d 100644 (file)
@@ -602,8 +602,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
         * but is is possible that the app intended SG_DXFER_TO_DEV, because there
         * is a non-zero input_size, so emit a warning.
         */
-       if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)
-               if (printk_ratelimit())
+       if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
+               static char cmd[TASK_COMM_LEN];
+               if (strcmp(current->comm, cmd) && printk_ratelimit()) {
                        printk(KERN_WARNING
                               "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
                               "guessing data in;\n" KERN_WARNING "   "
@@ -611,6 +612,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                               old_hdr.reply_len - (int)SZ_SG_HEADER,
                               input_size, (unsigned int) cmnd[0],
                               current->comm);
+                       strcpy(cmd, current->comm);
+               }
+       }
        k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
        return (k < 0) ? k : count;
 }
@@ -1418,7 +1422,6 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
                goto out;
        }
 
-       class_set_devdata(cl_dev, sdp);
        error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
        if (error)
                goto cdev_add_err;
@@ -1431,11 +1434,14 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
                                MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
                                cl_dev->dev, "%s",
                                disk->disk_name);
-               if (IS_ERR(sg_class_member))
-                       printk(KERN_WARNING "sg_add: "
-                               "class_device_create failed\n");
+               if (IS_ERR(sg_class_member)) {
+                       printk(KERN_ERR "sg_add: "
+                              "class_device_create failed\n");
+                       error = PTR_ERR(sg_class_member);
+                       goto cdev_add_err;
+               }
                class_set_devdata(sg_class_member, sdp);
-               error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 
+               error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
                                          &sg_class_member->kobj, "generic");
                if (error)
                        printk(KERN_ERR "sg_add: unable to make symlink "
@@ -1447,6 +1453,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
                    "Attached scsi generic sg%d type %d\n", sdp->index,
                    scsidp->type);
 
+       class_set_devdata(cl_dev, sdp);
+
        return 0;
 
 cdev_add_err:
@@ -2521,7 +2529,7 @@ sg_idr_max_id(int id, void *p, void *data)
 static int
 sg_last_dev(void)
 {
-       int k = 0;
+       int k = -1;
        unsigned long iflags;
 
        read_lock_irqsave(&sg_index_lock, iflags);
index eef82758d047c1dbab95e48285af5c7b43c6ae6d..d4ebe8c67ba92b901298f5d4dda08c4bd69507b0 100644 (file)
@@ -159,6 +159,7 @@ void sgiwd93_reset(unsigned long base)
        udelay(50);
        hregs->ctrl = 0;
 }
+EXPORT_SYMBOL_GPL(sgiwd93_reset);
 
 static inline void init_hpc_chain(struct hpc_data *hd)
 {
index c61999031141ca8912a3ac0cecd441bae53cc2db..1fcee16fa36dbd47246b659a2c2dfb1d23daecb9 100644 (file)
@@ -67,8 +67,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
 
 #define SR_DISKS       256
 
-#define MAX_RETRIES    3
-#define SR_TIMEOUT     (30 * HZ)
 #define SR_CAPABILITIES \
        (CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
         CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
@@ -179,21 +177,28 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 {
        struct scsi_cd *cd = cdi->handle;
        int retval;
+       struct scsi_sense_hdr *sshdr;
 
        if (CDSL_CURRENT != slot) {
                /* no changer support */
                return -EINVAL;
        }
 
-       retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES);
-       if (retval) {
-               /* Unable to test, unit probably not ready.  This usually
-                * means there is no disc in the drive.  Mark as changed,
-                * and we will figure it out later once the drive is
-                * available again.  */
+       sshdr =  kzalloc(sizeof(*sshdr), GFP_KERNEL);
+       retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
+                                     sshdr);
+       if (retval || (scsi_sense_valid(sshdr) &&
+                      /* 0x3a is medium not present */
+                      sshdr->asc == 0x3a)) {
+               /* Media not present or unable to test, unit probably not
+                * ready. This usually means there is no disc in the drive.
+                * Mark as changed, and we will figure it out later once
+                * the drive is available again.
+                */
                cd->device->changed = 1;
-               return 1;       /* This will force a flush, if called from
-                                * check_disk_change */
+               /* This will force a flush, if called from check_disk_change */
+               retval = 1;
+               goto out;
        };
 
        retval = cd->device->changed;
@@ -203,9 +208,17 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
        if (retval) {
                /* check multisession offset etc */
                sr_cd_check(cdi);
-
                get_sectorsize(cd);
        }
+
+out:
+       /* Notify userspace, that media has changed. */
+       if (retval != cd->previous_state)
+               sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
+                                    GFP_KERNEL);
+       cd->previous_state = retval;
+       kfree(sshdr);
+
        return retval;
 }
  
index d65de9621b276acdbcf6a9b1f114130ebfeab93c..81fbc0b78a5235cd5fe770e914c2eed60baa58cc 100644 (file)
@@ -20,6 +20,9 @@
 #include <linux/genhd.h>
 #include <linux/kref.h>
 
+#define MAX_RETRIES    3
+#define SR_TIMEOUT     (30 * HZ)
+
 struct scsi_device;
 
 /* The CDROM is fairly slow, so we need a little extra time */
@@ -37,6 +40,7 @@ typedef struct scsi_cd {
        unsigned xa_flag:1;     /* CD has XA sectors ? */
        unsigned readcd_known:1;        /* drive supports READ_CD (0xbe) */
        unsigned readcd_cdda:1; /* reading audio data using READ_CD */
+       unsigned previous_state:1;      /* media has changed */
        struct cdrom_device_info cdi;
        /* We hold gendisk and scsi_device references on probe and use
         * the refs on this kref to decide when to release them */
index e1589f91706a2f18187b2229599e8a1ecc744e46..d5cebff1d646dde9492072aa8d9f7a0846b48b79 100644 (file)
@@ -275,18 +275,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
 /* ---------------------------------------------------------------------- */
 /* interface to cdrom.c                                                   */
 
-static int test_unit_ready(Scsi_CD *cd)
-{
-       struct packet_command cgc;
-
-       memset(&cgc, 0, sizeof(struct packet_command));
-       cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
-       cgc.quiet = 1;
-       cgc.data_direction = DMA_NONE;
-       cgc.timeout = IOCTL_TIMEOUT;
-       return sr_do_ioctl(cd, &cgc);
-}
-
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
        Scsi_CD *cd = cdi->handle;
@@ -310,14 +298,46 @@ int sr_lock_door(struct cdrom_device_info *cdi, int lock)
 
 int sr_drive_status(struct cdrom_device_info *cdi, int slot)
 {
+       struct scsi_cd *cd = cdi->handle;
+       struct scsi_sense_hdr sshdr;
+       struct media_event_desc med;
+
        if (CDSL_CURRENT != slot) {
                /* we have no changer support */
                return -EINVAL;
        }
-       if (0 == test_unit_ready(cdi->handle))
+       if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
+                                     &sshdr))
                return CDS_DISC_OK;
 
-       return CDS_TRAY_OPEN;
+       if (!cdrom_get_media_event(cdi, &med)) {
+               if (med.media_present)
+                       return CDS_DISC_OK;
+               else if (med.door_open)
+                       return CDS_TRAY_OPEN;
+               else
+                       return CDS_NO_DISC;
+       }
+
+       /*
+        * 0x04 is format in progress .. but there must be a disc present!
+        */
+       if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04)
+               return CDS_DISC_OK;
+
+       /*
+        * If not using Mt Fuji extended media tray reports,
+        * just return TRAY_OPEN since ATAPI doesn't provide
+        * any other way to detect this...
+        */
+       if (scsi_sense_valid(&sshdr) &&
+           /* 0x3a is medium not present */
+           sshdr.asc == 0x3a)
+               return CDS_NO_DISC;
+       else
+               return CDS_TRAY_OPEN;
+
+       return CDS_DRIVE_NOT_READY;
 }
 
 int sr_disk_status(struct cdrom_device_info *cdi)
index 328c47c6aeb1928a720f901f43f2a25e01ebb52e..71952703125a634a05869e1c6d44fe929a02f1ba 100644 (file)
@@ -9,7 +9,7 @@
    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
    Michael Schaefer, J"org Weule, and Eric Youngdale.
 
-   Copyright 1992 - 2007 Kai Makisara
+   Copyright 1992 - 2008 Kai Makisara
    email Kai.Makisara@kolumbus.fi
 
    Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static const char *verstr = "20070203";
+static const char *verstr = "20080117";
 
 #include <linux/module.h>
 
@@ -3214,8 +3214,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
 
 
 /* The ioctl command */
-static int st_ioctl(struct inode *inode, struct file *file,
-                   unsigned int cmd_in, unsigned long arg)
+static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 {
        int i, cmd_nr, cmd_type, bt;
        int retval = 0;
@@ -3870,7 +3869,7 @@ static const struct file_operations st_fops =
        .owner =        THIS_MODULE,
        .read =         st_read,
        .write =        st_write,
-       .ioctl =        st_ioctl,
+       .unlocked_ioctl = st_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = st_compat_ioctl,
 #endif
index 2dcde373b20e45dda1d555f31c1c5e0429c7e058..bcaba86060abe0787936bff42143776ec81a712e 100644 (file)
@@ -515,9 +515,9 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
      * various queues are valid.
      */
 
-    if (cmd->use_sg) {
-       cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-       cmd->SCp.buffers_residual = cmd->use_sg - 1;
+    if (scsi_bufflen(cmd)) {
+       cmd->SCp.buffer = scsi_sglist(cmd);
+       cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
        cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
        cmd->SCp.this_residual = cmd->SCp.buffer->length;
 
@@ -528,8 +528,8 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
     } else {
        cmd->SCp.buffer = NULL;
        cmd->SCp.buffers_residual = 0;
-       cmd->SCp.ptr = (char *) cmd->request_buffer;
-       cmd->SCp.this_residual = cmd->request_bufflen;
+       cmd->SCp.ptr = NULL;
+       cmd->SCp.this_residual = 0;
     }
     
 }
@@ -935,7 +935,7 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
     }
 # endif
 # ifdef NCR5380_STAT_LIMIT
-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
        switch (cmd->cmnd[0])
        {
@@ -943,14 +943,14 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
            case WRITE_6:
            case WRITE_10:
                hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-               hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+               hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
                hostdata->pendingw++;
                break;
            case READ:
            case READ_6:
            case READ_10:
                hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-               hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+               hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
                hostdata->pendingr++;
                break;
        }
@@ -1345,7 +1345,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
                          struct scsi_cmnd *cmd)
 {
 # ifdef NCR5380_STAT_LIMIT
-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
        switch (cmd->cmnd[0])
        {
@@ -1353,14 +1353,14 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
            case WRITE_6:
            case WRITE_10:
                hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
-               /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+               /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
                hostdata->pendingw--;
                break;
            case READ:
            case READ_6:
            case READ_10:
                hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
-               /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+               /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
                hostdata->pendingr--;
                break;
        }
@@ -1863,7 +1863,7 @@ static int do_abort (struct Scsi_Host *host)
      * the target sees, so we just handshake.
      */
     
-    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+    while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
 
     NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
index 90cee94d9522df03d493a833ed7297c368bc9126..1f6fd16803351f7d67940d864cfdca2148eec3c7 100644 (file)
@@ -328,27 +328,13 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer,
 static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
 {
        struct Scsi_Host *dev = dev_id;
-       int base = 0;
+       int base = dev->io_port;
        int i;
        unsigned long flags = 0;
        unsigned char status_reg, pio_int_reg, int_reg;
        struct scatterlist *sg;
        unsigned int tot_trans = 0;
 
-       /* We search the base address of the host adapter which caused the interrupt */
-       /* FIXME: should pass dev_id sensibly as hosts[i] */
-       for(i = 0; i < host_index && !base; i++)
-               if(irq == hosts[i].irq)
-                       base = hosts[i].base;
-       /* If no adapter found, we cannot handle the interrupt. Leave a message */
-       /* and continue. This should never happen...                            */
-       if(!base)
-       {
-               printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
-               return IRQ_NONE;
-       }
-       /* Now we have the base address and we can start handling the interrupt */
-
        spin_lock_irqsave(dev->host_lock,flags);
        status_reg = inb(base + STATUS_REG);
        pio_int_reg = inb(base + PIO_INT_REG);
index 9e0908d1981a99f1fef86f3b6f4bf531e83366fa..21e926dcdab0bfc73d6bc89d85f7c4d177d5c0ea 100644 (file)
@@ -207,10 +207,9 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
                        /*
                         *  Bounce back the sense data to user.
                         */
-                       memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+                       memset(&cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
                        memcpy(cmd->sense_buffer, cp->sns_bbuf,
-                             min(sizeof(cmd->sense_buffer),
-                                 (size_t)SYM_SNS_BBUF_LEN));
+                              min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN));
 #if 0
                        /*
                         *  If the device reports a UNIT ATTENTION condition 
@@ -609,22 +608,24 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
         */
 #define WAIT_FOR_PCI_RECOVERY  35
        if (pci_channel_offline(pdev)) {
-               struct completion *io_reset;
                int finished_reset = 0;
                init_completion(&eh_done);
                spin_lock_irq(shost->host_lock);
                /* Make sure we didn't race */
                if (pci_channel_offline(pdev)) {
-                       if (!sym_data->io_reset)
-                               sym_data->io_reset = &eh_done;
-                       io_reset = sym_data->io_reset;
+                       BUG_ON(sym_data->io_reset);
+                       sym_data->io_reset = &eh_done;
                } else {
                        finished_reset = 1;
                }
                spin_unlock_irq(shost->host_lock);
                if (!finished_reset)
-                       finished_reset = wait_for_completion_timeout(io_reset,
+                       finished_reset = wait_for_completion_timeout
+                                               (sym_data->io_reset,
                                                WAIT_FOR_PCI_RECOVERY*HZ);
+               spin_lock_irq(shost->host_lock);
+               sym_data->io_reset = NULL;
+               spin_unlock_irq(shost->host_lock);
                if (!finished_reset)
                        return SCSI_FAILED;
        }
@@ -1744,7 +1745,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static void __devexit sym2_remove(struct pci_dev *pdev)
+static void sym2_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
 
@@ -1879,7 +1880,6 @@ static void sym2_io_resume(struct pci_dev *pdev)
        spin_lock_irq(shost->host_lock);
        if (sym_data->io_reset)
                complete_all(sym_data->io_reset);
-       sym_data->io_reset = NULL;
        spin_unlock_irq(shost->host_lock);
 }
 
@@ -2056,7 +2056,7 @@ static struct pci_driver sym2_driver = {
        .name           = NAME53C8XX,
        .id_table       = sym2_id_table,
        .probe          = sym2_probe,
-       .remove         = __devexit_p(sym2_remove),
+       .remove         = sym2_remove,
        .err_handler    = &sym2_err_handler,
 };
 
index 44193049c4aed96de169fcea061f52536bf7e92f..5b04ddfed26c6162c0234963963598998d79a4b3 100644 (file)
@@ -444,7 +444,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
 
        /* Map sense buffer */
        if (pSRB->SRBFlag & AUTO_REQSENSE) {
-               pSRB->pSegmentList      = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer));
+               pSRB->pSegmentList      = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
                pSRB->SGcount           = pci_map_sg(pdev, pSRB->pSegmentList, 1,
                                                     DMA_FROM_DEVICE);
                cmdp->saved_dma_handle  = sg_dma_address(pSRB->pSegmentList);
@@ -599,7 +599,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
            DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
            DC390_write8 (ScsiFifo, 0);
            DC390_write8 (ScsiFifo, 0);
-           DC390_write8 (ScsiFifo, sizeof(scmd->sense_buffer));
+           DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
            DC390_write8 (ScsiFifo, 0);
            DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));
          }
@@ -1389,7 +1389,7 @@ dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus
        DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
        DC390_write8 (ScsiFifo, 0);
        DC390_write8 (ScsiFifo, 0);
-       DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+       DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
        DC390_write8 (ScsiFifo, 0);
        DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
     }
index 7edd6ceb13b26ba8447f8d4b9096fdfde94ee07a..4bc5407f96958598f3a44ca56c8d387a6a86100e 100644 (file)
@@ -1121,9 +1121,9 @@ static void map_dma(unsigned int i, unsigned int j) {
 
    if (SCpnt->sense_buffer)
       cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
-                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+                           SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
 
-   cpp->sense_len = sizeof SCpnt->sense_buffer;
+   cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
    if (scsi_bufflen(SCpnt)) {
           count = scsi_dma_map(SCpnt);
index 6d1f0edd7985632384c83d47793946f88c262875..75eca6b22db561e7508d52dd2cb1be70cafdb98f 100644 (file)
@@ -298,9 +298,16 @@ static inline int find_and_clear_bit_16(unsigned long *field)
 {
   int rv;
 
-  if (*field == 0) panic("No free mscp");
-  asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
-      : "=&r" (rv), "=m" (*field) : "1" (*field));
+  if (*field == 0)
+    panic("No free mscp");
+
+  asm volatile (
+       "xorl %0,%0\n\t"
+       "0: bsfw %1,%w0\n\t"
+       "btr %0,%1\n\t"
+       "jnc 0b"
+       : "=&r" (rv), "=m" (*field) :);
+
   return rv;
 }
 
@@ -741,7 +748,7 @@ static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
     }
     my_mscp->command_link = 0;         /*???*/
     my_mscp->scsi_command_link_id = 0; /*???*/
-    my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
+    my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE;
     my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
     memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
     my_mscp->adapter_status = 0;
index fdbb92d1f72259aa72f82f90689b072fda504c2a..f286c37da7e0dfb51fc44435c4c54d0a6120ba28 100644 (file)
@@ -407,16 +407,16 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
  *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
-       if (cmd->use_sg) {
-               cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-               cmd->SCp.buffers_residual = cmd->use_sg - 1;
+       if (scsi_bufflen(cmd)) {
+               cmd->SCp.buffer = scsi_sglist(cmd);
+               cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
                cmd->SCp.buffers_residual = 0;
-               cmd->SCp.ptr = (char *) cmd->request_buffer;
-               cmd->SCp.this_residual = cmd->request_bufflen;
+               cmd->SCp.ptr = NULL;
+               cmd->SCp.this_residual = 0;
        }
 
 /* WD docs state that at the conclusion of a "LEVEL2" command, the
index 03cd44f231dff37f64024f48483afd99d2c49818..b4304ae78527e409bae6ad6334ec68b7199e22b1 100644 (file)
@@ -1108,13 +1108,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
        scb->host = host;
 
        nseg = scsi_sg_count(SCpnt);
-       if (nseg) {
+       if (nseg > 1) {
                struct scatterlist *sg;
                unsigned i;
 
-               if (SCpnt->device->host->sg_tablesize == SG_NONE) {
-                       panic("wd7000_queuecommand: scatter/gather not supported.\n");
-               }
                dprintk("Using scatter/gather with %d elements.\n", nseg);
 
                sgb = scb->sgb;
@@ -1128,7 +1125,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
                }
        } else {
                scb->op = 0;
-               any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt)));
+               if (nseg) {
+                       struct scatterlist *sg = scsi_sglist(SCpnt);
+                       any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
+               }
                any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
        }
 
@@ -1524,7 +1524,7 @@ static __init int wd7000_detect(struct scsi_host_template *tpnt)
                                 *  For boards before rev 6.0, scatter/gather isn't supported.
                                 */
                                if (host->rev1 < 6)
-                                       sh->sg_tablesize = SG_NONE;
+                                       sh->sg_tablesize = 1;
 
                                present++;      /* count it */
 
index 9d3105b64a7a597ba3f634ad4b270dd72d7e4ff9..9c2df5c857cfc85ff46e8378b786a4dd32602bba 100644 (file)
@@ -48,7 +48,7 @@
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
-#include <linux/kobject.h>
+#include <linux/kref.h>
 #include <linux/firmware.h>
 #include <linux/bitops.h>
 
@@ -65,7 +65,7 @@
 #define ICOM_VERSION_STR "1.3.1"
 #define NR_PORTS              128
 #define ICOM_PORT ((struct icom_port *)port)
-#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj)
+#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
 
 static const struct pci_device_id icom_pci_table[] = {
        {
@@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {};
 #else
 static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
 #endif
+static void icom_kref_release(struct kref *kref);
 
 static void free_port_memory(struct icom_port *icom_port)
 {
@@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port)
 {
        int retval;
 
-       kobject_get(&ICOM_PORT->adapter->kobj);
+       kref_get(&ICOM_PORT->adapter->kref);
        retval = startup(ICOM_PORT);
 
        if (retval) {
-               kobject_put(&ICOM_PORT->adapter->kobj);
+               kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
                trace(ICOM_PORT, "STARTUP_ERROR", 0);
                return retval;
        }
@@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port)
 
        shutdown(ICOM_PORT);
 
-       kobject_put(&ICOM_PORT->adapter->kobj);
+       kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
 }
 
 static void icom_set_termios(struct uart_port *port,
@@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter)
        pci_release_regions(icom_adapter->pci_dev);
 }
 
-static void icom_kobj_release(struct kobject *kobj)
+static void icom_kref_release(struct kref *kref)
 {
        struct icom_adapter *icom_adapter;
 
-       icom_adapter = to_icom_adapter(kobj);
+       icom_adapter = to_icom_adapter(kref);
        icom_remove_adapter(icom_adapter);
 }
 
-static struct kobj_type icom_kobj_type = {
-       .release = icom_kobj_release,
-};
-
 static int __devinit icom_probe(struct pci_dev *dev,
                                const struct pci_device_id *ent)
 {
@@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
                }
        }
 
-       kobject_init(&icom_adapter->kobj);
-       icom_adapter->kobj.ktype = &icom_kobj_type;
+       kref_init(&icom_adapter->kref);
        return 0;
 
 probe_exit2:
@@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev)
                icom_adapter = list_entry(tmp, struct icom_adapter,
                                          icom_adapter_entry);
                if (icom_adapter->pci_dev == dev) {
-                       kobject_put(&icom_adapter->kobj);
+                       kref_put(&icom_adapter->kref, icom_kref_release);
                        return;
                }
        }
index e8578d8cd35e8c9b0f428aa4b6467ba01b75e3bf..0274554967453b632be192c2ae180877d865d73b 100644 (file)
@@ -270,7 +270,7 @@ struct icom_adapter {
 #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM     0x0251
        int numb_ports;
        struct list_head icom_adapter_entry;
-       struct kobject kobj;
+       struct kref kref;
 };
 
 /* prototype */
index 3cdab131c4a9a55a0bea4221f5eb31aa0408b9aa..ea61724ae2256fe33035f77e29cce9a0a67eb48a 100644 (file)
@@ -350,6 +350,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                tx = xfer->tx_buf;
 
                do {
+                       c -= 1;
                        if (tx != NULL) {
                                if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -380,7 +381,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                                word_len, *(rx - 1));
 #endif
                        }
-                       c -= 1;
                } while (c);
        } else if (word_len <= 16) {
                u16             *rx;
@@ -389,6 +389,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
+                       c -= 2;
                        if (tx != NULL) {
                                if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -419,7 +420,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                                word_len, *(rx - 1));
 #endif
                        }
-                       c -= 2;
                } while (c);
        } else if (word_len <= 32) {
                u32             *rx;
@@ -428,6 +428,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
+                       c -= 4;
                        if (tx != NULL) {
                                if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -458,7 +459,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                                word_len, *(rx - 1));
 #endif
                        }
-                       c -= 4;
                } while (c);
        }
 
index 93e9de46977adc9b7bff784147c40f634fcf910b..682a6a48fec31e989dee472420cd37bc766c4b9f 100644 (file)
@@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master)
 }
 EXPORT_SYMBOL_GPL(spi_unregister_master);
 
+static int __spi_master_match(struct device *dev, void *data)
+{
+       struct spi_master *m;
+       u16 *bus_num = data;
+
+       m = container_of(dev, struct spi_master, dev);
+       return m->bus_num == *bus_num;
+}
+
 /**
  * spi_busnum_to_master - look up master associated with bus_num
  * @bus_num: the master's bus number
@@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
 {
        struct device           *dev;
        struct spi_master       *master = NULL;
-       struct spi_master       *m;
-
-       down(&spi_master_class.sem);
-       list_for_each_entry(dev, &spi_master_class.children, node) {
-               m = container_of(dev, struct spi_master, dev);
-               if (m->bus_num == bus_num) {
-                       master = spi_master_get(m);
-                       break;
-               }
-       }
-       up(&spi_master_class.sem);
+
+       dev = class_find_device(&spi_master_class, &bus_num,
+                               __spi_master_match);
+       if (dev)
+               master = container_of(dev, struct spi_master, dev);
+       /* reference got in class_find_device */
        return master;
 }
 EXPORT_SYMBOL_GPL(spi_busnum_to_master);
index 81639c6be1c73c052dafaa09ae1a99a80cb55d4f..f7f8580edad86c9be126ce1b6abd97d7629ee261 100644 (file)
@@ -184,6 +184,7 @@ int spi_bitbang_setup(struct spi_device *spi)
        struct spi_bitbang_cs   *cs = spi->controller_state;
        struct spi_bitbang      *bitbang;
        int                     retval;
+       unsigned long           flags;
 
        bitbang = spi_master_get_devdata(spi->master);
 
@@ -222,12 +223,12 @@ int spi_bitbang_setup(struct spi_device *spi)
         */
 
        /* deselect chip (low or high) */
-       spin_lock(&bitbang->lock);
+       spin_lock_irqsave(&bitbang->lock, flags);
        if (!bitbang->busy) {
                bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
                ndelay(cs->nsecs);
        }
-       spin_unlock(&bitbang->lock);
+       spin_unlock_irqrestore(&bitbang->lock, flags);
 
        return 0;
 }
index 96258c60919da86f84edd4896b0760f2a67ec13a..63ee5cfbefbbe983e87030757c21c1ba8666da8b 100644 (file)
@@ -388,6 +388,17 @@ int ssb_bus_scan(struct ssb_bus *bus,
                case SSB_DEV_PCI:
                case SSB_DEV_PCIE:
 #ifdef CONFIG_SSB_DRIVER_PCICORE
+                       if (bus->bustype == SSB_BUSTYPE_PCI) {
+                               /* Ignore PCI cores on PCI-E cards.
+                                * Ignore PCI-E cores on PCI cards. */
+                               if (dev->id.coreid == SSB_DEV_PCI) {
+                                       if (bus->host_pci->is_pcie)
+                                               continue;
+                               } else {
+                                       if (!bus->host_pci->is_pcie)
+                                               continue;
+                               }
+                       }
                        if (bus->pcicore.dev) {
                                ssb_printk(KERN_WARNING PFX
                                           "WARNING: Multiple PCI(E) cores found\n");
index 865f32b63b5c0d2d468348f77a1c2c8c07d34879..cc246faa35909116bb61d19541d47059c99ea0fb 100644 (file)
@@ -34,12 +34,12 @@ struct uio_device {
        wait_queue_head_t       wait;
        int                     vma_count;
        struct uio_info         *info;
-       struct kset             map_attr_kset;
+       struct kobject          *map_dir;
 };
 
 static int uio_major;
 static DEFINE_IDR(uio_idr);
-static struct file_operations uio_fops;
+static const struct file_operations uio_fops;
 
 /* UIO class infrastructure */
 static struct uio_class {
@@ -51,47 +51,48 @@ static struct uio_class {
  * attributes
  */
 
-static struct attribute attr_addr = {
-       .name  = "addr",
-       .mode  = S_IRUGO,
+struct uio_map {
+       struct kobject kobj;
+       struct uio_mem *mem;
 };
+#define to_map(map) container_of(map, struct uio_map, kobj)
 
-static struct attribute attr_size = {
-       .name  = "size",
-       .mode  = S_IRUGO,
-};
 
-static struct attribute* map_attrs[] = {
-       &attr_addr, &attr_size, NULL
-};
-
-static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
+static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
                             char *buf)
 {
-       struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
+       struct uio_map *map = to_map(kobj);
+       struct uio_mem *mem = map->mem;
 
-       if (strncmp(attr->name,"addr",4) == 0)
+       if (strncmp(attr->attr.name, "addr", 4) == 0)
                return sprintf(buf, "0x%lx\n", mem->addr);
 
-       if (strncmp(attr->name,"size",4) == 0)
+       if (strncmp(attr->attr.name, "size", 4) == 0)
                return sprintf(buf, "0x%lx\n", mem->size);
 
        return -ENODEV;
 }
 
-static void map_attr_release(struct kobject *kobj)
-{
-       /* TODO ??? */
-}
+static struct kobj_attribute attr_attribute =
+       __ATTR(addr, S_IRUGO, map_attr_show, NULL);
+static struct kobj_attribute size_attribute =
+       __ATTR(size, S_IRUGO, map_attr_show, NULL);
 
-static struct sysfs_ops map_attr_ops = {
-       .show  = map_attr_show,
+static struct attribute *attrs[] = {
+       &attr_attribute.attr,
+       &size_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
 };
 
+static void map_release(struct kobject *kobj)
+{
+       struct uio_map *map = to_map(kobj);
+       kfree(map);
+}
+
 static struct kobj_type map_attr_type = {
-       .release        = map_attr_release,
-       .sysfs_ops      = &map_attr_ops,
-       .default_attrs  = map_attrs,
+       .release        = map_release,
+       .default_attrs  = attrs,
 };
 
 static ssize_t show_name(struct device *dev,
@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
        int mi;
        int map_found = 0;
        struct uio_mem *mem;
+       struct uio_map *map;
 
        ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
        if (ret)
@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
                        break;
                if (!map_found) {
                        map_found = 1;
-                       kobject_set_name(&idev->map_attr_kset.kobj,"maps");
-                       idev->map_attr_kset.ktype = &map_attr_type;
-                       idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
-                       ret = kset_register(&idev->map_attr_kset);
-                       if (ret)
-                               goto err_remove_group;
+                       idev->map_dir = kobject_create_and_add("maps",
+                                                       &idev->dev->kobj);
+                       if (!idev->map_dir)
+                               goto err;
                }
-               kobject_init(&mem->kobj);
-               kobject_set_name(&mem->kobj,"map%d",mi);
-               mem->kobj.parent = &idev->map_attr_kset.kobj;
-               mem->kobj.kset = &idev->map_attr_kset;
-               ret = kobject_add(&mem->kobj);
+               map = kzalloc(sizeof(*map), GFP_KERNEL);
+               if (!map)
+                       goto err;
+               kobject_init(&map->kobj, &map_attr_type);
+               map->mem = mem;
+               mem->map = map;
+               ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
+               if (ret)
+                       goto err;
+               ret = kobject_uevent(&map->kobj, KOBJ_ADD);
                if (ret)
-                       goto err_remove_maps;
+                       goto err;
        }
 
        return 0;
 
-err_remove_maps:
+err:
        for (mi--; mi>=0; mi--) {
                mem = &idev->info->mem[mi];
-               kobject_unregister(&mem->kobj);
+               map = mem->map;
+               kobject_put(&map->kobj);
        }
-       kset_unregister(&idev->map_attr_kset); /* Needed ? */
-err_remove_group:
+       kobject_put(idev->map_dir);
        sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
 err_group:
        dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
                mem = &idev->info->mem[mi];
                if (mem->size == 0)
                        break;
-               kobject_unregister(&mem->kobj);
+               kobject_put(&mem->map->kobj);
        }
-       kset_unregister(&idev->map_attr_kset);
+       kobject_put(idev->map_dir);
        sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
 }
 
@@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
        }
 }
 
-static struct file_operations uio_fops = {
+static const struct file_operations uio_fops = {
        .owner          = THIS_MODULE,
        .open           = uio_open,
        .release        = uio_release,
index c51f8e9312e055222f2c473039d7ffb19eb45451..7c3aaa9c5402bf55a0738e0b310943fa81dde777 100644 (file)
@@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
                goto exit;
 
        if (usb_drv->probe != NULL)
-               error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
-                                         &driver_attr_new_id.attr);
+               error = driver_create_file(&usb_drv->drvwrap.driver,
+                                          &driver_attr_new_id);
 exit:
        return error;
 }
@@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
                return;
 
        if (usb_drv->probe != NULL)
-               sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
-                                 &driver_attr_new_id.attr);
+               driver_remove_file(&usb_drv->drvwrap.driver,
+                                  &driver_attr_new_id);
 }
 
 static void usb_free_dynids(struct usb_driver *usb_drv)
index feba9679ace8b35103fc7ac0315adefdf97b855f..7c069a02c1dd40817d93b58dffed4217bd740ff2 100644 (file)
@@ -447,7 +447,7 @@ static void usa26_indat_callback(struct urb *urb)
 
        port = (struct usb_serial_port *) urb->context;
        tty = port->tty;
-       if (urb->actual_length) {
+       if (tty && urb->actual_length) {
                /* 0x80 bit is error flag */
                if ((data[0] & 0x80) == 0) {
                        /* no errors on individual bytes, only possible overrun err*/
index cf8add91de0585a3f40fe150f6d03f9b9100f4dd..0da1df9c79bf044677e703c125212a0dd5f0f52f 100644 (file)
@@ -483,6 +483,13 @@ static void pl2303_set_termios(struct usb_serial_port *port,
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
+       /* The PL2303 is reported to lose bytes if you change
+          serial settings even to the same values as before. Thus
+          we actually need to filter in this specific case */
+
+       if (!tty_termios_hw_change(port->tty->termios, old_termios))
+               return;
+
        cflag = port->tty->termios->c_cflag;
 
        buf = kzalloc(7, GFP_KERNEL);
index 88aa59ab756321997d670082cc7c24ef84a6ba74..f5a4e8d6a3b1460274eb551343982f071e16ab0b 100644 (file)
@@ -132,8 +132,7 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
 
        /* Now transfer all of our blocks. */
        US_DEBUGP("Start of read\n");
-       result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
-                       count, srb->use_sg, &srb->resid);
+       result = usb_stor_bulk_srb(us, ipipe, srb);
        US_DEBUGP("freecom_readdata done!\n");
 
        if (result > USB_STOR_XFER_SHORT)
@@ -166,8 +165,7 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
 
        /* Now transfer all of our blocks. */
        US_DEBUGP("Start of write\n");
-       result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
-                       count, srb->use_sg, &srb->resid);
+       result = usb_stor_bulk_srb(us, opipe, srb);
 
        US_DEBUGP("freecom_writedata done!\n");
        if (result > USB_STOR_XFER_SHORT)
@@ -281,7 +279,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
         * and such will hang. */
        US_DEBUGP("Device indicates that it has %d bytes available\n",
                        le16_to_cpu (fst->Count));
-       US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
+       US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb));
 
        /* Find the length we desire to read. */
        switch (srb->cmnd[0]) {
@@ -292,12 +290,12 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
                        length = le16_to_cpu(fst->Count);
                        break;
                default:
-                       length = srb->request_bufflen;
+                       length = scsi_bufflen(srb);
        }
 
        /* verify that this amount is legal */
-       if (length > srb->request_bufflen) {
-               length = srb->request_bufflen;
+       if (length > scsi_bufflen(srb)) {
+               length = scsi_bufflen(srb);
                US_DEBUGP("Truncating request to match buffer length: %d\n", length);
        }
 
index 49ba6c0ff1e8b4272247bcb935f216acdf08fe76..178e8c2a8a2feb41f03fd7d16117347647f6247b 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/slab.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/scatterlist.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -287,6 +288,7 @@ struct isd200_info {
        /* maximum number of LUNs supported */
        unsigned char MaxLUNs;
        struct scsi_cmnd srb;
+       struct scatterlist sg;
 };
 
 
@@ -398,6 +400,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
  * Transport routines
  ***********************************************************************/
 
+/**************************************************************************
+ *  isd200_set_srb(), isd200_srb_set_bufflen()
+ *
+ * Two helpers to facilitate in initialization of scsi_cmnd structure
+ * Will need to change when struct scsi_cmnd changes
+ */
+static void isd200_set_srb(struct isd200_info *info,
+       enum dma_data_direction dir, void* buff, unsigned bufflen)
+{
+       struct scsi_cmnd *srb = &info->srb;
+
+       if (buff)
+               sg_init_one(&info->sg, buff, bufflen);
+
+       srb->sc_data_direction = dir;
+       srb->request_buffer = buff ? &info->sg : NULL;
+       srb->request_bufflen = bufflen;
+       srb->use_sg = buff ? 1 : 0;
+}
+
+static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen)
+{
+       srb->request_bufflen = bufflen;
+}
+
 
 /**************************************************************************
  *  isd200_action
@@ -432,9 +459,7 @@ static int isd200_action( struct us_data *us, int action,
                ata.generic.RegisterSelect =
                  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
                  REG_STATUS | REG_ERROR;
-               srb->sc_data_direction = DMA_FROM_DEVICE;
-               srb->request_buffer = pointer;
-               srb->request_bufflen = value;
+               isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value);
                break;
 
        case ACTION_ENUM:
@@ -444,7 +469,7 @@ static int isd200_action( struct us_data *us, int action,
                                           ACTION_SELECT_5;
                ata.generic.RegisterSelect = REG_DEVICE_HEAD;
                ata.write.DeviceHeadByte = value;
-               srb->sc_data_direction = DMA_NONE;
+               isd200_set_srb(info, DMA_NONE, NULL, 0);
                break;
 
        case ACTION_RESET:
@@ -453,7 +478,7 @@ static int isd200_action( struct us_data *us, int action,
                                           ACTION_SELECT_3|ACTION_SELECT_4;
                ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
                ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
-               srb->sc_data_direction = DMA_NONE;
+               isd200_set_srb(info, DMA_NONE, NULL, 0);
                break;
 
        case ACTION_REENABLE:
@@ -462,7 +487,7 @@ static int isd200_action( struct us_data *us, int action,
                                           ACTION_SELECT_3|ACTION_SELECT_4;
                ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
                ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
-               srb->sc_data_direction = DMA_NONE;
+               isd200_set_srb(info, DMA_NONE, NULL, 0);
                break;
 
        case ACTION_SOFT_RESET:
@@ -471,21 +496,20 @@ static int isd200_action( struct us_data *us, int action,
                ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
                ata.write.DeviceHeadByte = info->DeviceHead;
                ata.write.CommandByte = WIN_SRST;
-               srb->sc_data_direction = DMA_NONE;
+               isd200_set_srb(info, DMA_NONE, NULL, 0);
                break;
 
        case ACTION_IDENTIFY:
                US_DEBUGP("   isd200_action(IDENTIFY)\n");
                ata.generic.RegisterSelect = REG_COMMAND;
                ata.write.CommandByte = WIN_IDENTIFY;
-               srb->sc_data_direction = DMA_FROM_DEVICE;
-               srb->request_buffer = (void *) info->id;
-               srb->request_bufflen = sizeof(struct hd_driveid);
+               isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
+                                               sizeof(struct hd_driveid));
                break;
 
        default:
                US_DEBUGP("Error: Undefined action %d\n",action);
-               break;
+               return ISD200_ERROR;
        }
 
        memcpy(srb->cmnd, &ata, sizeof(ata.generic));
@@ -590,7 +614,7 @@ static void isd200_invoke_transport( struct us_data *us,
                return;
        }
 
-       if ((srb->resid > 0) &&
+       if ((scsi_get_resid(srb) > 0) &&
            !((srb->cmnd[0] == REQUEST_SENSE) ||
              (srb->cmnd[0] == INQUIRY) ||
              (srb->cmnd[0] == MODE_SENSE) ||
@@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
        return(retStatus);
 }
 
-
 /**************************************************************************
  * isd200_scsi_to_ata
  *                                                                      
@@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                        ataCdb->generic.TransferBlockSize = 1;
                        ataCdb->generic.RegisterSelect = REG_COMMAND;
                        ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
-                       srb->request_bufflen = 0;
+                       isd200_srb_set_bufflen(srb, 0);
                } else {
                        US_DEBUGP("   Media Status not supported, just report okay\n");
                        srb->result = SAM_STAT_GOOD;
@@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                        ataCdb->generic.TransferBlockSize = 1;
                        ataCdb->generic.RegisterSelect = REG_COMMAND;
                        ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
-                       srb->request_bufflen = 0;
+                       isd200_srb_set_bufflen(srb, 0);
                } else {
                        US_DEBUGP("   Media Status not supported, just report okay\n");
                        srb->result = SAM_STAT_GOOD;
@@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                        ataCdb->generic.RegisterSelect = REG_COMMAND;
                        ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
                                WIN_DOORLOCK : WIN_DOORUNLOCK;
-                       srb->request_bufflen = 0;
+                       isd200_srb_set_bufflen(srb, 0);
                } else {
                        US_DEBUGP("   Not removeable media, just report okay\n");
                        srb->result = SAM_STAT_GOOD;
@@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
                        ataCdb->generic.TransferBlockSize = 1;
                        ataCdb->generic.RegisterSelect = REG_COMMAND;
                        ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
-                       srb->request_bufflen = 0;
+                       isd200_srb_set_bufflen(srb, 0);
                } else {
                        US_DEBUGP("   Nothing to do, just report okay\n");
                        srb->result = SAM_STAT_GOOD;
@@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data *us)
 
 void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
 {
-       int sendToTransport = 1;
+       int sendToTransport = 1, orig_bufflen;
        union ata_cdb ataCdb;
 
        /* Make sure driver was initialized */
@@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
        if (us->extra == NULL)
                US_DEBUGP("ERROR Driver not initialized\n");
 
-       /* Convert command */
-       srb->resid = 0;
+       scsi_set_resid(srb, 0);
+       /* scsi_bufflen might change in protocol translation to ata */
+       orig_bufflen = scsi_bufflen(srb);
        sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
 
        /* send the command to the transport layer */
        if (sendToTransport)
                isd200_invoke_transport(us, srb, &ataCdb);
+
+       isd200_srb_set_bufflen(srb, orig_bufflen);
 }
index 889622baac20ff917f7f3d98c7251f24c10a0e2f..a41ce21c06970d0ee05bb07752545f4d3b3dc026 100644 (file)
@@ -149,11 +149,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
  ***********************************************************************/
 
 /* Copy a buffer of length buflen to/from the srb's transfer buffer.
- * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
- * points to a list of s-g entries and we ignore srb->request_bufflen.
- * For non-scatter-gather transfers, srb->request_buffer points to the
- * transfer buffer itself and srb->request_bufflen is the buffer's length.)
- * Update the *index and *offset variables so that the next copy will
+ * Update the **sgptr and *offset variables so that the next copy will
  * pick up from where this one left off. */
 
 unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
@@ -162,80 +158,64 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
 {
        unsigned int cnt;
 
-       /* If not using scatter-gather, just transfer the data directly.
-        * Make certain it will fit in the available buffer space. */
-       if (srb->use_sg == 0) {
-               if (*offset >= srb->request_bufflen)
-                       return 0;
-               cnt = min(buflen, srb->request_bufflen - *offset);
-               if (dir == TO_XFER_BUF)
-                       memcpy((unsigned char *) srb->request_buffer + *offset,
-                                       buffer, cnt);
-               else
-                       memcpy(buffer, (unsigned char *) srb->request_buffer +
-                                       *offset, cnt);
-               *offset += cnt;
-
-       /* Using scatter-gather.  We have to go through the list one entry
+       /* We have to go through the list one entry
         * at a time.  Each s-g entry contains some number of pages, and
         * each page has to be kmap()'ed separately.  If the page is already
         * in kernel-addressable memory then kmap() will return its address.
         * If the page is not directly accessible -- such as a user buffer
         * located in high memory -- then kmap() will map it to a temporary
         * position in the kernel's virtual address space. */
-       } else {
-               struct scatterlist *sg = *sgptr;
-
-               if (!sg)
-                       sg = (struct scatterlist *) srb->request_buffer;
-
-               /* This loop handles a single s-g list entry, which may
-                * include multiple pages.  Find the initial page structure
-                * and the starting offset within the page, and update
-                * the *offset and *index values for the next loop. */
-               cnt = 0;
-               while (cnt < buflen) {
-                       struct page *page = sg_page(sg) +
-                                       ((sg->offset + *offset) >> PAGE_SHIFT);
-                       unsigned int poff =
-                                       (sg->offset + *offset) & (PAGE_SIZE-1);
-                       unsigned int sglen = sg->length - *offset;
-
-                       if (sglen > buflen - cnt) {
-
-                               /* Transfer ends within this s-g entry */
-                               sglen = buflen - cnt;
-                               *offset += sglen;
-                       } else {
-
-                               /* Transfer continues to next s-g entry */
-                               *offset = 0;
-                               sg = sg_next(sg);
-                       }
-
-                       /* Transfer the data for all the pages in this
-                        * s-g entry.  For each page: call kmap(), do the
-                        * transfer, and call kunmap() immediately after. */
-                       while (sglen > 0) {
-                               unsigned int plen = min(sglen, (unsigned int)
-                                               PAGE_SIZE - poff);
-                               unsigned char *ptr = kmap(page);
-
-                               if (dir == TO_XFER_BUF)
-                                       memcpy(ptr + poff, buffer + cnt, plen);
-                               else
-                                       memcpy(buffer + cnt, ptr + poff, plen);
-                               kunmap(page);
-
-                               /* Start at the beginning of the next page */
-                               poff = 0;
-                               ++page;
-                               cnt += plen;
-                               sglen -= plen;
-                       }
+       struct scatterlist *sg = *sgptr;
+
+       if (!sg)
+               sg = scsi_sglist(srb);
+
+       /* This loop handles a single s-g list entry, which may
+               * include multiple pages.  Find the initial page structure
+               * and the starting offset within the page, and update
+               * the *offset and **sgptr values for the next loop. */
+       cnt = 0;
+       while (cnt < buflen) {
+               struct page *page = sg_page(sg) +
+                               ((sg->offset + *offset) >> PAGE_SHIFT);
+               unsigned int poff =
+                               (sg->offset + *offset) & (PAGE_SIZE-1);
+               unsigned int sglen = sg->length - *offset;
+
+               if (sglen > buflen - cnt) {
+
+                       /* Transfer ends within this s-g entry */
+                       sglen = buflen - cnt;
+                       *offset += sglen;
+               } else {
+
+                       /* Transfer continues to next s-g entry */
+                       *offset = 0;
+                       sg = sg_next(sg);
+               }
+
+               /* Transfer the data for all the pages in this
+                       * s-g entry.  For each page: call kmap(), do the
+                       * transfer, and call kunmap() immediately after. */
+               while (sglen > 0) {
+                       unsigned int plen = min(sglen, (unsigned int)
+                                       PAGE_SIZE - poff);
+                       unsigned char *ptr = kmap(page);
+
+                       if (dir == TO_XFER_BUF)
+                               memcpy(ptr + poff, buffer + cnt, plen);
+                       else
+                               memcpy(buffer + cnt, ptr + poff, plen);
+                       kunmap(page);
+
+                       /* Start at the beginning of the next page */
+                       poff = 0;
+                       ++page;
+                       cnt += plen;
+                       sglen -= plen;
                }
-               *sgptr = sg;
        }
+       *sgptr = sg;
 
        /* Return the amount actually transferred */
        return cnt;
@@ -251,6 +231,6 @@ void usb_stor_set_xfer_buf(unsigned char *buffer,
 
        usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
                        TO_XFER_BUF);
-       if (buflen < srb->request_bufflen)
-               srb->resid = srb->request_bufflen - buflen;
+       if (buflen < scsi_bufflen(srb))
+               scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
 }
index 7c9593b7b04e27da6c21577c18e6c3f907206f07..8c1e2954f3b9e8556601b823bb0238a8ed41b0a6 100644 (file)
@@ -81,6 +81,16 @@ static int slave_alloc (struct scsi_device *sdev)
         */
        sdev->inquiry_len = 36;
 
+       /* Scatter-gather buffers (all but the last) must have a length
+        * divisible by the bulk maxpacket size.  Otherwise a data packet
+        * would end up being short, causing a premature end to the data
+        * transfer.  Since high-speed bulk pipes have a maxpacket size
+        * of 512, we'll use that as the scsi device queue's DMA alignment
+        * mask.  Guaranteeing proper alignment of the first buffer will
+        * have the desired effect because, except at the beginning and
+        * the end, scatter-gather buffers follow page boundaries. */
+       blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
        /*
         * The UFI spec treates the Peripheral Qualifier bits in an
         * INQUIRY result as reserved and requires devices to set them
@@ -100,16 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
 {
        struct us_data *us = host_to_us(sdev->host);
 
-       /* Scatter-gather buffers (all but the last) must have a length
-        * divisible by the bulk maxpacket size.  Otherwise a data packet
-        * would end up being short, causing a premature end to the data
-        * transfer.  Since high-speed bulk pipes have a maxpacket size
-        * of 512, we'll use that as the scsi device queue's DMA alignment
-        * mask.  Guaranteeing proper alignment of the first buffer will
-        * have the desired effect because, except at the beginning and
-        * the end, scatter-gather buffers follow page boundaries. */
-       blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
-
        /* Many devices have trouble transfering more than 32KB at a time,
         * while others have trouble with more than 64K. At this time we
         * are limiting both to 32K (64 sectores).
@@ -187,6 +187,10 @@ static int slave_configure(struct scsi_device *sdev)
                 * automatically, requiring a START-STOP UNIT command. */
                sdev->allow_restart = 1;
 
+               /* Some USB cardreaders have trouble reading an sdcard's last
+                * sector in a larger then 1 sector read, since the performance
+                * impact is negible we set this flag for all USB disks */
+               sdev->last_sector_bug = 1;
        } else {
 
                /* Non-disk-type devices don't need to blacklist any pages
index b12202c5da2d058a074864b4e3f00959ea9e0c24..8972b17da843d219e798199fdb056f8d150714a1 100644 (file)
@@ -1623,7 +1623,7 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       if (srb->request_bufflen == 0)
+       if (scsi_bufflen(srb) == 0)
                return USB_STOR_TRANSPORT_GOOD;
 
        if (srb->sc_data_direction == DMA_TO_DEVICE ||
@@ -1634,12 +1634,9 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
                US_DEBUGP("SDDR09: %s %d bytes\n",
                          (srb->sc_data_direction == DMA_TO_DEVICE) ?
                          "sending" : "receiving",
-                         srb->request_bufflen);
+                         scsi_bufflen(srb));
 
-               result = usb_stor_bulk_transfer_sg(us, pipe,
-                                       srb->request_buffer,
-                                       srb->request_bufflen,
-                                       srb->use_sg, &srb->resid);
+               result = usb_stor_bulk_srb(us, pipe, srb);
 
                return (result == USB_STOR_XFER_GOOD ?
                        USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
index cb22a9ad16943cfbccdef9356651c1fa4f499342..570c1250f6f320e46284e7fa1554875d2d753982 100644 (file)
@@ -130,7 +130,7 @@ static int usbat_write(struct us_data *us,
  * Convenience function to perform a bulk read
  */
 static int usbat_bulk_read(struct us_data *us,
-                          unsigned char *data,
+                          void* buf,
                           unsigned int len,
                           int use_sg)
 {
@@ -138,14 +138,14 @@ static int usbat_bulk_read(struct us_data *us,
                return USB_STOR_XFER_GOOD;
 
        US_DEBUGP("usbat_bulk_read: len = %d\n", len);
-       return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL);
+       return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
 }
 
 /*
  * Convenience function to perform a bulk write
  */
 static int usbat_bulk_write(struct us_data *us,
-                           unsigned char *data,
+                           void* buf,
                            unsigned int len,
                            int use_sg)
 {
@@ -153,7 +153,7 @@ static int usbat_bulk_write(struct us_data *us,
                return USB_STOR_XFER_GOOD;
 
        US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
-       return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL);
+       return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
 }
 
 /*
@@ -314,7 +314,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
  * Read block data from the data register
  */
 static int usbat_read_block(struct us_data *us,
-                           unsigned char *content,
+                           void* buf,
                            unsigned short len,
                            int use_sg)
 {
@@ -337,7 +337,7 @@ static int usbat_read_block(struct us_data *us,
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       result = usbat_bulk_read(us, content, len, use_sg);
+       result = usbat_bulk_read(us, buf, len, use_sg);
        return (result == USB_STOR_XFER_GOOD ?
                        USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
 }
@@ -347,7 +347,7 @@ static int usbat_read_block(struct us_data *us,
  */
 static int usbat_write_block(struct us_data *us,
                             unsigned char access,
-                            unsigned char *content,
+                            void* buf,
                             unsigned short len,
                             int minutes,
                             int use_sg)
@@ -372,7 +372,7 @@ static int usbat_write_block(struct us_data *us,
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       result = usbat_bulk_write(us, content, len, use_sg);
+       result = usbat_bulk_write(us, buf, len, use_sg);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
@@ -392,7 +392,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
                                       unsigned char timeout,
                                       unsigned char qualifier,
                                       int direction,
-                                      unsigned char *content,
+                                      void *buf,
                                       unsigned short len,
                                       int use_sg,
                                       int minutes)
@@ -472,7 +472,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
                }
 
                result = usb_stor_bulk_transfer_sg(us,
-                       pipe, content, len, use_sg, NULL);
+                       pipe, buf, len, use_sg, NULL);
 
                /*
                 * If we get a stall on the bulk download, we'll retry
@@ -606,7 +606,7 @@ static int usbat_multiple_write(struct us_data *us,
  * other related details) are defined beforehand with _set_shuttle_features().
  */
 static int usbat_read_blocks(struct us_data *us,
-                            unsigned char *buffer,
+                            void* buffer,
                             int len,
                             int use_sg)
 {
@@ -648,7 +648,7 @@ static int usbat_read_blocks(struct us_data *us,
  * other related details) are defined beforehand with _set_shuttle_features().
  */
 static int usbat_write_blocks(struct us_data *us,
-                                                         unsigned char *buffer,
+                             void* buffer,
                              int len,
                              int use_sg)
 {
@@ -1170,15 +1170,15 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
        US_DEBUGP("handle_read10: transfersize %d\n",
                srb->transfersize);
 
-       if (srb->request_bufflen < 0x10000) {
+       if (scsi_bufflen(srb) < 0x10000) {
 
                result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
                        registers, data, 19,
                        USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
                        (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
                        DMA_FROM_DEVICE,
-                       srb->request_buffer, 
-                       srb->request_bufflen, srb->use_sg, 1);
+                       scsi_sglist(srb),
+                       scsi_bufflen(srb), scsi_sg_count(srb), 1);
 
                return result;
        }
@@ -1196,7 +1196,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
                len <<= 16;
                len |= data[7+7];
                US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
-               srb->transfersize = srb->request_bufflen/len;
+               srb->transfersize = scsi_bufflen(srb)/len;
        }
 
        if (!srb->transfersize)  {
@@ -1213,7 +1213,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
 
        len = (65535/srb->transfersize) * srb->transfersize;
        US_DEBUGP("Max read is %d bytes\n", len);
-       len = min(len, srb->request_bufflen);
+       len = min(len, scsi_bufflen(srb));
        buffer = kmalloc(len, GFP_NOIO);
        if (buffer == NULL) /* bloody hell! */
                return USB_STOR_TRANSPORT_FAILED;
@@ -1222,10 +1222,10 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
        sector |= short_pack(data[7+5], data[7+4]);
        transferred = 0;
 
-       while (transferred != srb->request_bufflen) {
+       while (transferred != scsi_bufflen(srb)) {
 
-               if (len > srb->request_bufflen - transferred)
-                       len = srb->request_bufflen - transferred;
+               if (len > scsi_bufflen(srb) - transferred)
+                       len = scsi_bufflen(srb) - transferred;
 
                data[3] = len&0xFF;       /* (cylL) = expected length (L) */
                data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
@@ -1261,7 +1261,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
                transferred += len;
                sector += len / srb->transfersize;
 
-       } /* while transferred != srb->request_bufflen */
+       } /* while transferred != scsi_bufflen(srb) */
 
        kfree(buffer);
        return result;
@@ -1429,9 +1429,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
        unsigned char data[32];
        unsigned int len;
        int i;
-       char string[64];
 
-       len = srb->request_bufflen;
+       len = scsi_bufflen(srb);
 
        /* Send A0 (ATA PACKET COMMAND).
           Note: I guess we're never going to get any of the ATA
@@ -1472,8 +1471,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
                        USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
                        (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
                        DMA_TO_DEVICE,
-                       srb->request_buffer, 
-                       len, srb->use_sg, 10);
+                       scsi_sglist(srb),
+                       len, scsi_sg_count(srb), 10);
 
                if (result == USB_STOR_TRANSPORT_GOOD) {
                        transferred += len;
@@ -1540,23 +1539,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
                        len = *status;
 
 
-               result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg);
-
-               /* Debug-print the first 32 bytes of the transfer */
-
-               if (!srb->use_sg) {
-                       string[0] = 0;
-                       for (i=0; i<len && i<32; i++) {
-                               sprintf(string+strlen(string), "%02X ",
-                                 ((unsigned char *)srb->request_buffer)[i]);
-                               if ((i%16)==15) {
-                                       US_DEBUGP("%s\n", string);
-                                       string[0] = 0;
-                               }
-                       }
-                       if (string[0]!=0)
-                               US_DEBUGP("%s\n", string);
-               }
+               result = usbat_read_block(us, scsi_sglist(srb), len,
+                                                          scsi_sg_count(srb));
        }
 
        return result;
index c646750ccc3076ddba7d6f9187c04a3d55da809c..d9f4912f873df0b57bb1b869f48bd09a6486e2ee 100644 (file)
@@ -458,6 +458,22 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
                        us->current_sg.bytes);
 }
 
+/*
+ * Common used function. Transfer a complete command
+ * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid
+ */
+int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+                     struct scsi_cmnd* srb)
+{
+       unsigned int partial;
+       int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
+                                     scsi_sg_count(srb), scsi_bufflen(srb),
+                                     &partial);
+
+       scsi_set_resid(srb, scsi_bufflen(srb) - partial);
+       return result;
+}
+
 /*
  * Transfer an entire SCSI command's worth of data payload over the bulk
  * pipe.
@@ -508,7 +524,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
        int result;
 
        /* send the command to the transport layer */
-       srb->resid = 0;
+       scsi_set_resid(srb, 0);
        result = us->transport(srb, us);
 
        /* if the command gets aborted by the higher layers, we need to
@@ -568,7 +584,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
         * A short transfer on a command where we don't expect it
         * is unusual, but it doesn't mean we need to auto-sense.
         */
-       if ((srb->resid > 0) &&
+       if ((scsi_get_resid(srb) > 0) &&
            !((srb->cmnd[0] == REQUEST_SENSE) ||
              (srb->cmnd[0] == INQUIRY) ||
              (srb->cmnd[0] == MODE_SENSE) ||
@@ -593,7 +609,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
                        srb->cmd_len = 12;
 
                /* issue the auto-sense command */
-               srb->resid = 0;
+               scsi_set_resid(srb, 0);
                temp_result = us->transport(us->srb, us);
 
                /* let's clean up right away */
@@ -649,7 +665,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 
        /* Did we transfer less than the minimum amount required? */
        if (srb->result == SAM_STAT_GOOD &&
-                       srb->request_bufflen - srb->resid < srb->underflow)
+                       scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
                srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
 
        return;
@@ -708,7 +724,7 @@ void usb_stor_stop_transport(struct us_data *us)
 
 int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-       unsigned int transfer_length = srb->request_bufflen;
+       unsigned int transfer_length = scsi_bufflen(srb);
        unsigned int pipe = 0;
        int result;
 
@@ -737,9 +753,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
        if (transfer_length) {
                pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
                                us->recv_bulk_pipe : us->send_bulk_pipe;
-               result = usb_stor_bulk_transfer_sg(us, pipe,
-                                       srb->request_buffer, transfer_length,
-                                       srb->use_sg, &srb->resid);
+               result = usb_stor_bulk_srb(us, pipe, srb);
                US_DEBUGP("CBI data stage result is 0x%x\n", result);
 
                /* if we stalled the data transfer it means command failed */
@@ -808,7 +822,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
  */
 int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-       unsigned int transfer_length = srb->request_bufflen;
+       unsigned int transfer_length = scsi_bufflen(srb);
        int result;
 
        /* COMMAND STAGE */
@@ -836,9 +850,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
        if (transfer_length) {
                unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
                                us->recv_bulk_pipe : us->send_bulk_pipe;
-               result = usb_stor_bulk_transfer_sg(us, pipe,
-                                       srb->request_buffer, transfer_length,
-                                       srb->use_sg, &srb->resid);
+               result = usb_stor_bulk_srb(us, pipe, srb);
                US_DEBUGP("CB data stage result is 0x%x\n", result);
 
                /* if we stalled the data transfer it means command failed */
@@ -904,7 +916,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
        struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
-       unsigned int transfer_length = srb->request_bufflen;
+       unsigned int transfer_length = scsi_bufflen(srb);
        unsigned int residue;
        int result;
        int fake_sense = 0;
@@ -955,9 +967,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
        if (transfer_length) {
                unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
                                us->recv_bulk_pipe : us->send_bulk_pipe;
-               result = usb_stor_bulk_transfer_sg(us, pipe,
-                                       srb->request_buffer, transfer_length,
-                                       srb->use_sg, &srb->resid);
+               result = usb_stor_bulk_srb(us, pipe, srb);
                US_DEBUGP("Bulk data transfer result 0x%x\n", result);
                if (result == USB_STOR_XFER_ERROR)
                        return USB_STOR_TRANSPORT_ERROR;
@@ -1036,7 +1046,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
        if (residue) {
                if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
                        residue = min(residue, transfer_length);
-                       srb->resid = max(srb->resid, (int) residue);
+                       scsi_set_resid(srb, max(scsi_get_resid(srb),
+                                                              (int) residue));
                }
        }
 
index 633a715850a43fe6f7654ee7cb659575b51c4acd..ada7c2f43f8475552d735734f85bfda0a051e95a 100644 (file)
@@ -139,6 +139,8 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
                void *buf, unsigned int length, unsigned int *act_len);
 extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
                void *buf, unsigned int length, int use_sg, int *residual);
+extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+               struct scsi_cmnd* srb);
 
 extern int usb_stor_port_reset(struct us_data *us);
 #endif
index 11a3a222dfc3b7a8a6f59991adf0b0354a2af73d..7c30cc8df71eb057b313a841f3c120ad75ae05dd 100644 (file)
@@ -801,5 +801,5 @@ module_init(atmel_lcdfb_init);
 module_exit(atmel_lcdfb_exit);
 
 MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
-MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
 MODULE_LICENSE("GPL");
index b87ed37ac0c1217c93a14638d0fd73b0d56a04bf..2b53d1f5628107b65d559e97cf5fc8007f41a6df 100644 (file)
@@ -6,7 +6,7 @@ menu "Console display driver support"
 
 config VGA_CONSOLE
        bool "VGA text console" if EMBEDDED || !X86
-       depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN
+       depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32
        default y
        help
          Saying Y here will allow you to use Linux in text mode through a
index 8d81ef019c6c6f8de6a5eeb6013b061de650a649..08d07255223343c13487d31162f009a89e95e172 100644 (file)
@@ -259,6 +259,10 @@ static const struct fb_videomode modedb[] = {
        /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
        NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5,
        0, FB_VMODE_NONINTERLACED
+   }, {
+       /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
+       NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3,
+       0, FB_VMODE_NONINTERLACED
     },
 };
 
index b3128903d67328fdcb5747de418e59b177fe2dc0..044a423a72cbe406e0a5811796b246cb788f1ec3 100644 (file)
@@ -443,8 +443,6 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
        u32 ddr_line_length, xdr_line_length;
        u64 ddr_base, xdr_base;
 
-       acquire_console_sem();
-
        if (frame > par->num_frames - 1) {
                dev_dbg(info->device, "%s: invalid frame number (%u)\n",
                        __func__, frame);
@@ -464,7 +462,6 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
                         xdr_line_length);
 
 out:
-       release_console_sem();
        return error;
 }
 
@@ -479,7 +476,10 @@ static int ps3fb_release(struct fb_info *info, int user)
        if (atomic_dec_and_test(&ps3fb.f_count)) {
                if (atomic_read(&ps3fb.ext_flip)) {
                        atomic_set(&ps3fb.ext_flip, 0);
-                       ps3fb_sync(info, 0);    /* single buffer */
+                       if (!try_acquire_console_sem()) {
+                               ps3fb_sync(info, 0);    /* single buffer */
+                               release_console_sem();
+                       }
                }
        }
        return 0;
@@ -865,7 +865,9 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
 
                dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
+               acquire_console_sem();
                retval = ps3fb_sync(info, val);
+               release_console_sem();
                break;
 
        default:
@@ -885,7 +887,9 @@ static int ps3fbd(void *arg)
                set_current_state(TASK_INTERRUPTIBLE);
                if (ps3fb.is_kicked) {
                        ps3fb.is_kicked = 0;
+                       acquire_console_sem();
                        ps3fb_sync(info, 0);    /* single buffer */
+                       release_console_sem();
                }
                schedule();
        }
@@ -1234,12 +1238,6 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
        ps3fb_flip_ctl(0, &ps3fb);      /* flip off */
        ps3fb.dinfo->irq.mask = 0;
 
-       if (info) {
-               unregister_framebuffer(info);
-               fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
-
        ps3av_register_flip_ctl(NULL, NULL);
        if (ps3fb.task) {
                struct task_struct *task = ps3fb.task;
@@ -1250,6 +1248,12 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
                free_irq(ps3fb.irq_no, &dev->core);
                ps3_irq_plug_destroy(ps3fb.irq_no);
        }
+       if (info) {
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
+               info = dev->core.driver_data = NULL;
+       }
        iounmap((u8 __iomem *)ps3fb.dinfo);
 
        status = lv1_gpu_context_free(ps3fb.context_handle);
index 5857ccf5f6b15208f64a7221405063f280b2d44a..b3c31d9dc591bc1c8e4780e9e086ec5254834a32 100644 (file)
@@ -488,7 +488,7 @@ static int s3c2410fb_set_par(struct fb_info *info)
                break;
        }
 
-       info->fix.line_length = (var->width * var->bits_per_pixel) / 8;
+       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
 
        /* activate this new configuration */
 
@@ -1026,7 +1026,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
        clk_enable(info->clk);
        msleep(1);
 
-       s3c2410fb_init_registers(info);
+       s3c2410fb_init_registers(fbinfo);
 
        return 0;
 }
index d1d6c0facd549737ef290d6325a4f4c29b7901d4..a14ef894d5716e4413affaea26cd59725b752341 100644 (file)
@@ -43,7 +43,7 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
 };
 
 static int mtrr                __devinitdata = 3; /* enable mtrr by default */
-static int blank       __devinitdata = 1; /* enable blanking by default */
+static int blank       = 1;               /* enable blanking by default */
 static int ypan                __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */
 static int pmi_setpal  __devinitdata = 1; /* use PMI for palette changes */
 static int nocrtc      __devinitdata; /* ignore CRTC settings */
@@ -1549,7 +1549,7 @@ static void __devinit uvesafb_init_info(struct fb_info *info,
                info->fbops->fb_pan_display = NULL;
 }
 
-static void uvesafb_init_mtrr(struct fb_info *info)
+static void __devinit uvesafb_init_mtrr(struct fb_info *info)
 {
 #ifdef CONFIG_MTRR
        if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) {
index 4318935678c5f68ad1559e4540f233fc30551a35..112f4ec59035424bc36b7251fcb6367c9bca7f77 100644 (file)
@@ -112,7 +112,7 @@ static struct w1_therm_family_converter w1_therm_families[] = {
 
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 {
-       int t = (rom[1] << 8) | rom[0];
+       s16 t = (rom[1] << 8) | rom[0];
        t /= 16;
        return t;
 }
@@ -204,7 +204,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj,
 
                                crc = w1_calc_crc8(rom, 8);
 
-                               if (rom[8] == crc && rom[0])
+                               if (rom[8] == crc)
                                        verdict = 1;
                        }
                }
index 070217322c9fb30e98b1db28c476bc68b5cdbbef..33e50310e9e02418763188665457b127f4ae7520 100644 (file)
@@ -869,11 +869,9 @@ void w1_search_process(struct w1_master *dev, u8 search_type)
        w1_search_devices(dev, search_type, w1_slave_found);
 
        list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
-               if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
+               if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl)
                        w1_slave_detach(sl);
-
-                       dev->slave_count--;
-               } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
+               else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
                        sl->ttl = dev->slave_ttl;
        }
 
index 52dff40ec192caeea2042f07cb09021914c52c36..fbd61127b9d9942ccd96f1ddcbab383d7d2761a2 100644 (file)
@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG
 
 config AT32AP700X_WDT
        tristate "AT32AP700x watchdog"
-       depends on CPU_AT32AP7000
+       depends on CPU_AT32AP700X
        help
          Watchdog timer embedded into AT32AP700x devices. This will reboot
          your system when the timeout is reached.
index 6ea125eabeaab3777dfc78f683d8eed9d0d9f5e7..c622a0e6c9aed57137b59ab0d1af4aabffefe1dc 100644 (file)
@@ -382,10 +382,8 @@ wdt_init(void)
                /* we will autodetect the W83697HF/HG watchdog */
                for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) {
                        wdt_io = w83697hf_ioports[i];
-                       if (!w83697hf_check_wdt()) {
+                       if (!w83697hf_check_wdt())
                                found++;
-                               break;
-                       }
                }
        } else {
                if (!w83697hf_check_wdt())
index 18cd2214946667080f5c2490a8cb1a92cf5a5e71..9656139d2e990ce8c11e6ed34a2b61182da332ff 100644 (file)
@@ -440,14 +440,8 @@ config OCFS2_FS
          Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
          OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
-         Note: Features which OCFS2 does not support yet:
-                 - extended attributes
-                 - quotas
-                 - cluster aware flock
-                 - Directory change notification (F_NOTIFY)
-                 - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
-                 - POSIX ACLs
-                 - readpages / writepages (not user visible)
+         For more information on OCFS2, see the file
+         <file:Documentation/filesystems/ocfs2.txt>.
 
 config OCFS2_DEBUG_MASKLOG
        bool "OCFS2 logging support"
@@ -1028,8 +1022,8 @@ config HUGETLB_PAGE
        def_bool HUGETLBFS
 
 config CONFIGFS_FS
-       tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
-       depends on SYSFS && EXPERIMENTAL
+       tristate "Userspace-driven configuration filesystem"
+       depends on SYSFS
        help
          configfs is a ram-based filesystem that provides the converse
          of sysfs's functionality. Where sysfs is a filesystem-based
@@ -1112,8 +1106,8 @@ config HFS_FS
        help
          If you say Y here, you will be able to mount Macintosh-formatted
          floppy disks and hard drive partitions with full read-write access.
-         Please read <file:fs/hfs/HFS.txt> to learn about the available mount
-         options.
+         Please read <file:Documentation/filesystems/hfs.txt> to learn about
+         the available mount options.
 
          To compile this file system support as a module, choose M here: the
          module will be called hfs.
@@ -2143,4 +2137,3 @@ source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
 endmenu
-
index ba8de7ca260bea7e0cf456b4a7bfe56434ad502f..f0b3171842f22e75796d2aa68a7713f30af2f111 100644 (file)
@@ -1384,7 +1384,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
        prstatus->pr_sigpend = p->pending.signal.sig[0];
        prstatus->pr_sighold = p->blocked.sig[0];
        prstatus->pr_pid = task_pid_vnr(p);
-       prstatus->pr_ppid = task_pid_vnr(p->parent);
+       prstatus->pr_ppid = task_pid_vnr(p->real_parent);
        prstatus->pr_pgrp = task_pgrp_vnr(p);
        prstatus->pr_sid = task_session_vnr(p);
        if (thread_group_leader(p)) {
@@ -1430,7 +1430,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
        psinfo->pr_psargs[len] = 0;
 
        psinfo->pr_pid = task_pid_vnr(p);
-       psinfo->pr_ppid = task_pid_vnr(p->parent);
+       psinfo->pr_ppid = task_pid_vnr(p->real_parent);
        psinfo->pr_pgrp = task_pgrp_vnr(p);
        psinfo->pr_sid = task_session_vnr(p);
 
index 993f78c55221c4c4083ac72114afceadfafd12fe..e48a630ae266331f2ca7e482e0b8eeeea9f65d6b 100644 (file)
@@ -738,9 +738,9 @@ EXPORT_SYMBOL(bd_release);
 static struct kobject *bdev_get_kobj(struct block_device *bdev)
 {
        if (bdev->bd_contains != bdev)
-               return kobject_get(&bdev->bd_part->kobj);
+               return kobject_get(&bdev->bd_part->dev.kobj);
        else
-               return kobject_get(&bdev->bd_disk->kobj);
+               return kobject_get(&bdev->bd_disk->dev.kobj);
 }
 
 static struct kobject *bdev_get_holder(struct block_device *bdev)
@@ -1176,7 +1176,7 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part)
                                ret = -ENXIO;
                                goto out_first;
                        }
-                       kobject_get(&p->kobj);
+                       kobject_get(&p->dev.kobj);
                        bdev->bd_part = p;
                        bd_set_size(bdev, (loff_t) p->nr_sects << 9);
                }
@@ -1299,7 +1299,7 @@ static int __blkdev_put(struct block_device *bdev, int for_part)
                module_put(owner);
 
                if (bdev->bd_contains != bdev) {
-                       kobject_put(&bdev->bd_part->kobj);
+                       kobject_put(&bdev->bd_part->dev.kobj);
                        bdev->bd_part = NULL;
                }
                bdev->bd_disk = NULL;
index c3bfa76765c45c6c516c467663cdb23e6d08907c..2c7a8b5b45989b25d40f8cb6a283d7ffb8940c5a 100644 (file)
@@ -510,9 +510,8 @@ struct cdev *cdev_alloc(void)
 {
        struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
        if (p) {
-               p->kobj.ktype = &ktype_cdev_dynamic;
                INIT_LIST_HEAD(&p->list);
-               kobject_init(&p->kobj);
+               kobject_init(&p->kobj, &ktype_cdev_dynamic);
        }
        return p;
 }
@@ -529,8 +528,7 @@ void cdev_init(struct cdev *cdev, const struct file_operations *fops)
 {
        memset(cdev, 0, sizeof *cdev);
        INIT_LIST_HEAD(&cdev->list);
-       cdev->kobj.ktype = &ktype_cdev_default;
-       kobject_init(&cdev->kobj);
+       kobject_init(&cdev->kobj, &ktype_cdev_default);
        cdev->ops = fops;
 }
 
index dcc6aead70f5ebd3b7a1337bc292484ccadbdb23..e3eb3556622b6808c6d15515e18e597a0ddc4f5b 100644 (file)
@@ -362,8 +362,8 @@ static int init_coda_psdev(void)
                goto out_chrdev;
        }               
        for (i = 0; i < MAX_CODADEVS; i++)
-               class_device_create(coda_psdev_class, NULL,
-                               MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i);
+               device_create(coda_psdev_class, NULL,
+                             MKDEV(CODA_PSDEV_MAJOR,i), "cfs%d", i);
        coda_sysctl_init();
        goto out;
 
@@ -405,7 +405,7 @@ static int __init init_coda(void)
        return 0;
 out:
        for (i = 0; i < MAX_CODADEVS; i++)
-               class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
+               device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
        class_destroy(coda_psdev_class);
        unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
        coda_sysctl_clean();
@@ -424,7 +424,7 @@ static void __exit exit_coda(void)
                 printk("coda: failed to unregister filesystem\n");
         }
        for (i = 0; i < MAX_CODADEVS; i++)
-               class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
+               device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
        class_destroy(coda_psdev_class);
        unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
        coda_sysctl_clean();
index 15078ce4c04a3b385de62b3a4d4a2ce498ca07b0..5216c3fd751771ab4349753f68395b6daba74063 100644 (file)
@@ -1104,10 +1104,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
        if (ret < 0)
                goto out;
 
-       ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
-       if (ret)
-               goto out;
-
        fnv = NULL;
        if (type == READ) {
                fn = file->f_op->read;
index e8b7c3a98a544922f886cf19631aab5a258ec101..da8cb3b3592c96ade1614ab8e553b5e16597b42a 100644 (file)
@@ -10,6 +10,8 @@
  * ioctls.
  */
 
+#include <linux/joystick.h>
+
 #include <linux/types.h>
 #include <linux/compat.h>
 #include <linux/kernel.h>
@@ -2642,6 +2644,12 @@ COMPATIBLE_IOCTL(VIDEO_SET_ATTRIBUTES)
 COMPATIBLE_IOCTL(VIDEO_GET_SIZE)
 COMPATIBLE_IOCTL(VIDEO_GET_FRAME_RATE)
 
+/* joystick */
+COMPATIBLE_IOCTL(JSIOCGVERSION)
+COMPATIBLE_IOCTL(JSIOCGAXES)
+COMPATIBLE_IOCTL(JSIOCGBUTTONS)
+COMPATIBLE_IOCTL(JSIOCGNAME(0))
+
 /* now things that need handlers */
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
index 50ed691098bc83f6d9058ccb8bc3bbdd142a15d1..a48dc7dd8765399936cd8c1fbd7fe80d7949e68c 100644 (file)
@@ -546,7 +546,7 @@ static int populate_groups(struct config_group *group)
                 * That said, taking our i_mutex is closer to mkdir
                 * emulation, and shouldn't hurt.
                 */
-               mutex_lock(&dentry->d_inode->i_mutex);
+               mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
 
                for (i = 0; group->default_groups[i]; i++) {
                        new_group = group->default_groups[i];
@@ -1405,7 +1405,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
        sd = configfs_sb->s_root->d_fsdata;
        link_group(to_config_group(sd->s_element), group);
 
-       mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
+       mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
+                       I_MUTEX_PARENT);
 
        name.name = group->cg_item.ci_name;
        name.len = strlen(name.name);
index a3658f9a082c691cc11c22de9177e253edbc5cf9..397cb503a180da62a9cbcdc2f0aeb86b81851cc6 100644 (file)
@@ -320,7 +320,7 @@ int configfs_add_file(struct dentry * dir, const struct configfs_attribute * att
        umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
        int error = 0;
 
-       mutex_lock(&dir->d_inode->i_mutex);
+       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL);
        error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
        mutex_unlock(&dir->d_inode->i_mutex);
 
index 3bf0278ea8435cdcb132662bb13fb17a2e78c004..de3b31d0a37d88a44185cb6be1efeefed6bc1cab 100644 (file)
@@ -128,7 +128,7 @@ void configfs_release_fs(void)
 }
 
 
-static decl_subsys(config, NULL, NULL);
+static struct kobject *config_kobj;
 
 static int __init configfs_init(void)
 {
@@ -140,9 +140,8 @@ static int __init configfs_init(void)
        if (!configfs_dir_cachep)
                goto out;
 
-       kobj_set_kset_s(&config_subsys, kernel_subsys);
-       err = subsystem_register(&config_subsys);
-       if (err) {
+       config_kobj = kobject_create_and_add("config", kernel_kobj);
+       if (!config_kobj) {
                kmem_cache_destroy(configfs_dir_cachep);
                configfs_dir_cachep = NULL;
                goto out;
@@ -151,7 +150,7 @@ static int __init configfs_init(void)
        err = register_filesystem(&configfs_fs_type);
        if (err) {
                printk(KERN_ERR "configfs: Unable to register filesystem!\n");
-               subsystem_unregister(&config_subsys);
+               kobject_put(config_kobj);
                kmem_cache_destroy(configfs_dir_cachep);
                configfs_dir_cachep = NULL;
                goto out;
@@ -160,7 +159,7 @@ static int __init configfs_init(void)
        err = configfs_inode_init();
        if (err) {
                unregister_filesystem(&configfs_fs_type);
-               subsystem_unregister(&config_subsys);
+               kobject_put(config_kobj);
                kmem_cache_destroy(configfs_dir_cachep);
                configfs_dir_cachep = NULL;
        }
@@ -171,7 +170,7 @@ out:
 static void __exit configfs_exit(void)
 {
        unregister_filesystem(&configfs_fs_type);
-       subsystem_unregister(&config_subsys);
+       kobject_put(config_kobj);
        kmem_cache_destroy(configfs_dir_cachep);
        configfs_dir_cachep = NULL;
        configfs_inode_exit();
index 6a713b33992f4caedaecb6ba604c47d25e6e6a07..d26e2826ba5b8242ec3a4ad1bcf3b849d64b5a8a 100644 (file)
@@ -426,20 +426,19 @@ exit:
 }
 EXPORT_SYMBOL_GPL(debugfs_rename);
 
-static decl_subsys(debug, NULL, NULL);
+static struct kobject *debug_kobj;
 
 static int __init debugfs_init(void)
 {
        int retval;
 
-       kobj_set_kset_s(&debug_subsys, kernel_subsys);
-       retval = subsystem_register(&debug_subsys);
-       if (retval)
-               return retval;
+       debug_kobj = kobject_create_and_add("debug", kernel_kobj);
+       if (!debug_kobj)
+               return -EINVAL;
 
        retval = register_filesystem(&debug_fs_type);
        if (retval)
-               subsystem_unregister(&debug_subsys);
+               kobject_put(debug_kobj);
        return retval;
 }
 
@@ -447,7 +446,7 @@ static void __exit debugfs_exit(void)
 {
        simple_release_fs(&debugfs_mount, &debugfs_mount_count);
        unregister_filesystem(&debug_fs_type);
-       subsystem_unregister(&debug_subsys);
+       kobject_put(debug_kobj);
 }
 
 core_initcall(debugfs_init);
index 6353a8384520f20190bc5039fc46e6c006ae5d77..5c108c49cb8cd30128d533630cdd3ac72810839d 100644 (file)
@@ -166,26 +166,7 @@ static struct kobj_type dlm_ktype = {
        .release       = lockspace_kobj_release,
 };
 
-static struct kset dlm_kset = {
-       .ktype  = &dlm_ktype,
-};
-
-static int kobject_setup(struct dlm_ls *ls)
-{
-       char lsname[DLM_LOCKSPACE_LEN];
-       int error;
-
-       memset(lsname, 0, DLM_LOCKSPACE_LEN);
-       snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
-
-       error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
-       if (error)
-               return error;
-
-       ls->ls_kobj.kset = &dlm_kset;
-       ls->ls_kobj.ktype = &dlm_ktype;
-       return 0;
-}
+static struct kset *dlm_kset;
 
 static int do_uevent(struct dlm_ls *ls, int in)
 {
@@ -220,24 +201,22 @@ static int do_uevent(struct dlm_ls *ls, int in)
 
 int dlm_lockspace_init(void)
 {
-       int error;
-
        ls_count = 0;
        mutex_init(&ls_lock);
        INIT_LIST_HEAD(&lslist);
        spin_lock_init(&lslist_lock);
 
-       kobject_set_name(&dlm_kset.kobj, "dlm");
-       kobj_set_kset_s(&dlm_kset, kernel_subsys);
-       error = kset_register(&dlm_kset);
-       if (error)
-               printk("dlm_lockspace_init: cannot register kset %d\n", error);
-       return error;
+       dlm_kset = kset_create_and_add("dlm", NULL, kernel_kobj);
+       if (!dlm_kset) {
+               printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+       return 0;
 }
 
 void dlm_lockspace_exit(void)
 {
-       kset_unregister(&dlm_kset);
+       kset_unregister(dlm_kset);
 }
 
 static int dlm_scand(void *data)
@@ -549,13 +528,12 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
                goto out_delist;
        }
 
-       error = kobject_setup(ls);
-       if (error)
-               goto out_stop;
-
-       error = kobject_register(&ls->ls_kobj);
+       ls->ls_kobj.kset = dlm_kset;
+       error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
+                                    "%s", ls->ls_name);
        if (error)
                goto out_stop;
+       kobject_uevent(&ls->ls_kobj, KOBJ_ADD);
 
        /* let kobject handle freeing of ls if there's an error */
        do_unreg = 1;
@@ -601,7 +579,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
        kfree(ls->ls_rsbtbl);
  out_lsfree:
        if (do_unreg)
-               kobject_unregister(&ls->ls_kobj);
+               kobject_put(&ls->ls_kobj);
        else
                kfree(ls);
  out:
@@ -750,7 +728,7 @@ static int release_lockspace(struct dlm_ls *ls, int force)
        dlm_clear_members(ls);
        dlm_clear_members_gone(ls);
        kfree(ls->ls_node_array);
-       kobject_unregister(&ls->ls_kobj);
+       kobject_put(&ls->ls_kobj);
        /* The ls structure will be freed when the kobject is done with */
 
        mutex_lock(&ls_lock);
index 0b1ab016fa2e513589c004373323c376af1de9ba..5a719180983cb36ebf3e264dc45c1559ebc209c0 100644 (file)
@@ -120,22 +120,9 @@ ecryptfs_do_create(struct inode *directory_inode,
        rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
                                             ecryptfs_dentry, mode, nd);
        if (rc) {
-               struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;
-               struct ecryptfs_inode_info *inode_info =
-                       ecryptfs_inode_to_private(ecryptfs_inode);
-
-               printk(KERN_WARNING "%s: Error creating underlying file; "
-                      "rc = [%d]; checking for existing\n", __FUNCTION__, rc);
-               if (inode_info) {
-                       mutex_lock(&inode_info->lower_file_mutex);
-                       if (!inode_info->lower_file) {
-                               mutex_unlock(&inode_info->lower_file_mutex);
-                               printk(KERN_ERR "%s: Failure to set underlying "
-                                      "file; rc = [%d]\n", __FUNCTION__, rc);
-                               goto out_lock;
-                       }
-                       mutex_unlock(&inode_info->lower_file_mutex);
-               }
+               printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
+                      "rc = [%d]\n", __FUNCTION__, rc);
+               goto out_lock;
        }
        rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
                                directory_inode->i_sb, 0);
@@ -451,6 +438,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
        dentry->d_inode->i_nlink =
                ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
        dentry->d_inode->i_ctime = dir->i_ctime;
+       d_drop(dentry);
 out_unlock:
        unlock_parent(lower_dentry);
        return rc;
index e5580bcb923a20e7d86e147f9bb9646b42722d15..0249aa4ae181886cd2a26921a465feb5f8d27d41 100644 (file)
@@ -734,127 +734,40 @@ static int ecryptfs_init_kmem_caches(void)
        return 0;
 }
 
-struct ecryptfs_obj {
-       char *name;
-       struct list_head slot_list;
-       struct kobject kobj;
-};
-
-struct ecryptfs_attribute {
-       struct attribute attr;
-       ssize_t(*show) (struct ecryptfs_obj *, char *);
-       ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
-};
+static struct kobject *ecryptfs_kobj;
 
-static ssize_t
-ecryptfs_attr_store(struct kobject *kobj,
-                   struct attribute *attr, const char *buf, size_t len)
+static ssize_t version_show(struct kobject *kobj,
+                           struct kobj_attribute *attr, char *buff)
 {
-       struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
-                                               kobj);
-       struct ecryptfs_attribute *attribute =
-               container_of(attr, struct ecryptfs_attribute, attr);
-
-       return (attribute->store ? attribute->store(obj, buf, len) : 0);
+       return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
 }
 
-static ssize_t
-ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-       struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
-                                               kobj);
-       struct ecryptfs_attribute *attribute =
-               container_of(attr, struct ecryptfs_attribute, attr);
-
-       return (attribute->show ? attribute->show(obj, buf) : 0);
-}
+static struct kobj_attribute version_attr = __ATTR_RO(version);
 
-static struct sysfs_ops ecryptfs_sysfs_ops = {
-       .show = ecryptfs_attr_show,
-       .store = ecryptfs_attr_store
+static struct attribute *attributes[] = {
+       &version_attr.attr,
+       NULL,
 };
 
-static struct kobj_type ecryptfs_ktype = {
-       .sysfs_ops = &ecryptfs_sysfs_ops
+static struct attribute_group attr_group = {
+       .attrs = attributes,
 };
 
-static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
-
-static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
-{
-       return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
-}
-
-static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
-
-static struct ecryptfs_version_str_map_elem {
-       u32 flag;
-       char *str;
-} ecryptfs_version_str_map[] = {
-       {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
-       {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
-       {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
-       {ECRYPTFS_VERSIONING_POLICY, "policy"},
-       {ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"},
-       {ECRYPTFS_VERSIONING_MULTKEY, "multiple keys per file"}
-};
-
-static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
-{
-       int i;
-       int remaining = PAGE_SIZE;
-       int total_written = 0;
-
-       buff[0] = '\0';
-       for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
-               int entry_size;
-
-               if (!(ECRYPTFS_VERSIONING_MASK
-                     & ecryptfs_version_str_map[i].flag))
-                       continue;
-               entry_size = strlen(ecryptfs_version_str_map[i].str);
-               if ((entry_size + 2) > remaining)
-                       goto out;
-               memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
-               buff[entry_size++] = '\n';
-               buff[entry_size] = '\0';
-               buff += entry_size;
-               total_written += entry_size;
-               remaining -= entry_size;
-       }
-out:
-       return total_written;
-}
-
-static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
-
 static int do_sysfs_registration(void)
 {
        int rc;
 
-       rc = subsystem_register(&ecryptfs_subsys);
-       if (rc) {
-               printk(KERN_ERR
-                      "Unable to register ecryptfs sysfs subsystem\n");
-               goto out;
-       }
-       rc = sysfs_create_file(&ecryptfs_subsys.kobj,
-                              &sysfs_attr_version.attr);
-       if (rc) {
-               printk(KERN_ERR
-                      "Unable to create ecryptfs version attribute\n");
-               subsystem_unregister(&ecryptfs_subsys);
+       ecryptfs_kobj = kobject_create_and_add("ecryptfs", fs_kobj);
+       if (!ecryptfs_kobj) {
+               printk(KERN_ERR "Unable to create ecryptfs kset\n");
+               rc = -ENOMEM;
                goto out;
        }
-       rc = sysfs_create_file(&ecryptfs_subsys.kobj,
-                              &sysfs_attr_version_str.attr);
+       rc = sysfs_create_group(ecryptfs_kobj, &attr_group);
        if (rc) {
                printk(KERN_ERR
-                      "Unable to create ecryptfs version_str attribute\n");
-               sysfs_remove_file(&ecryptfs_subsys.kobj,
-                                 &sysfs_attr_version.attr);
-               subsystem_unregister(&ecryptfs_subsys);
-               goto out;
+                      "Unable to create ecryptfs version attributes\n");
+               kobject_put(ecryptfs_kobj);
        }
 out:
        return rc;
@@ -862,11 +775,8 @@ out:
 
 static void do_sysfs_unregistration(void)
 {
-       sysfs_remove_file(&ecryptfs_subsys.kobj,
-                         &sysfs_attr_version.attr);
-       sysfs_remove_file(&ecryptfs_subsys.kobj,
-                         &sysfs_attr_version_str.attr);
-       subsystem_unregister(&ecryptfs_subsys);
+       sysfs_remove_group(ecryptfs_kobj, &attr_group);
+       kobject_put(ecryptfs_kobj);
 }
 
 static int __init ecryptfs_init(void)
@@ -894,7 +804,6 @@ static int __init ecryptfs_init(void)
                printk(KERN_ERR "Failed to register filesystem\n");
                goto out_free_kmem_caches;
        }
-       kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
        rc = do_sysfs_registration();
        if (rc) {
                printk(KERN_ERR "sysfs registration failed\n");
index f8cdab2bee3d717dee1b1cf5d4db2a512e54bb4e..4859c4eecd654c8b7493f51fec4fee228a9f3d8f 100644 (file)
@@ -86,7 +86,6 @@ static void ecryptfs_destroy_inode(struct inode *inode)
                        fput(inode_info->lower_file);
                        inode_info->lower_file = NULL;
                        d_drop(lower_dentry);
-                       d_delete(lower_dentry);
                }
        }
        mutex_unlock(&inode_info->lower_file_mutex);
index 2c1b73fb82ae29f5a135342c75c2d73fe0d5d931..5fb366992b73dcfdbf6a936c510622087b324444 100644 (file)
@@ -590,21 +590,49 @@ error:
 
 EXPORT_SYMBOL_GPL(fat_free_clusters);
 
+/* 128kb is the whole sectors for FAT12 and FAT16 */
+#define FAT_READA_SIZE         (128 * 1024)
+
+static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
+                         unsigned long reada_blocks)
+{
+       struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+       sector_t blocknr;
+       int i, offset;
+
+       ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
+
+       for (i = 0; i < reada_blocks; i++)
+               sb_breadahead(sb, blocknr + i);
+}
+
 int fat_count_free_clusters(struct super_block *sb)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct fatent_operations *ops = sbi->fatent_ops;
        struct fat_entry fatent;
+       unsigned long reada_blocks, reada_mask, cur_block;
        int err = 0, free;
 
        lock_fat(sbi);
        if (sbi->free_clusters != -1)
                goto out;
 
+       reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits;
+       reada_mask = reada_blocks - 1;
+       cur_block = 0;
+
        free = 0;
        fatent_init(&fatent);
        fatent_set_entry(&fatent, FAT_START_ENT);
        while (fatent.entry < sbi->max_cluster) {
+               /* readahead of fat blocks */
+               if ((cur_block & reada_mask) == 0) {
+                       unsigned long rest = sbi->fat_length - cur_block;
+                       fat_ent_reada(sb, &fatent, min(reada_blocks, rest));
+               }
+               cur_block++;
+
                err = fat_ent_read_block(sb, &fatent);
                if (err)
                        goto out;
index 0fca82021d7652df2d2fc8e1b1f33204e8712651..300324bd563c924ae87c10db7d5171726f8bffc1 100644 (file)
@@ -482,8 +482,6 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
                if (wbc->nr_to_write <= 0)
                        break;
        }
-       if (!list_empty(&sb->s_more_io))
-               wbc->more_io = 1;
        return;         /* Leave any unwritten inodes on s_io */
 }
 
index 84f9f7dfdf5b6bc1162d57ff5bf4f3845e7d743a..e5e80d1a46870dda75135efca29c793860164b15 100644 (file)
@@ -744,9 +744,6 @@ static inline void unregister_fuseblk(void)
 }
 #endif
 
-static decl_subsys(fuse, NULL, NULL);
-static decl_subsys(connections, NULL, NULL);
-
 static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
 {
        struct inode * inode = foo;
@@ -791,32 +788,37 @@ static void fuse_fs_cleanup(void)
        kmem_cache_destroy(fuse_inode_cachep);
 }
 
+static struct kobject *fuse_kobj;
+static struct kobject *connections_kobj;
+
 static int fuse_sysfs_init(void)
 {
        int err;
 
-       kobj_set_kset_s(&fuse_subsys, fs_subsys);
-       err = subsystem_register(&fuse_subsys);
-       if (err)
+       fuse_kobj = kobject_create_and_add("fuse", fs_kobj);
+       if (!fuse_kobj) {
+               err = -ENOMEM;
                goto out_err;
+       }
 
-       kobj_set_kset_s(&connections_subsys, fuse_subsys);
-       err = subsystem_register(&connections_subsys);
-       if (err)
+       connections_kobj = kobject_create_and_add("connections", fuse_kobj);
+       if (!connections_kobj) {
+               err = -ENOMEM;
                goto out_fuse_unregister;
+       }
 
        return 0;
 
  out_fuse_unregister:
-       subsystem_unregister(&fuse_subsys);
+       kobject_put(fuse_kobj);
  out_err:
        return err;
 }
 
 static void fuse_sysfs_cleanup(void)
 {
-       subsystem_unregister(&connections_subsys);
-       subsystem_unregister(&fuse_subsys);
+       kobject_put(connections_kobj);
+       kobject_put(fuse_kobj);
 }
 
 static int __init fuse_init(void)
index 04ad0caebedb40ff302eaf56dbbdd90232d45c83..8fff11058cee5b28e7cd0d4b22843dbd93d6a349 100644 (file)
@@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o
 gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
        glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \
        mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
-       ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \
+       ops_fstype.o ops_inode.o ops_super.o quota.o \
        recovery.o rgrp.o super.o sys.o trans.o util.o
 
 obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/
index 93fa427bb5f501cee6da6ab88afbfd921f584295..e4effc47abfc865f82f71b6855f06521253c25b5 100644 (file)
@@ -59,7 +59,6 @@ struct strip_mine {
 static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
                               u64 block, struct page *page)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct inode *inode = &ip->i_inode;
        struct buffer_head *bh;
        int release = 0;
@@ -95,7 +94,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
        set_buffer_uptodate(bh);
        if (!gfs2_is_jdata(ip))
                mark_buffer_dirty(bh);
-       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+       if (!gfs2_is_writeback(ip))
                gfs2_trans_add_bh(ip->i_gl, bh, 0);
 
        if (release) {
@@ -453,8 +452,8 @@ static inline void bmap_unlock(struct inode *inode, int create)
  * Returns: errno
  */
 
-int gfs2_block_map(struct inode *inode, u64 lblock, int create,
-                  struct buffer_head *bh_map)
+int gfs2_block_map(struct inode *inode, sector_t lblock,
+                  struct buffer_head *bh_map, int create)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -470,6 +469,7 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
        unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
        struct metapath mp;
        u64 size;
+       struct buffer_head *dibh = NULL;
 
        BUG_ON(maxlen == 0);
 
@@ -500,6 +500,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
        error = gfs2_meta_inode_buffer(ip, &bh);
        if (error)
                goto out_fail;
+       dibh = bh;
+       get_bh(dibh);
 
        for (x = 0; x < end_of_metadata; x++) {
                lookup_block(ip, bh, x, &mp, create, &new, &dblock);
@@ -518,13 +520,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
                if (boundary)
                        set_buffer_boundary(bh_map);
                if (new) {
-                       struct buffer_head *dibh;
-                       error = gfs2_meta_inode_buffer(ip, &dibh);
-                       if (!error) {
-                               gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-                               gfs2_dinode_out(ip, dibh->b_data);
-                               brelse(dibh);
-                       }
+                       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+                       gfs2_dinode_out(ip, dibh->b_data);
                        set_buffer_new(bh_map);
                        goto out_brelse;
                }
@@ -545,6 +542,8 @@ out_brelse:
 out_ok:
        error = 0;
 out_fail:
+       if (dibh)
+               brelse(dibh);
        bmap_unlock(inode, create);
        return error;
 }
@@ -560,7 +559,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
        BUG_ON(!new);
 
        bh.b_size = 1 << (inode->i_blkbits + 5);
-       ret = gfs2_block_map(inode, lblock, create, &bh);
+       ret = gfs2_block_map(inode, lblock, &bh, create);
        *extlen = bh.b_size >> inode->i_blkbits;
        *dblock = bh.b_blocknr;
        if (buffer_new(&bh))
@@ -684,7 +683,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        if (metadata)
                revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
 
-       error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);
+       error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
        if (error)
                return error;
 
@@ -786,7 +785,7 @@ out_rg_gunlock:
 out_rlist:
        gfs2_rlist_free(&rlist);
 out:
-       gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);
+       gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
        return error;
 }
 
@@ -879,7 +878,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
 {
        struct inode *inode = mapping->host;
        struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
        loff_t from = inode->i_size;
        unsigned long index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
@@ -911,7 +909,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
        err = 0;
 
        if (!buffer_mapped(bh)) {
-               gfs2_get_block(inode, iblock, bh, 0);
+               gfs2_block_map(inode, iblock, bh, 0);
                /* unmapped? It's a hole - nothing to do */
                if (!buffer_mapped(bh))
                        goto unlock;
@@ -931,7 +929,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
                err = 0;
        }
 
-       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+       if (!gfs2_is_writeback(ip))
                gfs2_trans_add_bh(ip->i_gl, bh, 0);
 
        zero_user_page(page, offset, length, KM_USER0);
@@ -1224,8 +1222,13 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
                do_div(lblock_stop, bsize);
        } else {
                unsigned int shift = sdp->sd_sb.sb_bsize_shift;
+               u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift;
                lblock = offset >> shift;
                lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
+               if (lblock_stop > end_of_file) {
+                       *alloc_required = 1;
+                       return 0;
+               }
        }
 
        for (; lblock < lblock_stop; lblock += extlen) {
index ac2fd04370dc445d4c21925d6ee86ea7942fa8f6..4e6cde2943bd5a7c0ca2f8b0082a79ad1b7418d4 100644 (file)
@@ -15,7 +15,7 @@ struct gfs2_inode;
 struct page;
 
 int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
-int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh);
+int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create);
 int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
 
 int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
index 3731ab0771d511ada7a2e6fbfceecb174b4075ee..e51991947d2cd876c39ba4eea0d8b6b31c838ebe 100644 (file)
@@ -82,56 +82,6 @@ int gfs2_recoverd(void *data)
        return 0;
 }
 
-/**
- * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
- * @sdp: Pointer to GFS2 superblock
- *
- * Also, periodically check to make sure that we're using the most recent
- * journal index.
- */
-
-int gfs2_logd(void *data)
-{
-       struct gfs2_sbd *sdp = data;
-       struct gfs2_holder ji_gh;
-       unsigned long t;
-       int need_flush;
-
-       while (!kthread_should_stop()) {
-               /* Advance the log tail */
-
-               t = sdp->sd_log_flush_time +
-                   gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
-
-               gfs2_ail1_empty(sdp, DIO_ALL);
-               gfs2_log_lock(sdp);
-               need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks);
-               gfs2_log_unlock(sdp);
-               if (need_flush || time_after_eq(jiffies, t)) {
-                       gfs2_log_flush(sdp, NULL);
-                       sdp->sd_log_flush_time = jiffies;
-               }
-
-               /* Check for latest journal index */
-
-               t = sdp->sd_jindex_refresh_time +
-                   gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
-
-               if (time_after_eq(jiffies, t)) {
-                       if (!gfs2_jindex_hold(sdp, &ji_gh))
-                               gfs2_glock_dq_uninit(&ji_gh);
-                       sdp->sd_jindex_refresh_time = jiffies;
-               }
-
-               t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
-               if (freezing(current))
-                       refrigerator();
-               schedule_timeout_interruptible(t);
-       }
-
-       return 0;
-}
-
 /**
  * gfs2_quotad - Write cached quota changes into the quota file
  * @sdp: Pointer to GFS2 superblock
index 0de9b35579555dcaabf74378bd6ee7fc465d971b..4be084fb6a6219356d691e7e857805458005fe5b 100644 (file)
@@ -12,7 +12,6 @@
 
 int gfs2_glockd(void *data);
 int gfs2_recoverd(void *data);
-int gfs2_logd(void *data);
 int gfs2_quotad(void *data);
 
 #endif /* __DAEMON_DOT_H__ */
index 9949bb746a52e2b0975c466e1b2bd9fe6b963766..57e2ed932adc1d910120d7d6c618210dfb20141f 100644 (file)
@@ -1876,7 +1876,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
        if (error)
                goto out;
 
-       error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);
+       error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
        if (error)
                goto out_qs;
 
@@ -1949,7 +1949,7 @@ out_rg_gunlock:
        gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
 out_rlist:
        gfs2_rlist_free(&rlist);
-       gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);
+       gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
 out_qs:
        gfs2_quota_unhold(dip);
 out:
index aa8dbf303f6d57185c83f40dc270759390fd0642..f114ba2b3557b780dbcde834502da0abd39a3852 100644 (file)
@@ -56,46 +56,6 @@ unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
        return type;
 }
 
-static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
-{
-       struct inode *inode = &ip->i_inode;
-       int error = permission(inode, MAY_READ, NULL);
-       if (error)
-               return error;
-
-       return gfs2_ea_get_i(ip, er);
-}
-
-static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
-{
-       struct inode *inode = &ip->i_inode;
-
-       if (S_ISREG(inode->i_mode) ||
-           (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
-               int error = permission(inode, MAY_WRITE, NULL);
-               if (error)
-                       return error;
-       } else
-               return -EPERM;
-
-       return gfs2_ea_set_i(ip, er);
-}
-
-static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
-{
-       struct inode *inode = &ip->i_inode;
-
-       if (S_ISREG(inode->i_mode) ||
-           (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
-               int error = permission(inode, MAY_WRITE, NULL);
-               if (error)
-                       return error;
-       } else
-               return -EPERM;
-
-       return gfs2_ea_remove_i(ip, er);
-}
-
 static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
 {
        if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
@@ -108,8 +68,6 @@ static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
             GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
                return -EOPNOTSUPP;
 
-
-
        return gfs2_ea_get_i(ip, er);
 }
 
@@ -170,40 +128,10 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
        return gfs2_ea_remove_i(ip, er);
 }
 
-static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
-{
-       struct inode *inode = &ip->i_inode;
-       int error = permission(inode, MAY_READ, NULL);
-       if (error)
-               return error;
-
-       return gfs2_ea_get_i(ip, er);
-}
-
-static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
-{
-       struct inode *inode = &ip->i_inode;
-       int error = permission(inode, MAY_WRITE, NULL);
-       if (error)
-               return error;
-
-       return gfs2_ea_set_i(ip, er);
-}
-
-static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
-{
-       struct inode *inode = &ip->i_inode;
-       int error = permission(inode, MAY_WRITE, NULL);
-       if (error)
-               return error;
-
-       return gfs2_ea_remove_i(ip, er);
-}
-
 static const struct gfs2_eattr_operations gfs2_user_eaops = {
-       .eo_get = user_eo_get,
-       .eo_set = user_eo_set,
-       .eo_remove = user_eo_remove,
+       .eo_get = gfs2_ea_get_i,
+       .eo_set = gfs2_ea_set_i,
+       .eo_remove = gfs2_ea_remove_i,
        .eo_name = "user",
 };
 
@@ -215,9 +143,9 @@ const struct gfs2_eattr_operations gfs2_system_eaops = {
 };
 
 static const struct gfs2_eattr_operations gfs2_security_eaops = {
-       .eo_get = security_eo_get,
-       .eo_set = security_eo_set,
-       .eo_remove = security_eo_remove,
+       .eo_get = gfs2_ea_get_i,
+       .eo_set = gfs2_ea_set_i,
+       .eo_remove = gfs2_ea_remove_i,
        .eo_name = "security",
 };
 
index 2a7435b5c4dc54442fd464d2053742bea923a56d..bee99704ea10b55f49f8bdcdfb17cb69aac63649 100644 (file)
@@ -1418,7 +1418,7 @@ out:
 static int ea_dealloc_block(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_rgrpd *rgd;
        struct buffer_head *dibh;
        int error;
index a37efe4aae6f37d4812be6490e3379e129658c31..80e09c50590a52ed1a6e77c47ea59459da4b1bde 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -217,7 +217,6 @@ int gfs2_glock_put(struct gfs2_glock *gl)
        if (atomic_dec_and_test(&gl->gl_ref)) {
                hlist_del(&gl->gl_list);
                write_unlock(gl_lock_addr(gl->gl_hash));
-               BUG_ON(spin_is_locked(&gl->gl_spin));
                gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
                gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
                gfs2_assert(sdp, list_empty(&gl->gl_holders));
@@ -346,7 +345,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl->gl_object = NULL;
        gl->gl_sbd = sdp;
        gl->gl_aspace = NULL;
-       lops_init_le(&gl->gl_le, &gfs2_glock_lops);
        INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
 
        /* If this glock protects actual on-disk data or metadata blocks,
@@ -461,7 +459,6 @@ static void wait_on_holder(struct gfs2_holder *gh)
 
 static void gfs2_demote_wake(struct gfs2_glock *gl)
 {
-       BUG_ON(!spin_is_locked(&gl->gl_spin));
        gl->gl_demote_state = LM_ST_EXCLUSIVE;
         clear_bit(GLF_DEMOTE, &gl->gl_flags);
         smp_mb__after_clear_bit();
@@ -507,21 +504,12 @@ static int rq_mutex(struct gfs2_holder *gh)
 static int rq_promote(struct gfs2_holder *gh)
 {
        struct gfs2_glock *gl = gh->gh_gl;
-       struct gfs2_sbd *sdp = gl->gl_sbd;
 
        if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
                if (list_empty(&gl->gl_holders)) {
                        gl->gl_req_gh = gh;
                        set_bit(GLF_LOCK, &gl->gl_flags);
                        spin_unlock(&gl->gl_spin);
-
-                       if (atomic_read(&sdp->sd_reclaim_count) >
-                           gfs2_tune_get(sdp, gt_reclaim_limit) &&
-                           !(gh->gh_flags & LM_FLAG_PRIORITY)) {
-                               gfs2_reclaim_glock(sdp);
-                               gfs2_reclaim_glock(sdp);
-                       }
-
                        gfs2_glock_xmote_th(gh->gh_gl, gh);
                        spin_lock(&gl->gl_spin);
                }
@@ -567,7 +555,10 @@ static int rq_demote(struct gfs2_glock *gl)
                gfs2_demote_wake(gl);
                return 0;
        }
+
        set_bit(GLF_LOCK, &gl->gl_flags);
+       set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
+
        if (gl->gl_demote_state == LM_ST_UNLOCKED ||
            gl->gl_state != LM_ST_EXCLUSIVE) {
                spin_unlock(&gl->gl_spin);
@@ -576,7 +567,9 @@ static int rq_demote(struct gfs2_glock *gl)
                spin_unlock(&gl->gl_spin);
                gfs2_glock_xmote_th(gl, NULL);
        }
+
        spin_lock(&gl->gl_spin);
+       clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
 
        return 0;
 }
@@ -598,23 +591,18 @@ static void run_queue(struct gfs2_glock *gl)
                if (!list_empty(&gl->gl_waiters1)) {
                        gh = list_entry(gl->gl_waiters1.next,
                                        struct gfs2_holder, gh_list);
-
-                       if (test_bit(HIF_MUTEX, &gh->gh_iflags))
-                               blocked = rq_mutex(gh);
-                       else
-                               gfs2_assert_warn(gl->gl_sbd, 0);
-
+                       blocked = rq_mutex(gh);
                } else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
                        blocked = rq_demote(gl);
+                       if (gl->gl_waiters2 && !blocked) {
+                               set_bit(GLF_DEMOTE, &gl->gl_flags);
+                               gl->gl_demote_state = LM_ST_UNLOCKED;
+                       }
+                       gl->gl_waiters2 = 0;
                } else if (!list_empty(&gl->gl_waiters3)) {
                        gh = list_entry(gl->gl_waiters3.next,
                                        struct gfs2_holder, gh_list);
-
-                       if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
-                               blocked = rq_promote(gh);
-                       else
-                               gfs2_assert_warn(gl->gl_sbd, 0);
-
+                       blocked = rq_promote(gh);
                } else
                        break;
 
@@ -632,27 +620,21 @@ static void run_queue(struct gfs2_glock *gl)
 
 static void gfs2_glmutex_lock(struct gfs2_glock *gl)
 {
-       struct gfs2_holder gh;
-
-       gfs2_holder_init(gl, 0, 0, &gh);
-       set_bit(HIF_MUTEX, &gh.gh_iflags);
-       if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
-               BUG();
-
        spin_lock(&gl->gl_spin);
        if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
+               struct gfs2_holder gh;
+
+               gfs2_holder_init(gl, 0, 0, &gh);
+               set_bit(HIF_WAIT, &gh.gh_iflags);
                list_add_tail(&gh.gh_list, &gl->gl_waiters1);
+               spin_unlock(&gl->gl_spin);
+               wait_on_holder(&gh);
+               gfs2_holder_uninit(&gh);
        } else {
                gl->gl_owner_pid = current->pid;
                gl->gl_ip = (unsigned long)__builtin_return_address(0);
-               clear_bit(HIF_WAIT, &gh.gh_iflags);
-               smp_mb();
-               wake_up_bit(&gh.gh_iflags, HIF_WAIT);
+               spin_unlock(&gl->gl_spin);
        }
-       spin_unlock(&gl->gl_spin);
-
-       wait_on_holder(&gh);
-       gfs2_holder_uninit(&gh);
 }
 
 /**
@@ -691,7 +673,6 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
        gl->gl_owner_pid = 0;
        gl->gl_ip = 0;
        run_queue(gl);
-       BUG_ON(!spin_is_locked(&gl->gl_spin));
        spin_unlock(&gl->gl_spin);
 }
 
@@ -722,7 +703,10 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
                }
        } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
                        gl->gl_demote_state != state) {
-               gl->gl_demote_state = LM_ST_UNLOCKED;
+               if (test_bit(GLF_DEMOTE_IN_PROGRESS,  &gl->gl_flags)) 
+                       gl->gl_waiters2 = 1;
+               else 
+                       gl->gl_demote_state = LM_ST_UNLOCKED;
        }
        spin_unlock(&gl->gl_spin);
 }
@@ -943,8 +927,8 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl)
        const struct gfs2_glock_operations *glops = gl->gl_ops;
        unsigned int ret;
 
-       if (glops->go_drop_th)
-               glops->go_drop_th(gl);
+       if (glops->go_xmote_th)
+               glops->go_xmote_th(gl);
 
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
        gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
@@ -1156,8 +1140,6 @@ restart:
                return -EIO;
        }
 
-       set_bit(HIF_PROMOTE, &gh->gh_iflags);
-
        spin_lock(&gl->gl_spin);
        add_to_queue(gh);
        run_queue(gl);
@@ -1248,12 +1230,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
        list_del_init(&gh->gh_list);
 
        if (list_empty(&gl->gl_holders)) {
-               spin_unlock(&gl->gl_spin);
-
-               if (glops->go_unlock)
+               if (glops->go_unlock) {
+                       spin_unlock(&gl->gl_spin);
                        glops->go_unlock(gh);
-
-               spin_lock(&gl->gl_spin);
+                       spin_lock(&gl->gl_spin);
+               }
                gl->gl_stamp = jiffies;
        }
 
@@ -1910,8 +1891,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
        print_dbg(gi, "  req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
        print_dbg(gi, "  lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
        print_dbg(gi, "  object = %s\n", (gl->gl_object) ? "yes" : "no");
-       print_dbg(gi, "  le = %s\n",
-                  (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
        print_dbg(gi, "  reclaim = %s\n",
                   (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
        if (gl->gl_aspace)
index 4670dcb2a87734b12643e11991b817de454693a4..c663b7a0f410a3c9c2a6c2136a722be8cf429b09 100644 (file)
@@ -56,7 +56,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
                bd = list_entry(head->next, struct gfs2_bufdata,
                                bd_ail_gl_list);
                bh = bd->bd_bh;
-               gfs2_remove_from_ail(NULL, bd);
+               gfs2_remove_from_ail(bd);
                bd->bd_bh = NULL;
                bh->b_private = NULL;
                bd->bd_blkno = bh->b_blocknr;
@@ -86,15 +86,10 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
        if (!ip || !S_ISREG(inode->i_mode))
                return;
 
-       if (!test_bit(GIF_PAGED, &ip->i_flags))
-               return;
-
        unmap_shared_mapping_range(inode->i_mapping, 0, 0);
-
        if (test_bit(GIF_SW_PAGED, &ip->i_flags))
                set_bit(GLF_DIRTY, &gl->gl_flags);
 
-       clear_bit(GIF_SW_PAGED, &ip->i_flags);
 }
 
 /**
@@ -143,43 +138,33 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
 static void inode_go_sync(struct gfs2_glock *gl)
 {
        struct gfs2_inode *ip = gl->gl_object;
+       struct address_space *metamapping = gl->gl_aspace->i_mapping;
+       int error;
+
+       if (gl->gl_state != LM_ST_UNLOCKED)
+               gfs2_pte_inval(gl);
+       if (gl->gl_state != LM_ST_EXCLUSIVE)
+               return;
 
        if (ip && !S_ISREG(ip->i_inode.i_mode))
                ip = NULL;
 
        if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
-               if (ip && !gfs2_is_jdata(ip))
-                       filemap_fdatawrite(ip->i_inode.i_mapping);
                gfs2_log_flush(gl->gl_sbd, gl);
-               if (ip && gfs2_is_jdata(ip))
-                       filemap_fdatawrite(ip->i_inode.i_mapping);
-               gfs2_meta_sync(gl);
+               filemap_fdatawrite(metamapping);
                if (ip) {
                        struct address_space *mapping = ip->i_inode.i_mapping;
-                       int error = filemap_fdatawait(mapping);
+                       filemap_fdatawrite(mapping);
+                       error = filemap_fdatawait(mapping);
                        mapping_set_error(mapping, error);
                }
+               error = filemap_fdatawait(metamapping);
+               mapping_set_error(metamapping, error);
                clear_bit(GLF_DIRTY, &gl->gl_flags);
                gfs2_ail_empty_gl(gl);
        }
 }
 
-/**
- * inode_go_xmote_th - promote/demote a glock
- * @gl: the glock
- * @state: the requested state
- * @flags:
- *
- */
-
-static void inode_go_xmote_th(struct gfs2_glock *gl)
-{
-       if (gl->gl_state != LM_ST_UNLOCKED)
-               gfs2_pte_inval(gl);
-       if (gl->gl_state == LM_ST_EXCLUSIVE)
-               inode_go_sync(gl);
-}
-
 /**
  * inode_go_xmote_bh - After promoting/demoting a glock
  * @gl: the glock
@@ -200,22 +185,6 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl)
        }
 }
 
-/**
- * inode_go_drop_th - unlock a glock
- * @gl: the glock
- *
- * Invoked from rq_demote().
- * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long)
- * is being purged from our node's glock cache; we're dropping lock.
- */
-
-static void inode_go_drop_th(struct gfs2_glock *gl)
-{
-       gfs2_pte_inval(gl);
-       if (gl->gl_state == LM_ST_EXCLUSIVE)
-               inode_go_sync(gl);
-}
-
 /**
  * inode_go_inval - prepare a inode glock to be released
  * @gl: the glock
@@ -234,10 +203,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
                        set_bit(GIF_INVALID, &ip->i_flags);
        }
 
-       if (ip && S_ISREG(ip->i_inode.i_mode)) {
+       if (ip && S_ISREG(ip->i_inode.i_mode))
                truncate_inode_pages(ip->i_inode.i_mapping, 0);
-               clear_bit(GIF_PAGED, &ip->i_flags);
-       }
 }
 
 /**
@@ -293,23 +260,6 @@ static int inode_go_lock(struct gfs2_holder *gh)
        return error;
 }
 
-/**
- * inode_go_unlock - operation done before an inode lock is unlocked by a
- *                  process
- * @gl: the glock
- * @flags:
- *
- */
-
-static void inode_go_unlock(struct gfs2_holder *gh)
-{
-       struct gfs2_glock *gl = gh->gh_gl;
-       struct gfs2_inode *ip = gl->gl_object;
-
-       if (ip)
-               gfs2_meta_cache_flush(ip);
-}
-
 /**
  * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
  * @gl: the glock
@@ -350,14 +300,14 @@ static void rgrp_go_unlock(struct gfs2_holder *gh)
 }
 
 /**
- * trans_go_xmote_th - promote/demote the transaction glock
+ * trans_go_sync - promote/demote the transaction glock
  * @gl: the glock
  * @state: the requested state
  * @flags:
  *
  */
 
-static void trans_go_xmote_th(struct gfs2_glock *gl)
+static void trans_go_sync(struct gfs2_glock *gl)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
 
@@ -384,7 +334,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl)
 
        if (gl->gl_state != LM_ST_UNLOCKED &&
            test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
-               gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode));
                j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
 
                error = gfs2_find_jhead(sdp->sd_jdesc, &head);
@@ -401,24 +350,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl)
        }
 }
 
-/**
- * trans_go_drop_th - unlock the transaction glock
- * @gl: the glock
- *
- * We want to sync the device even with localcaching.  Remember
- * that localcaching journal replay only marks buffers dirty.
- */
-
-static void trans_go_drop_th(struct gfs2_glock *gl)
-{
-       struct gfs2_sbd *sdp = gl->gl_sbd;
-
-       if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
-               gfs2_meta_syncfs(sdp);
-               gfs2_log_shutdown(sdp);
-       }
-}
-
 /**
  * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
  * @gl: the glock
@@ -433,25 +364,21 @@ static int quota_go_demote_ok(struct gfs2_glock *gl)
 
 const struct gfs2_glock_operations gfs2_meta_glops = {
        .go_xmote_th = meta_go_sync,
-       .go_drop_th = meta_go_sync,
        .go_type = LM_TYPE_META,
 };
 
 const struct gfs2_glock_operations gfs2_inode_glops = {
-       .go_xmote_th = inode_go_xmote_th,
+       .go_xmote_th = inode_go_sync,
        .go_xmote_bh = inode_go_xmote_bh,
-       .go_drop_th = inode_go_drop_th,
        .go_inval = inode_go_inval,
        .go_demote_ok = inode_go_demote_ok,
        .go_lock = inode_go_lock,
-       .go_unlock = inode_go_unlock,
        .go_type = LM_TYPE_INODE,
        .go_min_hold_time = HZ / 10,
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
        .go_xmote_th = meta_go_sync,
-       .go_drop_th = meta_go_sync,
        .go_inval = meta_go_inval,
        .go_demote_ok = rgrp_go_demote_ok,
        .go_lock = rgrp_go_lock,
@@ -461,9 +388,8 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
 };
 
 const struct gfs2_glock_operations gfs2_trans_glops = {
-       .go_xmote_th = trans_go_xmote_th,
+       .go_xmote_th = trans_go_sync,
        .go_xmote_bh = trans_go_xmote_bh,
-       .go_drop_th = trans_go_drop_th,
        .go_type = LM_TYPE_NONDISK,
 };
 
index eaddfb5a8e6fe103c792a1f8c0c0dee411a4421b..513aaf0dc0ab5b6bbba7d10e9567d40cf33515c7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -131,7 +131,6 @@ struct gfs2_bufdata {
 struct gfs2_glock_operations {
        void (*go_xmote_th) (struct gfs2_glock *gl);
        void (*go_xmote_bh) (struct gfs2_glock *gl);
-       void (*go_drop_th) (struct gfs2_glock *gl);
        void (*go_inval) (struct gfs2_glock *gl, int flags);
        int (*go_demote_ok) (struct gfs2_glock *gl);
        int (*go_lock) (struct gfs2_holder *gh);
@@ -141,10 +140,6 @@ struct gfs2_glock_operations {
 };
 
 enum {
-       /* Actions */
-       HIF_MUTEX               = 0,
-       HIF_PROMOTE             = 1,
-
        /* States */
        HIF_HOLDER              = 6,
        HIF_FIRST               = 7,
@@ -171,6 +166,8 @@ enum {
        GLF_DEMOTE              = 3,
        GLF_PENDING_DEMOTE      = 4,
        GLF_DIRTY               = 5,
+       GLF_DEMOTE_IN_PROGRESS  = 6,
+       GLF_LFLUSH              = 7,
 };
 
 struct gfs2_glock {
@@ -190,6 +187,7 @@ struct gfs2_glock {
        struct list_head gl_holders;
        struct list_head gl_waiters1;   /* HIF_MUTEX */
        struct list_head gl_waiters3;   /* HIF_PROMOTE */
+       int gl_waiters2;                /* GIF_DEMOTE */
 
        const struct gfs2_glock_operations *gl_ops;
 
@@ -210,7 +208,6 @@ struct gfs2_glock {
        struct gfs2_sbd *gl_sbd;
 
        struct inode *gl_aspace;
-       struct gfs2_log_element gl_le;
        struct list_head gl_ail_list;
        atomic_t gl_ail_count;
        struct delayed_work gl_work;
@@ -239,7 +236,6 @@ struct gfs2_alloc {
 enum {
        GIF_INVALID             = 0,
        GIF_QD_LOCKED           = 1,
-       GIF_PAGED               = 2,
        GIF_SW_PAGED            = 3,
 };
 
@@ -268,14 +264,10 @@ struct gfs2_inode {
        struct gfs2_glock *i_gl; /* Move into i_gh? */
        struct gfs2_holder i_iopen_gh;
        struct gfs2_holder i_gh; /* for prepare/commit_write only */
-       struct gfs2_alloc i_alloc;
+       struct gfs2_alloc *i_alloc;
        u64 i_last_rg_alloc;
 
-       spinlock_t i_spin;
        struct rw_semaphore i_rw_mutex;
-       unsigned long i_last_pfault;
-
-       struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
 };
 
 /*
@@ -287,19 +279,12 @@ static inline struct gfs2_inode *GFS2_I(struct inode *inode)
        return container_of(inode, struct gfs2_inode, i_inode);
 }
 
-/* To be removed? */
-static inline struct gfs2_sbd *GFS2_SB(struct inode *inode)
+static inline struct gfs2_sbd *GFS2_SB(const struct inode *inode)
 {
        return inode->i_sb->s_fs_info;
 }
 
-enum {
-       GFF_DID_DIRECT_ALLOC    = 0,
-       GFF_EXLOCK = 1,
-};
-
 struct gfs2_file {
-       unsigned long f_flags;          /* GFF_... */
        struct mutex f_fl_mutex;
        struct gfs2_holder f_fl_gh;
 };
@@ -373,8 +358,17 @@ struct gfs2_ail {
        u64 ai_sync_gen;
 };
 
+struct gfs2_journal_extent {
+       struct list_head extent_list;
+
+       unsigned int lblock; /* First logical block */
+       u64 dblock; /* First disk block */
+       u64 blocks;
+};
+
 struct gfs2_jdesc {
        struct list_head jd_list;
+       struct list_head extent_list;
 
        struct inode *jd_inode;
        unsigned int jd_jid;
@@ -421,13 +415,9 @@ struct gfs2_args {
 struct gfs2_tune {
        spinlock_t gt_spin;
 
-       unsigned int gt_ilimit;
-       unsigned int gt_ilimit_tries;
-       unsigned int gt_ilimit_min;
        unsigned int gt_demote_secs; /* Cache retention for unheld glock */
        unsigned int gt_incore_log_blocks;
        unsigned int gt_log_flush_secs;
-       unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
 
        unsigned int gt_recoverd_secs;
        unsigned int gt_logd_secs;
@@ -443,10 +433,8 @@ struct gfs2_tune {
        unsigned int gt_new_files_jdata;
        unsigned int gt_new_files_directio;
        unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
-       unsigned int gt_lockdump_size;
        unsigned int gt_stall_secs; /* Detects trouble! */
        unsigned int gt_complain_secs;
-       unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
        unsigned int gt_statfs_quantum;
        unsigned int gt_statfs_slow;
 };
@@ -539,7 +527,6 @@ struct gfs2_sbd {
        /* StatFS stuff */
 
        spinlock_t sd_statfs_spin;
-       struct mutex sd_statfs_mutex;
        struct gfs2_statfs_change_host sd_statfs_master;
        struct gfs2_statfs_change_host sd_statfs_local;
        unsigned long sd_statfs_sync_time;
@@ -602,20 +589,18 @@ struct gfs2_sbd {
        unsigned int sd_log_commited_databuf;
        unsigned int sd_log_commited_revoke;
 
-       unsigned int sd_log_num_gl;
        unsigned int sd_log_num_buf;
        unsigned int sd_log_num_revoke;
        unsigned int sd_log_num_rg;
        unsigned int sd_log_num_databuf;
 
-       struct list_head sd_log_le_gl;
        struct list_head sd_log_le_buf;
        struct list_head sd_log_le_revoke;
        struct list_head sd_log_le_rg;
        struct list_head sd_log_le_databuf;
        struct list_head sd_log_le_ordered;
 
-       unsigned int sd_log_blks_free;
+       atomic_t sd_log_blks_free;
        struct mutex sd_log_reserve_mutex;
 
        u64 sd_log_sequence;
index 5f6dc32946cd09c795ef5bf7226e6aadfe4942e8..728d3169e7bd5b32b112bf29852d52c394ef6915 100644 (file)
@@ -31,7 +31,6 @@
 #include "log.h"
 #include "meta_io.h"
 #include "ops_address.h"
-#include "ops_file.h"
 #include "ops_inode.h"
 #include "quota.h"
 #include "rgrp.h"
@@ -132,15 +131,21 @@ static struct inode *gfs2_iget_skip(struct super_block *sb,
 
 void gfs2_set_iop(struct inode *inode)
 {
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        umode_t mode = inode->i_mode;
 
        if (S_ISREG(mode)) {
                inode->i_op = &gfs2_file_iops;
-               inode->i_fop = &gfs2_file_fops;
-               inode->i_mapping->a_ops = &gfs2_file_aops;
+               if (sdp->sd_args.ar_localflocks)
+                       inode->i_fop = &gfs2_file_fops_nolock;
+               else
+                       inode->i_fop = &gfs2_file_fops;
        } else if (S_ISDIR(mode)) {
                inode->i_op = &gfs2_dir_iops;
-               inode->i_fop = &gfs2_dir_fops;
+               if (sdp->sd_args.ar_localflocks)
+                       inode->i_fop = &gfs2_dir_fops_nolock;
+               else
+                       inode->i_fop = &gfs2_dir_fops;
        } else if (S_ISLNK(mode)) {
                inode->i_op = &gfs2_symlink_iops;
        } else {
@@ -291,12 +296,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
        di->di_entries = be32_to_cpu(str->di_entries);
 
        di->di_eattr = be64_to_cpu(str->di_eattr);
-       return 0;
-}
+       if (S_ISREG(ip->i_inode.i_mode))
+               gfs2_set_aops(&ip->i_inode);
 
-static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh)
-{
-       ip->i_cache[0] = bh;
+       return 0;
 }
 
 /**
@@ -366,7 +369,8 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip)
        if (error)
                goto out_rg_gunlock;
 
-       gfs2_trans_add_gl(ip->i_gl);
+       set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
+       set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags);
 
        gfs2_free_di(rgd, ip);
 
@@ -707,9 +711,10 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        int error;
 
-       gfs2_alloc_get(dip);
+       if (gfs2_alloc_get(dip) == NULL)
+               return -ENOMEM;
 
-       dip->i_alloc.al_requested = RES_DINODE;
+       dip->i_alloc->al_requested = RES_DINODE;
        error = gfs2_inplace_reserve(dip);
        if (error)
                goto out;
@@ -855,7 +860,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
 
        error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
        if (alloc_required < 0)
-               goto fail;
+               goto fail_quota_locks;
        if (alloc_required) {
                error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid);
                if (error)
@@ -896,7 +901,7 @@ fail_end_trans:
        gfs2_trans_end(sdp);
 
 fail_ipreserv:
-       if (dip->i_alloc.al_rgd)
+       if (dip->i_alloc->al_rgd)
                gfs2_inplace_release(dip);
 
 fail_quota_locks:
@@ -966,7 +971,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
        int error;
        u64 generation;
-       struct buffer_head *bh=NULL;
+       struct buffer_head *bh = NULL;
 
        if (!name->len || name->len > GFS2_FNAMESIZE)
                return ERR_PTR(-ENAMETOOLONG);
@@ -1003,8 +1008,6 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        if (IS_ERR(inode))
                goto fail_gunlock2;
 
-       gfs2_inode_bh(GFS2_I(inode), bh);
-
        error = gfs2_inode_refresh(GFS2_I(inode));
        if (error)
                goto fail_gunlock2;
@@ -1021,6 +1024,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        if (error)
                goto fail_gunlock2;
 
+       if (bh)
+               brelse(bh);
        if (!inode)
                return ERR_PTR(-ENOMEM);
        return inode;
@@ -1032,6 +1037,8 @@ fail_gunlock2:
 fail_gunlock:
        gfs2_glock_dq(ghs);
 fail:
+       if (bh)
+               brelse(bh);
        return ERR_PTR(error);
 }
 
index 351ac87ab384e263f6fd71b4f5ede70a484b9e48..d446506626153989e459195fc12afd506881af5f 100644 (file)
@@ -20,6 +20,18 @@ static inline int gfs2_is_jdata(const struct gfs2_inode *ip)
        return ip->i_di.di_flags & GFS2_DIF_JDATA;
 }
 
+static inline int gfs2_is_writeback(const struct gfs2_inode *ip)
+{
+       const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       return (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK) && !gfs2_is_jdata(ip);
+}
+
+static inline int gfs2_is_ordered(const struct gfs2_inode *ip)
+{
+       const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       return (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) && !gfs2_is_jdata(ip);
+}
+
 static inline int gfs2_is_dir(const struct gfs2_inode *ip)
 {
        return S_ISDIR(ip->i_inode.i_mode);
index 41c5b04caaba4194712fe955a76750462066d4b2..f2efff424224dd3e0052284076e679d067e48ad8 100644 (file)
@@ -67,6 +67,11 @@ static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
        memset(data, 0, 256);
        strncpy(data, data_arg, 255);
 
+       if (!strlen(data)) {
+               log_error("no mount options, (u)mount helpers not installed");
+               return -EINVAL;
+       }
+
        for (options = data; (x = strsep(&options, ":")); ) {
                if (!*x)
                        continue;
index 1f7b038530b4f3df924121395b02c522d770b255..2ebd374b3143f1f04e2c620bf3bc0fdc8d38fa92 100644 (file)
@@ -89,15 +89,19 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
        op->info.number         = name->ln_number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
-       op->info.owner          = (__u64)(long) fl->fl_owner;
        if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
+               /* fl_owner is lockd which doesn't distinguish
+                  processes on the nfs client */
+               op->info.owner  = (__u64) fl->fl_pid;
                xop->callback   = fl->fl_lmops->fl_grant;
                locks_init_lock(&xop->flc);
                locks_copy_lock(&xop->flc, fl);
                xop->fl         = fl;
                xop->file       = file;
-       } else
+       } else {
+               op->info.owner  = (__u64)(long) fl->fl_owner;
                xop->callback   = NULL;
+       }
 
        send_op(op);
 
@@ -203,7 +207,10 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
        op->info.number         = name->ln_number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
-       op->info.owner          = (__u64)(long) fl->fl_owner;
+       if (fl->fl_lmops && fl->fl_lmops->fl_grant)
+               op->info.owner  = (__u64) fl->fl_pid;
+       else
+               op->info.owner  = (__u64)(long) fl->fl_owner;
 
        send_op(op);
        wait_event(recv_wq, (op->done != 0));
@@ -242,7 +249,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
        op->info.number         = name->ln_number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
-       op->info.owner          = (__u64)(long) fl->fl_owner;
+       if (fl->fl_lmops && fl->fl_lmops->fl_grant)
+               op->info.owner  = (__u64) fl->fl_pid;
+       else
+               op->info.owner  = (__u64)(long) fl->fl_owner;
 
        send_op(op);
        wait_event(recv_wq, (op->done != 0));
index ae9e6a25fe2ba67d390b507e21f678303ed54e59..a87b098397617cdc82a4fc1ebe0eb9edb121a7c0 100644 (file)
@@ -189,51 +189,39 @@ static struct kobj_type gdlm_ktype = {
        .sysfs_ops     = &gdlm_attr_ops,
 };
 
-static struct kset gdlm_kset = {
-       .ktype  = &gdlm_ktype,
-};
+static struct kset *gdlm_kset;
 
 int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
 {
        int error;
 
-       error = kobject_set_name(&ls->kobj, "%s", "lock_module");
-       if (error) {
-               log_error("can't set kobj name %d", error);
-               return error;
-       }
-
-       ls->kobj.kset = &gdlm_kset;
-       ls->kobj.ktype = &gdlm_ktype;
-       ls->kobj.parent = fskobj;
-
-       error = kobject_register(&ls->kobj);
+       ls->kobj.kset = gdlm_kset;
+       error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj,
+                                    "lock_module");
        if (error)
                log_error("can't register kobj %d", error);
+       kobject_uevent(&ls->kobj, KOBJ_ADD);
 
        return error;
 }
 
 void gdlm_kobject_release(struct gdlm_ls *ls)
 {
-       kobject_unregister(&ls->kobj);
+       kobject_put(&ls->kobj);
 }
 
 int gdlm_sysfs_init(void)
 {
-       int error;
-
-       kobject_set_name(&gdlm_kset.kobj, "lock_dlm");
-       kobj_set_kset_s(&gdlm_kset, kernel_subsys);
-       error = kset_register(&gdlm_kset);
-       if (error)
-               printk("lock_dlm: cannot register kset %d\n", error);
-
-       return error;
+       gdlm_kset = kset_create_and_add("lock_dlm", NULL, kernel_kobj);
+       if (!gdlm_kset) {
+               printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+       return 0;
 }
 
 void gdlm_sysfs_exit(void)
 {
-       kset_unregister(&gdlm_kset);
+       kset_unregister(gdlm_kset);
 }
 
index bd938f06481d47c77ac8bb19276281d95dfe45fb..521694fc19d672c010fe6afdb4455fd389598a8e 100644 (file)
@@ -273,18 +273,13 @@ static int gdlm_thread(void *data, int blist)
        struct gdlm_ls *ls = (struct gdlm_ls *) data;
        struct gdlm_lock *lp = NULL;
        uint8_t complete, blocking, submit, drop;
-       DECLARE_WAITQUEUE(wait, current);
 
        /* Only thread1 is allowed to do blocking callbacks since gfs
           may wait for a completion callback within a blocking cb. */
 
        while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&ls->thread_wait, &wait);
-               if (no_work(ls, blist))
-                       schedule();
-               remove_wait_queue(&ls->thread_wait, &wait);
-               set_current_state(TASK_RUNNING);
+               wait_event_interruptible(ls->thread_wait,
+                               !no_work(ls, blist) || kthread_should_stop());
 
                complete = blocking = submit = drop = 0;
 
index 7df7024732523b8beddb57e3a6d6c3d37e035768..161ab6f2058ee585ad46dc08f6caac9b43f31b48 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -16,6 +16,8 @@
 #include <linux/crc32.h>
 #include <linux/lm_interface.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -68,14 +70,12 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
  *
  */
 
-void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd)
+void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
 {
        bd->bd_ail = NULL;
        list_del_init(&bd->bd_ail_st_list);
        list_del_init(&bd->bd_ail_gl_list);
        atomic_dec(&bd->bd_gl->gl_ail_count);
-       if (mapping)
-               gfs2_meta_cache_flush(GFS2_I(mapping->host));
        brelse(bd->bd_bh);
 }
 
@@ -92,8 +92,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
        struct buffer_head *bh;
        int retry;
 
-       BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
-
        do {
                retry = 0;
 
@@ -210,7 +208,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
        gfs2_log_unlock(sdp);
 }
 
-int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
+static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
 {
        struct gfs2_ail *ai, *s;
        int ret;
@@ -248,7 +246,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
                bd = list_entry(head->prev, struct gfs2_bufdata,
                                bd_ail_st_list);
                gfs2_assert(sdp, bd->bd_ail == ai);
-               gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);
+               gfs2_remove_from_ail(bd);
        }
 }
 
@@ -303,7 +301,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
 
        mutex_lock(&sdp->sd_log_reserve_mutex);
        gfs2_log_lock(sdp);
-       while(sdp->sd_log_blks_free <= (blks + reserved_blks)) {
+       while(atomic_read(&sdp->sd_log_blks_free) <= (blks + reserved_blks)) {
                gfs2_log_unlock(sdp);
                gfs2_ail1_empty(sdp, 0);
                gfs2_log_flush(sdp, NULL);
@@ -312,7 +310,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
                        gfs2_ail1_start(sdp, 0);
                gfs2_log_lock(sdp);
        }
-       sdp->sd_log_blks_free -= blks;
+       atomic_sub(blks, &sdp->sd_log_blks_free);
        gfs2_log_unlock(sdp);
        mutex_unlock(&sdp->sd_log_reserve_mutex);
 
@@ -332,27 +330,23 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
 {
 
        gfs2_log_lock(sdp);
-       sdp->sd_log_blks_free += blks;
+       atomic_add(blks, &sdp->sd_log_blks_free);
        gfs2_assert_withdraw(sdp,
-                            sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
+                            atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
        gfs2_log_unlock(sdp);
        up_read(&sdp->sd_log_flush_lock);
 }
 
 static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
 {
-       struct inode *inode = sdp->sd_jdesc->jd_inode;
-       int error;
-       struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
-
-       bh_map.b_size = 1 << inode->i_blkbits;
-       error = gfs2_block_map(inode, lbn, 0, &bh_map);
-       if (error || !bh_map.b_blocknr)
-               printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error,
-                      (unsigned long long)bh_map.b_blocknr, lbn);
-       gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
-
-       return bh_map.b_blocknr;
+       struct gfs2_journal_extent *je;
+
+       list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) {
+               if (lbn >= je->lblock && lbn < je->lblock + je->blocks)
+                       return je->dblock + lbn - je->lblock;
+       }
+
+       return -1;
 }
 
 /**
@@ -561,8 +555,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
        ail2_empty(sdp, new_tail);
 
        gfs2_log_lock(sdp);
-       sdp->sd_log_blks_free += dist;
-       gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
+       atomic_add(dist, &sdp->sd_log_blks_free);
+       gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
        gfs2_log_unlock(sdp);
 
        sdp->sd_log_tail = new_tail;
@@ -652,7 +646,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
                get_bh(bh);
                gfs2_log_unlock(sdp);
                lock_buffer(bh);
-               if (test_clear_buffer_dirty(bh)) {
+               if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) {
                        bh->b_end_io = end_buffer_write_sync;
                        submit_bh(WRITE, bh);
                } else {
@@ -694,20 +688,16 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
  *
  */
 
-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
 {
        struct gfs2_ail *ai;
 
        down_write(&sdp->sd_log_flush_lock);
 
-       if (gl) {
-               gfs2_log_lock(sdp);
-               if (list_empty(&gl->gl_le.le_list)) {
-                       gfs2_log_unlock(sdp);
-                       up_write(&sdp->sd_log_flush_lock);
-                       return;
-               }
-               gfs2_log_unlock(sdp);
+       /* Log might have been flushed while we waited for the flush lock */
+       if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) {
+               up_write(&sdp->sd_log_flush_lock);
+               return;
        }
 
        ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
@@ -739,7 +729,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
                log_flush_commit(sdp);
        else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
                gfs2_log_lock(sdp);
-               sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */
+               atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
                gfs2_log_unlock(sdp);
                log_write_header(sdp, 0, PULL);
        }
@@ -767,7 +757,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
 static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
 {
        unsigned int reserved;
-       unsigned int old;
+       unsigned int unused;
 
        gfs2_log_lock(sdp);
 
@@ -779,14 +769,11 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
        sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
        gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
        reserved = calc_reserved(sdp);
-       old = sdp->sd_log_blks_free;
-       sdp->sd_log_blks_free += tr->tr_reserved -
-                                (reserved - sdp->sd_log_blks_reserved);
-
-       gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
-       gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <=
+       unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved;
+       gfs2_assert_withdraw(sdp, unused >= 0);
+       atomic_add(unused, &sdp->sd_log_blks_free);
+       gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
                             sdp->sd_jdesc->jd_blocks);
-
        sdp->sd_log_blks_reserved = reserved;
 
        gfs2_log_unlock(sdp);
@@ -825,7 +812,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
        down_write(&sdp->sd_log_flush_lock);
 
        gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
-       gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
@@ -838,7 +824,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
        log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT,
                         (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL);
 
-       gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
+       gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
        gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
        gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
 
@@ -866,3 +852,42 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
        }
 }
 
+
+/**
+ * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * Also, periodically check to make sure that we're using the most recent
+ * journal index.
+ */
+
+int gfs2_logd(void *data)
+{
+       struct gfs2_sbd *sdp = data;
+       unsigned long t;
+       int need_flush;
+
+       while (!kthread_should_stop()) {
+               /* Advance the log tail */
+
+               t = sdp->sd_log_flush_time +
+                   gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
+
+               gfs2_ail1_empty(sdp, DIO_ALL);
+               gfs2_log_lock(sdp);
+               need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks);
+               gfs2_log_unlock(sdp);
+               if (need_flush || time_after_eq(jiffies, t)) {
+                       gfs2_log_flush(sdp, NULL);
+                       sdp->sd_log_flush_time = jiffies;
+               }
+
+               t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
+               if (freezing(current))
+                       refrigerator();
+               schedule_timeout_interruptible(t);
+       }
+
+       return 0;
+}
+
index dae2824006273462408a78a36684a432ec16f9a6..7711528165088002a3601de4c57ef101eae755ba 100644 (file)
@@ -48,8 +48,6 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
 unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
                            unsigned int ssize);
 
-int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
-
 int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
 void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
 void gfs2_log_incr_head(struct gfs2_sbd *sdp);
@@ -57,11 +55,19 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp);
 struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
 struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
                                      struct buffer_head *real);
-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
+void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
+
+static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl)
+{
+       if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags))
+               __gfs2_log_flush(sbd, gl);
+}
+
 void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
-void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd);
+void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
 
 void gfs2_log_shutdown(struct gfs2_sbd *sdp);
 void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
+int gfs2_logd(void *data);
 
 #endif /* __LOG_DOT_H__ */
index 6c27cea761c6b6a195bd92f90592d3641367a18c..fae59d69d01a30d54df00b49b74d97d07fe1c0c2 100644 (file)
@@ -87,6 +87,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
        }
        bd->bd_ail = ai;
        list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+       clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
        gfs2_log_unlock(sdp);
        unlock_buffer(bh);
 }
@@ -124,49 +125,6 @@ static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
        return bh;
 }
 
-static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
-{
-       struct gfs2_glock *gl;
-       struct gfs2_trans *tr = current->journal_info;
-
-       tr->tr_touched = 1;
-
-       gl = container_of(le, struct gfs2_glock, gl_le);
-       if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
-               return;
-
-       if (!list_empty(&le->le_list))
-               return;
-
-       gfs2_glock_hold(gl);
-       set_bit(GLF_DIRTY, &gl->gl_flags);
-       sdp->sd_log_num_gl++;
-       list_add(&le->le_list, &sdp->sd_log_le_gl);
-}
-
-static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
-{
-       gfs2_log_lock(sdp);
-       __glock_lo_add(sdp, le);
-       gfs2_log_unlock(sdp);
-}
-
-static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
-{
-       struct list_head *head = &sdp->sd_log_le_gl;
-       struct gfs2_glock *gl;
-
-       while (!list_empty(head)) {
-               gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list);
-               list_del_init(&gl->gl_le.le_list);
-               sdp->sd_log_num_gl--;
-
-               gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl));
-               gfs2_glock_put(gl);
-       }
-       gfs2_assert_warn(sdp, !sdp->sd_log_num_gl);
-}
-
 static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
 {
        struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
@@ -182,7 +140,8 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        list_add(&bd->bd_list_tr, &tr->tr_list_buf);
        if (!list_empty(&le->le_list))
                goto out;
-       __glock_lo_add(sdp, &bd->bd_gl->gl_le);
+       set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+       set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
        gfs2_meta_check(sdp, bd->bd_bh);
        gfs2_pin(sdp, bd->bd_bh);
        sdp->sd_log_num_buf++;
@@ -556,17 +515,20 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
 
        lock_buffer(bd->bd_bh);
        gfs2_log_lock(sdp);
-       if (!list_empty(&bd->bd_list_tr))
-               goto out;
-       tr->tr_touched = 1;
-       if (gfs2_is_jdata(ip)) {
-               tr->tr_num_buf++;
-               list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+       if (tr) {
+               if (!list_empty(&bd->bd_list_tr))
+                       goto out;
+               tr->tr_touched = 1;
+               if (gfs2_is_jdata(ip)) {
+                       tr->tr_num_buf++;
+                       list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+               }
        }
        if (!list_empty(&le->le_list))
                goto out;
 
-       __glock_lo_add(sdp, &bd->bd_gl->gl_le);
+       set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+       set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
        if (gfs2_is_jdata(ip)) {
                gfs2_pin(sdp, bd->bd_bh);
                tr->tr_num_databuf_new++;
@@ -773,12 +735,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
 }
 
 
-const struct gfs2_log_operations gfs2_glock_lops = {
-       .lo_add = glock_lo_add,
-       .lo_after_commit = glock_lo_after_commit,
-       .lo_name = "glock",
-};
-
 const struct gfs2_log_operations gfs2_buf_lops = {
        .lo_add = buf_lo_add,
        .lo_incore_commit = buf_lo_incore_commit,
@@ -816,7 +772,6 @@ const struct gfs2_log_operations gfs2_databuf_lops = {
 };
 
 const struct gfs2_log_operations *gfs2_log_ops[] = {
-       &gfs2_glock_lops,
        &gfs2_databuf_lops,
        &gfs2_buf_lops,
        &gfs2_rg_lops,
index 7ecfe0d3a4913e7d5dc2396599526cb2f781527f..9c7765c12d62eeac6443d853cf6bde4584019690 100644 (file)
@@ -29,9 +29,8 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo)
        struct gfs2_inode *ip = foo;
 
        inode_init_once(&ip->i_inode);
-       spin_lock_init(&ip->i_spin);
        init_rwsem(&ip->i_rw_mutex);
-       memset(ip->i_cache, 0, sizeof(ip->i_cache));
+       ip->i_alloc = NULL;
 }
 
 static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo)
index 4da423985e4f9178dd752a92fa5c102cd287e66a..85aea27b4a862f178fd0d1233b97f23064c6df7d 100644 (file)
@@ -50,6 +50,7 @@ static int gfs2_aspace_writepage(struct page *page,
 static const struct address_space_operations aspace_aops = {
        .writepage = gfs2_aspace_writepage,
        .releasepage = gfs2_releasepage,
+       .sync_page = block_sync_page,
 };
 
 /**
@@ -221,13 +222,14 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
                   struct buffer_head **bhp)
 {
        *bhp = getbuf(gl, blkno, CREATE);
-       if (!buffer_uptodate(*bhp))
+       if (!buffer_uptodate(*bhp)) {
                ll_rw_block(READ_META, 1, bhp);
-       if (flags & DIO_WAIT) {
-               int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
-               if (error) {
-                       brelse(*bhp);
-                       return error;
+               if (flags & DIO_WAIT) {
+                       int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
+                       if (error) {
+                               brelse(*bhp);
+                               return error;
+                       }
                }
        }
 
@@ -282,7 +284,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
                return;
        }
 
-       bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL),
+       bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL);
        bd->bd_bh = bh;
        bd->bd_gl = gl;
 
@@ -317,7 +319,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int
        }
        if (bd) {
                if (bd->bd_ail) {
-                       gfs2_remove_from_ail(NULL, bd);
+                       gfs2_remove_from_ail(bd);
                        bh->b_private = NULL;
                        bd->bd_bh = NULL;
                        bd->bd_blkno = bh->b_blocknr;
@@ -357,32 +359,6 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
        }
 }
 
-/**
- * gfs2_meta_cache_flush - get rid of any references on buffers for this inode
- * @ip: The GFS2 inode
- *
- * This releases buffers that are in the most-recently-used array of
- * blocks used for indirect block addressing for this inode.
- */
-
-void gfs2_meta_cache_flush(struct gfs2_inode *ip)
-{
-       struct buffer_head **bh_slot;
-       unsigned int x;
-
-       spin_lock(&ip->i_spin);
-
-       for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
-               bh_slot = &ip->i_cache[x];
-               if (*bh_slot) {
-                       brelse(*bh_slot);
-                       *bh_slot = NULL;
-               }
-       }
-
-       spin_unlock(&ip->i_spin);
-}
-
 /**
  * gfs2_meta_indirect_buffer - Get a metadata buffer
  * @ip: The GFS2 inode
@@ -391,8 +367,6 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip)
  * @new: Non-zero if we may create a new buffer
  * @bhp: the buffer is returned here
  *
- * Try to use the gfs2_inode's MRU metadata tree cache.
- *
  * Returns: errno
  */
 
@@ -401,58 +375,25 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_glock *gl = ip->i_gl;
-       struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
-       int in_cache = 0;
-
-       BUG_ON(!gl);
-       BUG_ON(!sdp);
-
-       spin_lock(&ip->i_spin);
-       if (*bh_slot && (*bh_slot)->b_blocknr == num) {
-               bh = *bh_slot;
-               get_bh(bh);
-               in_cache = 1;
-       }
-       spin_unlock(&ip->i_spin);
-
-       if (!bh)
-               bh = getbuf(gl, num, CREATE);
-
-       if (!bh)
-               return -ENOBUFS;
+       struct buffer_head *bh;
+       int ret = 0;
 
        if (new) {
-               if (gfs2_assert_warn(sdp, height))
-                       goto err;
-               meta_prep_new(bh);
+               BUG_ON(height == 0);
+               bh = gfs2_meta_new(gl, num);
                gfs2_trans_add_bh(ip->i_gl, bh, 1);
                gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
                gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
        } else {
                u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
-               if (!buffer_uptodate(bh)) {
-                       ll_rw_block(READ_META, 1, &bh);
-                       if (gfs2_meta_wait(sdp, bh))
-                               goto err;
+               ret = gfs2_meta_read(gl, num, DIO_WAIT, &bh);
+               if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) {
+                       brelse(bh);
+                       ret = -EIO;
                }
-               if (gfs2_metatype_check(sdp, bh, mtype))
-                       goto err;
-       }
-
-       if (!in_cache) {
-               spin_lock(&ip->i_spin);
-               if (*bh_slot)
-                       brelse(*bh_slot);
-               *bh_slot = bh;
-               get_bh(bh);
-               spin_unlock(&ip->i_spin);
        }
-
        *bhp = bh;
-       return 0;
-err:
-       brelse(bh);
-       return -EIO;
+       return ret;
 }
 
 /**
index b7048222ebb46fb1c4fdd9157430823a48e8c603..73e3b1c76fe145c637707bb241faab0a0c00513a 100644 (file)
@@ -56,7 +56,6 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
 
 void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
 
-void gfs2_meta_cache_flush(struct gfs2_inode *ip);
 int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
                              int new, struct buffer_head **bhp);
 
index 9679f8b9870d4b662a9a49023fc8b604ade25a68..38dbe99a30ede1ac388596278ef02ca9e9590bae 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/swap.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/lm_interface.h>
+#include <linux/backing-dev.h>
+#include <linux/pagevec.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -32,7 +34,6 @@
 #include "quota.h"
 #include "trans.h"
 #include "rgrp.h"
-#include "ops_file.h"
 #include "super.h"
 #include "util.h"
 #include "glops.h"
@@ -57,22 +58,6 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
        }
 }
 
-/**
- * gfs2_get_block - Fills in a buffer head with details about a block
- * @inode: The inode
- * @lblock: The block number to look up
- * @bh_result: The buffer head to return the result in
- * @create: Non-zero if we may add block to the file
- *
- * Returns: errno
- */
-
-int gfs2_get_block(struct inode *inode, sector_t lblock,
-                  struct buffer_head *bh_result, int create)
-{
-       return gfs2_block_map(inode, lblock, create, bh_result);
-}
-
 /**
  * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
  * @inode: The inode
@@ -88,7 +73,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
 {
        int error;
 
-       error = gfs2_block_map(inode, lblock, 0, bh_result);
+       error = gfs2_block_map(inode, lblock, bh_result, 0);
        if (error)
                return error;
        if (!buffer_mapped(bh_result))
@@ -99,20 +84,19 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
 static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
                                 struct buffer_head *bh_result, int create)
 {
-       return gfs2_block_map(inode, lblock, 0, bh_result);
+       return gfs2_block_map(inode, lblock, bh_result, 0);
 }
 
 /**
- * gfs2_writepage - Write complete page
- * @page: Page to write
+ * gfs2_writepage_common - Common bits of writepage
+ * @page: The page to be written
+ * @wbc: The writeback control
  *
- * Returns: errno
- *
- * Some of this is copied from block_write_full_page() although we still
- * call it to do most of the work.
+ * Returns: 1 if writepage is ok, otherwise an error code or zero if no error.
  */
 
-static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
+static int gfs2_writepage_common(struct page *page,
+                                struct writeback_control *wbc)
 {
        struct inode *inode = page->mapping->host;
        struct gfs2_inode *ip = GFS2_I(inode);
@@ -120,41 +104,133 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
        loff_t i_size = i_size_read(inode);
        pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
        unsigned offset;
-       int error;
-       int done_trans = 0;
+       int ret = -EIO;
 
-       if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
-               unlock_page(page);
-               return -EIO;
-       }
+       if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl)))
+               goto out;
+       ret = 0;
        if (current->journal_info)
-               goto out_ignore;
-
+               goto redirty;
        /* Is the page fully outside i_size? (truncate in progress) */
-        offset = i_size & (PAGE_CACHE_SIZE-1);
+       offset = i_size & (PAGE_CACHE_SIZE-1);
        if (page->index > end_index || (page->index == end_index && !offset)) {
                page->mapping->a_ops->invalidatepage(page, 0);
-               unlock_page(page);
-               return 0; /* don't care */
+               goto out;
+       }
+       return 1;
+redirty:
+       redirty_page_for_writepage(wbc, page);
+out:
+       unlock_page(page);
+       return 0;
+}
+
+/**
+ * gfs2_writeback_writepage - Write page for writeback mappings
+ * @page: The page
+ * @wbc: The writeback control
+ *
+ */
+
+static int gfs2_writeback_writepage(struct page *page,
+                                   struct writeback_control *wbc)
+{
+       int ret;
+
+       ret = gfs2_writepage_common(page, wbc);
+       if (ret <= 0)
+               return ret;
+
+       ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
+       if (ret == -EAGAIN)
+               ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
+       return ret;
+}
+
+/**
+ * gfs2_ordered_writepage - Write page for ordered data files
+ * @page: The page to write
+ * @wbc: The writeback control
+ *
+ */
+
+static int gfs2_ordered_writepage(struct page *page,
+                                 struct writeback_control *wbc)
+{
+       struct inode *inode = page->mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       int ret;
+
+       ret = gfs2_writepage_common(page, wbc);
+       if (ret <= 0)
+               return ret;
+
+       if (!page_has_buffers(page)) {
+               create_empty_buffers(page, inode->i_sb->s_blocksize,
+                                    (1 << BH_Dirty)|(1 << BH_Uptodate));
        }
+       gfs2_page_add_databufs(ip, page, 0, inode->i_sb->s_blocksize-1);
+       return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
+}
 
-       if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) &&
-           PageChecked(page)) {
+/**
+ * __gfs2_jdata_writepage - The core of jdata writepage
+ * @page: The page to write
+ * @wbc: The writeback control
+ *
+ * This is shared between writepage and writepages and implements the
+ * core of the writepage operation. If a transaction is required then
+ * PageChecked will have been set and the transaction will have
+ * already been started before this is called.
+ */
+
+static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
+{
+       struct inode *inode = page->mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+       if (PageChecked(page)) {
                ClearPageChecked(page);
-               error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
-               if (error)
-                       goto out_ignore;
                if (!page_has_buffers(page)) {
                        create_empty_buffers(page, inode->i_sb->s_blocksize,
                                             (1 << BH_Dirty)|(1 << BH_Uptodate));
                }
                gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
+       }
+       return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
+}
+
+/**
+ * gfs2_jdata_writepage - Write complete page
+ * @page: Page to write
+ *
+ * Returns: errno
+ *
+ */
+
+static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
+{
+       struct inode *inode = page->mapping->host;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       int error;
+       int done_trans = 0;
+
+       error = gfs2_writepage_common(page, wbc);
+       if (error <= 0)
+               return error;
+
+       if (PageChecked(page)) {
+               if (wbc->sync_mode != WB_SYNC_ALL)
+                       goto out_ignore;
+               error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
+               if (error)
+                       goto out_ignore;
                done_trans = 1;
        }
-       error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
+       error = __gfs2_jdata_writepage(page, wbc);
        if (done_trans)
                gfs2_trans_end(sdp);
-       gfs2_meta_cache_flush(ip);
        return error;
 
 out_ignore:
@@ -164,29 +240,190 @@ out_ignore:
 }
 
 /**
- * gfs2_writepages - Write a bunch of dirty pages back to disk
+ * gfs2_writeback_writepages - Write a bunch of dirty pages back to disk
  * @mapping: The mapping to write
  * @wbc: Write-back control
  *
- * For journaled files and/or ordered writes this just falls back to the
- * kernel's default writepages path for now. We will probably want to change
- * that eventually (i.e. when we look at allocate on flush).
- *
- * For the data=writeback case though we can already ignore buffer heads
+ * For the data=writeback case we can already ignore buffer heads
  * and write whole extents at once. This is a big reduction in the
  * number of I/O requests we send and the bmap calls we make in this case.
  */
-static int gfs2_writepages(struct address_space *mapping,
-                          struct writeback_control *wbc)
+static int gfs2_writeback_writepages(struct address_space *mapping,
+                                    struct writeback_control *wbc)
+{
+       return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+}
+
+/**
+ * gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages
+ * @mapping: The mapping
+ * @wbc: The writeback control
+ * @writepage: The writepage function to call for each page
+ * @pvec: The vector of pages
+ * @nr_pages: The number of pages to write
+ *
+ * Returns: non-zero if loop should terminate, zero otherwise
+ */
+
+static int gfs2_write_jdata_pagevec(struct address_space *mapping,
+                                   struct writeback_control *wbc,
+                                   struct pagevec *pvec,
+                                   int nr_pages, pgoff_t end)
 {
        struct inode *inode = mapping->host;
-       struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
+       loff_t i_size = i_size_read(inode);
+       pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+       unsigned offset = i_size & (PAGE_CACHE_SIZE-1);
+       unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize);
+       struct backing_dev_info *bdi = mapping->backing_dev_info;
+       int i;
+       int ret;
+
+       ret = gfs2_trans_begin(sdp, nrblocks, 0);
+       if (ret < 0)
+               return ret;
+
+       for(i = 0; i < nr_pages; i++) {
+               struct page *page = pvec->pages[i];
+
+               lock_page(page);
+
+               if (unlikely(page->mapping != mapping)) {
+                       unlock_page(page);
+                       continue;
+               }
+
+               if (!wbc->range_cyclic && page->index > end) {
+                       ret = 1;
+                       unlock_page(page);
+                       continue;
+               }
+
+               if (wbc->sync_mode != WB_SYNC_NONE)
+                       wait_on_page_writeback(page);
+
+               if (PageWriteback(page) ||
+                   !clear_page_dirty_for_io(page)) {
+                       unlock_page(page);
+                       continue;
+               }
+
+               /* Is the page fully outside i_size? (truncate in progress) */
+               if (page->index > end_index || (page->index == end_index && !offset)) {
+                       page->mapping->a_ops->invalidatepage(page, 0);
+                       unlock_page(page);
+                       continue;
+               }
+
+               ret = __gfs2_jdata_writepage(page, wbc);
+
+               if (ret || (--(wbc->nr_to_write) <= 0))
+                       ret = 1;
+               if (wbc->nonblocking && bdi_write_congested(bdi)) {
+                       wbc->encountered_congestion = 1;
+                       ret = 1;
+               }
+
+       }
+       gfs2_trans_end(sdp);
+       return ret;
+}
+
+/**
+ * gfs2_write_cache_jdata - Like write_cache_pages but different
+ * @mapping: The mapping to write
+ * @wbc: The writeback control
+ * @writepage: The writepage function to call
+ * @data: The data to pass to writepage
+ *
+ * The reason that we use our own function here is that we need to
+ * start transactions before we grab page locks. This allows us
+ * to get the ordering right.
+ */
+
+static int gfs2_write_cache_jdata(struct address_space *mapping,
+                                 struct writeback_control *wbc)
+{
+       struct backing_dev_info *bdi = mapping->backing_dev_info;
+       int ret = 0;
+       int done = 0;
+       struct pagevec pvec;
+       int nr_pages;
+       pgoff_t index;
+       pgoff_t end;
+       int scanned = 0;
+       int range_whole = 0;
+
+       if (wbc->nonblocking && bdi_write_congested(bdi)) {
+               wbc->encountered_congestion = 1;
+               return 0;
+       }
+
+       pagevec_init(&pvec, 0);
+       if (wbc->range_cyclic) {
+               index = mapping->writeback_index; /* Start from prev offset */
+               end = -1;
+       } else {
+               index = wbc->range_start >> PAGE_CACHE_SHIFT;
+               end = wbc->range_end >> PAGE_CACHE_SHIFT;
+               if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+                       range_whole = 1;
+               scanned = 1;
+       }
 
-       if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
-               return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+retry:
+        while (!done && (index <= end) &&
+               (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                                              PAGECACHE_TAG_DIRTY,
+                                              min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
+               scanned = 1;
+               ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end);
+               if (ret)
+                       done = 1;
+               if (ret > 0)
+                       ret = 0;
+
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+
+       if (!scanned && !done) {
+               /*
+                * We hit the last page and there is more work to be done: wrap
+                * back to the start of the file
+                */
+               scanned = 1;
+               index = 0;
+               goto retry;
+       }
+
+       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
+               mapping->writeback_index = index;
+       return ret;
+}
+
+
+/**
+ * gfs2_jdata_writepages - Write a bunch of dirty pages back to disk
+ * @mapping: The mapping to write
+ * @wbc: The writeback control
+ * 
+ */
 
-       return generic_writepages(mapping, wbc);
+static int gfs2_jdata_writepages(struct address_space *mapping,
+                                struct writeback_control *wbc)
+{
+       struct gfs2_inode *ip = GFS2_I(mapping->host);
+       struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
+       int ret;
+
+       ret = gfs2_write_cache_jdata(mapping, wbc);
+       if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) {
+               gfs2_log_flush(sdp, ip->i_gl);
+               ret = gfs2_write_cache_jdata(mapping, wbc);
+       }
+       return ret;
 }
 
 /**
@@ -231,62 +468,107 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
 
 
 /**
- * gfs2_readpage - readpage with locking
- * @file: The file to read a page for. N.B. This may be NULL if we are
- * reading an internal file.
+ * __gfs2_readpage - readpage
+ * @file: The file to read a page for
  * @page: The page to read
  *
- * Returns: errno
+ * This is the core of gfs2's readpage. Its used by the internal file
+ * reading code as in that case we already hold the glock. Also its
+ * called by gfs2_readpage() once the required lock has been granted.
+ *
  */
 
-static int gfs2_readpage(struct file *file, struct page *page)
+static int __gfs2_readpage(void *file, struct page *page)
 {
        struct gfs2_inode *ip = GFS2_I(page->mapping->host);
        struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
-       struct gfs2_file *gf = NULL;
-       struct gfs2_holder gh;
        int error;
-       int do_unlock = 0;
-
-       if (likely(file != &gfs2_internal_file_sentinel)) {
-               if (file) {
-                       gf = file->private_data;
-                       if (test_bit(GFF_EXLOCK, &gf->f_flags))
-                               /* gfs2_sharewrite_fault has grabbed the ip->i_gl already */
-                               goto skip_lock;
-               }
-               gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
-               do_unlock = 1;
-               error = gfs2_glock_nq_atime(&gh);
-               if (unlikely(error))
-                       goto out_unlock;
-       }
 
-skip_lock:
        if (gfs2_is_stuffed(ip)) {
                error = stuffed_readpage(ip, page);
                unlock_page(page);
-       } else
-               error = mpage_readpage(page, gfs2_get_block);
+       } else {
+               error = mpage_readpage(page, gfs2_block_map);
+       }
 
        if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-               error = -EIO;
+               return -EIO;
+
+       return error;
+}
+
+/**
+ * gfs2_readpage - read a page of a file
+ * @file: The file to read
+ * @page: The page of the file
+ *
+ * This deals with the locking required. We use a trylock in order to
+ * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE
+ * in the event that we are unable to get the lock.
+ */
+
+static int gfs2_readpage(struct file *file, struct page *page)
+{
+       struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+       struct gfs2_holder gh;
+       int error;
 
-       if (do_unlock) {
-               gfs2_glock_dq_m(1, &gh);
-               gfs2_holder_uninit(&gh);
+       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
+       error = gfs2_glock_nq_atime(&gh);
+       if (unlikely(error)) {
+               unlock_page(page);
+               goto out;
        }
+       error = __gfs2_readpage(file, page);
+       gfs2_glock_dq(&gh);
 out:
-       return error;
-out_unlock:
-       unlock_page(page);
+       gfs2_holder_uninit(&gh);
        if (error == GLR_TRYFAILED) {
-               error = AOP_TRUNCATED_PAGE;
                yield();
+               return AOP_TRUNCATED_PAGE;
        }
-       if (do_unlock)
-               gfs2_holder_uninit(&gh);
-       goto out;
+       return error;
+}
+
+/**
+ * gfs2_internal_read - read an internal file
+ * @ip: The gfs2 inode
+ * @ra_state: The readahead state (or NULL for no readahead)
+ * @buf: The buffer to fill
+ * @pos: The file position
+ * @size: The amount to read
+ *
+ */
+
+int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
+                       char *buf, loff_t *pos, unsigned size)
+{
+       struct address_space *mapping = ip->i_inode.i_mapping;
+       unsigned long index = *pos / PAGE_CACHE_SIZE;
+       unsigned offset = *pos & (PAGE_CACHE_SIZE - 1);
+       unsigned copied = 0;
+       unsigned amt;
+       struct page *page;
+       void *p;
+
+       do {
+               amt = size - copied;
+               if (offset + size > PAGE_CACHE_SIZE)
+                       amt = PAGE_CACHE_SIZE - offset;
+               page = read_cache_page(mapping, index, __gfs2_readpage, NULL);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+               p = kmap_atomic(page, KM_USER0);
+               memcpy(buf + copied, p + offset, amt);
+               kunmap_atomic(p, KM_USER0);
+               mark_page_accessed(page);
+               page_cache_release(page);
+               copied += amt;
+               index++;
+               offset = 0;
+       } while(copied < size);
+       (*pos) += size;
+       return size;
 }
 
 /**
@@ -300,10 +582,9 @@ out_unlock:
  *    Any I/O we ignore at this time will be done via readpage later.
  * 2. We don't handle stuffed files here we let readpage do the honours.
  * 3. mpage_readpages() does most of the heavy lifting in the common case.
- * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
- * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
- *    well as read-ahead.
+ * 4. gfs2_block_map() is relied upon to set BH_Boundary in the right places.
  */
+
 static int gfs2_readpages(struct file *file, struct address_space *mapping,
                          struct list_head *pages, unsigned nr_pages)
 {
@@ -311,42 +592,20 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct gfs2_holder gh;
-       int ret = 0;
-       int do_unlock = 0;
+       int ret;
 
-       if (likely(file != &gfs2_internal_file_sentinel)) {
-               if (file) {
-                       struct gfs2_file *gf = file->private_data;
-                       if (test_bit(GFF_EXLOCK, &gf->f_flags))
-                               goto skip_lock;
-               }
-               gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
-                                LM_FLAG_TRY_1CB|GL_ATIME, &gh);
-               do_unlock = 1;
-               ret = gfs2_glock_nq_atime(&gh);
-               if (ret == GLR_TRYFAILED)
-                       goto out_noerror;
-               if (unlikely(ret))
-                       goto out_unlock;
-       }
-skip_lock:
+       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+       ret = gfs2_glock_nq_atime(&gh);
+       if (unlikely(ret))
+               goto out_uninit;
        if (!gfs2_is_stuffed(ip))
-               ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
-
-       if (do_unlock) {
-               gfs2_glock_dq_m(1, &gh);
-               gfs2_holder_uninit(&gh);
-       }
-out:
+               ret = mpage_readpages(mapping, pages, nr_pages, gfs2_block_map);
+       gfs2_glock_dq(&gh);
+out_uninit:
+       gfs2_holder_uninit(&gh);
        if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
                ret = -EIO;
        return ret;
-out_noerror:
-       ret = 0;
-out_unlock:
-       if (do_unlock)
-               gfs2_holder_uninit(&gh);
-       goto out;
 }
 
 /**
@@ -382,20 +641,11 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        if (unlikely(error))
                goto out_uninit;
 
-       error = -ENOMEM;
-       page = __grab_cache_page(mapping, index);
-       *pagep = page;
-       if (!page)
-               goto out_unlock;
-
        gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
-
        error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
        if (error)
-               goto out_putpage;
-
+               goto out_unlock;
 
-       ip->i_alloc.al_requested = 0;
        if (alloc_required) {
                al = gfs2_alloc_get(ip);
 
@@ -424,40 +674,47 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        if (error)
                goto out_trans_fail;
 
+       error = -ENOMEM;
+       page = __grab_cache_page(mapping, index);
+       *pagep = page;
+       if (unlikely(!page))
+               goto out_endtrans;
+
        if (gfs2_is_stuffed(ip)) {
+               error = 0;
                if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
                        error = gfs2_unstuff_dinode(ip, page);
                        if (error == 0)
                                goto prepare_write;
-               } else if (!PageUptodate(page))
+               } else if (!PageUptodate(page)) {
                        error = stuffed_readpage(ip, page);
+               }
                goto out;
        }
 
 prepare_write:
-       error = block_prepare_write(page, from, to, gfs2_get_block);
-
+       error = block_prepare_write(page, from, to, gfs2_block_map);
 out:
-       if (error) {
-               gfs2_trans_end(sdp);
+       if (error == 0)
+               return 0;
+
+       page_cache_release(page);
+       if (pos + len > ip->i_inode.i_size)
+               vmtruncate(&ip->i_inode, ip->i_inode.i_size);
+out_endtrans:
+       gfs2_trans_end(sdp);
 out_trans_fail:
-               if (alloc_required) {
-                       gfs2_inplace_release(ip);
+       if (alloc_required) {
+               gfs2_inplace_release(ip);
 out_qunlock:
-                       gfs2_quota_unlock(ip);
+               gfs2_quota_unlock(ip);
 out_alloc_put:
-                       gfs2_alloc_put(ip);
-               }
-out_putpage:
-               page_cache_release(page);
-               if (pos + len > ip->i_inode.i_size)
-                       vmtruncate(&ip->i_inode, ip->i_inode.i_size);
+               gfs2_alloc_put(ip);
+       }
 out_unlock:
-               gfs2_glock_dq_m(1, &ip->i_gh);
+       gfs2_glock_dq(&ip->i_gh);
 out_uninit:
-               gfs2_holder_uninit(&ip->i_gh);
-       }
-
+       gfs2_holder_uninit(&ip->i_gh);
        return error;
 }
 
@@ -565,7 +822,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct buffer_head *dibh;
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_dinode *di;
        unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
        unsigned int to = from + len;
@@ -585,19 +842,16 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        if (gfs2_is_stuffed(ip))
                return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page);
 
-       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+       if (!gfs2_is_writeback(ip))
                gfs2_page_add_databufs(ip, page, from, to);
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
 
-       if (likely(ret >= 0)) {
-               copied = ret;
-               if  ((pos + copied) > inode->i_size) {
-                       di = (struct gfs2_dinode *)dibh->b_data;
-                       ip->i_di.di_size = inode->i_size;
-                       di->di_size = cpu_to_be64(inode->i_size);
-                       mark_inode_dirty(inode);
-               }
+       if (likely(ret >= 0) && (inode->i_size > ip->i_di.di_size)) {
+               di = (struct gfs2_dinode *)dibh->b_data;
+               ip->i_di.di_size = inode->i_size;
+               di->di_size = cpu_to_be64(inode->i_size);
+               mark_inode_dirty(inode);
        }
 
        if (inode == sdp->sd_rindex)
@@ -606,7 +860,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        brelse(dibh);
        gfs2_trans_end(sdp);
 failed:
-       if (al->al_requested) {
+       if (al) {
                gfs2_inplace_release(ip);
                gfs2_quota_unlock(ip);
                gfs2_alloc_put(ip);
@@ -625,11 +879,7 @@ failed:
  
 static int gfs2_set_page_dirty(struct page *page)
 {
-       struct gfs2_inode *ip = GFS2_I(page->mapping->host);
-       struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
-
-       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
-               SetPageChecked(page);
+       SetPageChecked(page);
        return __set_page_dirty_buffers(page);
 }
 
@@ -653,7 +903,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
                return 0;
 
        if (!gfs2_is_stuffed(ip))
-               dblock = generic_block_bmap(mapping, lblock, gfs2_get_block);
+               dblock = generic_block_bmap(mapping, lblock, gfs2_block_map);
 
        gfs2_glock_dq_uninit(&i_gh);
 
@@ -719,13 +969,9 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
 {
        /*
         * Should we return an error here? I can't see that O_DIRECT for
-        * a journaled file makes any sense. For now we'll silently fall
-        * back to buffered I/O, likewise we do the same for stuffed
-        * files since they are (a) small and (b) unaligned.
+        * a stuffed file makes any sense. For now we'll silently fall
+        * back to buffered I/O
         */
-       if (gfs2_is_jdata(ip))
-               return 0;
-
        if (gfs2_is_stuffed(ip))
                return 0;
 
@@ -836,9 +1082,23 @@ cannot_release:
        return 0;
 }
 
-const struct address_space_operations gfs2_file_aops = {
-       .writepage = gfs2_writepage,
-       .writepages = gfs2_writepages,
+static const struct address_space_operations gfs2_writeback_aops = {
+       .writepage = gfs2_writeback_writepage,
+       .writepages = gfs2_writeback_writepages,
+       .readpage = gfs2_readpage,
+       .readpages = gfs2_readpages,
+       .sync_page = block_sync_page,
+       .write_begin = gfs2_write_begin,
+       .write_end = gfs2_write_end,
+       .bmap = gfs2_bmap,
+       .invalidatepage = gfs2_invalidatepage,
+       .releasepage = gfs2_releasepage,
+       .direct_IO = gfs2_direct_IO,
+       .migratepage = buffer_migrate_page,
+};
+
+static const struct address_space_operations gfs2_ordered_aops = {
+       .writepage = gfs2_ordered_writepage,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
        .sync_page = block_sync_page,
@@ -849,5 +1109,34 @@ const struct address_space_operations gfs2_file_aops = {
        .invalidatepage = gfs2_invalidatepage,
        .releasepage = gfs2_releasepage,
        .direct_IO = gfs2_direct_IO,
+       .migratepage = buffer_migrate_page,
 };
 
+static const struct address_space_operations gfs2_jdata_aops = {
+       .writepage = gfs2_jdata_writepage,
+       .writepages = gfs2_jdata_writepages,
+       .readpage = gfs2_readpage,
+       .readpages = gfs2_readpages,
+       .sync_page = block_sync_page,
+       .write_begin = gfs2_write_begin,
+       .write_end = gfs2_write_end,
+       .set_page_dirty = gfs2_set_page_dirty,
+       .bmap = gfs2_bmap,
+       .invalidatepage = gfs2_invalidatepage,
+       .releasepage = gfs2_releasepage,
+};
+
+void gfs2_set_aops(struct inode *inode)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+
+       if (gfs2_is_writeback(ip))
+               inode->i_mapping->a_ops = &gfs2_writeback_aops;
+       else if (gfs2_is_ordered(ip))
+               inode->i_mapping->a_ops = &gfs2_ordered_aops;
+       else if (gfs2_is_jdata(ip))
+               inode->i_mapping->a_ops = &gfs2_jdata_aops;
+       else
+               BUG();
+}
+
index fa1b5b3d28b99b50c08d428de760dc6c260b2098..5da21285bba453dad3745df7eca637260c53633a 100644 (file)
 #include <linux/buffer_head.h>
 #include <linux/mm.h>
 
-extern const struct address_space_operations gfs2_file_aops;
-extern int gfs2_get_block(struct inode *inode, sector_t lblock,
-                         struct buffer_head *bh_result, int create);
 extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
+extern int gfs2_internal_read(struct gfs2_inode *ip,
+                             struct file_ra_state *ra_state,
+                             char *buf, loff_t *pos, unsigned size);
+extern void gfs2_set_aops(struct inode *inode);
 
 #endif /* __OPS_ADDRESS_DOT_H__ */
index bb11fd6752d3d47e0f50eaeae330e2ecad391f1b..f4842f2548cdb8c55346836aab9f287370e4e9f1 100644 (file)
 #include "lm.h"
 #include "log.h"
 #include "meta_io.h"
-#include "ops_file.h"
-#include "ops_vm.h"
 #include "quota.h"
 #include "rgrp.h"
 #include "trans.h"
 #include "util.h"
 #include "eaops.h"
-
-/*
- * Most fields left uninitialised to catch anybody who tries to
- * use them. f_flags set to prevent file_accessed() from touching
- * any other part of this. Its use is purely as a flag so that we
- * know (in readpage()) whether or not do to locking.
- */
-struct file gfs2_internal_file_sentinel = {
-       .f_flags = O_NOATIME|O_RDONLY,
-};
-
-static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
-                          unsigned long offset, unsigned long size)
-{
-       char *kaddr;
-       unsigned long count = desc->count;
-
-       if (size > count)
-               size = count;
-
-       kaddr = kmap(page);
-       memcpy(desc->arg.data, kaddr + offset, size);
-       kunmap(page);
-
-       desc->count = count - size;
-       desc->written += size;
-       desc->arg.buf += size;
-       return size;
-}
-
-int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
-                      char *buf, loff_t *pos, unsigned size)
-{
-       struct inode *inode = &ip->i_inode;
-       read_descriptor_t desc;
-       desc.written = 0;
-       desc.arg.data = buf;
-       desc.count = size;
-       desc.error = 0;
-       do_generic_mapping_read(inode->i_mapping, ra_state,
-                               &gfs2_internal_file_sentinel, pos, &desc,
-                               gfs2_read_actor);
-       return desc.written ? desc.written : desc.error;
-}
+#include "ops_address.h"
 
 /**
  * gfs2_llseek - seek to a location in a file
@@ -214,7 +169,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
        if (put_user(fsflags, ptr))
                error = -EFAULT;
 
-       gfs2_glock_dq_m(1, &gh);
+       gfs2_glock_dq(&gh);
        gfs2_holder_uninit(&gh);
        return error;
 }
@@ -291,7 +246,16 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
                if (error)
                        goto out;
        }
-
+       if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
+               if (flags & GFS2_DIF_JDATA)
+                       gfs2_log_flush(sdp, ip->i_gl);
+               error = filemap_fdatawrite(inode->i_mapping);
+               if (error)
+                       goto out;
+               error = filemap_fdatawait(inode->i_mapping);
+               if (error)
+                       goto out;
+       }
        error = gfs2_trans_begin(sdp, RES_DINODE, 0);
        if (error)
                goto out;
@@ -303,6 +267,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
        gfs2_dinode_out(ip, bh->b_data);
        brelse(bh);
        gfs2_set_inode_flags(inode);
+       gfs2_set_aops(inode);
 out_trans_end:
        gfs2_trans_end(sdp);
 out:
@@ -338,6 +303,128 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        return -ENOTTY;
 }
 
+/**
+ * gfs2_allocate_page_backing - Use bmap to allocate blocks
+ * @page: The (locked) page to allocate backing for
+ *
+ * We try to allocate all the blocks required for the page in
+ * one go. This might fail for various reasons, so we keep
+ * trying until all the blocks to back this page are allocated.
+ * If some of the blocks are already allocated, thats ok too.
+ */
+
+static int gfs2_allocate_page_backing(struct page *page)
+{
+       struct inode *inode = page->mapping->host;
+       struct buffer_head bh;
+       unsigned long size = PAGE_CACHE_SIZE;
+       u64 lblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+       do {
+               bh.b_state = 0;
+               bh.b_size = size;
+               gfs2_block_map(inode, lblock, &bh, 1);
+               if (!buffer_mapped(&bh))
+                       return -EIO;
+               size -= bh.b_size;
+               lblock += (bh.b_size >> inode->i_blkbits);
+       } while(size > 0);
+       return 0;
+}
+
+/**
+ * gfs2_page_mkwrite - Make a shared, mmap()ed, page writable
+ * @vma: The virtual memory area
+ * @page: The page which is about to become writable
+ *
+ * When the page becomes writable, we need to ensure that we have
+ * blocks allocated on disk to back that page.
+ */
+
+static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       unsigned long last_index;
+       u64 pos = page->index << (PAGE_CACHE_SIZE - inode->i_blkbits);
+       unsigned int data_blocks, ind_blocks, rblocks;
+       int alloc_required = 0;
+       struct gfs2_holder gh;
+       struct gfs2_alloc *al;
+       int ret;
+
+       gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &gh);
+       ret = gfs2_glock_nq_atime(&gh);
+       if (ret)
+               goto out;
+
+       set_bit(GIF_SW_PAGED, &ip->i_flags);
+       gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
+       ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
+       if (ret || !alloc_required)
+               goto out_unlock;
+       ret = -ENOMEM;
+       al = gfs2_alloc_get(ip);
+       if (al == NULL)
+               goto out_unlock;
+
+       ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+       if (ret)
+               goto out_alloc_put;
+       ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
+       if (ret)
+               goto out_quota_unlock;
+       al->al_requested = data_blocks + ind_blocks;
+       ret = gfs2_inplace_reserve(ip);
+       if (ret)
+               goto out_quota_unlock;
+
+       rblocks = RES_DINODE + ind_blocks;
+       if (gfs2_is_jdata(ip))
+               rblocks += data_blocks ? data_blocks : 1;
+       if (ind_blocks || data_blocks)
+               rblocks += RES_STATFS + RES_QUOTA;
+       ret = gfs2_trans_begin(sdp, rblocks, 0);
+       if (ret)
+               goto out_trans_fail;
+
+       lock_page(page);
+       ret = -EINVAL;
+       last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
+       if (page->index > last_index)
+               goto out_unlock_page;
+       ret = 0;
+       if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
+               goto out_unlock_page;
+       if (gfs2_is_stuffed(ip)) {
+               ret = gfs2_unstuff_dinode(ip, page);
+               if (ret)
+                       goto out_unlock_page;
+       }
+       ret = gfs2_allocate_page_backing(page);
+
+out_unlock_page:
+       unlock_page(page);
+       gfs2_trans_end(sdp);
+out_trans_fail:
+       gfs2_inplace_release(ip);
+out_quota_unlock:
+       gfs2_quota_unlock(ip);
+out_alloc_put:
+       gfs2_alloc_put(ip);
+out_unlock:
+       gfs2_glock_dq(&gh);
+out:
+       gfs2_holder_uninit(&gh);
+       return ret;
+}
+
+static struct vm_operations_struct gfs2_vm_ops = {
+       .fault = filemap_fault,
+       .page_mkwrite = gfs2_page_mkwrite,
+};
+
 
 /**
  * gfs2_mmap -
@@ -360,14 +447,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
                return error;
        }
 
-       /* This is VM_MAYWRITE instead of VM_WRITE because a call
-          to mprotect() can turn on VM_WRITE later. */
-
-       if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
-           (VM_MAYSHARE | VM_MAYWRITE))
-               vma->vm_ops = &gfs2_vm_ops_sharewrite;
-       else
-               vma->vm_ops = &gfs2_vm_ops_private;
+       vma->vm_ops = &gfs2_vm_ops;
 
        gfs2_glock_dq_uninit(&i_gh);
 
@@ -538,15 +618,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
        if (__mandatory_lock(&ip->i_inode))
                return -ENOLCK;
 
-       if (sdp->sd_args.ar_localflocks) {
-               if (IS_GETLK(cmd)) {
-                       posix_test_lock(file, fl);
-                       return 0;
-               } else {
-                       return posix_lock_file_wait(file, fl);
-               }
-       }
-
        if (cmd == F_CANCELLK) {
                /* Hack: */
                cmd = F_SETLK;
@@ -632,16 +703,12 @@ static void do_unflock(struct file *file, struct file_lock *fl)
 static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 {
        struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
-       struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
 
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
        if (__mandatory_lock(&ip->i_inode))
                return -ENOLCK;
 
-       if (sdp->sd_args.ar_localflocks)
-               return flock_lock_file_wait(file, fl);
-
        if (fl->fl_type == F_UNLCK) {
                do_unflock(file, fl);
                return 0;
@@ -678,3 +745,27 @@ const struct file_operations gfs2_dir_fops = {
        .flock          = gfs2_flock,
 };
 
+const struct file_operations gfs2_file_fops_nolock = {
+       .llseek         = gfs2_llseek,
+       .read           = do_sync_read,
+       .aio_read       = generic_file_aio_read,
+       .write          = do_sync_write,
+       .aio_write      = generic_file_aio_write,
+       .unlocked_ioctl = gfs2_ioctl,
+       .mmap           = gfs2_mmap,
+       .open           = gfs2_open,
+       .release        = gfs2_close,
+       .fsync          = gfs2_fsync,
+       .splice_read    = generic_file_splice_read,
+       .splice_write   = generic_file_splice_write,
+       .setlease       = gfs2_setlease,
+};
+
+const struct file_operations gfs2_dir_fops_nolock = {
+       .readdir        = gfs2_readdir,
+       .unlocked_ioctl = gfs2_ioctl,
+       .open           = gfs2_open,
+       .release        = gfs2_close,
+       .fsync          = gfs2_fsync,
+};
+
diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
deleted file mode 100644 (file)
index 7e5d8ec..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#ifndef __OPS_FILE_DOT_H__
-#define __OPS_FILE_DOT_H__
-
-#include <linux/fs.h>
-struct gfs2_inode;
-
-extern struct file gfs2_internal_file_sentinel;
-extern int gfs2_internal_read(struct gfs2_inode *ip,
-                             struct file_ra_state *ra_state,
-                             char *buf, loff_t *pos, unsigned size);
-extern void gfs2_set_inode_flags(struct inode *inode);
-extern const struct file_operations gfs2_file_fops;
-extern const struct file_operations gfs2_dir_fops;
-
-#endif /* __OPS_FILE_DOT_H__ */
index 17de58e83d92e3e10907a50e641858620d5b3ba5..43d511bba52d3a11a388e011c12b8de9a34890d1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -21,6 +21,7 @@
 
 #include "gfs2.h"
 #include "incore.h"
+#include "bmap.h"
 #include "daemon.h"
 #include "glock.h"
 #include "glops.h"
@@ -59,7 +60,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        mutex_init(&sdp->sd_inum_mutex);
        spin_lock_init(&sdp->sd_statfs_spin);
-       mutex_init(&sdp->sd_statfs_mutex);
 
        spin_lock_init(&sdp->sd_rindex_spin);
        mutex_init(&sdp->sd_rindex_mutex);
@@ -77,7 +77,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        spin_lock_init(&sdp->sd_log_lock);
 
-       INIT_LIST_HEAD(&sdp->sd_log_le_gl);
        INIT_LIST_HEAD(&sdp->sd_log_le_buf);
        INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
        INIT_LIST_HEAD(&sdp->sd_log_le_rg);
@@ -303,6 +302,67 @@ out:
        return error;
 }
 
+/**
+ * map_journal_extents - create a reusable "extent" mapping from all logical
+ * blocks to all physical blocks for the given journal.  This will save
+ * us time when writing journal blocks.  Most journals will have only one
+ * extent that maps all their logical blocks.  That's because gfs2.mkfs
+ * arranges the journal blocks sequentially to maximize performance.
+ * So the extent would map the first block for the entire file length.
+ * However, gfs2_jadd can happen while file activity is happening, so
+ * those journals may not be sequential.  Less likely is the case where
+ * the users created their own journals by mounting the metafs and
+ * laying it out.  But it's still possible.  These journals might have
+ * several extents.
+ *
+ * TODO: This should be done in bigger chunks rather than one block at a time,
+ *       but since it's only done at mount time, I'm not worried about the
+ *       time it takes.
+ */
+static int map_journal_extents(struct gfs2_sbd *sdp)
+{
+       struct gfs2_jdesc *jd = sdp->sd_jdesc;
+       unsigned int lb;
+       u64 db, prev_db; /* logical block, disk block, prev disk block */
+       struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+       struct gfs2_journal_extent *jext = NULL;
+       struct buffer_head bh;
+       int rc = 0;
+
+       prev_db = 0;
+
+       for (lb = 0; lb < ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; lb++) {
+               bh.b_state = 0;
+               bh.b_blocknr = 0;
+               bh.b_size = 1 << ip->i_inode.i_blkbits;
+               rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0);
+               db = bh.b_blocknr;
+               if (rc || !db) {
+                       printk(KERN_INFO "GFS2 journal mapping error %d: lb="
+                              "%u db=%llu\n", rc, lb, (unsigned long long)db);
+                       break;
+               }
+               if (!prev_db || db != prev_db + 1) {
+                       jext = kzalloc(sizeof(struct gfs2_journal_extent),
+                                      GFP_KERNEL);
+                       if (!jext) {
+                               printk(KERN_INFO "GFS2 error: out of memory "
+                                      "mapping journal extents.\n");
+                               rc = -ENOMEM;
+                               break;
+                       }
+                       jext->dblock = db;
+                       jext->lblock = lb;
+                       jext->blocks = 1;
+                       list_add_tail(&jext->extent_list, &jd->extent_list);
+               } else {
+                       jext->blocks++;
+               }
+               prev_db = db;
+       }
+       return rc;
+}
+
 static int init_journal(struct gfs2_sbd *sdp, int undo)
 {
        struct gfs2_holder ji_gh;
@@ -340,7 +400,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
 
        if (sdp->sd_args.ar_spectator) {
                sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
-               sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
+               atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
        } else {
                if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
                        fs_err(sdp, "can't mount journal #%u\n",
@@ -377,7 +437,10 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                               sdp->sd_jdesc->jd_jid, error);
                        goto fail_jinode_gh;
                }
-               sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
+               atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
+
+               /* Map the extents for this journal's blocks */
+               map_journal_extents(sdp);
        }
 
        if (sdp->sd_lockstruct.ls_first) {
index 291f0c7eaa3bcf8249876a73e43f8920dbfa1f24..9f71372c1757b04f17c0295b01a4a6fc17398cde 100644 (file)
@@ -61,7 +61,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
                inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0);
                if (!IS_ERR(inode)) {
                        gfs2_trans_end(sdp);
-                       if (dip->i_alloc.al_rgd)
+                       if (dip->i_alloc->al_rgd)
                                gfs2_inplace_release(dip);
                        gfs2_quota_unlock(dip);
                        gfs2_alloc_put(dip);
@@ -113,8 +113,18 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
        if (inode && IS_ERR(inode))
                return ERR_PTR(PTR_ERR(inode));
 
-       if (inode)
+       if (inode) {
+               struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
+               struct gfs2_holder gh;
+               int error;
+               error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
+               if (error) {
+                       iput(inode);
+                       return ERR_PTR(error);
+               }
+               gfs2_glock_dq_uninit(&gh);
                return d_splice_alias(inode, dentry);
+       }
        d_add(dentry, inode);
 
        return NULL;
@@ -366,7 +376,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
        }
 
        gfs2_trans_end(sdp);
-       if (dip->i_alloc.al_rgd)
+       if (dip->i_alloc->al_rgd)
                gfs2_inplace_release(dip);
        gfs2_quota_unlock(dip);
        gfs2_alloc_put(dip);
@@ -442,7 +452,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
 
        gfs2_trans_end(sdp);
-       if (dip->i_alloc.al_rgd)
+       if (dip->i_alloc->al_rgd)
                gfs2_inplace_release(dip);
        gfs2_quota_unlock(dip);
        gfs2_alloc_put(dip);
@@ -548,7 +558,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
        }
 
        gfs2_trans_end(sdp);
-       if (dip->i_alloc.al_rgd)
+       if (dip->i_alloc->al_rgd)
                gfs2_inplace_release(dip);
        gfs2_quota_unlock(dip);
        gfs2_alloc_put(dip);
index 34f0caac1a030f2453a7e84df95cc3a6509c4098..fd8cee231e1d87887081ffb2bc2ec4b0d15b03b3 100644 (file)
@@ -16,5 +16,11 @@ extern const struct inode_operations gfs2_file_iops;
 extern const struct inode_operations gfs2_dir_iops;
 extern const struct inode_operations gfs2_symlink_iops;
 extern const struct inode_operations gfs2_dev_iops;
+extern const struct file_operations gfs2_file_fops;
+extern const struct file_operations gfs2_dir_fops;
+extern const struct file_operations gfs2_file_fops_nolock;
+extern const struct file_operations gfs2_dir_fops_nolock;
+
+extern void gfs2_set_inode_flags(struct inode *inode);
 
 #endif /* __OPS_INODE_DOT_H__ */
index 950f31460e8b756d64967e22abca0c51709d4f03..5e524217944a14b9862a618fb6d68f68cf8abbfe 100644 (file)
@@ -487,7 +487,6 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
        if (ip) {
                ip->i_flags = 0;
                ip->i_gl = NULL;
-               ip->i_last_pfault = jiffies;
        }
        return &ip->i_inode;
 }
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
deleted file mode 100644 (file)
index 927d739..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/buffer_head.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/gfs2_ondisk.h>
-#include <linux/lm_interface.h>
-
-#include "gfs2.h"
-#include "incore.h"
-#include "bmap.h"
-#include "glock.h"
-#include "inode.h"
-#include "ops_vm.h"
-#include "quota.h"
-#include "rgrp.h"
-#include "trans.h"
-#include "util.h"
-
-static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-       struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host);
-
-       set_bit(GIF_PAGED, &ip->i_flags);
-       return filemap_fault(vma, vmf);
-}
-
-static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
-{
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       unsigned long index = page->index;
-       u64 lblock = index << (PAGE_CACHE_SHIFT -
-                                   sdp->sd_sb.sb_bsize_shift);
-       unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
-       struct gfs2_alloc *al;
-       unsigned int data_blocks, ind_blocks;
-       unsigned int x;
-       int error;
-
-       al = gfs2_alloc_get(ip);
-
-       error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
-       if (error)
-               goto out;
-
-       error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
-       if (error)
-               goto out_gunlock_q;
-
-       gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
-
-       al->al_requested = data_blocks + ind_blocks;
-
-       error = gfs2_inplace_reserve(ip);
-       if (error)
-               goto out_gunlock_q;
-
-       error = gfs2_trans_begin(sdp, al->al_rgd->rd_length +
-                                ind_blocks + RES_DINODE +
-                                RES_STATFS + RES_QUOTA, 0);
-       if (error)
-               goto out_ipres;
-
-       if (gfs2_is_stuffed(ip)) {
-               error = gfs2_unstuff_dinode(ip, NULL);
-               if (error)
-                       goto out_trans;
-       }
-
-       for (x = 0; x < blocks; ) {
-               u64 dblock;
-               unsigned int extlen;
-               int new = 1;
-
-               error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
-               if (error)
-                       goto out_trans;
-
-               lblock += extlen;
-               x += extlen;
-       }
-
-       gfs2_assert_warn(sdp, al->al_alloced);
-
-out_trans:
-       gfs2_trans_end(sdp);
-out_ipres:
-       gfs2_inplace_release(ip);
-out_gunlock_q:
-       gfs2_quota_unlock(ip);
-out:
-       gfs2_alloc_put(ip);
-       return error;
-}
-
-static int gfs2_sharewrite_fault(struct vm_area_struct *vma,
-                                               struct vm_fault *vmf)
-{
-       struct file *file = vma->vm_file;
-       struct gfs2_file *gf = file->private_data;
-       struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
-       struct gfs2_holder i_gh;
-       int alloc_required;
-       int error;
-       int ret = 0;
-
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
-       if (error)
-               goto out;
-
-       set_bit(GIF_PAGED, &ip->i_flags);
-       set_bit(GIF_SW_PAGED, &ip->i_flags);
-
-       error = gfs2_write_alloc_required(ip,
-                                       (u64)vmf->pgoff << PAGE_CACHE_SHIFT,
-                                       PAGE_CACHE_SIZE, &alloc_required);
-       if (error) {
-               ret = VM_FAULT_OOM; /* XXX: are these right? */
-               goto out_unlock;
-       }
-
-       set_bit(GFF_EXLOCK, &gf->f_flags);
-       ret = filemap_fault(vma, vmf);
-       clear_bit(GFF_EXLOCK, &gf->f_flags);
-       if (ret & VM_FAULT_ERROR)
-               goto out_unlock;
-
-       if (alloc_required) {
-               /* XXX: do we need to drop page lock around alloc_page_backing?*/
-               error = alloc_page_backing(ip, vmf->page);
-               if (error) {
-                       /*
-                        * VM_FAULT_LOCKED should always be the case for
-                        * filemap_fault, but it may not be in a future
-                        * implementation.
-                        */
-                       if (ret & VM_FAULT_LOCKED)
-                               unlock_page(vmf->page);
-                       page_cache_release(vmf->page);
-                       ret = VM_FAULT_OOM;
-                       goto out_unlock;
-               }
-               set_page_dirty(vmf->page);
-       }
-
-out_unlock:
-       gfs2_glock_dq_uninit(&i_gh);
-out:
-       return ret;
-}
-
-struct vm_operations_struct gfs2_vm_ops_private = {
-       .fault = gfs2_private_fault,
-};
-
-struct vm_operations_struct gfs2_vm_ops_sharewrite = {
-       .fault = gfs2_sharewrite_fault,
-};
-
diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h
deleted file mode 100644 (file)
index 4ae8f43..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License version 2.
- */
-
-#ifndef __OPS_VM_DOT_H__
-#define __OPS_VM_DOT_H__
-
-#include <linux/mm.h>
-
-extern struct vm_operations_struct gfs2_vm_ops_private;
-extern struct vm_operations_struct gfs2_vm_ops_sharewrite;
-
-#endif /* __OPS_VM_DOT_H__ */
index addb51e0f1353118267fff55ebe74f3d1a8f6eb9..a08dabd6ce904c4eb7a92cdc4255a7b779a674cd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -59,7 +59,6 @@
 #include "super.h"
 #include "trans.h"
 #include "inode.h"
-#include "ops_file.h"
 #include "ops_address.h"
 #include "util.h"
 
@@ -274,10 +273,10 @@ static int bh_get(struct gfs2_quota_data *qd)
        }
 
        block = qd->qd_slot / sdp->sd_qc_per_block;
-       offset = qd->qd_slot % sdp->sd_qc_per_block;;
+       offset = qd->qd_slot % sdp->sd_qc_per_block;
 
        bh_map.b_size = 1 << ip->i_inode.i_blkbits;
-       error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map);
+       error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0);
        if (error)
                goto fail;
        error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
@@ -454,7 +453,7 @@ static void qdsb_put(struct gfs2_quota_data *qd)
 int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_quota_data **qd = al->al_qd;
        int error;
 
@@ -502,7 +501,7 @@ out:
 void gfs2_quota_unhold(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        unsigned int x;
 
        gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
@@ -646,7 +645,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        }
 
        if (!buffer_mapped(bh)) {
-               gfs2_get_block(inode, iblock, bh, 1);
+               gfs2_block_map(inode, iblock, bh, 1);
                if (!buffer_mapped(bh))
                        goto unlock;
        }
@@ -793,11 +792,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
        struct gfs2_holder i_gh;
        struct gfs2_quota_host q;
        char buf[sizeof(struct gfs2_quota)];
-       struct file_ra_state ra_state;
        int error;
        struct gfs2_quota_lvb *qlvb;
 
-       file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping);
 restart:
        error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
        if (error)
@@ -820,8 +817,8 @@ restart:
 
                memset(buf, 0, sizeof(struct gfs2_quota));
                pos = qd2offset(qd);
-               error = gfs2_internal_read(ip, &ra_state, buf,
-                                          &pos, sizeof(struct gfs2_quota));
+               error = gfs2_internal_read(ip, NULL, buf, &pos,
+                                          sizeof(struct gfs2_quota));
                if (error < 0)
                        goto fail_gunlock;
 
@@ -856,7 +853,7 @@ fail:
 int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        unsigned int x;
        int error = 0;
 
@@ -924,7 +921,7 @@ static int need_sync(struct gfs2_quota_data *qd)
 
 void gfs2_quota_unlock(struct gfs2_inode *ip)
 {
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_quota_data *qda[4];
        unsigned int count = 0;
        unsigned int x;
@@ -972,7 +969,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
 int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_quota_data *qd;
        s64 value;
        unsigned int x;
@@ -1016,10 +1013,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
                       u32 uid, u32 gid)
 {
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_quota_data *qd;
        unsigned int x;
-       unsigned int found = 0;
 
        if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change))
                return;
@@ -1032,7 +1028,6 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
                if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
                    (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
                        do_qc(qd, change);
-                       found++;
                }
        }
 }
index beb6c7ac0086623d5fe9fe39da480ce4b31419a0..b249e294a95bfa76cde2699716a3e96f817d6e03 100644 (file)
@@ -391,7 +391,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea
        lblock = head->lh_blkno;
        gfs2_replay_incr_blk(sdp, &lblock);
        bh_map.b_size = 1 << ip->i_inode.i_blkbits;
-       error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map);
+       error = gfs2_block_map(&ip->i_inode, lblock, &bh_map, 0);
        if (error)
                return error;
        if (!bh_map.b_blocknr) {
@@ -504,13 +504,21 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
                        if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
                                ro = 1;
                } else {
-                       if (sdp->sd_vfs->s_flags & MS_RDONLY)
-                               ro = 1;
+                       if (sdp->sd_vfs->s_flags & MS_RDONLY) {
+                               /* check if device itself is read-only */
+                               ro = bdev_read_only(sdp->sd_vfs->s_bdev);
+                               if (!ro) {
+                                       fs_info(sdp, "recovery required on "
+                                               "read-only filesystem.\n");
+                                       fs_info(sdp, "write access will be "
+                                               "enabled during recovery.\n");
+                               }
+                       }
                }
 
                if (ro) {
-                       fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n",
-                               jd->jd_jid);
+                       fs_warn(sdp, "jid=%u: Can't replay: read-only block "
+                               "device\n", jd->jd_jid);
                        error = -EROFS;
                        goto fail_gunlock_tr;
                }
index 708c287e1d0ef7327d08a8ca5d14ca36ac6e04ad..3552110b2e5f197ef4e1b1f905d868133f02a74a 100644 (file)
 #include "rgrp.h"
 #include "super.h"
 #include "trans.h"
-#include "ops_file.h"
 #include "util.h"
 #include "log.h"
 #include "inode.h"
+#include "ops_address.h"
 
 #define BFITNOENT ((u32)~0)
 #define NO_BLOCK ((u64)~0)
@@ -126,41 +126,43 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
  * Return: the block number (bitmap buffer scope) that was found
  */
 
-static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
-                           unsigned int buflen, u32 goal,
-                           unsigned char old_state)
+static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal,
+                      unsigned char old_state)
 {
-       unsigned char *byte, *end, alloc;
+       unsigned char *byte;
        u32 blk = goal;
-       unsigned int bit;
+       unsigned int bit, bitlong;
+       unsigned long *plong, plong55;
 
        byte = buffer + (goal / GFS2_NBBY);
+       plong = (unsigned long *)(buffer + (goal / GFS2_NBBY));
        bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
-       end = buffer + buflen;
-       alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
-
-       while (byte < end) {
-               /* If we're looking for a free block we can eliminate all
-                  bitmap settings with 0x55, which represents four data
-                  blocks in a row.  If we're looking for a data block, we can
-                  eliminate 0x00 which corresponds to four free blocks. */
-               if ((*byte & 0x55) == alloc) {
-                       blk += (8 - bit) >> 1;
-
-                       bit = 0;
-                       byte++;
-
+       bitlong = bit;
+#if BITS_PER_LONG == 32
+       plong55 = 0x55555555;
+#else
+       plong55 = 0x5555555555555555;
+#endif
+       while (byte < buffer + buflen) {
+
+               if (bitlong == 0 && old_state == 0 && *plong == plong55) {
+                       plong++;
+                       byte += sizeof(unsigned long);
+                       blk += sizeof(unsigned long) * GFS2_NBBY;
                        continue;
                }
-
                if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
                        return blk;
-
                bit += GFS2_BIT_SIZE;
                if (bit >= 8) {
                        bit = 0;
                        byte++;
                }
+               bitlong += GFS2_BIT_SIZE;
+               if (bitlong >= sizeof(unsigned long) * 8) {
+                       bitlong = 0;
+                       plong++;
+               }
 
                blk++;
        }
@@ -817,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
 
 struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
 {
-       struct gfs2_alloc *al = &ip->i_alloc;
-
-       /* FIXME: Should assert that the correct locks are held here... */
-       memset(al, 0, sizeof(*al));
-       return al;
+       BUG_ON(ip->i_alloc != NULL);
+       ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL);
+       return ip->i_alloc;
 }
 
 /**
@@ -1059,26 +1059,34 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
        struct inode *inode = NULL;
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrpd *rgd, *begin = NULL;
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        int flags = LM_FLAG_TRY;
        int skipped = 0;
        int loops = 0;
-       int error;
+       int error, rg_locked;
 
        /* Try recently successful rgrps */
 
        rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
 
        while (rgd) {
-               error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
-                                          LM_FLAG_TRY, &al->al_rgd_gh);
+               rg_locked = 0;
+
+               if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
+                       rg_locked = 1;
+                       error = 0;
+               } else {
+                       error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
+                                                  LM_FLAG_TRY, &al->al_rgd_gh);
+               }
                switch (error) {
                case 0:
                        if (try_rgrp_fit(rgd, al))
                                goto out;
                        if (rgd->rd_flags & GFS2_RDF_CHECK)
                                inode = try_rgrp_unlink(rgd, last_unlinked);
-                       gfs2_glock_dq_uninit(&al->al_rgd_gh);
+                       if (!rg_locked)
+                               gfs2_glock_dq_uninit(&al->al_rgd_gh);
                        if (inode)
                                return inode;
                        rgd = recent_rgrp_next(rgd, 1);
@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
        begin = rgd = forward_rgrp_get(sdp);
 
        for (;;) {
-               error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
-                                         &al->al_rgd_gh);
+               rg_locked = 0;
+
+               if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
+                       rg_locked = 1;
+                       error = 0;
+               } else {
+                       error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
+                                                  &al->al_rgd_gh);
+               }
                switch (error) {
                case 0:
                        if (try_rgrp_fit(rgd, al))
                                goto out;
                        if (rgd->rd_flags & GFS2_RDF_CHECK)
                                inode = try_rgrp_unlink(rgd, last_unlinked);
-                       gfs2_glock_dq_uninit(&al->al_rgd_gh);
+                       if (!rg_locked)
+                               gfs2_glock_dq_uninit(&al->al_rgd_gh);
                        if (inode)
                                return inode;
                        break;
@@ -1158,7 +1174,7 @@ out:
 int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct inode *inode;
        int error = 0;
        u64 last_unlinked = NO_BLOCK;
@@ -1204,7 +1220,7 @@ try_again:
 void gfs2_inplace_release(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
 
        if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
                fs_warn(sdp, "al_alloced = %u, al_requested = %u "
@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
                             al->al_line);
 
        al->al_rgd = NULL;
-       gfs2_glock_dq_uninit(&al->al_rgd_gh);
+       if (al->al_rgd_gh.gh_gl)
+               gfs2_glock_dq_uninit(&al->al_rgd_gh);
        if (ip != GFS2_I(sdp->sd_rindex))
                gfs2_glock_dq_uninit(&al->al_ri_gh);
 }
@@ -1301,11 +1318,10 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
                /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
                   bitmaps, so we must search the originals for that. */
                if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
-                       blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
+                       blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset,
                                          bi->bi_len, goal, old_state);
                else
-                       blk = gfs2_bitfit(rgd,
-                                         bi->bi_bh->b_data + bi->bi_offset,
+                       blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset,
                                          bi->bi_len, goal, old_state);
                if (blk != BFITNOENT)
                        break;
@@ -1394,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
 u64 gfs2_alloc_data(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_rgrpd *rgd = al->al_rgd;
        u32 goal, blk;
        u64 block;
@@ -1439,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip)
 u64 gfs2_alloc_meta(struct gfs2_inode *ip)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al = &ip->i_alloc;
+       struct gfs2_alloc *al = ip->i_alloc;
        struct gfs2_rgrpd *rgd = al->al_rgd;
        u32 goal, blk;
        u64 block;
@@ -1485,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip)
 u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
-       struct gfs2_alloc *al = &dip->i_alloc;
+       struct gfs2_alloc *al = dip->i_alloc;
        struct gfs2_rgrpd *rgd = al->al_rgd;
        u32 blk;
        u64 block;
index b4c6adfc6f2ebe447697c9bdadf8f7837ea7170e..149bb161f4b6628d76076ce0a4d1ff51247c8f65 100644 (file)
@@ -32,7 +32,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
 struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
 static inline void gfs2_alloc_put(struct gfs2_inode *ip)
 {
-       return; /* So we can see where ip->i_alloc is used */
+       BUG_ON(ip->i_alloc == NULL);
+       kfree(ip->i_alloc);
+       ip->i_alloc = NULL;
 }
 
 int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
index dd3e737f528e0b111387b506608e63fc99ef5c0b..ef0562c3bc71986705dab6c7593f0f29c9908da4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -51,13 +51,9 @@ void gfs2_tune_init(struct gfs2_tune *gt)
 {
        spin_lock_init(&gt->gt_spin);
 
-       gt->gt_ilimit = 100;
-       gt->gt_ilimit_tries = 3;
-       gt->gt_ilimit_min = 1;
        gt->gt_demote_secs = 300;
        gt->gt_incore_log_blocks = 1024;
        gt->gt_log_flush_secs = 60;
-       gt->gt_jindex_refresh_secs = 60;
        gt->gt_recoverd_secs = 60;
        gt->gt_logd_secs = 1;
        gt->gt_quotad_secs = 5;
@@ -71,10 +67,8 @@ void gfs2_tune_init(struct gfs2_tune *gt)
        gt->gt_new_files_jdata = 0;
        gt->gt_new_files_directio = 0;
        gt->gt_max_readahead = 1 << 18;
-       gt->gt_lockdump_size = 131072;
        gt->gt_stall_secs = 600;
        gt->gt_complain_secs = 10;
-       gt->gt_reclaim_limit = 5000;
        gt->gt_statfs_quantum = 30;
        gt->gt_statfs_slow = 0;
 }
@@ -393,6 +387,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
                if (!jd)
                        break;
 
+               INIT_LIST_HEAD(&jd->extent_list);
                jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
                if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
                        if (!jd->jd_inode)
@@ -422,8 +417,9 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
 
 void gfs2_jindex_free(struct gfs2_sbd *sdp)
 {
-       struct list_head list;
+       struct list_head list, *head;
        struct gfs2_jdesc *jd;
+       struct gfs2_journal_extent *jext;
 
        spin_lock(&sdp->sd_jindex_spin);
        list_add(&list, &sdp->sd_jindex_list);
@@ -433,6 +429,14 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
 
        while (!list_empty(&list)) {
                jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
+               head = &jd->extent_list;
+               while (!list_empty(head)) {
+                       jext = list_entry(head->next,
+                                         struct gfs2_journal_extent,
+                                         extent_list);
+                       list_del(&jext->extent_list);
+                       kfree(jext);
+               }
                list_del(&jd->jd_list);
                iput(jd->jd_inode);
                kfree(jd);
@@ -543,7 +547,6 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
        if (error)
                return error;
 
-       gfs2_meta_cache_flush(ip);
        j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
 
        error = gfs2_find_jhead(sdp->sd_jdesc, &head);
@@ -686,9 +689,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
        if (error)
                return;
 
-       mutex_lock(&sdp->sd_statfs_mutex);
        gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
-       mutex_unlock(&sdp->sd_statfs_mutex);
 
        spin_lock(&sdp->sd_statfs_spin);
        l_sc->sc_total += total;
@@ -736,9 +737,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp)
        if (error)
                goto out_bh2;
 
-       mutex_lock(&sdp->sd_statfs_mutex);
        gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
-       mutex_unlock(&sdp->sd_statfs_mutex);
 
        spin_lock(&sdp->sd_statfs_spin);
        m_sc->sc_total += l_sc->sc_total;
index 06e0b7768d9743817eef2715ced2cc1d025b0f2d..eaa3b7b2f99e64f4e95206b262a420329e693c61 100644 (file)
@@ -32,7 +32,8 @@ spinlock_t gfs2_sys_margs_lock;
 
 static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id);
+       return snprintf(buf, PAGE_SIZE, "%u:%u\n",
+                       MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev));
 }
 
 static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
@@ -221,9 +222,7 @@ static struct kobj_type gfs2_ktype = {
        .sysfs_ops     = &gfs2_attr_ops,
 };
 
-static struct kset gfs2_kset = {
-       .ktype  = &gfs2_ktype,
-};
+static struct kset *gfs2_kset;
 
 /*
  * display struct lm_lockstruct fields
@@ -427,13 +426,11 @@ TUNE_ATTR_2(name, name##_store)
 TUNE_ATTR(demote_secs, 0);
 TUNE_ATTR(incore_log_blocks, 0);
 TUNE_ATTR(log_flush_secs, 0);
-TUNE_ATTR(jindex_refresh_secs, 0);
 TUNE_ATTR(quota_warn_period, 0);
 TUNE_ATTR(quota_quantum, 0);
 TUNE_ATTR(atime_quantum, 0);
 TUNE_ATTR(max_readahead, 0);
 TUNE_ATTR(complain_secs, 0);
-TUNE_ATTR(reclaim_limit, 0);
 TUNE_ATTR(statfs_slow, 0);
 TUNE_ATTR(new_files_jdata, 0);
 TUNE_ATTR(new_files_directio, 0);
@@ -450,13 +447,11 @@ static struct attribute *tune_attrs[] = {
        &tune_attr_demote_secs.attr,
        &tune_attr_incore_log_blocks.attr,
        &tune_attr_log_flush_secs.attr,
-       &tune_attr_jindex_refresh_secs.attr,
        &tune_attr_quota_warn_period.attr,
        &tune_attr_quota_quantum.attr,
        &tune_attr_atime_quantum.attr,
        &tune_attr_max_readahead.attr,
        &tune_attr_complain_secs.attr,
-       &tune_attr_reclaim_limit.attr,
        &tune_attr_statfs_slow.attr,
        &tune_attr_quota_simul_sync.attr,
        &tune_attr_quota_cache_secs.attr,
@@ -495,14 +490,9 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
 {
        int error;
 
-       sdp->sd_kobj.kset = &gfs2_kset;
-       sdp->sd_kobj.ktype = &gfs2_ktype;
-
-       error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
-       if (error)
-               goto fail;
-
-       error = kobject_register(&sdp->sd_kobj);
+       sdp->sd_kobj.kset = gfs2_kset;
+       error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
+                                    "%s", sdp->sd_table_name);
        if (error)
                goto fail;
 
@@ -522,6 +512,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
        if (error)
                goto fail_args;
 
+       kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
        return 0;
 
 fail_args:
@@ -531,7 +522,7 @@ fail_counters:
 fail_lockstruct:
        sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
 fail_reg:
-       kobject_unregister(&sdp->sd_kobj);
+       kobject_put(&sdp->sd_kobj);
 fail:
        fs_err(sdp, "error %d adding sysfs files", error);
        return error;
@@ -543,21 +534,22 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
        sysfs_remove_group(&sdp->sd_kobj, &args_group);
        sysfs_remove_group(&sdp->sd_kobj, &counters_group);
        sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
-       kobject_unregister(&sdp->sd_kobj);
+       kobject_put(&sdp->sd_kobj);
 }
 
 int gfs2_sys_init(void)
 {
        gfs2_sys_margs = NULL;
        spin_lock_init(&gfs2_sys_margs_lock);
-       kobject_set_name(&gfs2_kset.kobj, "gfs2");
-       kobj_set_kset_s(&gfs2_kset, fs_subsys);
-       return kset_register(&gfs2_kset);
+       gfs2_kset = kset_create_and_add("gfs2", NULL, fs_kobj);
+       if (!gfs2_kset)
+               return -ENOMEM;
+       return 0;
 }
 
 void gfs2_sys_uninit(void)
 {
        kfree(gfs2_sys_margs);
-       kset_unregister(&gfs2_kset);
+       kset_unregister(gfs2_kset);
 }
 
index 717983e2c2ae3a6b262dd5e29c7a0abb29f1bc8a..73e5d92a657ca4aa119afb3658814d648ac4486a 100644 (file)
@@ -114,11 +114,6 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
                gfs2_log_flush(sdp, NULL);
 }
 
-void gfs2_trans_add_gl(struct gfs2_glock *gl)
-{
-       lops_add(gl->gl_sbd, &gl->gl_le);
-}
-
 /**
  * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction
  * @gl: the glock the buffer belongs to
index 043d5f4b9c4c34d5c519e574563219decd4603a1..e826f0dab80a841834d19336e59f9590eed8017f 100644 (file)
@@ -30,7 +30,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
 
 void gfs2_trans_end(struct gfs2_sbd *sdp);
 
-void gfs2_trans_add_gl(struct gfs2_glock *gl);
 void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
 void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
 void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
index f13f1494d4fe8099ca8779c8aaf0771ca1ec95c9..f8452a0eab562085ddd50e3f3e52352bebcc4cb2 100644 (file)
@@ -52,6 +52,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
                rec = (e + b) / 2;
                len = hfs_brec_lenoff(bnode, rec, &off);
                keylen = hfs_brec_keylen(bnode, rec);
+               if (keylen == HFS_BAD_KEYLEN) {
+                       res = -EINVAL;
+                       goto done;
+               }
                hfs_bnode_read(bnode, fd->key, off, keylen);
                cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
                if (!cmpval) {
@@ -67,6 +71,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
        if (rec != e && e >= 0) {
                len = hfs_brec_lenoff(bnode, e, &off);
                keylen = hfs_brec_keylen(bnode, e);
+               if (keylen == HFS_BAD_KEYLEN) {
+                       res = -EINVAL;
+                       goto done;
+               }
                hfs_bnode_read(bnode, fd->key, off, keylen);
        }
 done:
@@ -198,6 +206,10 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
 
        len = hfs_brec_lenoff(bnode, fd->record, &off);
        keylen = hfs_brec_keylen(bnode, fd->record);
+       if (keylen == HFS_BAD_KEYLEN) {
+               res = -EINVAL;
+               goto out;
+       }
        fd->keyoffset = off;
        fd->keylength = keylen;
        fd->entryoffset = off + keylen;
index 5c87cf4801fcb00f05311d2883c9977dbfa5ef2f..8626ee375ea811d3a4e794a5f72a05d96b09bea0 100644 (file)
@@ -44,10 +44,21 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
                recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
                if (!recoff)
                        return 0;
-               if (node->tree->attributes & HFS_TREE_BIGKEYS)
+               if (node->tree->attributes & HFS_TREE_BIGKEYS) {
                        retval = hfs_bnode_read_u16(node, recoff) + 2;
-               else
+                       if (retval > node->tree->max_key_len + 2) {
+                               printk(KERN_ERR "hfs: keylen %d too large\n",
+                                       retval);
+                               retval = HFS_BAD_KEYLEN;
+                       }
+               } else {
                        retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
+                       if (retval > node->tree->max_key_len + 1) {
+                               printk(KERN_ERR "hfs: keylen %d too large\n",
+                                       retval);
+                               retval = HFS_BAD_KEYLEN;
+                       }
+               }
        }
        return retval;
 }
index 8a3a650abc87a9ed4520318a811fb76619933a7e..110dd3515dc89b27e226a9a65867f338df18de69 100644 (file)
@@ -61,7 +61,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
        mapping = tree->inode->i_mapping;
        page = read_mapping_page(mapping, 0, NULL);
        if (IS_ERR(page))
-               goto free_tree;
+               goto free_inode;
 
        /* Load the header */
        head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
@@ -81,6 +81,17 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
                goto fail_page;
        if (!tree->node_count)
                goto fail_page;
+       if ((id == HFS_EXT_CNID) && (tree->max_key_len != HFS_MAX_EXT_KEYLEN)) {
+               printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
+                       tree->max_key_len);
+               goto fail_page;
+       }
+       if ((id == HFS_CAT_CNID) && (tree->max_key_len != HFS_MAX_CAT_KEYLEN)) {
+               printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
+                       tree->max_key_len);
+               goto fail_page;
+       }
+
        tree->node_size_shift = ffs(size) - 1;
        tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
@@ -88,11 +99,12 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
        page_cache_release(page);
        return tree;
 
- fail_page:
-       tree->inode->i_mapping->a_ops = &hfs_aops;
+fail_page:
        page_cache_release(page);
- free_tree:
+free_inode:
+       tree->inode->i_mapping->a_ops = &hfs_aops;
        iput(tree->inode);
+free_tree:
        kfree(tree);
        return NULL;
 }
index 1445e3a56ed45695428a1633a344c2f5f6462d1b..c6aae61adfe6f098f9c0fc260b1090b1331d29d9 100644 (file)
@@ -28,6 +28,8 @@
 #define HFS_MAX_NAMELEN                128
 #define HFS_MAX_VALENCE                32767U
 
+#define HFS_BAD_KEYLEN         0xFF
+
 /* Meanings of the drAtrb field of the MDB,
  * Reference: _Inside Macintosh: Files_ p. 2-61
  */
@@ -167,6 +169,9 @@ typedef union hfs_btree_key {
        struct hfs_ext_key ext;
 } hfs_btree_key;
 
+#define HFS_MAX_CAT_KEYLEN     (sizeof(struct hfs_cat_key) - sizeof(u8))
+#define HFS_MAX_EXT_KEYLEN     (sizeof(struct hfs_ext_key) - sizeof(u8))
+
 typedef union hfs_btree_key btree_key;
 
 struct hfs_extent {
index 08ff6c7028cc585b13cab54d01abb8ca1c6ea15d..038ed743619911799dfff8e27623e75f593fc60c 100644 (file)
@@ -288,10 +288,12 @@ handle_t *journal_start(journal_t *journal, int nblocks)
                jbd_free_handle(handle);
                current->journal_info = NULL;
                handle = ERR_PTR(err);
+               goto out;
        }
 
        lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_);
 
+out:
        return handle;
 }
 
index df25ecc418af0c7a3e06932255853312eb7b2e84..4dcc0581999881063ece0e2f6d745b7d52da2a5b 100644 (file)
@@ -284,11 +284,11 @@ static struct dir_table_slot *find_index(struct inode *ip, u32 index,
                        release_metapage(*mp);
                        *mp = NULL;
                }
-               if (*mp == 0) {
+               if (!(*mp)) {
                        *lblock = blkno;
                        *mp = read_index_page(ip, blkno);
                }
-               if (*mp == 0) {
+               if (!(*mp)) {
                        jfs_err("free_index: error reading directory table");
                        return NULL;
                }
@@ -413,7 +413,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
                }
                ip->i_size = PSIZE;
 
-               if ((mp = get_index_page(ip, 0)) == 0) {
+               mp = get_index_page(ip, 0);
+               if (!mp) {
                        jfs_err("add_index: get_metapage failed!");
                        xtTruncate(tid, ip, 0, COMMIT_PWMAP);
                        memcpy(&jfs_ip->i_dirtable, temp_table,
@@ -461,7 +462,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
        } else
                mp = read_index_page(ip, blkno);
 
-       if (mp == 0) {
+       if (!mp) {
                jfs_err("add_index: get/read_metapage failed!");
                goto clean_up;
        }
@@ -499,7 +500,7 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
 
        dirtab_slot = find_index(ip, index, &mp, &lblock);
 
-       if (dirtab_slot == 0)
+       if (!dirtab_slot)
                return;
 
        dirtab_slot->flag = DIR_INDEX_FREE;
@@ -526,7 +527,7 @@ static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
 
        dirtab_slot = find_index(ip, index, mp, lblock);
 
-       if (dirtab_slot == 0)
+       if (!dirtab_slot)
                return;
 
        DTSaddress(dirtab_slot, bn);
@@ -552,7 +553,7 @@ static int read_index(struct inode *ip, u32 index,
        struct dir_table_slot *slot;
 
        slot = find_index(ip, index, &mp, &lblock);
-       if (slot == 0) {
+       if (!slot) {
                return -EIO;
        }
 
@@ -592,10 +593,8 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
        struct component_name ciKey;
        struct super_block *sb = ip->i_sb;
 
-       ciKey.name =
-           (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
-                               GFP_NOFS);
-       if (ciKey.name == 0) {
+       ciKey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS);
+       if (!ciKey.name) {
                rc = -ENOMEM;
                goto dtSearch_Exit2;
        }
@@ -957,10 +956,8 @@ static int dtSplitUp(tid_t tid,
        smp = split->mp;
        sp = DT_PAGE(ip, smp);
 
-       key.name =
-           (wchar_t *) kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t),
-                               GFP_NOFS);
-       if (key.name == 0) {
+       key.name = kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t), GFP_NOFS);
+       if (!key.name) {
                DT_PUTPAGE(smp);
                rc = -ENOMEM;
                goto dtSplitUp_Exit;
index 8561c6ecece096648a7ea054d013686f58ab7fd1..cdac2d5bafeb3547a4ca51831bfd134b1f03ebd1 100644 (file)
@@ -74,7 +74,7 @@ struct idtentry {
 #define DTIHDRDATALEN  11
 
 /* compute number of slots for entry */
-#define        NDTINTERNAL(klen) ( ((4 + (klen)) + (15 - 1)) / 15 )
+#define        NDTINTERNAL(klen) (DIV_ROUND_UP((4 + (klen)), 15))
 
 
 /*
@@ -133,7 +133,7 @@ struct dir_table_slot {
        ( ((s64)((dts)->addr1)) << 32 | __le32_to_cpu((dts)->addr2) )
 
 /* compute number of slots for entry */
-#define        NDTLEAF_LEGACY(klen)    ( ((2 + (klen)) + (15 - 1)) / 15 )
+#define        NDTLEAF_LEGACY(klen)    (DIV_ROUND_UP((2 + (klen)), 15))
 #define        NDTLEAF NDTINTERNAL
 
 
index 3870ba8b9086b8f2c1c481eaf6a1eb2c79497238..9bf29f7717378c1dace7745751d9ff32f93d1dbf 100644 (file)
@@ -381,7 +381,7 @@ int diRead(struct inode *ip)
 
        /* read the page of disk inode */
        mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
-       if (mp == 0) {
+       if (!mp) {
                jfs_err("diRead: read_metapage failed");
                return -EIO;
        }
@@ -654,7 +654,7 @@ int diWrite(tid_t tid, struct inode *ip)
        /* read the page of disk inode */
       retry:
        mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
-       if (mp == 0)
+       if (!mp)
                return -EIO;
 
        /* get the pointer to the disk inode */
index 15a3974cdeeb1f478cb4040e47b80a61994a6ca5..325a9679b95a7f8e1e30cb9bbb255cbfc222be0e 100644 (file)
@@ -208,6 +208,17 @@ static struct lmStat {
 } lmStat;
 #endif
 
+static void write_special_inodes(struct jfs_log *log,
+                                int (*writer)(struct address_space *))
+{
+       struct jfs_sb_info *sbi;
+
+       list_for_each_entry(sbi, &log->sb_list, log_list) {
+               writer(sbi->ipbmap->i_mapping);
+               writer(sbi->ipimap->i_mapping);
+               writer(sbi->direct_inode->i_mapping);
+       }
+}
 
 /*
  * NAME:       lmLog()
@@ -935,22 +946,13 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
        struct lrd lrd;
        int lsn;
        struct logsyncblk *lp;
-       struct jfs_sb_info *sbi;
        unsigned long flags;
 
        /* push dirty metapages out to disk */
        if (hard_sync)
-               list_for_each_entry(sbi, &log->sb_list, log_list) {
-                       filemap_fdatawrite(sbi->ipbmap->i_mapping);
-                       filemap_fdatawrite(sbi->ipimap->i_mapping);
-                       filemap_fdatawrite(sbi->direct_inode->i_mapping);
-               }
+               write_special_inodes(log, filemap_fdatawrite);
        else
-               list_for_each_entry(sbi, &log->sb_list, log_list) {
-                       filemap_flush(sbi->ipbmap->i_mapping);
-                       filemap_flush(sbi->ipimap->i_mapping);
-                       filemap_flush(sbi->direct_inode->i_mapping);
-               }
+               write_special_inodes(log, filemap_flush);
 
        /*
         *      forward syncpt
@@ -1536,7 +1538,6 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
 {
        int i;
        struct tblock *target = NULL;
-       struct jfs_sb_info *sbi;
 
        /* jfs_write_inode may call us during read-only mount */
        if (!log)
@@ -1598,11 +1599,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
        if (wait < 2)
                return;
 
-       list_for_each_entry(sbi, &log->sb_list, log_list) {
-               filemap_fdatawrite(sbi->ipbmap->i_mapping);
-               filemap_fdatawrite(sbi->ipimap->i_mapping);
-               filemap_fdatawrite(sbi->direct_inode->i_mapping);
-       }
+       write_special_inodes(log, filemap_fdatawrite);
 
        /*
         * If there was recent activity, we may need to wait
@@ -1611,6 +1608,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
        if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
                for (i = 0; i < 200; i++) {     /* Too much? */
                        msleep(250);
+                       write_special_inodes(log, filemap_fdatawrite);
                        if (list_empty(&log->cqueue) &&
                            list_empty(&log->synclist))
                                break;
@@ -2347,7 +2345,7 @@ int jfsIOWait(void *arg)
 
        do {
                spin_lock_irq(&log_redrive_lock);
-               while ((bp = log_redrive_list) != 0) {
+               while ((bp = log_redrive_list)) {
                        log_redrive_list = bp->l_redrive_next;
                        bp->l_redrive_next = NULL;
                        spin_unlock_irq(&log_redrive_lock);
index f5cd8d38af7a9ff7af5ac2f4627d73964ccd5814..d1e64f2f2fcd1b434b4c07434bb19b82e6b189f9 100644 (file)
@@ -39,11 +39,11 @@ static struct {
 #endif
 
 #define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)
-#define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag)
+#define trylock_metapage(mp) test_and_set_bit_lock(META_locked, &(mp)->flag)
 
 static inline void unlock_metapage(struct metapage *mp)
 {
-       clear_bit(META_locked, &mp->flag);
+       clear_bit_unlock(META_locked, &mp->flag);
        wake_up(&mp->wait);
 }
 
@@ -88,7 +88,7 @@ struct meta_anchor {
 };
 #define mp_anchor(page) ((struct meta_anchor *)page_private(page))
 
-static inline struct metapage *page_to_mp(struct page *page, uint offset)
+static inline struct metapage *page_to_mp(struct page *page, int offset)
 {
        if (!PagePrivate(page))
                return NULL;
@@ -153,7 +153,7 @@ static inline void dec_io(struct page *page, void (*handler) (struct page *))
 }
 
 #else
-static inline struct metapage *page_to_mp(struct page *page, uint offset)
+static inline struct metapage *page_to_mp(struct page *page, int offset)
 {
        return PagePrivate(page) ? (struct metapage *)page_private(page) : NULL;
 }
@@ -249,7 +249,7 @@ static inline void drop_metapage(struct page *page, struct metapage *mp)
  */
 
 static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
-                                   unsigned int *len)
+                                   int *len)
 {
        int rc = 0;
        int xflag;
@@ -352,25 +352,27 @@ static void metapage_write_end_io(struct bio *bio, int err)
 static int metapage_writepage(struct page *page, struct writeback_control *wbc)
 {
        struct bio *bio = NULL;
-       unsigned int block_offset;      /* block offset of mp within page */
+       int block_offset;       /* block offset of mp within page */
        struct inode *inode = page->mapping->host;
-       unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
-       unsigned int len;
-       unsigned int xlen;
+       int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
+       int len;
+       int xlen;
        struct metapage *mp;
        int redirty = 0;
        sector_t lblock;
+       int nr_underway = 0;
        sector_t pblock;
        sector_t next_block = 0;
        sector_t page_start;
        unsigned long bio_bytes = 0;
        unsigned long bio_offset = 0;
-       unsigned int offset;
+       int offset;
 
        page_start = (sector_t)page->index <<
                     (PAGE_CACHE_SHIFT - inode->i_blkbits);
        BUG_ON(!PageLocked(page));
        BUG_ON(PageWriteback(page));
+       set_page_writeback(page);
 
        for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
                mp = page_to_mp(page, offset);
@@ -413,11 +415,10 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                        if (!bio->bi_size)
                                goto dump_bio;
                        submit_bio(WRITE, bio);
+                       nr_underway++;
                        bio = NULL;
-               } else {
-                       set_page_writeback(page);
+               } else
                        inc_io(page);
-               }
                xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
                pblock = metapage_get_blocks(inode, lblock, &xlen);
                if (!pblock) {
@@ -427,7 +428,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                        continue;
                }
                set_bit(META_io, &mp->flag);
-               len = min(xlen, (uint) JFS_SBI(inode->i_sb)->nbperpage);
+               len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage);
 
                bio = bio_alloc(GFP_NOFS, 1);
                bio->bi_bdev = inode->i_sb->s_bdev;
@@ -449,12 +450,16 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                        goto dump_bio;
 
                submit_bio(WRITE, bio);
+               nr_underway++;
        }
        if (redirty)
                redirty_page_for_writepage(wbc, page);
 
        unlock_page(page);
 
+       if (nr_underway == 0)
+               end_page_writeback(page);
+
        return 0;
 add_failed:
        /* We should never reach here, since we're only adding one vec */
@@ -475,13 +480,13 @@ static int metapage_readpage(struct file *fp, struct page *page)
 {
        struct inode *inode = page->mapping->host;
        struct bio *bio = NULL;
-       unsigned int block_offset;
-       unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
+       int block_offset;
+       int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
        sector_t page_start;    /* address of page in fs blocks */
        sector_t pblock;
-       unsigned int xlen;
+       int xlen;
        unsigned int len;
-       unsigned int offset;
+       int offset;
 
        BUG_ON(!PageLocked(page));
        page_start = (sector_t)page->index <<
@@ -530,7 +535,7 @@ static int metapage_releasepage(struct page *page, gfp_t gfp_mask)
 {
        struct metapage *mp;
        int ret = 1;
-       unsigned int offset;
+       int offset;
 
        for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
                mp = page_to_mp(page, offset);
index 644429acb8c05d92d49e2129df8d155d37792c4b..7b698f2ec45afc5f598ff21ffea3bc95fc0422c2 100644 (file)
@@ -147,7 +147,7 @@ int jfs_mount(struct super_block *sb)
         */
        if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
                ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
-               if (ipaimap2 == 0) {
+               if (!ipaimap2) {
                        jfs_err("jfs_mount: Faild to read AGGREGATE_I");
                        rc = -EIO;
                        goto errout35;
index 7971f37534a359e0dcfed248cb56e56a14c7fac7..adcf92d3b6035f0396f4a3428aa91f0fddae1055 100644 (file)
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
                /*
                 * Wait for outstanding transactions to be written to log:
                 */
-               jfs_flush_journal(log, 2);
+               jfs_flush_journal(log, 1);
 
        /*
         * close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
         *
         * remove file system from log active file system list.
         */
-       jfs_flush_journal(log, 2);
+       jfs_flush_journal(log, 1);
 
        /*
         * Make sure all metadata makes it to disk
index 4e0a8493cef69c394bcab1478f0872e7268b0425..f8718de3505e9fc56805b5a338fbb244c59e3488 100644 (file)
@@ -1103,8 +1103,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * Make sure dest inode number (if any) is what we think it is
         */
        rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
-       if (rc == 0) {
-               if ((new_ip == 0) || (ino != new_ip->i_ino)) {
+       if (!rc) {
+               if ((!new_ip) || (ino != new_ip->i_ino)) {
                        rc = -ESTALE;
                        goto out3;
                }
index 71984ee95346cd214cdab467e71a646cc496b279..7f24a0bb08ca0a25d31352e9611273de87d2ee1b 100644 (file)
@@ -172,7 +172,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
         */
        t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
            << L2BPERDMAP;
-       t32 = ((t64 + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50;
+       t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50;
        newFSCKSize = t32 << sbi->l2nbperpage;
        newFSCKAddress = newLogAddress - newFSCKSize;
 
index 314bb4ff1ba8a185715c8979feee658613eb6f13..70a14001c98f4c3b13a523346635195fb51cae96 100644 (file)
@@ -598,6 +598,12 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_printf(seq, ",umask=%03o", sbi->umask);
        if (sbi->flag & JFS_NOINTEGRITY)
                seq_puts(seq, ",nointegrity");
+       if (sbi->nls_tab)
+               seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
+       if (sbi->flag & JFS_ERR_CONTINUE)
+               seq_printf(seq, ",errors=continue");
+       if (sbi->flag & JFS_ERR_PANIC)
+               seq_printf(seq, ",errors=panic");
 
 #ifdef CONFIG_QUOTA
        if (sbi->flag & JFS_USRQUOTA)
index 3b993db26cee2c2df753f883239e6e917039bd38..73e2e665817a100c9f05c33a12756f639d9c5ae7 100644 (file)
@@ -1605,7 +1605,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
        if (S_ISLNK(inode->i_mode))
                return -ELOOP;
        
-       if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
+       if (S_ISDIR(inode->i_mode) && (acc_mode & MAY_WRITE))
                return -EISDIR;
 
        /*
@@ -1620,7 +1620,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
                        return -EACCES;
 
                flag &= ~O_TRUNC;
-       } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
+       } else if (IS_RDONLY(inode) && (acc_mode & MAY_WRITE))
                return -EROFS;
 
        error = vfs_permission(nd, acc_mode);
index 06083885b21e85314e3a196d13c7822dcc7c6e9d..61bf376e29e85bfda2456cb929c0a0eeb38af1b3 100644 (file)
@@ -41,8 +41,8 @@ static struct kmem_cache *mnt_cache __read_mostly;
 static struct rw_semaphore namespace_sem;
 
 /* /sys/fs */
-decl_subsys(fs, NULL, NULL);
-EXPORT_SYMBOL_GPL(fs_subsys);
+struct kobject *fs_kobj;
+EXPORT_SYMBOL_GPL(fs_kobj);
 
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
@@ -1861,10 +1861,9 @@ void __init mnt_init(void)
        if (err)
                printk(KERN_WARNING "%s: sysfs_init error: %d\n",
                        __FUNCTION__, err);
-       err = subsystem_register(&fs_subsys);
-       if (err)
-               printk(KERN_WARNING "%s: subsystem_register error: %d\n",
-                       __FUNCTION__, err);
+       fs_kobj = kobject_create_and_add("fs", NULL);
+       if (!fs_kobj)
+               printk(KERN_WARNING "%s: kobj create error\n", __FUNCTION__);
        init_rootfs();
        init_mount_tree();
 }
index b35069a2aa9e575bd81fa09f59b67048718cca48..bd1b9d663fb9545893dc0b95722185c98a0666fa 100644 (file)
@@ -115,6 +115,7 @@ struct nfs4_lock_state {
 #define NFS_LOCK_INITIALIZED 1
        int                     ls_flags;
        struct nfs_seqid_counter        ls_seqid;
+       struct rpc_sequence     ls_sequence;
        struct nfs_unique_id    ls_id;
        nfs4_stateid            ls_stateid;
        atomic_t                ls_count;
index f03d9d5f5ba40d9d3db91a1dbb4ef43d74ab64bc..9e2e1c7291dbfd5959ba53389351f72c233629b8 100644 (file)
@@ -741,10 +741,10 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
        if (data->rpc_status == 0) {
                memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
                                sizeof(data->o_res.stateid.data));
+               nfs_confirm_seqid(&data->owner->so_seqid, 0);
                renew_lease(data->o_res.server, data->timestamp);
                data->rpc_done = 1;
        }
-       nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status);
        nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid);
 }
 
@@ -759,7 +759,6 @@ static void nfs4_open_confirm_release(void *calldata)
        /* In case of error, no cleanup! */
        if (!data->rpc_done)
                goto out_free;
-       nfs_confirm_seqid(&data->owner->so_seqid, 0);
        state = nfs4_opendata_to_nfs4_state(data);
        if (!IS_ERR(state))
                nfs4_close_state(&data->path, state, data->o_arg.open_flags);
@@ -886,7 +885,6 @@ static void nfs4_open_release(void *calldata)
        /* In case we need an open_confirm, no cleanup! */
        if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
                goto out_free;
-       nfs_confirm_seqid(&data->owner->so_seqid, 0);
        state = nfs4_opendata_to_nfs4_state(data);
        if (!IS_ERR(state))
                nfs4_close_state(&data->path, state, data->o_arg.open_flags);
@@ -3333,6 +3331,12 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
 
        p->arg.fh = NFS_FH(inode);
        p->arg.fl = &p->fl;
+       if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) {
+               p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid);
+               if (p->arg.open_seqid == NULL)
+                       goto out_free;
+
+       }
        p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid);
        if (p->arg.lock_seqid == NULL)
                goto out_free;
@@ -3345,6 +3349,8 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        memcpy(&p->fl, fl, sizeof(p->fl));
        return p;
 out_free:
+       if (p->arg.open_seqid != NULL)
+               nfs_free_seqid(p->arg.open_seqid);
        kfree(p);
        return NULL;
 }
@@ -3361,23 +3367,23 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
                .rpc_cred = sp->so_cred,
        };
 
-       if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
-               return;
        dprintk("%s: begin!\n", __FUNCTION__);
        /* Do we need to do an open_to_lock_owner? */
        if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
-               data->arg.open_seqid = nfs_alloc_seqid(&sp->so_seqid);
-               if (data->arg.open_seqid == NULL) {
-                       data->rpc_status = -ENOMEM;
-                       task->tk_action = NULL;
-                       goto out;
-               }
+               if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
+                       return;
                data->arg.open_stateid = &state->stateid;
                data->arg.new_lock_owner = 1;
+               /* Retest in case we raced... */
+               if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED))
+                       goto do_rpc;
        }
+       if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
+               return;
+       data->arg.new_lock_owner = 0;
+do_rpc:        
        data->timestamp = jiffies;
        rpc_call_setup(task, &msg, 0);
-out:
        dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status);
 }
 
@@ -3413,8 +3419,6 @@ static void nfs4_lock_release(void *calldata)
        struct nfs4_lockdata *data = calldata;
 
        dprintk("%s: begin!\n", __FUNCTION__);
-       if (data->arg.open_seqid != NULL)
-               nfs_free_seqid(data->arg.open_seqid);
        if (data->cancelled != 0) {
                struct rpc_task *task;
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
@@ -3424,6 +3428,8 @@ static void nfs4_lock_release(void *calldata)
                dprintk("%s: cancelling lock!\n", __FUNCTION__);
        } else
                nfs_free_seqid(data->arg.lock_seqid);
+       if (data->arg.open_seqid != NULL)
+               nfs_free_seqid(data->arg.open_seqid);
        nfs4_put_lock_state(data->lsp);
        put_nfs_open_context(data->ctx);
        kfree(data);
index 3ea352d82eba23dc0db2b2d890904e352d7dba78..5e2e4af1a0e6c016237448b8e810165da63190d3 100644 (file)
@@ -133,9 +133,7 @@ nfs4_renewd_prepare_shutdown(struct nfs_server *server)
 void
 nfs4_kill_renewd(struct nfs_client *clp)
 {
-       down_read(&clp->cl_sem);
        cancel_delayed_work_sync(&clp->cl_renewd);
-       up_read(&clp->cl_sem);
 }
 
 /*
index 23a9a36556bf5f5ca4dba357157cbb35dc9ac331..5a39c6f78acf9394960885a1b774392d84019629 100644 (file)
@@ -509,7 +509,10 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
        lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
        if (lsp == NULL)
                return NULL;
-       lsp->ls_seqid.sequence = &state->owner->so_sequence;
+       rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue");
+       spin_lock_init(&lsp->ls_sequence.lock);
+       INIT_LIST_HEAD(&lsp->ls_sequence.list);
+       lsp->ls_seqid.sequence = &lsp->ls_sequence;
        atomic_set(&lsp->ls_count, 1);
        lsp->ls_owner = fl_owner;
        spin_lock(&clp->cl_lock);
index ea929207f27412e24a04631a301339b5990f7830..0b0c72a072ffd5c5c772a518d01db5a75fe4392a 100644 (file)
@@ -1475,7 +1475,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
                error = PTR_ERR(mntroot);
                goto error_splat_super;
        }
-       if (mntroot->d_inode->i_op != server->nfs_client->rpc_ops->dir_inode_ops) {
+       if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
                dput(mntroot);
                error = -ESTALE;
                goto error_splat_super;
@@ -1826,6 +1826,11 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
                error = PTR_ERR(mntroot);
                goto error_splat_super;
        }
+       if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
+               dput(mntroot);
+               error = -ESTALE;
+               goto error_splat_super;
+       }
 
        s->s_flags |= MS_ACTIVE;
        mnt->mnt_sb = s;
@@ -1900,6 +1905,11 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
                error = PTR_ERR(mntroot);
                goto error_splat_super;
        }
+       if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
+               dput(mntroot);
+               error = -ESTALE;
+               goto error_splat_super;
+       }
 
        s->s_flags |= MS_ACTIVE;
        mnt->mnt_sb = s;
index 2d116d2298f8e3aec23982bc04795dd9daf69ca2..f917fd25858af81a4edaf712fffa3480ee3a8e6b 100644 (file)
@@ -388,8 +388,11 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
         * Round the length of the data which was specified up to
         * the next multiple of XDR units and then compare that
         * against the length which was actually received.
+        * Note that when RPCSEC/GSS (for example) is used, the
+        * data buffer can be padded so dlen might be larger
+        * than required.  It must never be smaller.
         */
-       if (dlen != XDR_QUADLEN(len)*4)
+       if (dlen < XDR_QUADLEN(len)*4)
                return 0;
 
        if (args->count > max_blocksize) {
index 986f9b32083c655f792ada9476d3658a71bb37d7..b86e3658a0af10ebce825e260ee1fc5fd879f367 100644 (file)
@@ -313,8 +313,11 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
         * Round the length of the data which was specified up to
         * the next multiple of XDR units and then compare that
         * against the length which was actually received.
+        * Note that when RPCSEC/GSS (for example) is used, the
+        * data buffer can be padded so dlen might be larger
+        * than required.  It must never be smaller.
         */
-       if (dlen != XDR_QUADLEN(len)*4)
+       if (dlen < XDR_QUADLEN(len)*4)
                return 0;
 
        rqstp->rq_vec[0].iov_base = (void*)p;
index 9fb8132f19b0f97f049cb3dd19e62625702155ac..4d4ce48bb42c2eb29f4ecb099b5bd63a97040e2a 100644 (file)
@@ -19,16 +19,17 @@ ocfs2-objs := \
        ioctl.o                 \
        journal.o               \
        localalloc.o            \
+       locks.o                 \
        mmap.o                  \
        namei.o                 \
+       resize.o                \
        slot_map.o              \
        suballoc.o              \
        super.o                 \
        symlink.o               \
        sysfile.o               \
        uptodate.o              \
-       ver.o                   \
-       vote.o
+       ver.o
 
 obj-$(CONFIG_OCFS2_FS) += cluster/
 obj-$(CONFIG_OCFS2_FS) += dlm/
index 23c8cda43f191c02e0bd15b4c7aaef564dfe2568..e6df06ac64059bb495a742f892530e1dd3212f3b 100644 (file)
@@ -4731,7 +4731,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
 
        mutex_lock(&data_alloc_inode->i_mutex);
 
-       status = ocfs2_meta_lock(data_alloc_inode, &data_alloc_bh, 1);
+       status = ocfs2_inode_lock(data_alloc_inode, &data_alloc_bh, 1);
        if (status < 0) {
                mlog_errno(status);
                goto out_mutex;
@@ -4753,7 +4753,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
 
 out_unlock:
        brelse(data_alloc_bh);
-       ocfs2_meta_unlock(data_alloc_inode, 1);
+       ocfs2_inode_unlock(data_alloc_inode, 1);
 
 out_mutex:
        mutex_unlock(&data_alloc_inode->i_mutex);
@@ -5077,7 +5077,7 @@ static int ocfs2_free_cached_items(struct ocfs2_super *osb,
 
        mutex_lock(&inode->i_mutex);
 
-       ret = ocfs2_meta_lock(inode, &di_bh, 1);
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
        if (ret) {
                mlog_errno(ret);
                goto out_mutex;
@@ -5118,7 +5118,7 @@ out_journal:
        ocfs2_commit_trans(osb, handle);
 
 out_unlock:
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
        brelse(di_bh);
 out_mutex:
        mutex_unlock(&inode->i_mutex);
index 56f7790cad46d6bb0ca7c7805e62df8561d7dbb0..bc7b4cbbe8eca6f418761b64d0ff8f24141242b0 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/byteorder.h>
 #include <linux/swap.h>
 #include <linux/pipe_fs_i.h>
+#include <linux/mpage.h>
 
 #define MLOG_MASK_PREFIX ML_FILE_IO
 #include <cluster/masklog.h>
@@ -139,7 +140,8 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
 {
        int err = 0;
        unsigned int ext_flags;
-       u64 p_blkno, past_eof;
+       u64 max_blocks = bh_result->b_size >> inode->i_blkbits;
+       u64 p_blkno, count, past_eof;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode,
@@ -155,7 +157,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
                goto bail;
        }
 
-       err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL,
+       err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &count,
                                          &ext_flags);
        if (err) {
                mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
@@ -164,6 +166,9 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
                goto bail;
        }
 
+       if (max_blocks < count)
+               count = max_blocks;
+
        /*
         * ocfs2 never allocates in this function - the only time we
         * need to use BH_New is when we're extending i_size on a file
@@ -178,6 +183,8 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
        if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
                map_bh(bh_result, inode->i_sb, p_blkno);
 
+       bh_result->b_size = count << inode->i_blkbits;
+
        if (!ocfs2_sparse_alloc(osb)) {
                if (p_blkno == 0) {
                        err = -EIO;
@@ -210,7 +217,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
                           struct buffer_head *di_bh)
 {
        void *kaddr;
-       unsigned int size;
+       loff_t size;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 
        if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) {
@@ -224,8 +231,9 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
        if (size > PAGE_CACHE_SIZE ||
            size > ocfs2_max_inline_data(inode->i_sb)) {
                ocfs2_error(inode->i_sb,
-                           "Inode %llu has with inline data has bad size: %u",
-                           (unsigned long long)OCFS2_I(inode)->ip_blkno, size);
+                           "Inode %llu has with inline data has bad size: %Lu",
+                           (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                           (unsigned long long)size);
                return -EROFS;
        }
 
@@ -275,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
 
        mlog_entry("(0x%p, %lu)\n", file, (page ? page->index : 0));
 
-       ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page);
+       ret = ocfs2_inode_lock_with_page(inode, NULL, 0, page);
        if (ret != 0) {
                if (ret == AOP_TRUNCATED_PAGE)
                        unlock = 0;
@@ -285,7 +293,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
 
        if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
                ret = AOP_TRUNCATED_PAGE;
-               goto out_meta_unlock;
+               goto out_inode_unlock;
        }
 
        /*
@@ -305,25 +313,16 @@ static int ocfs2_readpage(struct file *file, struct page *page)
                goto out_alloc;
        }
 
-       ret = ocfs2_data_lock_with_page(inode, 0, page);
-       if (ret != 0) {
-               if (ret == AOP_TRUNCATED_PAGE)
-                       unlock = 0;
-               mlog_errno(ret);
-               goto out_alloc;
-       }
-
        if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
                ret = ocfs2_readpage_inline(inode, page);
        else
                ret = block_read_full_page(page, ocfs2_get_block);
        unlock = 0;
 
-       ocfs2_data_unlock(inode, 0);
 out_alloc:
        up_read(&OCFS2_I(inode)->ip_alloc_sem);
-out_meta_unlock:
-       ocfs2_meta_unlock(inode, 0);
+out_inode_unlock:
+       ocfs2_inode_unlock(inode, 0);
 out:
        if (unlock)
                unlock_page(page);
@@ -331,6 +330,62 @@ out:
        return ret;
 }
 
+/*
+ * This is used only for read-ahead. Failures or difficult to handle
+ * situations are safe to ignore.
+ *
+ * Right now, we don't bother with BH_Boundary - in-inode extent lists
+ * are quite large (243 extents on 4k blocks), so most inodes don't
+ * grow out to a tree. If need be, detecting boundary extents could
+ * trivially be added in a future version of ocfs2_get_block().
+ */
+static int ocfs2_readpages(struct file *filp, struct address_space *mapping,
+                          struct list_head *pages, unsigned nr_pages)
+{
+       int ret, err = -EIO;
+       struct inode *inode = mapping->host;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       loff_t start;
+       struct page *last;
+
+       /*
+        * Use the nonblocking flag for the dlm code to avoid page
+        * lock inversion, but don't bother with retrying.
+        */
+       ret = ocfs2_inode_lock_full(inode, NULL, 0, OCFS2_LOCK_NONBLOCK);
+       if (ret)
+               return err;
+
+       if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
+               ocfs2_inode_unlock(inode, 0);
+               return err;
+       }
+
+       /*
+        * Don't bother with inline-data. There isn't anything
+        * to read-ahead in that case anyway...
+        */
+       if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               goto out_unlock;
+
+       /*
+        * Check whether a remote node truncated this file - we just
+        * drop out in that case as it's not worth handling here.
+        */
+       last = list_entry(pages->prev, struct page, lru);
+       start = (loff_t)last->index << PAGE_CACHE_SHIFT;
+       if (start >= i_size_read(inode))
+               goto out_unlock;
+
+       err = mpage_readpages(mapping, pages, nr_pages, ocfs2_get_block);
+
+out_unlock:
+       up_read(&oi->ip_alloc_sem);
+       ocfs2_inode_unlock(inode, 0);
+
+       return err;
+}
+
 /* Note: Because we don't support holes, our allocation has
  * already happened (allocation writes zeros to the file data)
  * so we don't have to worry about ordered writes in
@@ -452,7 +507,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
         * accessed concurrently from multiple nodes.
         */
        if (!INODE_JOURNAL(inode)) {
-               err = ocfs2_meta_lock(inode, NULL, 0);
+               err = ocfs2_inode_lock(inode, NULL, 0);
                if (err) {
                        if (err != -ENOENT)
                                mlog_errno(err);
@@ -467,7 +522,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
 
        if (!INODE_JOURNAL(inode)) {
                up_read(&OCFS2_I(inode)->ip_alloc_sem);
-               ocfs2_meta_unlock(inode, 0);
+               ocfs2_inode_unlock(inode, 0);
        }
 
        if (err) {
@@ -638,34 +693,12 @@ static ssize_t ocfs2_direct_IO(int rw,
        if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
                return 0;
 
-       if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
-               /*
-                * We get PR data locks even for O_DIRECT.  This
-                * allows concurrent O_DIRECT I/O but doesn't let
-                * O_DIRECT with extending and buffered zeroing writes
-                * race.  If they did race then the buffered zeroing
-                * could be written back after the O_DIRECT I/O.  It's
-                * one thing to tell people not to mix buffered and
-                * O_DIRECT writes, but expecting them to understand
-                * that file extension is also an implicit buffered
-                * write is too much.  By getting the PR we force
-                * writeback of the buffered zeroing before
-                * proceeding.
-                */
-               ret = ocfs2_data_lock(inode, 0);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto out;
-               }
-               ocfs2_data_unlock(inode, 0);
-       }
-
        ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
                                            inode->i_sb->s_bdev, iov, offset,
                                            nr_segs, 
                                            ocfs2_direct_IO_get_blocks,
                                            ocfs2_dio_end_io);
-out:
+
        mlog_exit(ret);
        return ret;
 }
@@ -1754,7 +1787,7 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
        struct buffer_head *di_bh = NULL;
        struct inode *inode = mapping->host;
 
-       ret = ocfs2_meta_lock(inode, &di_bh, 1);
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
        if (ret) {
                mlog_errno(ret);
                return ret;
@@ -1769,30 +1802,22 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
         */
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-       ret = ocfs2_data_lock(inode, 1);
-       if (ret) {
-               mlog_errno(ret);
-               goto out_fail;
-       }
-
        ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep,
                                       fsdata, di_bh, NULL);
        if (ret) {
                mlog_errno(ret);
-               goto out_fail_data;
+               goto out_fail;
        }
 
        brelse(di_bh);
 
        return 0;
 
-out_fail_data:
-       ocfs2_data_unlock(inode, 1);
 out_fail:
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
 
        brelse(di_bh);
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 
        return ret;
 }
@@ -1908,15 +1933,15 @@ static int ocfs2_write_end(struct file *file, struct address_space *mapping,
 
        ret = ocfs2_write_end_nolock(mapping, pos, len, copied, page, fsdata);
 
-       ocfs2_data_unlock(inode, 1);
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 
        return ret;
 }
 
 const struct address_space_operations ocfs2_aops = {
        .readpage       = ocfs2_readpage,
+       .readpages      = ocfs2_readpages,
        .writepage      = ocfs2_writepage,
        .write_begin    = ocfs2_write_begin,
        .write_end      = ocfs2_write_end,
index c9037414f4f65fad9f0b812b9ba75f7c9823cc6d..f136639f5b41d023ea0f71d9c2bd1b7084c39322 100644 (file)
@@ -79,7 +79,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
                 * information for this bh as it's not marked locally
                 * uptodate. */
                ret = -EIO;
-               brelse(bh);
+               put_bh(bh);
        }
 
        mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
@@ -256,7 +256,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                                 * for this bh as it's not marked locally
                                 * uptodate. */
                                status = -EIO;
-                               brelse(bh);
+                               put_bh(bh);
                                bhs[i] = NULL;
                                continue;
                        }
@@ -280,3 +280,64 @@ bail:
        mlog_exit(status);
        return status;
 }
+
+/* Check whether the blkno is the super block or one of the backups. */
+static void ocfs2_check_super_or_backup(struct super_block *sb,
+                                       sector_t blkno)
+{
+       int i;
+       u64 backup_blkno;
+
+       if (blkno == OCFS2_SUPER_BLOCK_BLKNO)
+               return;
+
+       for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
+               backup_blkno = ocfs2_backup_super_blkno(sb, i);
+               if (backup_blkno == blkno)
+                       return;
+       }
+
+       BUG();
+}
+
+/*
+ * Write super block and backups doesn't need to collaborate with journal,
+ * so we don't need to lock ip_io_mutex and inode doesn't need to bea passed
+ * into this function.
+ */
+int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
+                               struct buffer_head *bh)
+{
+       int ret = 0;
+
+       mlog_entry_void();
+
+       BUG_ON(buffer_jbd(bh));
+       ocfs2_check_super_or_backup(osb->sb, bh->b_blocknr);
+
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) {
+               ret = -EROFS;
+               goto out;
+       }
+
+       lock_buffer(bh);
+       set_buffer_uptodate(bh);
+
+       /* remove from dirty list before I/O. */
+       clear_buffer_dirty(bh);
+
+       get_bh(bh); /* for end_buffer_write_sync() */
+       bh->b_end_io = end_buffer_write_sync;
+       submit_bh(WRITE, bh);
+
+       wait_on_buffer(bh);
+
+       if (!buffer_uptodate(bh)) {
+               ret = -EIO;
+               put_bh(bh);
+       }
+
+out:
+       mlog_exit(ret);
+       return ret;
+}
index 6cc20930fac31429319ce76a060b7475e94f45e9..c2e78614c3e50970ed01521d5e38e2371adeb388 100644 (file)
@@ -47,6 +47,8 @@ int ocfs2_read_blocks(struct ocfs2_super          *osb,
                      int                  flags,
                      struct inode        *inode);
 
+int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
+                               struct buffer_head *bh);
 
 #define OCFS2_BH_CACHED            1
 #define OCFS2_BH_READAHEAD         8
index 35397dd5ecdbb42c3922cbc9e930081c4c522b87..e511339886b31040e5597695726692b91be07e11 100644 (file)
@@ -35,7 +35,7 @@
 #define O2HB_LIVE_THRESHOLD       2
 /* number of equal samples to be seen as dead */
 extern unsigned int o2hb_dead_threshold;
-#define O2HB_DEFAULT_DEAD_THRESHOLD       7
+#define O2HB_DEFAULT_DEAD_THRESHOLD       31
 /* Otherwise MAX_WRITE_TIMEOUT will be zero... */
 #define O2HB_MIN_DEAD_THRESHOLD          2
 #define O2HB_MAX_WRITE_TIMEOUT_MS (O2HB_REGION_TIMEOUT_MS * (o2hb_dead_threshold - 1))
index a4882c8df945ef402694d8b4a392261a0db45dea..23c732f275293bfdd24dad2d03ddbb07c7c4b8e8 100644 (file)
@@ -146,7 +146,7 @@ static struct kset mlog_kset = {
        .kobj   = {.ktype = &mlog_ktype},
 };
 
-int mlog_sys_init(struct kset *o2cb_subsys)
+int mlog_sys_init(struct kset *o2cb_kset)
 {
        int i = 0;
 
@@ -157,7 +157,7 @@ int mlog_sys_init(struct kset *o2cb_subsys)
        mlog_attr_ptrs[i] = NULL;
 
        kobject_set_name(&mlog_kset.kobj, "logmask");
-       kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
+       mlog_kset.kobj.kset = o2cb_kset;
        return kset_register(&mlog_kset);
 }
 
index 64f6f378fd097d4dd33a740b82a8df35224cf7e3..a4b07730b2e1d0abb257a126fce7f3911ae1d434 100644 (file)
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
+#include <linux/fs.h>
 
 #include "ocfs2_nodemanager.h"
 #include "masklog.h"
 #include "sys.h"
 
-struct o2cb_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(char *buf);
-       ssize_t (*store)(const char *buf, size_t count);
-};
-
-#define O2CB_ATTR(_name, _mode, _show, _store) \
-struct o2cb_attribute o2cb_attr_##_name = __ATTR(_name, _mode, _show, _store)
-
-#define to_o2cb_attr(_attr) container_of(_attr, struct o2cb_attribute, attr)
 
-static ssize_t o2cb_interface_revision_show(char *buf)
+static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
+                           char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%u\n", O2NM_API_VERSION);
 }
-
-static O2CB_ATTR(interface_revision, S_IFREG | S_IRUGO, o2cb_interface_revision_show, NULL);
+static struct kobj_attribute attr_version =
+       __ATTR(interface_revision, S_IFREG | S_IRUGO, version_show, NULL);
 
 static struct attribute *o2cb_attrs[] = {
-       &o2cb_attr_interface_revision.attr,
+       &attr_version.attr,
        NULL,
 };
 
-static ssize_t
-o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer);
-static ssize_t
-o2cb_store(struct kobject * kobj, struct attribute * attr,
-          const char * buffer, size_t count);
-static struct sysfs_ops o2cb_sysfs_ops = {
-       .show   = o2cb_show,
-       .store  = o2cb_store,
+static struct attribute_group o2cb_attr_group = {
+       .attrs = o2cb_attrs,
 };
 
-static struct kobj_type o2cb_subsys_type = {
-       .default_attrs  = o2cb_attrs,
-       .sysfs_ops      = &o2cb_sysfs_ops,
-};
-
-/* gives us o2cb_subsys */
-static decl_subsys(o2cb, NULL, NULL);
-
-static ssize_t
-o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer)
-{
-       struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
-       struct kset *sbs = to_kset(kobj);
-
-       BUG_ON(sbs != &o2cb_subsys);
-
-       if (o2cb_attr->show)
-               return o2cb_attr->show(buffer);
-       return -EIO;
-}
-
-static ssize_t
-o2cb_store(struct kobject * kobj, struct attribute * attr,
-            const char * buffer, size_t count)
-{
-       struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
-       struct kset *sbs = to_kset(kobj);
-
-       BUG_ON(sbs != &o2cb_subsys);
-
-       if (o2cb_attr->store)
-               return o2cb_attr->store(buffer, count);
-       return -EIO;
-}
+static struct kset *o2cb_kset;
 
 void o2cb_sys_shutdown(void)
 {
        mlog_sys_shutdown();
-       subsystem_unregister(&o2cb_subsys);
+       kset_unregister(o2cb_kset);
 }
 
 int o2cb_sys_init(void)
 {
        int ret;
 
-       o2cb_subsys.kobj.ktype = &o2cb_subsys_type;
-       ret = subsystem_register(&o2cb_subsys);
+       o2cb_kset = kset_create_and_add("o2cb", NULL, fs_kobj);
+       if (!o2cb_kset)
+               return -ENOMEM;
+
+       ret = sysfs_create_group(&o2cb_kset->kobj, &o2cb_attr_group);
        if (ret)
-               return ret;
+               goto error;
 
-       ret = mlog_sys_init(&o2cb_subsys);
+       ret = mlog_sys_init(o2cb_kset);
        if (ret)
-               subsystem_unregister(&o2cb_subsys);
+               goto error;
+       return 0;
+error:
+       kset_unregister(o2cb_kset);
        return ret;
 }
index da880fc215f075ccc50aac915810409b8efd35e4..f36f66aab3dd788e200ddca6be96546939af03ad 100644 (file)
@@ -60,8 +60,8 @@ typedef void (o2net_post_msg_handler_func)(int status, void *data,
 /* same as hb delay, we're waiting for another node to recognize our hb */
 #define O2NET_RECONNECT_DELAY_MS_DEFAULT       2000
 
-#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT       5000
-#define O2NET_IDLE_TIMEOUT_MS_DEFAULT          10000
+#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT       2000
+#define O2NET_IDLE_TIMEOUT_MS_DEFAULT          30000
 
 
 /* TODO: figure this out.... */
index 9606111fe89d0964bb5c29d80427ddaddff6ab7f..b2e832aca5679cc1bd52d05c826d59cff1954fbb 100644 (file)
  * locking semantics of the file system using the protocol.  It should 
  * be somewhere else, I'm sure, but right now it isn't.
  *
+ * New in version 10:
+ *     - Meta/data locks combined
+ *
+ * New in version 9:
+ *     - All votes removed
+ *
  * New in version 8:
  *     - Replace delete inode votes with a cluster lock
  *
@@ -60,7 +66,7 @@
  *     - full 64 bit i_size in the metadata lock lvbs
  *     - introduction of "rw" lock and pushing meta/data locking down
  */
-#define O2NET_PROTOCOL_VERSION 8ULL
+#define O2NET_PROTOCOL_VERSION 10ULL
 struct o2net_handshake {
        __be64  protocol_version;
        __be64  connector_id;
index 7286c48bb30d4500d5294878e6e8ff4719018012..a56eee6abad33dd28687176fecdb468b1f11e1ab 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "ver.h"
 
-#define CLUSTER_BUILD_VERSION "1.3.3"
+#define CLUSTER_BUILD_VERSION "1.5.0"
 
 #define VERSION_STR "OCFS2 Node Manager " CLUSTER_BUILD_VERSION
 
index 9923278ea6d4df3f3ef0b9cd8247d64e86c9a849..b1cc7c381e889b5d898ad5f3e2a9bddeb9b39fd1 100644 (file)
@@ -128,9 +128,9 @@ static int ocfs2_match_dentry(struct dentry *dentry,
 /*
  * Walk the inode alias list, and find a dentry which has a given
  * parent. ocfs2_dentry_attach_lock() wants to find _any_ alias as it
- * is looking for a dentry_lock reference. The vote thread is looking
- * to unhash aliases, so we allow it to skip any that already have
- * that property.
+ * is looking for a dentry_lock reference. The downconvert thread is
+ * looking to unhash aliases, so we allow it to skip any that already
+ * have that property.
  */
 struct dentry *ocfs2_find_local_alias(struct inode *inode,
                                      u64 parent_blkno,
@@ -266,7 +266,7 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
        dl->dl_count = 0;
        /*
         * Does this have to happen below, for all attaches, in case
-        * the struct inode gets blown away by votes?
+        * the struct inode gets blown away by the downconvert thread?
         */
        dl->dl_inode = igrab(inode);
        dl->dl_parent_blkno = parent_blkno;
index 63b28fdceb4a3c7b425e87290d08237b5182a790..6b0107f21344734f583ea103b56cc10bee7d6b74 100644 (file)
@@ -846,14 +846,14 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
        mlog_entry("dirino=%llu\n",
                   (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
-       error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+       error = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
        if (lock_level && error >= 0) {
                /* We release EX lock which used to update atime
                 * and get PR lock again to reduce contention
                 * on commonly accessed directories. */
-               ocfs2_meta_unlock(inode, 1);
+               ocfs2_inode_unlock(inode, 1);
                lock_level = 0;
-               error = ocfs2_meta_lock(inode, NULL, 0);
+               error = ocfs2_inode_lock(inode, NULL, 0);
        }
        if (error < 0) {
                if (error != -ENOENT)
@@ -865,7 +865,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
        error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
                                      dirent, filldir, NULL);
 
-       ocfs2_meta_unlock(inode, lock_level);
+       ocfs2_inode_unlock(inode, lock_level);
 
 bail_nolock:
        mlog_exit(error);
index d2be3ad841f9e534eb963f61184d22b424592cd3..a733b3321f83f0d801e6a6f1472ad8a6a2effc8f 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "dlmfsver.h"
 
-#define DLM_BUILD_VERSION "1.3.3"
+#define DLM_BUILD_VERSION "1.5.0"
 
 #define VERSION_STR "OCFS2 DLMFS " DLM_BUILD_VERSION
 
index 2fde7bf91434b0e95faddaf188d193877d803b39..91f747b8a538b0eb4217f176140064189594211d 100644 (file)
@@ -2270,6 +2270,12 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
                }
        }
 
+       /* Clean up join state on node death. */
+       if (dlm->joining_node == idx) {
+               mlog(0, "Clearing join state for node %u\n", idx);
+               __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
+       }
+
        /* check to see if the node is already considered dead */
        if (!test_bit(idx, dlm->live_nodes_map)) {
                mlog(0, "for domain %s, node %d is already dead. "
@@ -2288,12 +2294,6 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
 
        clear_bit(idx, dlm->live_nodes_map);
 
-       /* Clean up join state on node death. */
-       if (dlm->joining_node == idx) {
-               mlog(0, "Clearing join state for node %u\n", idx);
-               __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
-       }
-
        /* make sure local cleanup occurs before the heartbeat events */
        if (!test_bit(idx, dlm->recovery_map))
                dlm_do_local_recovery_cleanup(dlm, idx);
@@ -2321,6 +2321,13 @@ void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data)
        if (!dlm_grab(dlm))
                return;
 
+       /*
+        * This will notify any dlm users that a node in our domain
+        * went away without notifying us first.
+        */
+       if (test_bit(idx, dlm->domain_map))
+               dlm_fire_domain_eviction_callbacks(dlm, idx);
+
        spin_lock(&dlm->spinlock);
        __dlm_hb_node_down(dlm, idx);
        spin_unlock(&dlm->spinlock);
index 7ef2653f8f41cfd3fd346f014f082384669f340a..dfc0da4d158dc49090389a1c7164a71a01cf1136 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "dlmver.h"
 
-#define DLM_BUILD_VERSION "1.3.3"
+#define DLM_BUILD_VERSION "1.5.0"
 
 #define VERSION_STR "OCFS2 DLM " DLM_BUILD_VERSION
 
index 4e97dcceaf8f5354fab2b4e78563f56b5853bf35..3867244fb144a4c639f0e1ed2fdd41dcffc7798d 100644 (file)
@@ -55,7 +55,6 @@
 #include "slot_map.h"
 #include "super.h"
 #include "uptodate.h"
-#include "vote.h"
 
 #include "buffer_head_io.h"
 
@@ -69,6 +68,7 @@ struct ocfs2_mask_waiter {
 
 static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
 static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
+static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres);
 
 /*
  * Return value from ->downconvert_worker functions.
@@ -153,10 +153,10 @@ struct ocfs2_lock_res_ops {
        struct ocfs2_super * (*get_osb)(struct ocfs2_lock_res *);
 
        /*
-        * Optionally called in the downconvert (or "vote") thread
-        * after a successful downconvert. The lockres will not be
-        * referenced after this callback is called, so it is safe to
-        * free memory, etc.
+        * Optionally called in the downconvert thread after a
+        * successful downconvert. The lockres will not be referenced
+        * after this callback is called, so it is safe to free
+        * memory, etc.
         *
         * The exact semantics of when this is called are controlled
         * by ->downconvert_worker()
@@ -225,17 +225,12 @@ static struct ocfs2_lock_res_ops ocfs2_inode_rw_lops = {
        .flags          = 0,
 };
 
-static struct ocfs2_lock_res_ops ocfs2_inode_meta_lops = {
+static struct ocfs2_lock_res_ops ocfs2_inode_inode_lops = {
        .get_osb        = ocfs2_get_inode_osb,
        .check_downconvert = ocfs2_check_meta_downconvert,
        .set_lvb        = ocfs2_set_meta_lvb,
-       .flags          = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
-};
-
-static struct ocfs2_lock_res_ops ocfs2_inode_data_lops = {
-       .get_osb        = ocfs2_get_inode_osb,
        .downconvert_worker = ocfs2_data_convert_worker,
-       .flags          = 0,
+       .flags          = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
 };
 
 static struct ocfs2_lock_res_ops ocfs2_super_lops = {
@@ -258,10 +253,14 @@ static struct ocfs2_lock_res_ops ocfs2_inode_open_lops = {
        .flags          = 0,
 };
 
+static struct ocfs2_lock_res_ops ocfs2_flock_lops = {
+       .get_osb        = ocfs2_get_file_osb,
+       .flags          = 0,
+};
+
 static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
 {
        return lockres->l_type == OCFS2_LOCK_TYPE_META ||
-               lockres->l_type == OCFS2_LOCK_TYPE_DATA ||
                lockres->l_type == OCFS2_LOCK_TYPE_RW ||
                lockres->l_type == OCFS2_LOCK_TYPE_OPEN;
 }
@@ -310,12 +309,24 @@ static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres,
                "resource %s: %s\n", dlm_errname(_stat), _func, \
                _lockres->l_name, dlm_errmsg(_stat));           \
 } while (0)
-static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
-                                struct ocfs2_lock_res *lockres);
-static int ocfs2_meta_lock_update(struct inode *inode,
+static int ocfs2_downconvert_thread(void *arg);
+static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
+                                       struct ocfs2_lock_res *lockres);
+static int ocfs2_inode_lock_update(struct inode *inode,
                                  struct buffer_head **bh);
 static void ocfs2_drop_osb_locks(struct ocfs2_super *osb);
 static inline int ocfs2_highest_compat_lock_level(int level);
+static void ocfs2_prepare_downconvert(struct ocfs2_lock_res *lockres,
+                                     int new_level);
+static int ocfs2_downconvert_lock(struct ocfs2_super *osb,
+                                 struct ocfs2_lock_res *lockres,
+                                 int new_level,
+                                 int lvb);
+static int ocfs2_prepare_cancel_convert(struct ocfs2_super *osb,
+                                       struct ocfs2_lock_res *lockres);
+static int ocfs2_cancel_convert(struct ocfs2_super *osb,
+                               struct ocfs2_lock_res *lockres);
+
 
 static void ocfs2_build_lock_name(enum ocfs2_lock_type type,
                                  u64 blkno,
@@ -402,10 +413,7 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
                        ops = &ocfs2_inode_rw_lops;
                        break;
                case OCFS2_LOCK_TYPE_META:
-                       ops = &ocfs2_inode_meta_lops;
-                       break;
-               case OCFS2_LOCK_TYPE_DATA:
-                       ops = &ocfs2_inode_data_lops;
+                       ops = &ocfs2_inode_inode_lops;
                        break;
                case OCFS2_LOCK_TYPE_OPEN:
                        ops = &ocfs2_inode_open_lops;
@@ -428,6 +436,13 @@ static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres)
        return OCFS2_SB(inode->i_sb);
 }
 
+static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres)
+{
+       struct ocfs2_file_private *fp = lockres->l_priv;
+
+       return OCFS2_SB(fp->fp_file->f_mapping->host->i_sb);
+}
+
 static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres)
 {
        __be64 inode_blkno_be;
@@ -508,6 +523,21 @@ static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res,
                                   &ocfs2_rename_lops, osb);
 }
 
+void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
+                             struct ocfs2_file_private *fp)
+{
+       struct inode *inode = fp->fp_file->f_mapping->host;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+       ocfs2_lock_res_init_once(lockres);
+       ocfs2_build_lock_name(OCFS2_LOCK_TYPE_FLOCK, oi->ip_blkno,
+                             inode->i_generation, lockres->l_name);
+       ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres,
+                                  OCFS2_LOCK_TYPE_FLOCK, &ocfs2_flock_lops,
+                                  fp);
+       lockres->l_flags |= OCFS2_LOCK_NOCACHE;
+}
+
 void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
 {
        mlog_entry_void();
@@ -724,6 +754,13 @@ static void ocfs2_blocking_ast(void *opaque, int level)
             lockres->l_name, level, lockres->l_level,
             ocfs2_lock_type_string(lockres->l_type));
 
+       /*
+        * We can skip the bast for locks which don't enable caching -
+        * they'll be dropped at the earliest possible time anyway.
+        */
+       if (lockres->l_flags & OCFS2_LOCK_NOCACHE)
+               return;
+
        spin_lock_irqsave(&lockres->l_lock, flags);
        needs_downconvert = ocfs2_generic_handle_bast(lockres, level);
        if (needs_downconvert)
@@ -732,7 +769,7 @@ static void ocfs2_blocking_ast(void *opaque, int level)
 
        wake_up(&lockres->l_event);
 
-       ocfs2_kick_vote_thread(osb);
+       ocfs2_wake_downconvert_thread(osb);
 }
 
 static void ocfs2_locking_ast(void *opaque)
@@ -935,6 +972,21 @@ static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
 
 }
 
+static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw,
+                                            struct ocfs2_lock_res *lockres)
+{
+       int ret;
+
+       ret = wait_for_completion_interruptible(&mw->mw_complete);
+       if (ret)
+               lockres_remove_mask_waiter(lockres, mw);
+       else
+               ret = mw->mw_status;
+       /* Re-arm the completion in case we want to wait on it again */
+       INIT_COMPLETION(mw->mw_complete);
+       return ret;
+}
+
 static int ocfs2_cluster_lock(struct ocfs2_super *osb,
                              struct ocfs2_lock_res *lockres,
                              int level,
@@ -1089,7 +1141,7 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
        mlog_entry_void();
        spin_lock_irqsave(&lockres->l_lock, flags);
        ocfs2_dec_holders(lockres, level);
-       ocfs2_vote_on_unlock(osb, lockres);
+       ocfs2_downconvert_on_unlock(osb, lockres);
        spin_unlock_irqrestore(&lockres->l_lock, flags);
        mlog_exit_void();
 }
@@ -1147,13 +1199,7 @@ int ocfs2_create_new_inode_locks(struct inode *inode)
         * We don't want to use LKM_LOCAL on a meta data lock as they
         * don't use a generation in their lock names.
         */
-       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1, 0);
-       if (ret) {
-               mlog_errno(ret);
-               goto bail;
-       }
-
-       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1);
+       ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_inode_lockres, 1, 0);
        if (ret) {
                mlog_errno(ret);
                goto bail;
@@ -1311,76 +1357,221 @@ out:
        mlog_exit_void();
 }
 
-int ocfs2_data_lock_full(struct inode *inode,
-                        int write,
-                        int arg_flags)
+static int ocfs2_flock_handle_signal(struct ocfs2_lock_res *lockres,
+                                    int level)
 {
-       int status = 0, level;
-       struct ocfs2_lock_res *lockres;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       int ret;
+       struct ocfs2_super *osb = ocfs2_get_lockres_osb(lockres);
+       unsigned long flags;
+       struct ocfs2_mask_waiter mw;
 
-       BUG_ON(!inode);
+       ocfs2_init_mask_waiter(&mw);
 
-       mlog_entry_void();
+retry_cancel:
+       spin_lock_irqsave(&lockres->l_lock, flags);
+       if (lockres->l_flags & OCFS2_LOCK_BUSY) {
+               ret = ocfs2_prepare_cancel_convert(osb, lockres);
+               if (ret) {
+                       spin_unlock_irqrestore(&lockres->l_lock, flags);
+                       ret = ocfs2_cancel_convert(osb, lockres);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               goto out;
+                       }
+                       goto retry_cancel;
+               }
+               lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
+               spin_unlock_irqrestore(&lockres->l_lock, flags);
 
-       mlog(0, "inode %llu take %s DATA lock\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno,
-            write ? "EXMODE" : "PRMODE");
+               ocfs2_wait_for_mask(&mw);
+               goto retry_cancel;
+       }
 
-       /* We'll allow faking a readonly data lock for
-        * rodevices. */
-       if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) {
-               if (write) {
-                       status = -EROFS;
-                       mlog_errno(status);
+       ret = -ERESTARTSYS;
+       /*
+        * We may still have gotten the lock, in which case there's no
+        * point to restarting the syscall.
+        */
+       if (lockres->l_level == level)
+               ret = 0;
+
+       mlog(0, "Cancel returning %d. flags: 0x%lx, level: %d, act: %d\n", ret,
+            lockres->l_flags, lockres->l_level, lockres->l_action);
+
+       spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+out:
+       return ret;
+}
+
+/*
+ * ocfs2_file_lock() and ocfs2_file_unlock() map to a single pair of
+ * flock() calls. The locking approach this requires is sufficiently
+ * different from all other cluster lock types that we implement a
+ * seperate path to the "low-level" dlm calls. In particular:
+ *
+ * - No optimization of lock levels is done - we take at exactly
+ *   what's been requested.
+ *
+ * - No lock caching is employed. We immediately downconvert to
+ *   no-lock at unlock time. This also means flock locks never go on
+ *   the blocking list).
+ *
+ * - Since userspace can trivially deadlock itself with flock, we make
+ *   sure to allow cancellation of a misbehaving applications flock()
+ *   request.
+ *
+ * - Access to any flock lockres doesn't require concurrency, so we
+ *   can simplify the code by requiring the caller to guarantee
+ *   serialization of dlmglue flock calls.
+ */
+int ocfs2_file_lock(struct file *file, int ex, int trylock)
+{
+       int ret, level = ex ? LKM_EXMODE : LKM_PRMODE;
+       unsigned int lkm_flags = trylock ? LKM_NOQUEUE : 0;
+       unsigned long flags;
+       struct ocfs2_file_private *fp = file->private_data;
+       struct ocfs2_lock_res *lockres = &fp->fp_flock;
+       struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb);
+       struct ocfs2_mask_waiter mw;
+
+       ocfs2_init_mask_waiter(&mw);
+
+       if ((lockres->l_flags & OCFS2_LOCK_BUSY) ||
+           (lockres->l_level > LKM_NLMODE)) {
+               mlog(ML_ERROR,
+                    "File lock \"%s\" has busy or locked state: flags: 0x%lx, "
+                    "level: %u\n", lockres->l_name, lockres->l_flags,
+                    lockres->l_level);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&lockres->l_lock, flags);
+       if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED)) {
+               lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
+               spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+               /*
+                * Get the lock at NLMODE to start - that way we
+                * can cancel the upconvert request if need be.
+                */
+               ret = ocfs2_lock_create(osb, lockres, LKM_NLMODE, 0);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
                }
-               goto out;
+
+               ret = ocfs2_wait_for_mask(&mw);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               spin_lock_irqsave(&lockres->l_lock, flags);
        }
 
-       if (ocfs2_mount_local(osb))
-               goto out;
+       lockres->l_action = OCFS2_AST_CONVERT;
+       lkm_flags |= LKM_CONVERT;
+       lockres->l_requested = level;
+       lockres_or_flags(lockres, OCFS2_LOCK_BUSY);
 
-       lockres = &OCFS2_I(inode)->ip_data_lockres;
+       lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
+       spin_unlock_irqrestore(&lockres->l_lock, flags);
 
-       level = write ? LKM_EXMODE : LKM_PRMODE;
+       ret = dlmlock(osb->dlm, level, &lockres->l_lksb, lkm_flags,
+                     lockres->l_name, OCFS2_LOCK_ID_MAX_LEN - 1,
+                     ocfs2_locking_ast, lockres, ocfs2_blocking_ast);
+       if (ret != DLM_NORMAL) {
+               if (trylock && ret == DLM_NOTQUEUED)
+                       ret = -EAGAIN;
+               else {
+                       ocfs2_log_dlm_error("dlmlock", ret, lockres);
+                       ret = -EINVAL;
+               }
 
-       status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, level,
-                                   0, arg_flags);
-       if (status < 0 && status != -EAGAIN)
-               mlog_errno(status);
+               ocfs2_recover_from_dlm_error(lockres, 1);
+               lockres_remove_mask_waiter(lockres, &mw);
+               goto out;
+       }
+
+       ret = ocfs2_wait_for_mask_interruptible(&mw, lockres);
+       if (ret == -ERESTARTSYS) {
+               /*
+                * Userspace can cause deadlock itself with
+                * flock(). Current behavior locally is to allow the
+                * deadlock, but abort the system call if a signal is
+                * received. We follow this example, otherwise a
+                * poorly written program could sit in kernel until
+                * reboot.
+                *
+                * Handling this is a bit more complicated for Ocfs2
+                * though. We can't exit this function with an
+                * outstanding lock request, so a cancel convert is
+                * required. We intentionally overwrite 'ret' - if the
+                * cancel fails and the lock was granted, it's easier
+                * to just bubble sucess back up to the user.
+                */
+               ret = ocfs2_flock_handle_signal(lockres, level);
+       }
 
 out:
-       mlog_exit(status);
-       return status;
+
+       mlog(0, "Lock: \"%s\" ex: %d, trylock: %d, returns: %d\n",
+            lockres->l_name, ex, trylock, ret);
+       return ret;
 }
 
-/* see ocfs2_meta_lock_with_page() */
-int ocfs2_data_lock_with_page(struct inode *inode,
-                             int write,
-                             struct page *page)
+void ocfs2_file_unlock(struct file *file)
 {
        int ret;
+       unsigned long flags;
+       struct ocfs2_file_private *fp = file->private_data;
+       struct ocfs2_lock_res *lockres = &fp->fp_flock;
+       struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb);
+       struct ocfs2_mask_waiter mw;
 
-       ret = ocfs2_data_lock_full(inode, write, OCFS2_LOCK_NONBLOCK);
-       if (ret == -EAGAIN) {
-               unlock_page(page);
-               if (ocfs2_data_lock(inode, write) == 0)
-                       ocfs2_data_unlock(inode, write);
-               ret = AOP_TRUNCATED_PAGE;
+       ocfs2_init_mask_waiter(&mw);
+
+       if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED))
+               return;
+
+       if (lockres->l_level == LKM_NLMODE)
+               return;
+
+       mlog(0, "Unlock: \"%s\" flags: 0x%lx, level: %d, act: %d\n",
+            lockres->l_name, lockres->l_flags, lockres->l_level,
+            lockres->l_action);
+
+       spin_lock_irqsave(&lockres->l_lock, flags);
+       /*
+        * Fake a blocking ast for the downconvert code.
+        */
+       lockres_or_flags(lockres, OCFS2_LOCK_BLOCKED);
+       lockres->l_blocking = LKM_EXMODE;
+
+       ocfs2_prepare_downconvert(lockres, LKM_NLMODE);
+       lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
+       spin_unlock_irqrestore(&lockres->l_lock, flags);
+
+       ret = ocfs2_downconvert_lock(osb, lockres, LKM_NLMODE, 0);
+       if (ret) {
+               mlog_errno(ret);
+               return;
        }
 
-       return ret;
+       ret = ocfs2_wait_for_mask(&mw);
+       if (ret)
+               mlog_errno(ret);
 }
 
-static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
-                                struct ocfs2_lock_res *lockres)
+static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
+                                       struct ocfs2_lock_res *lockres)
 {
        int kick = 0;
 
        mlog_entry_void();
 
        /* If we know that another node is waiting on our lock, kick
-        * the vote thread * pre-emptively when we reach a release
+        * the downconvert thread * pre-emptively when we reach a release
         * condition. */
        if (lockres->l_flags & OCFS2_LOCK_BLOCKED) {
                switch(lockres->l_blocking) {
@@ -1398,27 +1589,7 @@ static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
        }
 
        if (kick)
-               ocfs2_kick_vote_thread(osb);
-
-       mlog_exit_void();
-}
-
-void ocfs2_data_unlock(struct inode *inode,
-                      int write)
-{
-       int level = write ? LKM_EXMODE : LKM_PRMODE;
-       struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_data_lockres;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-
-       mlog_entry_void();
-
-       mlog(0, "inode %llu drop %s DATA lock\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno,
-            write ? "EXMODE" : "PRMODE");
-
-       if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) &&
-           !ocfs2_mount_local(osb))
-               ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
+               ocfs2_wake_downconvert_thread(osb);
 
        mlog_exit_void();
 }
@@ -1442,11 +1613,11 @@ static u64 ocfs2_pack_timespec(struct timespec *spec)
 
 /* Call this with the lockres locked. I am reasonably sure we don't
  * need ip_lock in this function as anyone who would be changing those
- * values is supposed to be blocked in ocfs2_meta_lock right now. */
+ * values is supposed to be blocked in ocfs2_inode_lock right now. */
 static void __ocfs2_stuff_meta_lvb(struct inode *inode)
 {
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
-       struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
+       struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
        struct ocfs2_meta_lvb *lvb;
 
        mlog_entry_void();
@@ -1496,7 +1667,7 @@ static void ocfs2_unpack_timespec(struct timespec *spec,
 static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
 {
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
-       struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
+       struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
        struct ocfs2_meta_lvb *lvb;
 
        mlog_entry_void();
@@ -1604,12 +1775,12 @@ static inline void ocfs2_complete_lock_res_refresh(struct ocfs2_lock_res *lockre
 }
 
 /* may or may not return a bh if it went to disk. */
-static int ocfs2_meta_lock_update(struct inode *inode,
+static int ocfs2_inode_lock_update(struct inode *inode,
                                  struct buffer_head **bh)
 {
        int status = 0;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
-       struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
+       struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
        struct ocfs2_dinode *fe;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
@@ -1721,7 +1892,7 @@ static int ocfs2_assign_bh(struct inode *inode,
  * returns < 0 error if the callback will never be called, otherwise
  * the result of the lock will be communicated via the callback.
  */
-int ocfs2_meta_lock_full(struct inode *inode,
+int ocfs2_inode_lock_full(struct inode *inode,
                         struct buffer_head **ret_bh,
                         int ex,
                         int arg_flags)
@@ -1756,7 +1927,7 @@ int ocfs2_meta_lock_full(struct inode *inode,
                wait_event(osb->recovery_event,
                           ocfs2_node_map_is_empty(osb, &osb->recovery_map));
 
-       lockres = &OCFS2_I(inode)->ip_meta_lockres;
+       lockres = &OCFS2_I(inode)->ip_inode_lockres;
        level = ex ? LKM_EXMODE : LKM_PRMODE;
        dlm_flags = 0;
        if (arg_flags & OCFS2_META_LOCK_NOQUEUE)
@@ -1795,11 +1966,11 @@ local:
        }
 
        /* This is fun. The caller may want a bh back, or it may
-        * not. ocfs2_meta_lock_update definitely wants one in, but
+        * not. ocfs2_inode_lock_update definitely wants one in, but
         * may or may not read one, depending on what's in the
         * LVB. The result of all of this is that we've *only* gone to
         * disk if we have to, so the complexity is worthwhile. */
-       status = ocfs2_meta_lock_update(inode, &local_bh);
+       status = ocfs2_inode_lock_update(inode, &local_bh);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -1821,7 +1992,7 @@ bail:
                        *ret_bh = NULL;
                }
                if (acquired)
-                       ocfs2_meta_unlock(inode, ex);
+                       ocfs2_inode_unlock(inode, ex);
        }
 
        if (local_bh)
@@ -1832,19 +2003,20 @@ bail:
 }
 
 /*
- * This is working around a lock inversion between tasks acquiring DLM locks
- * while holding a page lock and the vote thread which blocks dlm lock acquiry
- * while acquiring page locks.
+ * This is working around a lock inversion between tasks acquiring DLM
+ * locks while holding a page lock and the downconvert thread which
+ * blocks dlm lock acquiry while acquiring page locks.
  *
  * ** These _with_page variantes are only intended to be called from aop
  * methods that hold page locks and return a very specific *positive* error
  * code that aop methods pass up to the VFS -- test for errors with != 0. **
  *
- * The DLM is called such that it returns -EAGAIN if it would have blocked
- * waiting for the vote thread.  In that case we unlock our page so the vote
- * thread can make progress.  Once we've done this we have to return
- * AOP_TRUNCATED_PAGE so the aop method that called us can bubble that back up
- * into the VFS who will then immediately retry the aop call.
+ * The DLM is called such that it returns -EAGAIN if it would have
+ * blocked waiting for the downconvert thread.  In that case we unlock
+ * our page so the downconvert thread can make progress.  Once we've
+ * done this we have to return AOP_TRUNCATED_PAGE so the aop method
+ * that called us can bubble that back up into the VFS who will then
+ * immediately retry the aop call.
  *
  * We do a blocking lock and immediate unlock before returning, though, so that
  * the lock has a great chance of being cached on this node by the time the VFS
@@ -1852,32 +2024,32 @@ bail:
  * ping locks back and forth, but that's a risk we're willing to take to avoid
  * the lock inversion simply.
  */
-int ocfs2_meta_lock_with_page(struct inode *inode,
+int ocfs2_inode_lock_with_page(struct inode *inode,
                              struct buffer_head **ret_bh,
                              int ex,
                              struct page *page)
 {
        int ret;
 
-       ret = ocfs2_meta_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
+       ret = ocfs2_inode_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
        if (ret == -EAGAIN) {
                unlock_page(page);
-               if (ocfs2_meta_lock(inode, ret_bh, ex) == 0)
-                       ocfs2_meta_unlock(inode, ex);
+               if (ocfs2_inode_lock(inode, ret_bh, ex) == 0)
+                       ocfs2_inode_unlock(inode, ex);
                ret = AOP_TRUNCATED_PAGE;
        }
 
        return ret;
 }
 
-int ocfs2_meta_lock_atime(struct inode *inode,
+int ocfs2_inode_lock_atime(struct inode *inode,
                          struct vfsmount *vfsmnt,
                          int *level)
 {
        int ret;
 
        mlog_entry_void();
-       ret = ocfs2_meta_lock(inode, NULL, 0);
+       ret = ocfs2_inode_lock(inode, NULL, 0);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -1890,8 +2062,8 @@ int ocfs2_meta_lock_atime(struct inode *inode,
        if (ocfs2_should_update_atime(inode, vfsmnt)) {
                struct buffer_head *bh = NULL;
 
-               ocfs2_meta_unlock(inode, 0);
-               ret = ocfs2_meta_lock(inode, &bh, 1);
+               ocfs2_inode_unlock(inode, 0);
+               ret = ocfs2_inode_lock(inode, &bh, 1);
                if (ret < 0) {
                        mlog_errno(ret);
                        return ret;
@@ -1908,11 +2080,11 @@ int ocfs2_meta_lock_atime(struct inode *inode,
        return ret;
 }
 
-void ocfs2_meta_unlock(struct inode *inode,
+void ocfs2_inode_unlock(struct inode *inode,
                       int ex)
 {
        int level = ex ? LKM_EXMODE : LKM_PRMODE;
-       struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres;
+       struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_inode_lockres;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        mlog_entry_void();
@@ -2320,11 +2492,11 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
                goto bail;
        }
 
-       /* launch vote thread */
-       osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote");
-       if (IS_ERR(osb->vote_task)) {
-               status = PTR_ERR(osb->vote_task);
-               osb->vote_task = NULL;
+       /* launch downconvert thread */
+       osb->dc_task = kthread_run(ocfs2_downconvert_thread, osb, "ocfs2dc");
+       if (IS_ERR(osb->dc_task)) {
+               status = PTR_ERR(osb->dc_task);
+               osb->dc_task = NULL;
                mlog_errno(status);
                goto bail;
        }
@@ -2353,8 +2525,8 @@ local:
 bail:
        if (status < 0) {
                ocfs2_dlm_shutdown_debug(osb);
-               if (osb->vote_task)
-                       kthread_stop(osb->vote_task);
+               if (osb->dc_task)
+                       kthread_stop(osb->dc_task);
        }
 
        mlog_exit(status);
@@ -2369,9 +2541,9 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb)
 
        ocfs2_drop_osb_locks(osb);
 
-       if (osb->vote_task) {
-               kthread_stop(osb->vote_task);
-               osb->vote_task = NULL;
+       if (osb->dc_task) {
+               kthread_stop(osb->dc_task);
+               osb->dc_task = NULL;
        }
 
        ocfs2_lock_res_free(&osb->osb_super_lockres);
@@ -2527,7 +2699,7 @@ out:
 
 /* Mark the lockres as being dropped. It will no longer be
  * queued if blocking, but we still may have to wait on it
- * being dequeued from the vote thread before we can consider
+ * being dequeued from the downconvert thread before we can consider
  * it safe to drop. 
  *
  * You can *not* attempt to call cluster_lock on this lockres anymore. */
@@ -2590,14 +2762,7 @@ int ocfs2_drop_inode_locks(struct inode *inode)
        status = err;
 
        err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
-                             &OCFS2_I(inode)->ip_data_lockres);
-       if (err < 0)
-               mlog_errno(err);
-       if (err < 0 && !status)
-               status = err;
-
-       err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
-                             &OCFS2_I(inode)->ip_meta_lockres);
+                             &OCFS2_I(inode)->ip_inode_lockres);
        if (err < 0)
                mlog_errno(err);
        if (err < 0 && !status)
@@ -2850,6 +3015,9 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
                inode = ocfs2_lock_res_inode(lockres);
        mapping = inode->i_mapping;
 
+       if (S_ISREG(inode->i_mode))
+               goto out;
+
        /*
         * We need this before the filemap_fdatawrite() so that it can
         * transfer the dirty bit from the PTE to the
@@ -2875,6 +3043,7 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
                filemap_fdatawait(mapping);
        }
 
+out:
        return UNBLOCK_CONTINUE;
 }
 
@@ -2903,7 +3072,7 @@ static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres)
 
 /*
  * Does the final reference drop on our dentry lock. Right now this
- * happens in the vote thread, but we could choose to simplify the
+ * happens in the downconvert thread, but we could choose to simplify the
  * dlmglue API and push these off to the ocfs2_wq in the future.
  */
 static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
@@ -3042,7 +3211,7 @@ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
        mlog(0, "lockres %s blocked.\n", lockres->l_name);
 
        /* Detect whether a lock has been marked as going away while
-        * the vote thread was processing other things. A lock can
+        * the downconvert thread was processing other things. A lock can
         * still be marked with OCFS2_LOCK_FREEING after this check,
         * but short circuiting here will still save us some
         * performance. */
@@ -3091,13 +3260,104 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
 
        lockres_or_flags(lockres, OCFS2_LOCK_QUEUED);
 
-       spin_lock(&osb->vote_task_lock);
+       spin_lock(&osb->dc_task_lock);
        if (list_empty(&lockres->l_blocked_list)) {
                list_add_tail(&lockres->l_blocked_list,
                              &osb->blocked_lock_list);
                osb->blocked_lock_count++;
        }
-       spin_unlock(&osb->vote_task_lock);
+       spin_unlock(&osb->dc_task_lock);
+
+       mlog_exit_void();
+}
+
+static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
+{
+       unsigned long processed;
+       struct ocfs2_lock_res *lockres;
+
+       mlog_entry_void();
+
+       spin_lock(&osb->dc_task_lock);
+       /* grab this early so we know to try again if a state change and
+        * wake happens part-way through our work  */
+       osb->dc_work_sequence = osb->dc_wake_sequence;
+
+       processed = osb->blocked_lock_count;
+       while (processed) {
+               BUG_ON(list_empty(&osb->blocked_lock_list));
+
+               lockres = list_entry(osb->blocked_lock_list.next,
+                                    struct ocfs2_lock_res, l_blocked_list);
+               list_del_init(&lockres->l_blocked_list);
+               osb->blocked_lock_count--;
+               spin_unlock(&osb->dc_task_lock);
+
+               BUG_ON(!processed);
+               processed--;
+
+               ocfs2_process_blocked_lock(osb, lockres);
+
+               spin_lock(&osb->dc_task_lock);
+       }
+       spin_unlock(&osb->dc_task_lock);
 
        mlog_exit_void();
 }
+
+static int ocfs2_downconvert_thread_lists_empty(struct ocfs2_super *osb)
+{
+       int empty = 0;
+
+       spin_lock(&osb->dc_task_lock);
+       if (list_empty(&osb->blocked_lock_list))
+               empty = 1;
+
+       spin_unlock(&osb->dc_task_lock);
+       return empty;
+}
+
+static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb)
+{
+       int should_wake = 0;
+
+       spin_lock(&osb->dc_task_lock);
+       if (osb->dc_work_sequence != osb->dc_wake_sequence)
+               should_wake = 1;
+       spin_unlock(&osb->dc_task_lock);
+
+       return should_wake;
+}
+
+int ocfs2_downconvert_thread(void *arg)
+{
+       int status = 0;
+       struct ocfs2_super *osb = arg;
+
+       /* only quit once we've been asked to stop and there is no more
+        * work available */
+       while (!(kthread_should_stop() &&
+               ocfs2_downconvert_thread_lists_empty(osb))) {
+
+               wait_event_interruptible(osb->dc_event,
+                                        ocfs2_downconvert_thread_should_wake(osb) ||
+                                        kthread_should_stop());
+
+               mlog(0, "downconvert_thread: awoken\n");
+
+               ocfs2_downconvert_thread_do_work(osb);
+       }
+
+       osb->dc_task = NULL;
+       return status;
+}
+
+void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb)
+{
+       spin_lock(&osb->dc_task_lock);
+       /* make sure the voting thread gets a swipe at whatever changes
+        * the caller may have made to the voting state */
+       osb->dc_wake_sequence++;
+       spin_unlock(&osb->dc_task_lock);
+       wake_up(&osb->dc_event);
+}
index 87a785e41205c4cef900e6d38aeebf288a7f1adf..5f17243ba5017dfe3af0f2384bee683a4d77f6d3 100644 (file)
@@ -49,12 +49,12 @@ struct ocfs2_meta_lvb {
        __be32       lvb_reserved2;
 };
 
-/* ocfs2_meta_lock_full() and ocfs2_data_lock_full() 'arg_flags' flags */
+/* ocfs2_inode_lock_full() 'arg_flags' flags */
 /* don't wait on recovery. */
 #define OCFS2_META_LOCK_RECOVERY       (0x01)
 /* Instruct the dlm not to queue ourselves on the other node. */
 #define OCFS2_META_LOCK_NOQUEUE                (0x02)
-/* don't block waiting for the vote thread, instead return -EAGAIN */
+/* don't block waiting for the downconvert thread, instead return -EAGAIN */
 #define OCFS2_LOCK_NONBLOCK            (0x04)
 
 int ocfs2_dlm_init(struct ocfs2_super *osb);
@@ -66,38 +66,32 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
                               struct inode *inode);
 void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
                                u64 parent, struct inode *inode);
+struct ocfs2_file_private;
+void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
+                             struct ocfs2_file_private *fp);
 void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
 int ocfs2_create_new_inode_locks(struct inode *inode);
 int ocfs2_drop_inode_locks(struct inode *inode);
-int ocfs2_data_lock_full(struct inode *inode,
-                        int write,
-                        int arg_flags);
-#define ocfs2_data_lock(inode, write) ocfs2_data_lock_full(inode, write, 0)
-int ocfs2_data_lock_with_page(struct inode *inode,
-                             int write,
-                             struct page *page);
-void ocfs2_data_unlock(struct inode *inode,
-                      int write);
 int ocfs2_rw_lock(struct inode *inode, int write);
 void ocfs2_rw_unlock(struct inode *inode, int write);
 int ocfs2_open_lock(struct inode *inode);
 int ocfs2_try_open_lock(struct inode *inode, int write);
 void ocfs2_open_unlock(struct inode *inode);
-int ocfs2_meta_lock_atime(struct inode *inode,
+int ocfs2_inode_lock_atime(struct inode *inode,
                          struct vfsmount *vfsmnt,
                          int *level);
-int ocfs2_meta_lock_full(struct inode *inode,
+int ocfs2_inode_lock_full(struct inode *inode,
                         struct buffer_head **ret_bh,
                         int ex,
                         int arg_flags);
-int ocfs2_meta_lock_with_page(struct inode *inode,
+int ocfs2_inode_lock_with_page(struct inode *inode,
                              struct buffer_head **ret_bh,
                              int ex,
                              struct page *page);
 /* 99% of the time we don't want to supply any additional flags --
  * those are for very specific cases only. */
-#define ocfs2_meta_lock(i, b, e) ocfs2_meta_lock_full(i, b, e, 0)
-void ocfs2_meta_unlock(struct inode *inode,
+#define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0)
+void ocfs2_inode_unlock(struct inode *inode,
                       int ex);
 int ocfs2_super_lock(struct ocfs2_super *osb,
                     int ex);
@@ -107,14 +101,17 @@ int ocfs2_rename_lock(struct ocfs2_super *osb);
 void ocfs2_rename_unlock(struct ocfs2_super *osb);
 int ocfs2_dentry_lock(struct dentry *dentry, int ex);
 void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
+int ocfs2_file_lock(struct file *file, int ex, int trylock);
+void ocfs2_file_unlock(struct file *file);
 
 void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
 void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
                               struct ocfs2_lock_res *lockres);
 
-/* for the vote thread */
+/* for the downconvert thread */
 void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
                                struct ocfs2_lock_res *lockres);
+void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb);
 
 struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void);
 void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug);
index ff257628af16c24f71bc6782d972ed09d93db6de..1942e09f6ee588fc153ce696cb14d76a7a6c39d1 100644 (file)
@@ -37,11 +37,6 @@ static inline void le64_add_cpu(__le64 *var, u64 val)
        *var = cpu_to_le64(le64_to_cpu(*var) + val);
 }
 
-static inline void le32_and_cpu(__le32 *var, u32 val)
-{
-       *var = cpu_to_le32(le32_to_cpu(*var) & val);
-}
-
 static inline void be32_add_cpu(__be32 *var, u32 val)
 {
        *var = cpu_to_be32(be32_to_cpu(*var) + val);
index 535bfa9568a4af534a9cfbe91a025dd854e2c9f3..67527cebf21400fb7d86039dccbe566f2265b9b5 100644 (file)
@@ -58,7 +58,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
                return ERR_PTR(-ESTALE);
        }
 
-       inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0);
+       inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0);
 
        if (IS_ERR(inode))
                return (void *)inode;
@@ -95,7 +95,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
        mlog(0, "find parent of directory %llu\n",
             (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
-       status = ocfs2_meta_lock(dir, NULL, 0);
+       status = ocfs2_inode_lock(dir, NULL, 0);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -109,7 +109,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
                goto bail_unlock;
        }
 
-       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
+       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
        if (IS_ERR(inode)) {
                mlog(ML_ERROR, "Unable to create inode %llu\n",
                     (unsigned long long)blkno);
@@ -126,7 +126,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
        parent->d_op = &ocfs2_dentry_ops;
 
 bail_unlock:
-       ocfs2_meta_unlock(dir, 0);
+       ocfs2_inode_unlock(dir, 0);
 
 bail:
        mlog_exit_ptr(parent);
index b75b2e1f0e42609e78768c1ab9d72c160639a139..ed5d5232e85d9cef09b0d7f312d5a11ee8bd7426 100644 (file)
@@ -51,6 +51,7 @@
 #include "inode.h"
 #include "ioctl.h"
 #include "journal.h"
+#include "locks.h"
 #include "mmap.h"
 #include "suballoc.h"
 #include "super.h"
@@ -63,6 +64,35 @@ static int ocfs2_sync_inode(struct inode *inode)
        return sync_mapping_buffers(inode->i_mapping);
 }
 
+static int ocfs2_init_file_private(struct inode *inode, struct file *file)
+{
+       struct ocfs2_file_private *fp;
+
+       fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
+       if (!fp)
+               return -ENOMEM;
+
+       fp->fp_file = file;
+       mutex_init(&fp->fp_mutex);
+       ocfs2_file_lock_res_init(&fp->fp_flock, fp);
+       file->private_data = fp;
+
+       return 0;
+}
+
+static void ocfs2_free_file_private(struct inode *inode, struct file *file)
+{
+       struct ocfs2_file_private *fp = file->private_data;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (fp) {
+               ocfs2_simple_drop_lockres(osb, &fp->fp_flock);
+               ocfs2_lock_res_free(&fp->fp_flock);
+               kfree(fp);
+               file->private_data = NULL;
+       }
+}
+
 static int ocfs2_file_open(struct inode *inode, struct file *file)
 {
        int status;
@@ -89,7 +119,18 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
 
        oi->ip_open_count++;
        spin_unlock(&oi->ip_lock);
-       status = 0;
+
+       status = ocfs2_init_file_private(inode, file);
+       if (status) {
+               /*
+                * We want to set open count back if we're failing the
+                * open.
+                */
+               spin_lock(&oi->ip_lock);
+               oi->ip_open_count--;
+               spin_unlock(&oi->ip_lock);
+       }
+
 leave:
        mlog_exit(status);
        return status;
@@ -108,11 +149,24 @@ static int ocfs2_file_release(struct inode *inode, struct file *file)
                oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
        spin_unlock(&oi->ip_lock);
 
+       ocfs2_free_file_private(inode, file);
+
        mlog_exit(0);
 
        return 0;
 }
 
+static int ocfs2_dir_open(struct inode *inode, struct file *file)
+{
+       return ocfs2_init_file_private(inode, file);
+}
+
+static int ocfs2_dir_release(struct inode *inode, struct file *file)
+{
+       ocfs2_free_file_private(inode, file);
+       return 0;
+}
+
 static int ocfs2_sync_file(struct file *file,
                           struct dentry *dentry,
                           int datasync)
@@ -382,18 +436,13 @@ static int ocfs2_truncate_file(struct inode *inode,
 
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-       /* This forces other nodes to sync and drop their pages. Do
-        * this even if we have a truncate without allocation change -
-        * ocfs2 cluster sizes can be much greater than page size, so
-        * we have to truncate them anyway.  */
-       status = ocfs2_data_lock(inode, 1);
-       if (status < 0) {
-               up_write(&OCFS2_I(inode)->ip_alloc_sem);
-
-               mlog_errno(status);
-               goto bail;
-       }
-
+       /*
+        * The inode lock forced other nodes to sync and drop their
+        * pages, which (correctly) happens even if we have a truncate
+        * without allocation change - ocfs2 cluster sizes can be much
+        * greater than page size, so we have to truncate them
+        * anyway.
+        */
        unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
        truncate_inode_pages(inode->i_mapping, new_i_size);
 
@@ -403,7 +452,7 @@ static int ocfs2_truncate_file(struct inode *inode,
                if (status)
                        mlog_errno(status);
 
-               goto bail_unlock_data;
+               goto bail_unlock_sem;
        }
 
        /* alright, we're going to need to do a full blown alloc size
@@ -413,25 +462,23 @@ static int ocfs2_truncate_file(struct inode *inode,
        status = ocfs2_orphan_for_truncate(osb, inode, di_bh, new_i_size);
        if (status < 0) {
                mlog_errno(status);
-               goto bail_unlock_data;
+               goto bail_unlock_sem;
        }
 
        status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc);
        if (status < 0) {
                mlog_errno(status);
-               goto bail_unlock_data;
+               goto bail_unlock_sem;
        }
 
        status = ocfs2_commit_truncate(osb, inode, di_bh, tc);
        if (status < 0) {
                mlog_errno(status);
-               goto bail_unlock_data;
+               goto bail_unlock_sem;
        }
 
        /* TODO: orphan dir cleanup here. */
-bail_unlock_data:
-       ocfs2_data_unlock(inode, 1);
-
+bail_unlock_sem:
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
 
 bail:
@@ -579,7 +626,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
 
        mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
             "clusters_to_add = %u, extents_to_split = %u\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode),
+            (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode),
             le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split);
 
        num_free_extents = ocfs2_num_free_extents(osb, inode, di);
@@ -760,7 +807,7 @@ restarted_transaction:
             le32_to_cpu(fe->i_clusters),
             (unsigned long long)le64_to_cpu(fe->i_size));
        mlog(0, "inode: ip_clusters=%u, i_size=%lld\n",
-            OCFS2_I(inode)->ip_clusters, i_size_read(inode));
+            OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode));
 
 leave:
        if (handle) {
@@ -917,7 +964,7 @@ static int ocfs2_extend_file(struct inode *inode,
                             struct buffer_head *di_bh,
                             u64 new_i_size)
 {
-       int ret = 0, data_locked = 0;
+       int ret = 0;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
        BUG_ON(!di_bh);
@@ -943,20 +990,6 @@ static int ocfs2_extend_file(struct inode *inode,
            && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
                goto out_update_size;
 
-       /* 
-        * protect the pages that ocfs2_zero_extend is going to be
-        * pulling into the page cache.. we do this before the
-        * metadata extend so that we don't get into the situation
-        * where we've extended the metadata but can't get the data
-        * lock to zero.
-        */
-       ret = ocfs2_data_lock(inode, 1);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out;
-       }
-       data_locked = 1;
-
        /*
         * The alloc sem blocks people in read/write from reading our
         * allocation until we're done changing it. We depend on
@@ -980,7 +1013,7 @@ static int ocfs2_extend_file(struct inode *inode,
                        up_write(&oi->ip_alloc_sem);
 
                        mlog_errno(ret);
-                       goto out_unlock;
+                       goto out;
                }
        }
 
@@ -991,7 +1024,7 @@ static int ocfs2_extend_file(struct inode *inode,
 
        if (ret < 0) {
                mlog_errno(ret);
-               goto out_unlock;
+               goto out;
        }
 
 out_update_size:
@@ -999,10 +1032,6 @@ out_update_size:
        if (ret < 0)
                mlog_errno(ret);
 
-out_unlock:
-       if (data_locked)
-               ocfs2_data_unlock(inode, 1);
-
 out:
        return ret;
 }
@@ -1050,7 +1079,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                }
        }
 
-       status = ocfs2_meta_lock(inode, &bh, 1);
+       status = ocfs2_inode_lock(inode, &bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -1102,7 +1131,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 bail_commit:
        ocfs2_commit_trans(osb, handle);
 bail_unlock:
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 bail_unlock_rw:
        if (size_change)
                ocfs2_rw_unlock(inode, 1);
@@ -1149,7 +1178,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
 
        mlog_entry_void();
 
-       ret = ocfs2_meta_lock(inode, NULL, 0);
+       ret = ocfs2_inode_lock(inode, NULL, 0);
        if (ret) {
                if (ret != -ENOENT)
                        mlog_errno(ret);
@@ -1158,7 +1187,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
 
        ret = generic_permission(inode, mask, NULL);
 
-       ocfs2_meta_unlock(inode, 0);
+       ocfs2_inode_unlock(inode, 0);
 out:
        mlog_exit(ret);
        return ret;
@@ -1630,7 +1659,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_meta_lock(inode, &di_bh, 1);
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
        if (ret) {
                mlog_errno(ret);
                goto out_rw_unlock;
@@ -1638,7 +1667,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
 
        if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
                ret = -EPERM;
-               goto out_meta_unlock;
+               goto out_inode_unlock;
        }
 
        switch (sr->l_whence) {
@@ -1652,7 +1681,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
                break;
        default:
                ret = -EINVAL;
-               goto out_meta_unlock;
+               goto out_inode_unlock;
        }
        sr->l_whence = 0;
 
@@ -1663,14 +1692,14 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
            || (sr->l_start + llen) < 0
            || (sr->l_start + llen) > max_off) {
                ret = -EINVAL;
-               goto out_meta_unlock;
+               goto out_inode_unlock;
        }
        size = sr->l_start + sr->l_len;
 
        if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) {
                if (sr->l_len <= 0) {
                        ret = -EINVAL;
-                       goto out_meta_unlock;
+                       goto out_inode_unlock;
                }
        }
 
@@ -1678,7 +1707,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
                ret = __ocfs2_write_remove_suid(inode, di_bh);
                if (ret) {
                        mlog_errno(ret);
-                       goto out_meta_unlock;
+                       goto out_inode_unlock;
                }
        }
 
@@ -1704,7 +1733,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
        if (ret) {
                mlog_errno(ret);
-               goto out_meta_unlock;
+               goto out_inode_unlock;
        }
 
        /*
@@ -1714,7 +1743,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                mlog_errno(ret);
-               goto out_meta_unlock;
+               goto out_inode_unlock;
        }
 
        if (change_size && i_size_read(inode) < size)
@@ -1727,9 +1756,9 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
 
        ocfs2_commit_trans(osb, handle);
 
-out_meta_unlock:
+out_inode_unlock:
        brelse(di_bh);
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 out_rw_unlock:
        ocfs2_rw_unlock(inode, 1);
 
@@ -1799,7 +1828,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
         * if we need to make modifications here.
         */
        for(;;) {
-               ret = ocfs2_meta_lock(inode, NULL, meta_level);
+               ret = ocfs2_inode_lock(inode, NULL, meta_level);
                if (ret < 0) {
                        meta_level = -1;
                        mlog_errno(ret);
@@ -1817,7 +1846,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                 * set inode->i_size at the end of a write. */
                if (should_remove_suid(dentry)) {
                        if (meta_level == 0) {
-                               ocfs2_meta_unlock(inode, meta_level);
+                               ocfs2_inode_unlock(inode, meta_level);
                                meta_level = 1;
                                continue;
                        }
@@ -1886,7 +1915,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                *ppos = saved_pos;
 
 out_unlock:
-       ocfs2_meta_unlock(inode, meta_level);
+       ocfs2_inode_unlock(inode, meta_level);
 
 out:
        return ret;
@@ -2099,12 +2128,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
        /*
         * See the comment in ocfs2_file_aio_read()
         */
-       ret = ocfs2_meta_lock(inode, NULL, 0);
+       ret = ocfs2_inode_lock(inode, NULL, 0);
        if (ret < 0) {
                mlog_errno(ret);
                goto bail;
        }
-       ocfs2_meta_unlock(inode, 0);
+       ocfs2_inode_unlock(inode, 0);
 
        ret = generic_file_splice_read(in, ppos, pipe, len, flags);
 
@@ -2160,12 +2189,12 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
         * like i_size. This allows the checks down below
         * generic_file_aio_read() a chance of actually working. 
         */
-       ret = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+       ret = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
        if (ret < 0) {
                mlog_errno(ret);
                goto bail;
        }
-       ocfs2_meta_unlock(inode, lock_level);
+       ocfs2_inode_unlock(inode, lock_level);
 
        ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
        if (ret == -EINVAL)
@@ -2204,6 +2233,7 @@ const struct inode_operations ocfs2_special_file_iops = {
 };
 
 const struct file_operations ocfs2_fops = {
+       .llseek         = generic_file_llseek,
        .read           = do_sync_read,
        .write          = do_sync_write,
        .mmap           = ocfs2_mmap,
@@ -2216,16 +2246,21 @@ const struct file_operations ocfs2_fops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ocfs2_compat_ioctl,
 #endif
+       .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
        .splice_write   = ocfs2_file_splice_write,
 };
 
 const struct file_operations ocfs2_dops = {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ocfs2_readdir,
        .fsync          = ocfs2_sync_file,
+       .release        = ocfs2_dir_release,
+       .open           = ocfs2_dir_open,
        .ioctl          = ocfs2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ocfs2_compat_ioctl,
 #endif
+       .flock          = ocfs2_flock,
 };
index 066f14add3a8c2f06ad465b2d9b81011ffaf0e4b..048ddcaf5c80e9b2bb76b1e06d3f6ddb340856c8 100644 (file)
@@ -32,6 +32,12 @@ extern const struct inode_operations ocfs2_file_iops;
 extern const struct inode_operations ocfs2_special_file_iops;
 struct ocfs2_alloc_context;
 
+struct ocfs2_file_private {
+       struct file             *fp_file;
+       struct mutex            fp_mutex;
+       struct ocfs2_lock_res   fp_flock;
+};
+
 enum ocfs2_alloc_restarted {
        RESTART_NONE = 0,
        RESTART_TRANS,
index c4c36171240d0555d5db10d0edb341c2a52627c9..c0efd9489fe8168f88d28c1abe6acdb2cedb3385 100644 (file)
@@ -30,9 +30,6 @@
 #include <linux/highmem.h>
 #include <linux/kmod.h>
 
-#include <cluster/heartbeat.h>
-#include <cluster/nodemanager.h>
-
 #include <dlm/dlmapi.h>
 
 #define MLOG_MASK_PREFIX ML_SUPER
 #include "heartbeat.h"
 #include "inode.h"
 #include "journal.h"
-#include "vote.h"
 
 #include "buffer_head_io.h"
 
-#define OCFS2_HB_NODE_DOWN_PRI     (0x0000002)
-#define OCFS2_HB_NODE_UP_PRI      OCFS2_HB_NODE_DOWN_PRI
-
 static inline void __ocfs2_node_map_set_bit(struct ocfs2_node_map *map,
                                            int bit);
 static inline void __ocfs2_node_map_clear_bit(struct ocfs2_node_map *map,
@@ -64,9 +57,7 @@ static void __ocfs2_node_map_set(struct ocfs2_node_map *target,
 void ocfs2_init_node_maps(struct ocfs2_super *osb)
 {
        spin_lock_init(&osb->node_map_lock);
-       ocfs2_node_map_init(&osb->mounted_map);
        ocfs2_node_map_init(&osb->recovery_map);
-       ocfs2_node_map_init(&osb->umount_map);
        ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs);
 }
 
@@ -87,24 +78,7 @@ static void ocfs2_do_node_down(int node_num,
                return;
        }
 
-       if (ocfs2_node_map_test_bit(osb, &osb->umount_map, node_num)) {
-               /* If a node is in the umount map, then we've been
-                * expecting him to go down and we know ahead of time
-                * that recovery is not necessary. */
-               ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
-               return;
-       }
-
        ocfs2_recovery_thread(osb, node_num);
-
-       ocfs2_remove_node_from_vote_queues(osb, node_num);
-}
-
-static void ocfs2_hb_node_down_cb(struct o2nm_node *node,
-                                 int node_num,
-                                 void *data)
-{
-       ocfs2_do_node_down(node_num, (struct ocfs2_super *) data);
 }
 
 /* Called from the dlm when it's about to evict a node. We may also
@@ -121,27 +95,8 @@ static void ocfs2_dlm_eviction_cb(int node_num,
        ocfs2_do_node_down(node_num, osb);
 }
 
-static void ocfs2_hb_node_up_cb(struct o2nm_node *node,
-                               int node_num,
-                               void *data)
-{
-       struct ocfs2_super *osb = data;
-
-       BUG_ON(osb->node_num == node_num);
-
-       mlog(0, "node up event for %d\n", node_num);
-       ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
-}
-
 void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
 {
-       o2hb_setup_callback(&osb->osb_hb_down, O2HB_NODE_DOWN_CB,
-                           ocfs2_hb_node_down_cb, osb,
-                           OCFS2_HB_NODE_DOWN_PRI);
-
-       o2hb_setup_callback(&osb->osb_hb_up, O2HB_NODE_UP_CB,
-                           ocfs2_hb_node_up_cb, osb, OCFS2_HB_NODE_UP_PRI);
-
        /* Not exactly a heartbeat callback, but leads to essentially
         * the same path so we set it up here. */
        dlm_setup_eviction_cb(&osb->osb_eviction_cb,
@@ -149,39 +104,6 @@ void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
                              osb);
 }
 
-/* Most functions here are just stubs for now... */
-int ocfs2_register_hb_callbacks(struct ocfs2_super *osb)
-{
-       int status;
-
-       if (ocfs2_mount_local(osb))
-               return 0;
-
-       status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_down);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_up);
-       if (status < 0) {
-               mlog_errno(status);
-               o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
-       }
-
-bail:
-       return status;
-}
-
-void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb)
-{
-       if (ocfs2_mount_local(osb))
-               return;
-
-       o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
-       o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_up);
-}
-
 void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
 {
        int ret;
@@ -341,8 +263,6 @@ int ocfs2_recovery_map_set(struct ocfs2_super *osb,
 
        spin_lock(&osb->node_map_lock);
 
-       __ocfs2_node_map_clear_bit(&osb->mounted_map, num);
-
        if (!test_bit(num, osb->recovery_map.map)) {
            __ocfs2_node_map_set_bit(&osb->recovery_map, num);
            set = 1;
index e8fb079122e43beffd7cfde858459a21fdf27a2b..56859211888a18cd6f22ed9a9fecf20eaba040ce 100644 (file)
@@ -29,8 +29,6 @@
 void ocfs2_init_node_maps(struct ocfs2_super *osb);
 
 void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb);
-int ocfs2_register_hb_callbacks(struct ocfs2_super *osb);
-void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb);
 void ocfs2_stop_heartbeat(struct ocfs2_super *osb);
 
 /* node map functions - used to keep track of mounted and in-recovery
index ebb2bbe30f358b9384662ee0f3d182a74db83c66..7e9e4c79aec7bf4b3e4488190f47972821a3945f 100644 (file)
@@ -49,7 +49,6 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
-#include "vote.h"
 
 #include "buffer_head_io.h"
 
@@ -58,8 +57,11 @@ struct ocfs2_find_inode_args
        u64             fi_blkno;
        unsigned long   fi_ino;
        unsigned int    fi_flags;
+       unsigned int    fi_sysfile_type;
 };
 
+static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
+
 static int ocfs2_read_locked_inode(struct inode *inode,
                                   struct ocfs2_find_inode_args *args);
 static int ocfs2_init_locked_inode(struct inode *inode, void *opaque);
@@ -107,7 +109,8 @@ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi)
                oi->ip_attr |= OCFS2_DIRSYNC_FL;
 }
 
-struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
+struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
+                        int sysfile_type)
 {
        struct inode *inode = NULL;
        struct super_block *sb = osb->sb;
@@ -127,6 +130,7 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
        args.fi_blkno = blkno;
        args.fi_flags = flags;
        args.fi_ino = ino_from_blkno(sb, blkno);
+       args.fi_sysfile_type = sysfile_type;
 
        inode = iget5_locked(sb, args.fi_ino, ocfs2_find_actor,
                             ocfs2_init_locked_inode, &args);
@@ -201,6 +205,9 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
 
        inode->i_ino = args->fi_ino;
        OCFS2_I(inode)->ip_blkno = args->fi_blkno;
+       if (args->fi_sysfile_type != 0)
+               lockdep_set_class(&inode->i_mutex,
+                       &ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
 
        mlog_exit(0);
        return 0;
@@ -322,7 +329,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
                 */
                BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL);
 
-               ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
+               ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres,
                                          OCFS2_LOCK_TYPE_META, 0, inode);
 
                ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres,
@@ -333,10 +340,6 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
                                  OCFS2_LOCK_TYPE_RW, inode->i_generation,
                                  inode);
 
-       ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres,
-                                 OCFS2_LOCK_TYPE_DATA, inode->i_generation,
-                                 inode);
-
        ocfs2_set_inode_flags(inode);
 
        status = 0;
@@ -414,7 +417,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
        if (args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
                generation = osb->fs_generation;
 
-       ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
+       ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres,
                                  OCFS2_LOCK_TYPE_META,
                                  generation, inode);
 
@@ -429,7 +432,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
                        mlog_errno(status);
                        return status;
                }
-               status = ocfs2_meta_lock(inode, NULL, 0);
+               status = ocfs2_inode_lock(inode, NULL, 0);
                if (status) {
                        make_bad_inode(inode);
                        mlog_errno(status);
@@ -484,7 +487,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 
 bail:
        if (can_lock)
-               ocfs2_meta_unlock(inode, 0);
+               ocfs2_inode_unlock(inode, 0);
 
        if (status < 0)
                make_bad_inode(inode);
@@ -586,7 +589,7 @@ static int ocfs2_remove_inode(struct inode *inode,
        }
 
        mutex_lock(&inode_alloc_inode->i_mutex);
-       status = ocfs2_meta_lock(inode_alloc_inode, &inode_alloc_bh, 1);
+       status = ocfs2_inode_lock(inode_alloc_inode, &inode_alloc_bh, 1);
        if (status < 0) {
                mutex_unlock(&inode_alloc_inode->i_mutex);
 
@@ -617,7 +620,7 @@ static int ocfs2_remove_inode(struct inode *inode,
        }
 
        di->i_dtime = cpu_to_le64(CURRENT_TIME.tv_sec);
-       le32_and_cpu(&di->i_flags, ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL));
+       di->i_flags &= cpu_to_le32(~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL));
 
        status = ocfs2_journal_dirty(handle, di_bh);
        if (status < 0) {
@@ -635,7 +638,7 @@ static int ocfs2_remove_inode(struct inode *inode,
 bail_commit:
        ocfs2_commit_trans(osb, handle);
 bail_unlock:
-       ocfs2_meta_unlock(inode_alloc_inode, 1);
+       ocfs2_inode_unlock(inode_alloc_inode, 1);
        mutex_unlock(&inode_alloc_inode->i_mutex);
        brelse(inode_alloc_bh);
 bail:
@@ -709,7 +712,7 @@ static int ocfs2_wipe_inode(struct inode *inode,
         * delete_inode operation. We do this now to avoid races with
         * recovery completion on other nodes. */
        mutex_lock(&orphan_dir_inode->i_mutex);
-       status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+       status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
        if (status < 0) {
                mutex_unlock(&orphan_dir_inode->i_mutex);
 
@@ -718,8 +721,8 @@ static int ocfs2_wipe_inode(struct inode *inode,
        }
 
        /* we do this while holding the orphan dir lock because we
-        * don't want recovery being run from another node to vote for
-        * an inode delete on us -- this will result in two nodes
+        * don't want recovery being run from another node to try an
+        * inode delete underneath us -- this will result in two nodes
         * truncating the same file! */
        status = ocfs2_truncate_for_delete(osb, inode, di_bh);
        if (status < 0) {
@@ -733,7 +736,7 @@ static int ocfs2_wipe_inode(struct inode *inode,
                mlog_errno(status);
 
 bail_unlock_dir:
-       ocfs2_meta_unlock(orphan_dir_inode, 1);
+       ocfs2_inode_unlock(orphan_dir_inode, 1);
        mutex_unlock(&orphan_dir_inode->i_mutex);
        brelse(orphan_dir_bh);
 bail:
@@ -744,7 +747,7 @@ bail:
 }
 
 /* There is a series of simple checks that should be done before a
- * vote is even considered. Encapsulate those in this function. */
+ * trylock is even considered. Encapsulate those in this function. */
 static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
 {
        int ret = 0;
@@ -758,14 +761,14 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
                goto bail;
        }
 
-       /* If we're coming from process_vote we can't go into our own
+       /* If we're coming from downconvert_thread we can't go into our own
         * voting [hello, deadlock city!], so unforuntately we just
         * have to skip deleting this guy. That's OK though because
         * the node who's doing the actual deleting should handle it
         * anyway. */
-       if (current == osb->vote_task) {
+       if (current == osb->dc_task) {
                mlog(0, "Skipping delete of %lu because we're currently "
-                    "in process_vote\n", inode->i_ino);
+                    "in downconvert\n", inode->i_ino);
                goto bail;
        }
 
@@ -779,10 +782,9 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
                goto bail_unlock;
        }
 
-       /* If we have voted "yes" on the wipe of this inode for
-        * another node, it will be marked here so we can safely skip
-        * it. Recovery will cleanup any inodes we might inadvertantly
-        * skip here. */
+       /* If we have allowd wipe of this inode for another node, it
+        * will be marked here so we can safely skip it. Recovery will
+        * cleanup any inodes we might inadvertantly skip here. */
        if (oi->ip_flags & OCFS2_INODE_SKIP_DELETE) {
                mlog(0, "Skipping delete of %lu because another node "
                     "has done this for us.\n", inode->i_ino);
@@ -929,13 +931,13 @@ void ocfs2_delete_inode(struct inode *inode)
 
        /* Lock down the inode. This gives us an up to date view of
         * it's metadata (for verification), and allows us to
-        * serialize delete_inode votes. 
+        * serialize delete_inode on multiple nodes.
         *
         * Even though we might be doing a truncate, we don't take the
         * allocation lock here as it won't be needed - nobody will
         * have the file open.
         */
-       status = ocfs2_meta_lock(inode, &di_bh, 1);
+       status = ocfs2_inode_lock(inode, &di_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -947,15 +949,15 @@ void ocfs2_delete_inode(struct inode *inode)
         * before we go ahead and wipe the inode. */
        status = ocfs2_query_inode_wipe(inode, di_bh, &wipe);
        if (!wipe || status < 0) {
-               /* Error and inode busy vote both mean we won't be
+               /* Error and remote inode busy both mean we won't be
                 * removing the inode, so they take almost the same
                 * path. */
                if (status < 0)
                        mlog_errno(status);
 
-               /* Someone in the cluster has voted to not wipe this
-                * inode, or it was never completely orphaned. Write
-                * out the pages and exit now. */
+               /* Someone in the cluster has disallowed a wipe of
+                * this inode, or it was never completely
+                * orphaned. Write out the pages and exit now. */
                ocfs2_cleanup_delete_inode(inode, 1);
                goto bail_unlock_inode;
        }
@@ -981,7 +983,7 @@ void ocfs2_delete_inode(struct inode *inode)
        OCFS2_I(inode)->ip_flags |= OCFS2_INODE_DELETED;
 
 bail_unlock_inode:
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
        brelse(di_bh);
 bail_unblock:
        status = sigprocmask(SIG_SETMASK, &oldset, NULL);
@@ -1008,15 +1010,14 @@ void ocfs2_clear_inode(struct inode *inode)
        mlog_bug_on_msg(OCFS2_SB(inode->i_sb) == NULL,
                        "Inode=%lu\n", inode->i_ino);
 
-       /* For remove delete_inode vote, we hold open lock before,
-        * now it is time to unlock PR and EX open locks. */
+       /* To preven remote deletes we hold open lock before, now it
+        * is time to unlock PR and EX open locks. */
        ocfs2_open_unlock(inode);
 
        /* Do these before all the other work so that we don't bounce
-        * the vote thread while waiting to destroy the locks. */
+        * the downconvert thread while waiting to destroy the locks. */
        ocfs2_mark_lockres_freeing(&oi->ip_rw_lockres);
-       ocfs2_mark_lockres_freeing(&oi->ip_meta_lockres);
-       ocfs2_mark_lockres_freeing(&oi->ip_data_lockres);
+       ocfs2_mark_lockres_freeing(&oi->ip_inode_lockres);
        ocfs2_mark_lockres_freeing(&oi->ip_open_lockres);
 
        /* We very well may get a clear_inode before all an inodes
@@ -1039,8 +1040,7 @@ void ocfs2_clear_inode(struct inode *inode)
                mlog_errno(status);
 
        ocfs2_lock_res_free(&oi->ip_rw_lockres);
-       ocfs2_lock_res_free(&oi->ip_meta_lockres);
-       ocfs2_lock_res_free(&oi->ip_data_lockres);
+       ocfs2_lock_res_free(&oi->ip_inode_lockres);
        ocfs2_lock_res_free(&oi->ip_open_lockres);
 
        ocfs2_metadata_cache_purge(inode);
@@ -1184,15 +1184,15 @@ int ocfs2_inode_revalidate(struct dentry *dentry)
        }
        spin_unlock(&OCFS2_I(inode)->ip_lock);
 
-       /* Let ocfs2_meta_lock do the work of updating our struct
+       /* Let ocfs2_inode_lock do the work of updating our struct
         * inode for us. */
-       status = ocfs2_meta_lock(inode, NULL, 0);
+       status = ocfs2_inode_lock(inode, NULL, 0);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
                goto bail;
        }
-       ocfs2_meta_unlock(inode, 0);
+       ocfs2_inode_unlock(inode, 0);
 bail:
        mlog_exit(status);
 
index 70e881c5553621d4e8f6fc380f1b682c5499587d..390a85596aa01841a5546e9464aa7a24cfcc23ea 100644 (file)
@@ -34,8 +34,7 @@ struct ocfs2_inode_info
        u64                     ip_blkno;
 
        struct ocfs2_lock_res           ip_rw_lockres;
-       struct ocfs2_lock_res           ip_meta_lockres;
-       struct ocfs2_lock_res           ip_data_lockres;
+       struct ocfs2_lock_res           ip_inode_lockres;
        struct ocfs2_lock_res           ip_open_lockres;
 
        /* protects allocation changes on this inode. */
@@ -121,9 +120,10 @@ void ocfs2_delete_inode(struct inode *inode);
 void ocfs2_drop_inode(struct inode *inode);
 
 /* Flags for ocfs2_iget() */
-#define OCFS2_FI_FLAG_SYSFILE          0x4
-#define OCFS2_FI_FLAG_ORPHAN_RECOVERY  0x8
-struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, int flags);
+#define OCFS2_FI_FLAG_SYSFILE          0x1
+#define OCFS2_FI_FLAG_ORPHAN_RECOVERY  0x2
+struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
+                        int sysfile_type);
 int ocfs2_inode_init_private(struct inode *inode);
 int ocfs2_inode_revalidate(struct dentry *dentry);
 int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
index 87dcece7e1b5cc1d0439da96c7fffe5199af1311..5177fba5162b55616c77d8a1a2db7b5c28842297 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "ocfs2_fs.h"
 #include "ioctl.h"
+#include "resize.h"
 
 #include <linux/ext2_fs.h>
 
@@ -27,14 +28,14 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
 {
        int status;
 
-       status = ocfs2_meta_lock(inode, NULL, 0);
+       status = ocfs2_inode_lock(inode, NULL, 0);
        if (status < 0) {
                mlog_errno(status);
                return status;
        }
        ocfs2_get_inode_flags(OCFS2_I(inode));
        *flags = OCFS2_I(inode)->ip_attr;
-       ocfs2_meta_unlock(inode, 0);
+       ocfs2_inode_unlock(inode, 0);
 
        mlog_exit(status);
        return status;
@@ -52,7 +53,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
 
        mutex_lock(&inode->i_mutex);
 
-       status = ocfs2_meta_lock(inode, &bh, 1);
+       status = ocfs2_inode_lock(inode, &bh, 1);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -100,7 +101,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
 
        ocfs2_commit_trans(osb, handle);
 bail_unlock:
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 bail:
        mutex_unlock(&inode->i_mutex);
 
@@ -115,8 +116,10 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
        unsigned int cmd, unsigned long arg)
 {
        unsigned int flags;
+       int new_clusters;
        int status;
        struct ocfs2_space_resv sr;
+       struct ocfs2_new_group_input input;
 
        switch (cmd) {
        case OCFS2_IOC_GETFLAGS:
@@ -140,6 +143,23 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
                        return -EFAULT;
 
                return ocfs2_change_file_space(filp, cmd, &sr);
+       case OCFS2_IOC_GROUP_EXTEND:
+               if (!capable(CAP_SYS_RESOURCE))
+                       return -EPERM;
+
+               if (get_user(new_clusters, (int __user *)arg))
+                       return -EFAULT;
+
+               return ocfs2_group_extend(inode, new_clusters);
+       case OCFS2_IOC_GROUP_ADD:
+       case OCFS2_IOC_GROUP_ADD64:
+               if (!capable(CAP_SYS_RESOURCE))
+                       return -EPERM;
+
+               if (copy_from_user(&input, (int __user *) arg, sizeof(input)))
+                       return -EFAULT;
+
+               return ocfs2_group_add(inode, &input);
        default:
                return -ENOTTY;
        }
@@ -162,6 +182,9 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case OCFS2_IOC_RESVSP64:
        case OCFS2_IOC_UNRESVSP:
        case OCFS2_IOC_UNRESVSP64:
+       case OCFS2_IOC_GROUP_EXTEND:
+       case OCFS2_IOC_GROUP_ADD:
+       case OCFS2_IOC_GROUP_ADD64:
                break;
        default:
                return -ENOIOCTLCMD;
index 8d81f6c1b877e98a6e9b6a1ad2f5bf6ea5d43a0c..f31c7e8c19c32bf091117a8fbd114b69c200f7ae 100644 (file)
@@ -44,7 +44,6 @@
 #include "localalloc.h"
 #include "slot_map.h"
 #include "super.h"
-#include "vote.h"
 #include "sysfile.h"
 
 #include "buffer_head_io.h"
@@ -103,7 +102,7 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
        mlog(0, "commit_thread: flushed transaction %lu (%u handles)\n",
             journal->j_trans_id, flushed);
 
-       ocfs2_kick_vote_thread(osb);
+       ocfs2_wake_downconvert_thread(osb);
        wake_up(&journal->j_checkpointed);
 finally:
        mlog_exit(status);
@@ -314,14 +313,18 @@ int ocfs2_journal_dirty_data(handle_t *handle,
        return err;
 }
 
-#define OCFS2_DEFAULT_COMMIT_INTERVAL  (HZ * 5)
+#define OCFS2_DEFAULT_COMMIT_INTERVAL  (HZ * JBD_DEFAULT_MAX_COMMIT_AGE)
 
 void ocfs2_set_journal_params(struct ocfs2_super *osb)
 {
        journal_t *journal = osb->journal->j_journal;
+       unsigned long commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
+
+       if (osb->osb_commit_interval)
+               commit_interval = osb->osb_commit_interval;
 
        spin_lock(&journal->j_state_lock);
-       journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
+       journal->j_commit_interval = commit_interval;
        if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
                journal->j_flags |= JFS_BARRIER;
        else
@@ -337,7 +340,7 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
        struct ocfs2_dinode *di = NULL;
        struct buffer_head *bh = NULL;
        struct ocfs2_super *osb;
-       int meta_lock = 0;
+       int inode_lock = 0;
 
        mlog_entry_void();
 
@@ -367,14 +370,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
        /* Skip recovery waits here - journal inode metadata never
         * changes in a live cluster so it can be considered an
         * exception to the rule. */
-       status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
+       status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
        if (status < 0) {
                if (status != -ERESTARTSYS)
                        mlog(ML_ERROR, "Could not get lock on journal!\n");
                goto done;
        }
 
-       meta_lock = 1;
+       inode_lock = 1;
        di = (struct ocfs2_dinode *)bh->b_data;
 
        if (inode->i_size <  OCFS2_MIN_JOURNAL_SIZE) {
@@ -414,8 +417,8 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
        status = 0;
 done:
        if (status < 0) {
-               if (meta_lock)
-                       ocfs2_meta_unlock(inode, 1);
+               if (inode_lock)
+                       ocfs2_inode_unlock(inode, 1);
                if (bh != NULL)
                        brelse(bh);
                if (inode) {
@@ -544,7 +547,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
        OCFS2_I(inode)->ip_open_count--;
 
        /* unlock our journal */
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 
        brelse(journal->j_bh);
        journal->j_bh = NULL;
@@ -883,8 +886,8 @@ restart:
        ocfs2_super_unlock(osb, 1);
 
        /* We always run recovery on our own orphan dir - the dead
-        * node(s) may have voted "no" on an inode delete earlier. A
-        * revote is therefore required. */
+        * node(s) may have disallowd a previos inode delete. Re-processing
+        * is therefore required. */
        ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
                                        NULL);
 
@@ -973,9 +976,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
        }
        SET_INODE_JOURNAL(inode);
 
-       status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
+       status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
        if (status < 0) {
-               mlog(0, "status returned from ocfs2_meta_lock=%d\n", status);
+               mlog(0, "status returned from ocfs2_inode_lock=%d\n", status);
                if (status != -ERESTARTSYS)
                        mlog(ML_ERROR, "Could not lock journal!\n");
                goto done;
@@ -1047,7 +1050,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
 done:
        /* drop the lock on this nodes journal */
        if (got_lock)
-               ocfs2_meta_unlock(inode, 1);
+               ocfs2_inode_unlock(inode, 1);
 
        if (inode)
                iput(inode);
@@ -1162,14 +1165,14 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb,
        SET_INODE_JOURNAL(inode);
 
        flags = OCFS2_META_LOCK_RECOVERY | OCFS2_META_LOCK_NOQUEUE;
-       status = ocfs2_meta_lock_full(inode, NULL, 1, flags);
+       status = ocfs2_inode_lock_full(inode, NULL, 1, flags);
        if (status < 0) {
                if (status != -EAGAIN)
                        mlog_errno(status);
                goto bail;
        }
 
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 bail:
        if (inode)
                iput(inode);
@@ -1241,7 +1244,7 @@ static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
 
        /* Skip bad inodes so that recovery can continue */
        iter = ocfs2_iget(p->osb, ino,
-                         OCFS2_FI_FLAG_ORPHAN_RECOVERY);
+                         OCFS2_FI_FLAG_ORPHAN_RECOVERY, 0);
        if (IS_ERR(iter))
                return 0;
 
@@ -1277,7 +1280,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
        }       
 
        mutex_lock(&orphan_dir_inode->i_mutex);
-       status = ocfs2_meta_lock(orphan_dir_inode, NULL, 0);
+       status = ocfs2_inode_lock(orphan_dir_inode, NULL, 0);
        if (status < 0) {
                mlog_errno(status);
                goto out;
@@ -1293,7 +1296,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
        *head = priv.head;
 
 out_cluster:
-       ocfs2_meta_unlock(orphan_dir_inode, 0);
+       ocfs2_inode_unlock(orphan_dir_inode, 0);
 out:
        mutex_unlock(&orphan_dir_inode->i_mutex);
        iput(orphan_dir_inode);
@@ -1380,10 +1383,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
                iter = oi->ip_next_orphan;
 
                spin_lock(&oi->ip_lock);
-               /* Delete voting may have set these on the assumption
-                * that the other node would wipe them successfully.
-                * If they are still in the node's orphan dir, we need
-                * to reset that state. */
+               /* The remote delete code may have set these on the
+                * assumption that the other node would wipe them
+                * successfully.  If they are still in the node's
+                * orphan dir, we need to reset that state. */
                oi->ip_flags &= ~(OCFS2_INODE_DELETED|OCFS2_INODE_SKIP_DELETE);
 
                /* Set the proper information to get us going into
index 4b32e0961568e34372a7ad02c7c8b77b3e0c6c24..220f3e818e78c4148db49bb6dea4fc5e22ca0728 100644 (file)
@@ -278,6 +278,12 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
 /* simple file updates like chmod, etc. */
 #define OCFS2_INODE_UPDATE_CREDITS 1
 
+/* group extend. inode update and last group update. */
+#define OCFS2_GROUP_EXTEND_CREDITS     (OCFS2_INODE_UPDATE_CREDITS + 1)
+
+/* group add. inode update and the new group update. */
+#define OCFS2_GROUP_ADD_CREDITS        (OCFS2_INODE_UPDATE_CREDITS + 1)
+
 /* get one bit out of a suballocator: dinode + group descriptor +
  * prev. group desc. if we relink. */
 #define OCFS2_SUBALLOC_ALLOC (3)
index 58ea88b5af36c44a25e1159f1f13e098a1dd54c4..add1ffdc5c6c75bb2accdb65972466f2651e80c8 100644 (file)
@@ -75,18 +75,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
 static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
                                          struct inode *local_alloc_inode);
 
-/*
- * Determine how large our local alloc window should be, in bits.
- *
- * These values (and the behavior in ocfs2_alloc_should_use_local) have
- * been chosen so that most allocations, including new block groups go
- * through local alloc.
- */
 static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
 {
-       BUG_ON(osb->s_clustersize_bits < 12);
+       BUG_ON(osb->s_clustersize_bits > 20);
 
-       return 2048 >> (osb->s_clustersize_bits - 12);
+       /* Size local alloc windows by the megabyte */
+       return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
 }
 
 /*
@@ -96,18 +90,23 @@ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
 int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
 {
        int la_bits = ocfs2_local_alloc_window_bits(osb);
+       int ret = 0;
 
        if (osb->local_alloc_state != OCFS2_LA_ENABLED)
-               return 0;
+               goto bail;
 
        /* la_bits should be at least twice the size (in clusters) of
         * a new block group. We want to be sure block group
         * allocations go through the local alloc, so allow an
         * allocation to take up to half the bitmap. */
        if (bits > (la_bits / 2))
-               return 0;
+               goto bail;
 
-       return 1;
+       ret = 1;
+bail:
+       mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
+            osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
+       return ret;
 }
 
 int ocfs2_load_local_alloc(struct ocfs2_super *osb)
@@ -121,6 +120,19 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
+       if (ocfs2_mount_local(osb))
+               goto bail;
+
+       if (osb->local_alloc_size == 0)
+               goto bail;
+
+       if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) {
+               mlog(ML_NOTICE, "Requested local alloc window %d is larger "
+                    "than max possible %u. Using defaults.\n",
+                    ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1));
+               osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
+       }
+
        /* read the alloc off disk */
        inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE,
                                            osb->slot_num);
@@ -181,6 +193,9 @@ bail:
        if (inode)
                iput(inode);
 
+       mlog(0, "Local alloc window bits = %d\n",
+            ocfs2_local_alloc_window_bits(osb));
+
        mlog_exit(status);
        return status;
 }
@@ -231,7 +246,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
 
        mutex_lock(&main_bm_inode->i_mutex);
 
-       status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);
+       status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
        if (status < 0) {
                mlog_errno(status);
                goto out_mutex;
@@ -286,7 +301,7 @@ out_unlock:
        if (main_bm_bh)
                brelse(main_bm_bh);
 
-       ocfs2_meta_unlock(main_bm_inode, 1);
+       ocfs2_inode_unlock(main_bm_inode, 1);
 
 out_mutex:
        mutex_unlock(&main_bm_inode->i_mutex);
@@ -399,7 +414,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
 
        mutex_lock(&main_bm_inode->i_mutex);
 
-       status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);
+       status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
        if (status < 0) {
                mlog_errno(status);
                goto out_mutex;
@@ -424,7 +439,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
        ocfs2_commit_trans(osb, handle);
 
 out_unlock:
-       ocfs2_meta_unlock(main_bm_inode, 1);
+       ocfs2_inode_unlock(main_bm_inode, 1);
 
 out_mutex:
        mutex_unlock(&main_bm_inode->i_mutex);
@@ -521,6 +536,9 @@ bail:
                iput(local_alloc_inode);
        }
 
+       mlog(0, "bits=%d, slot=%d, ret=%d\n", bits_wanted, osb->slot_num,
+            status);
+
        mlog_exit(status);
        return status;
 }
diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c
new file mode 100644 (file)
index 0000000..203f871
--- /dev/null
@@ -0,0 +1,125 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * locks.c
+ *
+ * Userspace file locking support
+ *
+ * Copyright (C) 2007 Oracle.  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.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#include <linux/fs.h>
+
+#define MLOG_MASK_PREFIX ML_INODE
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+
+#include "dlmglue.h"
+#include "file.h"
+#include "locks.h"
+
+static int ocfs2_do_flock(struct file *file, struct inode *inode,
+                         int cmd, struct file_lock *fl)
+{
+       int ret = 0, level = 0, trylock = 0;
+       struct ocfs2_file_private *fp = file->private_data;
+       struct ocfs2_lock_res *lockres = &fp->fp_flock;
+
+       if (fl->fl_type == F_WRLCK)
+               level = 1;
+       if (!IS_SETLKW(cmd))
+               trylock = 1;
+
+       mutex_lock(&fp->fp_mutex);
+
+       if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
+           lockres->l_level > LKM_NLMODE) {
+               int old_level = 0;
+
+               if (lockres->l_level == LKM_EXMODE)
+                       old_level = 1;
+
+               if (level == old_level)
+                       goto out;
+
+               /*
+                * Converting an existing lock is not guaranteed to be
+                * atomic, so we can get away with simply unlocking
+                * here and allowing the lock code to try at the new
+                * level.
+                */
+
+               flock_lock_file_wait(file,
+                                    &(struct file_lock){.fl_type = F_UNLCK});
+
+               ocfs2_file_unlock(file);
+       }
+
+       ret = ocfs2_file_lock(file, level, trylock);
+       if (ret) {
+               if (ret == -EAGAIN && trylock)
+                       ret = -EWOULDBLOCK;
+               else
+                       mlog_errno(ret);
+               goto out;
+       }
+
+       ret = flock_lock_file_wait(file, fl);
+
+out:
+       mutex_unlock(&fp->fp_mutex);
+
+       return ret;
+}
+
+static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
+{
+       int ret;
+       struct ocfs2_file_private *fp = file->private_data;
+
+       mutex_lock(&fp->fp_mutex);
+       ocfs2_file_unlock(file);
+       ret = flock_lock_file_wait(file, fl);
+       mutex_unlock(&fp->fp_mutex);
+
+       return ret;
+}
+
+/*
+ * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
+ */
+int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+       struct inode *inode = file->f_mapping->host;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (!(fl->fl_flags & FL_FLOCK))
+               return -ENOLCK;
+       if (__mandatory_lock(inode))
+               return -ENOLCK;
+
+       if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
+           ocfs2_mount_local(osb))
+               return flock_lock_file_wait(file, fl);
+
+       if (fl->fl_type == F_UNLCK)
+               return ocfs2_do_funlock(file, cmd, fl);
+       else
+               return ocfs2_do_flock(file, inode, cmd, fl);
+}
diff --git a/fs/ocfs2/locks.h b/fs/ocfs2/locks.h
new file mode 100644 (file)
index 0000000..9743ef2
--- /dev/null
@@ -0,0 +1,31 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * locks.h
+ *
+ * Function prototypes for Userspace file locking support
+ *
+ * Copyright (C) 2002, 2004 Oracle.  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.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#ifndef OCFS2_LOCKS_H
+#define OCFS2_LOCKS_H
+
+int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
+
+#endif /* OCFS2_LOCKS_H */
index 98756156d29878b8df182497214b9640d45ac79d..3dc18d67557c38b5df6ca59cc4c675178c0ad48f 100644 (file)
@@ -168,7 +168,7 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
         * node. Taking the data lock will also ensure that we don't
         * attempt page truncation as part of a downconvert.
         */
-       ret = ocfs2_meta_lock(inode, &di_bh, 1);
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
@@ -181,21 +181,12 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
         */
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-       ret = ocfs2_data_lock(inode, 1);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out_meta_unlock;
-       }
-
        ret = __ocfs2_page_mkwrite(inode, di_bh, page);
 
-       ocfs2_data_unlock(inode, 1);
-
-out_meta_unlock:
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
 
        brelse(di_bh);
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 
 out:
        ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
@@ -214,13 +205,13 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
 {
        int ret = 0, lock_level = 0;
 
-       ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode,
+       ret = ocfs2_inode_lock_atime(file->f_dentry->d_inode,
                                    file->f_vfsmnt, &lock_level);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
        }
-       ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
+       ocfs2_inode_unlock(file->f_dentry->d_inode, lock_level);
 out:
        vma->vm_ops = &ocfs2_file_vm_ops;
        vma->vm_flags |= VM_CAN_NONLINEAR;
index 989ac271858758065c83d6eb7681f9555ba54fd2..ae9ad9587516641366ddcb5753b61a120d9b137b 100644 (file)
@@ -60,7 +60,6 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
-#include "vote.h"
 
 #include "buffer_head_io.h"
 
@@ -116,7 +115,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
        mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len,
             dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
-       status = ocfs2_meta_lock(dir, NULL, 0);
+       status = ocfs2_inode_lock(dir, NULL, 0);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -129,7 +128,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
        if (status < 0)
                goto bail_add;
 
-       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
+       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
        if (IS_ERR(inode)) {
                ret = ERR_PTR(-EACCES);
                goto bail_unlock;
@@ -176,8 +175,8 @@ bail_unlock:
        /* Don't drop the cluster lock until *after* the d_add --
         * unlink on another node will message us to remove that
         * dentry under this lock so otherwise we can race this with
-        * the vote thread and have a stale dentry. */
-       ocfs2_meta_unlock(dir, 0);
+        * the downconvert thread and have a stale dentry. */
+       ocfs2_inode_unlock(dir, 0);
 
 bail:
 
@@ -209,7 +208,7 @@ static int ocfs2_mknod(struct inode *dir,
        /* get our super block */
        osb = OCFS2_SB(dir->i_sb);
 
-       status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
+       status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -323,7 +322,7 @@ leave:
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (status == -ENOSPC)
                mlog(0, "Disk is full\n");
@@ -553,7 +552,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
-       err = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
+       err = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
        if (err < 0) {
                if (err != -ENOENT)
                        mlog_errno(err);
@@ -578,7 +577,7 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto out;
        }
 
-       err = ocfs2_meta_lock(inode, &fe_bh, 1);
+       err = ocfs2_inode_lock(inode, &fe_bh, 1);
        if (err < 0) {
                if (err != -ENOENT)
                        mlog_errno(err);
@@ -643,10 +642,10 @@ static int ocfs2_link(struct dentry *old_dentry,
 out_commit:
        ocfs2_commit_trans(osb, handle);
 out_unlock_inode:
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 
 out:
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (de_bh)
                brelse(de_bh);
@@ -720,7 +719,7 @@ static int ocfs2_unlink(struct inode *dir,
                return -EPERM;
        }
 
-       status = ocfs2_meta_lock(dir, &parent_node_bh, 1);
+       status = ocfs2_inode_lock(dir, &parent_node_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -745,7 +744,7 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       status = ocfs2_meta_lock(inode, &fe_bh, 1);
+       status = ocfs2_inode_lock(inode, &fe_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -765,7 +764,7 @@ static int ocfs2_unlink(struct inode *dir,
 
        status = ocfs2_remote_dentry_delete(dentry);
        if (status < 0) {
-               /* This vote should succeed under all normal
+               /* This remote delete should succeed under all normal
                 * circumstances. */
                mlog_errno(status);
                goto leave;
@@ -841,13 +840,13 @@ leave:
                ocfs2_commit_trans(osb, handle);
 
        if (child_locked)
-               ocfs2_meta_unlock(inode, 1);
+               ocfs2_inode_unlock(inode, 1);
 
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (orphan_dir) {
                /* This was locked for us in ocfs2_prepare_orphan_dir() */
-               ocfs2_meta_unlock(orphan_dir, 1);
+               ocfs2_inode_unlock(orphan_dir, 1);
                mutex_unlock(&orphan_dir->i_mutex);
                iput(orphan_dir);
        }
@@ -908,7 +907,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
                        inode1 = tmpinode;
                }
                /* lock id2 */
-               status = ocfs2_meta_lock(inode2, bh2, 1);
+               status = ocfs2_inode_lock(inode2, bh2, 1);
                if (status < 0) {
                        if (status != -ENOENT)
                                mlog_errno(status);
@@ -917,14 +916,14 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
        }
 
        /* lock id1 */
-       status = ocfs2_meta_lock(inode1, bh1, 1);
+       status = ocfs2_inode_lock(inode1, bh1, 1);
        if (status < 0) {
                /*
                 * An error return must mean that no cluster locks
                 * were held on function exit.
                 */
                if (oi1->ip_blkno != oi2->ip_blkno)
-                       ocfs2_meta_unlock(inode2, 1);
+                       ocfs2_inode_unlock(inode2, 1);
 
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -937,10 +936,10 @@ bail:
 
 static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
 {
-       ocfs2_meta_unlock(inode1, 1);
+       ocfs2_inode_unlock(inode1, 1);
 
        if (inode1 != inode2)
-               ocfs2_meta_unlock(inode2, 1);
+               ocfs2_inode_unlock(inode2, 1);
 }
 
 static int ocfs2_rename(struct inode *old_dir,
@@ -1031,10 +1030,11 @@ static int ocfs2_rename(struct inode *old_dir,
 
        /*
         * Aside from allowing a meta data update, the locking here
-        * also ensures that the vote thread on other nodes won't have
-        * to concurrently downconvert the inode and the dentry locks.
+        * also ensures that the downconvert thread on other nodes
+        * won't have to concurrently downconvert the inode and the
+        * dentry locks.
         */
-       status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1);
+       status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -1143,7 +1143,7 @@ static int ocfs2_rename(struct inode *old_dir,
                        goto bail;
                }
 
-               status = ocfs2_meta_lock(new_inode, &newfe_bh, 1);
+               status = ocfs2_inode_lock(new_inode, &newfe_bh, 1);
                if (status < 0) {
                        if (status != -ENOENT)
                                mlog_errno(status);
@@ -1355,14 +1355,14 @@ bail:
                ocfs2_double_unlock(old_dir, new_dir);
 
        if (old_child_locked)
-               ocfs2_meta_unlock(old_inode, 1);
+               ocfs2_inode_unlock(old_inode, 1);
 
        if (new_child_locked)
-               ocfs2_meta_unlock(new_inode, 1);
+               ocfs2_inode_unlock(new_inode, 1);
 
        if (orphan_dir) {
                /* This was locked for us in ocfs2_prepare_orphan_dir() */
-               ocfs2_meta_unlock(orphan_dir, 1);
+               ocfs2_inode_unlock(orphan_dir, 1);
                mutex_unlock(&orphan_dir->i_mutex);
                iput(orphan_dir);
        }
@@ -1530,7 +1530,7 @@ static int ocfs2_symlink(struct inode *dir,
        credits = ocfs2_calc_symlink_credits(sb);
 
        /* lock the parent directory */
-       status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
+       status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -1657,7 +1657,7 @@ bail:
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (new_fe_bh)
                brelse(new_fe_bh);
@@ -1735,7 +1735,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
 
        mutex_lock(&orphan_dir_inode->i_mutex);
 
-       status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+       status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -1745,7 +1745,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                              orphan_dir_bh, name,
                                              OCFS2_ORPHAN_NAMELEN, de_bh);
        if (status < 0) {
-               ocfs2_meta_unlock(orphan_dir_inode, 1);
+               ocfs2_inode_unlock(orphan_dir_inode, 1);
 
                mlog_errno(status);
                goto leave;
index 60a23e1906b0c054c9b3a7091a662437cb3c7ab5..d08480580470e237562dd75239f513d13ee28386 100644 (file)
@@ -101,6 +101,7 @@ enum ocfs2_unlock_action {
                                               * about to be
                                               * dropped. */
 #define OCFS2_LOCK_QUEUED        (0x00000100) /* queued for downconvert */
+#define OCFS2_LOCK_NOCACHE       (0x00000200) /* don't use a holder count */
 
 struct ocfs2_lock_res_ops;
 
@@ -170,6 +171,7 @@ enum ocfs2_mount_options
        OCFS2_MOUNT_NOINTR  = 1 << 2,   /* Don't catch signals */
        OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
        OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
+       OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */
 };
 
 #define OCFS2_OSB_SOFT_RO      0x0001
@@ -189,9 +191,7 @@ struct ocfs2_super
        struct ocfs2_slot_info *slot_info;
 
        spinlock_t node_map_lock;
-       struct ocfs2_node_map mounted_map;
        struct ocfs2_node_map recovery_map;
-       struct ocfs2_node_map umount_map;
 
        u64 root_blkno;
        u64 system_dir_blkno;
@@ -231,7 +231,9 @@ struct ocfs2_super
        wait_queue_head_t checkpoint_event;
        atomic_t needs_checkpoint;
        struct ocfs2_journal *journal;
+       unsigned long osb_commit_interval;
 
+       int local_alloc_size;
        enum ocfs2_local_alloc_state local_alloc_state;
        struct buffer_head *local_alloc_bh;
        u64 la_last_gd;
@@ -254,28 +256,21 @@ struct ocfs2_super
 
        wait_queue_head_t recovery_event;
 
-       spinlock_t vote_task_lock;
-       struct task_struct *vote_task;
-       wait_queue_head_t vote_event;
-       unsigned long vote_wake_sequence;
-       unsigned long vote_work_sequence;
+       spinlock_t dc_task_lock;
+       struct task_struct *dc_task;
+       wait_queue_head_t dc_event;
+       unsigned long dc_wake_sequence;
+       unsigned long dc_work_sequence;
 
+       /*
+        * Any thread can add locks to the list, but the downconvert
+        * thread is the only one allowed to remove locks. Any change
+        * to this rule requires updating
+        * ocfs2_downconvert_thread_do_work().
+        */
        struct list_head blocked_lock_list;
        unsigned long blocked_lock_count;
 
-       struct list_head vote_list;
-       int vote_count;
-
-       u32 net_key;
-       spinlock_t net_response_lock;
-       unsigned int net_response_ids;
-       struct list_head net_response_list;
-
-       struct o2hb_callback_func osb_hb_up;
-       struct o2hb_callback_func osb_hb_down;
-
-       struct list_head        osb_net_handlers;
-
        wait_queue_head_t               osb_mount_event;
 
        /* Truncate log info */
index 6ef876759a737eb098d7abbf70e87d69663114f9..3633edd3982f731a1c1c67bf1cdab945eea0689e 100644 (file)
@@ -231,6 +231,20 @@ struct ocfs2_space_resv {
 #define OCFS2_IOC_RESVSP64     _IOW ('X', 42, struct ocfs2_space_resv)
 #define OCFS2_IOC_UNRESVSP64   _IOW ('X', 43, struct ocfs2_space_resv)
 
+/* Used to pass group descriptor data when online resize is done */
+struct ocfs2_new_group_input {
+       __u64 group;            /* Group descriptor's blkno. */
+       __u32 clusters;         /* Total number of clusters in this group */
+       __u32 frees;            /* Total free clusters in this group */
+       __u16 chain;            /* Chain for this group */
+       __u16 reserved1;
+       __u32 reserved2;
+};
+
+#define OCFS2_IOC_GROUP_EXTEND _IOW('o', 1, int)
+#define OCFS2_IOC_GROUP_ADD    _IOW('o', 2,struct ocfs2_new_group_input)
+#define OCFS2_IOC_GROUP_ADD64  _IOW('o', 3,struct ocfs2_new_group_input)
+
 /*
  * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
  */
@@ -256,6 +270,14 @@ struct ocfs2_space_resv {
 /* Journal limits (in bytes) */
 #define OCFS2_MIN_JOURNAL_SIZE         (4 * 1024 * 1024)
 
+/*
+ * Default local alloc size (in megabytes)
+ *
+ * The value chosen should be such that most allocations, including new
+ * block groups, use local alloc.
+ */
+#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8
+
 struct ocfs2_system_inode_info {
        char    *si_name;
        int     si_iflags;
index 4ca02b1c38ac548ab3abf61424bcc72b9464c26b..86f3e3799c2b00d91f5c456792b3c73ed791be51 100644 (file)
@@ -45,6 +45,7 @@ enum ocfs2_lock_type {
        OCFS2_LOCK_TYPE_RW,
        OCFS2_LOCK_TYPE_DENTRY,
        OCFS2_LOCK_TYPE_OPEN,
+       OCFS2_LOCK_TYPE_FLOCK,
        OCFS2_NUM_LOCK_TYPES
 };
 
@@ -73,6 +74,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
                case OCFS2_LOCK_TYPE_OPEN:
                        c = 'O';
                        break;
+               case OCFS2_LOCK_TYPE_FLOCK:
+                       c = 'F';
+                       break;
                default:
                        c = '\0';
        }
@@ -90,6 +94,7 @@ static char *ocfs2_lock_type_strings[] = {
        [OCFS2_LOCK_TYPE_RW] = "Write/Read",
        [OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
        [OCFS2_LOCK_TYPE_OPEN] = "Open",
+       [OCFS2_LOCK_TYPE_FLOCK] = "Flock",
 };
 
 static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
new file mode 100644 (file)
index 0000000..37835ff
--- /dev/null
@@ -0,0 +1,634 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * resize.c
+ *
+ * volume resize.
+ * Inspired by ext3/resize.c.
+ *
+ * Copyright (C) 2007 Oracle.  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.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#define MLOG_MASK_PREFIX ML_DISK_ALLOC
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+
+#include "alloc.h"
+#include "dlmglue.h"
+#include "inode.h"
+#include "journal.h"
+#include "super.h"
+#include "sysfile.h"
+#include "uptodate.h"
+
+#include "buffer_head_io.h"
+#include "suballoc.h"
+#include "resize.h"
+
+/*
+ * Check whether there are new backup superblocks exist
+ * in the last group. If there are some, mark them or clear
+ * them in the bitmap.
+ *
+ * Return how many backups we find in the last group.
+ */
+static u16 ocfs2_calc_new_backup_super(struct inode *inode,
+                                      struct ocfs2_group_desc *gd,
+                                      int new_clusters,
+                                      u32 first_new_cluster,
+                                      u16 cl_cpg,
+                                      int set)
+{
+       int i;
+       u16 backups = 0;
+       u32 cluster;
+       u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno);
+
+       for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
+               blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
+               cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
+
+               gd_blkno = ocfs2_which_cluster_group(inode, cluster);
+               if (gd_blkno < lgd_blkno)
+                       continue;
+               else if (gd_blkno > lgd_blkno)
+                       break;
+
+               if (set)
+                       ocfs2_set_bit(cluster % cl_cpg,
+                                     (unsigned long *)gd->bg_bitmap);
+               else
+                       ocfs2_clear_bit(cluster % cl_cpg,
+                                       (unsigned long *)gd->bg_bitmap);
+               backups++;
+       }
+
+       mlog_exit_void();
+       return backups;
+}
+
+static int ocfs2_update_last_group_and_inode(handle_t *handle,
+                                            struct inode *bm_inode,
+                                            struct buffer_head *bm_bh,
+                                            struct buffer_head *group_bh,
+                                            u32 first_new_cluster,
+                                            int new_clusters)
+{
+       int ret = 0;
+       struct ocfs2_super *osb = OCFS2_SB(bm_inode->i_sb);
+       struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bm_bh->b_data;
+       struct ocfs2_chain_list *cl = &fe->id2.i_chain;
+       struct ocfs2_chain_rec *cr;
+       struct ocfs2_group_desc *group;
+       u16 chain, num_bits, backups = 0;
+       u16 cl_bpc = le16_to_cpu(cl->cl_bpc);
+       u16 cl_cpg = le16_to_cpu(cl->cl_cpg);
+
+       mlog_entry("(new_clusters=%d, first_new_cluster = %u)\n",
+                  new_clusters, first_new_cluster);
+
+       ret = ocfs2_journal_access(handle, bm_inode, group_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       group = (struct ocfs2_group_desc *)group_bh->b_data;
+
+       /* update the group first. */
+       num_bits = new_clusters * cl_bpc;
+       le16_add_cpu(&group->bg_bits, num_bits);
+       le16_add_cpu(&group->bg_free_bits_count, num_bits);
+
+       /*
+        * check whether there are some new backup superblocks exist in
+        * this group and update the group bitmap accordingly.
+        */
+       if (OCFS2_HAS_COMPAT_FEATURE(osb->sb,
+                                    OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+               backups = ocfs2_calc_new_backup_super(bm_inode,
+                                                    group,
+                                                    new_clusters,
+                                                    first_new_cluster,
+                                                    cl_cpg, 1);
+               le16_add_cpu(&group->bg_free_bits_count, -1 * backups);
+       }
+
+       ret = ocfs2_journal_dirty(handle, group_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_rollback;
+       }
+
+       /* update the inode accordingly. */
+       ret = ocfs2_journal_access(handle, bm_inode, bm_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_rollback;
+       }
+
+       chain = le16_to_cpu(group->bg_chain);
+       cr = (&cl->cl_recs[chain]);
+       le32_add_cpu(&cr->c_total, num_bits);
+       le32_add_cpu(&cr->c_free, num_bits);
+       le32_add_cpu(&fe->id1.bitmap1.i_total, num_bits);
+       le32_add_cpu(&fe->i_clusters, new_clusters);
+
+       if (backups) {
+               le32_add_cpu(&cr->c_free, -1 * backups);
+               le32_add_cpu(&fe->id1.bitmap1.i_used, backups);
+       }
+
+       spin_lock(&OCFS2_I(bm_inode)->ip_lock);
+       OCFS2_I(bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
+       le64_add_cpu(&fe->i_size, new_clusters << osb->s_clustersize_bits);
+       spin_unlock(&OCFS2_I(bm_inode)->ip_lock);
+       i_size_write(bm_inode, le64_to_cpu(fe->i_size));
+
+       ocfs2_journal_dirty(handle, bm_bh);
+
+out_rollback:
+       if (ret < 0) {
+               ocfs2_calc_new_backup_super(bm_inode,
+                                           group,
+                                           new_clusters,
+                                           first_new_cluster,
+                                           cl_cpg, 0);
+               le16_add_cpu(&group->bg_free_bits_count, backups);
+               le16_add_cpu(&group->bg_bits, -1 * num_bits);
+               le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits);
+       }
+out:
+       mlog_exit(ret);
+       return ret;
+}
+
+static int update_backups(struct inode * inode, u32 clusters, char *data)
+{
+       int i, ret = 0;
+       u32 cluster;
+       u64 blkno;
+       struct buffer_head *backup = NULL;
+       struct ocfs2_dinode *backup_di = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       /* calculate the real backups we need to update. */
+       for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
+               blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
+               cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
+               if (cluster > clusters)
+                       break;
+
+               ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       break;
+               }
+
+               memcpy(backup->b_data, data, inode->i_sb->s_blocksize);
+
+               backup_di = (struct ocfs2_dinode *)backup->b_data;
+               backup_di->i_blkno = cpu_to_le64(blkno);
+
+               ret = ocfs2_write_super_or_backup(osb, backup);
+               brelse(backup);
+               backup = NULL;
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static void ocfs2_update_super_and_backups(struct inode *inode,
+                                          int new_clusters)
+{
+       int ret;
+       u32 clusters = 0;
+       struct buffer_head *super_bh = NULL;
+       struct ocfs2_dinode *super_di = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       /*
+        * update the superblock last.
+        * It doesn't matter if the write failed.
+        */
+       ret = ocfs2_read_block(osb, OCFS2_SUPER_BLOCK_BLKNO,
+                              &super_bh, 0, NULL);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       super_di = (struct ocfs2_dinode *)super_bh->b_data;
+       le32_add_cpu(&super_di->i_clusters, new_clusters);
+       clusters = le32_to_cpu(super_di->i_clusters);
+
+       ret = ocfs2_write_super_or_backup(osb, super_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_COMPAT_BACKUP_SB))
+               ret = update_backups(inode, clusters, super_bh->b_data);
+
+out:
+       brelse(super_bh);
+       if (ret)
+               printk(KERN_WARNING "ocfs2: Failed to update super blocks on %s"
+                       " during fs resize. This condition is not fatal,"
+                       " but fsck.ocfs2 should be run to fix it\n",
+                       osb->dev_str);
+       return;
+}
+
+/*
+ * Extend the filesystem to the new number of clusters specified.  This entry
+ * point is only used to extend the current filesystem to the end of the last
+ * existing group.
+ */
+int ocfs2_group_extend(struct inode * inode, int new_clusters)
+{
+       int ret;
+       handle_t *handle;
+       struct buffer_head *main_bm_bh = NULL;
+       struct buffer_head *group_bh = NULL;
+       struct inode *main_bm_inode = NULL;
+       struct ocfs2_dinode *fe = NULL;
+       struct ocfs2_group_desc *group = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       u16 cl_bpc;
+       u32 first_new_cluster;
+       u64 lgd_blkno;
+
+       mlog_entry_void();
+
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+               return -EROFS;
+
+       if (new_clusters < 0)
+               return -EINVAL;
+       else if (new_clusters == 0)
+               return 0;
+
+       main_bm_inode = ocfs2_get_system_file_inode(osb,
+                                                   GLOBAL_BITMAP_SYSTEM_INODE,
+                                                   OCFS2_INVALID_SLOT);
+       if (!main_bm_inode) {
+               ret = -EINVAL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       mutex_lock(&main_bm_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_mutex;
+       }
+
+       fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
+
+       if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
+                                ocfs2_group_bitmap_size(osb->sb) * 8) {
+               mlog(ML_ERROR, "The disk is too old and small. "
+                    "Force to do offline resize.");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       if (!OCFS2_IS_VALID_DINODE(fe)) {
+               OCFS2_RO_ON_INVALID_DINODE(main_bm_inode->i_sb, fe);
+               ret = -EIO;
+               goto out_unlock;
+       }
+
+       first_new_cluster = le32_to_cpu(fe->i_clusters);
+       lgd_blkno = ocfs2_which_cluster_group(main_bm_inode,
+                                             first_new_cluster - 1);
+
+       ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED,
+                              main_bm_inode);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       group = (struct ocfs2_group_desc *)group_bh->b_data;
+
+       ret = ocfs2_check_group_descriptor(inode->i_sb, fe, group);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
+       if (le16_to_cpu(group->bg_bits) / cl_bpc + new_clusters >
+               le16_to_cpu(fe->id2.i_chain.cl_cpg)) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       mlog(0, "extend the last group at %llu, new clusters = %d\n",
+            (unsigned long long)le64_to_cpu(group->bg_blkno), new_clusters);
+
+       handle = ocfs2_start_trans(osb, OCFS2_GROUP_EXTEND_CREDITS);
+       if (IS_ERR(handle)) {
+               mlog_errno(PTR_ERR(handle));
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       /* update the last group descriptor and inode. */
+       ret = ocfs2_update_last_group_and_inode(handle, main_bm_inode,
+                                               main_bm_bh, group_bh,
+                                               first_new_cluster,
+                                               new_clusters);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ocfs2_update_super_and_backups(main_bm_inode, new_clusters);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out_unlock:
+       brelse(group_bh);
+       brelse(main_bm_bh);
+
+       ocfs2_inode_unlock(main_bm_inode, 1);
+
+out_mutex:
+       mutex_unlock(&main_bm_inode->i_mutex);
+       iput(main_bm_inode);
+
+out:
+       mlog_exit_void();
+       return ret;
+}
+
+static int ocfs2_check_new_group(struct inode *inode,
+                                struct ocfs2_dinode *di,
+                                struct ocfs2_new_group_input *input,
+                                struct buffer_head *group_bh)
+{
+       int ret;
+       struct ocfs2_group_desc *gd;
+       u16 cl_bpc = le16_to_cpu(di->id2.i_chain.cl_bpc);
+       unsigned int max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) *
+                               le16_to_cpu(di->id2.i_chain.cl_bpc);
+
+
+       gd = (struct ocfs2_group_desc *)group_bh->b_data;
+
+       ret = -EIO;
+       if (!OCFS2_IS_VALID_GROUP_DESC(gd))
+               mlog(ML_ERROR, "Group descriptor # %llu isn't valid.\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno));
+       else if (di->i_blkno != gd->bg_parent_dinode)
+               mlog(ML_ERROR, "Group descriptor # %llu has bad parent "
+                    "pointer (%llu, expected %llu)\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    (unsigned long long)le64_to_cpu(gd->bg_parent_dinode),
+                    (unsigned long long)le64_to_cpu(di->i_blkno));
+       else if (le16_to_cpu(gd->bg_bits) > max_bits)
+               mlog(ML_ERROR, "Group descriptor # %llu has bit count of %u\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    le16_to_cpu(gd->bg_bits));
+       else if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits))
+               mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
+                    "claims that %u are free\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    le16_to_cpu(gd->bg_bits),
+                    le16_to_cpu(gd->bg_free_bits_count));
+       else if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size)))
+               mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
+                    "max bitmap bits of %u\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    le16_to_cpu(gd->bg_bits),
+                    8 * le16_to_cpu(gd->bg_size));
+       else if (le16_to_cpu(gd->bg_chain) != input->chain)
+               mlog(ML_ERROR, "Group descriptor # %llu has bad chain %u "
+                    "while input has %u set.\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    le16_to_cpu(gd->bg_chain), input->chain);
+       else if (le16_to_cpu(gd->bg_bits) != input->clusters * cl_bpc)
+               mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
+                    "input has %u clusters set\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    le16_to_cpu(gd->bg_bits), input->clusters);
+       else if (le16_to_cpu(gd->bg_free_bits_count) != input->frees * cl_bpc)
+               mlog(ML_ERROR, "Group descriptor # %llu has free bit count %u "
+                    "but it should have %u set\n",
+                    (unsigned long long)le64_to_cpu(gd->bg_blkno),
+                    le16_to_cpu(gd->bg_bits),
+                    input->frees * cl_bpc);
+       else
+               ret = 0;
+
+       return ret;
+}
+
+static int ocfs2_verify_group_and_input(struct inode *inode,
+                                       struct ocfs2_dinode *di,
+                                       struct ocfs2_new_group_input *input,
+                                       struct buffer_head *group_bh)
+{
+       u16 cl_count = le16_to_cpu(di->id2.i_chain.cl_count);
+       u16 cl_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
+       u16 next_free = le16_to_cpu(di->id2.i_chain.cl_next_free_rec);
+       u32 cluster = ocfs2_blocks_to_clusters(inode->i_sb, input->group);
+       u32 total_clusters = le32_to_cpu(di->i_clusters);
+       int ret = -EINVAL;
+
+       if (cluster < total_clusters)
+               mlog(ML_ERROR, "add a group which is in the current volume.\n");
+       else if (input->chain >= cl_count)
+               mlog(ML_ERROR, "input chain exceeds the limit.\n");
+       else if (next_free != cl_count && next_free != input->chain)
+               mlog(ML_ERROR,
+                    "the add group should be in chain %u\n", next_free);
+       else if (total_clusters + input->clusters < total_clusters)
+               mlog(ML_ERROR, "add group's clusters overflow.\n");
+       else if (input->clusters > cl_cpg)
+               mlog(ML_ERROR, "the cluster exceeds the maximum of a group\n");
+       else if (input->frees > input->clusters)
+               mlog(ML_ERROR, "the free cluster exceeds the total clusters\n");
+       else if (total_clusters % cl_cpg != 0)
+               mlog(ML_ERROR,
+                    "the last group isn't full. Use group extend first.\n");
+       else if (input->group != ocfs2_which_cluster_group(inode, cluster))
+               mlog(ML_ERROR, "group blkno is invalid\n");
+       else if ((ret = ocfs2_check_new_group(inode, di, input, group_bh)))
+               mlog(ML_ERROR, "group descriptor check failed.\n");
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* Add a new group descriptor to global_bitmap. */
+int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
+{
+       int ret;
+       handle_t *handle;
+       struct buffer_head *main_bm_bh = NULL;
+       struct inode *main_bm_inode = NULL;
+       struct ocfs2_dinode *fe = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct buffer_head *group_bh = NULL;
+       struct ocfs2_group_desc *group = NULL;
+       struct ocfs2_chain_list *cl;
+       struct ocfs2_chain_rec *cr;
+       u16 cl_bpc;
+
+       mlog_entry_void();
+
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+               return -EROFS;
+
+       main_bm_inode = ocfs2_get_system_file_inode(osb,
+                                                   GLOBAL_BITMAP_SYSTEM_INODE,
+                                                   OCFS2_INVALID_SLOT);
+       if (!main_bm_inode) {
+               ret = -EINVAL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       mutex_lock(&main_bm_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_mutex;
+       }
+
+       fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
+
+       if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
+                                ocfs2_group_bitmap_size(osb->sb) * 8) {
+               mlog(ML_ERROR, "The disk is too old and small."
+                    " Force to do offline resize.");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL);
+       if (ret < 0) {
+               mlog(ML_ERROR, "Can't read the group descriptor # %llu "
+                    "from the device.", (unsigned long long)input->group);
+               goto out_unlock;
+       }
+
+       ocfs2_set_new_buffer_uptodate(inode, group_bh);
+
+       ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       mlog(0, "Add a new group  %llu in chain = %u, length = %u\n",
+            (unsigned long long)input->group, input->chain, input->clusters);
+
+       handle = ocfs2_start_trans(osb, OCFS2_GROUP_ADD_CREDITS);
+       if (IS_ERR(handle)) {
+               mlog_errno(PTR_ERR(handle));
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
+       cl = &fe->id2.i_chain;
+       cr = &cl->cl_recs[input->chain];
+
+       ret = ocfs2_journal_access(handle, main_bm_inode, group_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       group = (struct ocfs2_group_desc *)group_bh->b_data;
+       group->bg_next_group = cr->c_blkno;
+
+       ret = ocfs2_journal_dirty(handle, group_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_journal_access(handle, main_bm_inode, main_bm_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       if (input->chain == le16_to_cpu(cl->cl_next_free_rec)) {
+               le16_add_cpu(&cl->cl_next_free_rec, 1);
+               memset(cr, 0, sizeof(struct ocfs2_chain_rec));
+       }
+
+       cr->c_blkno = le64_to_cpu(input->group);
+       le32_add_cpu(&cr->c_total, input->clusters * cl_bpc);
+       le32_add_cpu(&cr->c_free, input->frees * cl_bpc);
+
+       le32_add_cpu(&fe->id1.bitmap1.i_total, input->clusters *cl_bpc);
+       le32_add_cpu(&fe->id1.bitmap1.i_used,
+                    (input->clusters - input->frees) * cl_bpc);
+       le32_add_cpu(&fe->i_clusters, input->clusters);
+
+       ocfs2_journal_dirty(handle, main_bm_bh);
+
+       spin_lock(&OCFS2_I(main_bm_inode)->ip_lock);
+       OCFS2_I(main_bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
+       le64_add_cpu(&fe->i_size, input->clusters << osb->s_clustersize_bits);
+       spin_unlock(&OCFS2_I(main_bm_inode)->ip_lock);
+       i_size_write(main_bm_inode, le64_to_cpu(fe->i_size));
+
+       ocfs2_update_super_and_backups(main_bm_inode, input->clusters);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out_unlock:
+       brelse(group_bh);
+       brelse(main_bm_bh);
+
+       ocfs2_inode_unlock(main_bm_inode, 1);
+
+out_mutex:
+       mutex_unlock(&main_bm_inode->i_mutex);
+       iput(main_bm_inode);
+
+out:
+       mlog_exit_void();
+       return ret;
+}
diff --git a/fs/ocfs2/resize.h b/fs/ocfs2/resize.h
new file mode 100644 (file)
index 0000000..f38841a
--- /dev/null
@@ -0,0 +1,32 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * resize.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2007 Oracle.  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.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#ifndef OCFS2_RESIZE_H
+#define OCFS2_RESIZE_H
+
+int ocfs2_group_extend(struct inode * inode, int new_clusters);
+int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input);
+
+#endif /* OCFS2_RESIZE_H */
index af4882b62cfae7c914fb4c22aad90761d039dc96..3a50ce555e641f339c72b820a52eae07b047343b 100644 (file)
@@ -48,25 +48,6 @@ static void __ocfs2_fill_slot(struct ocfs2_slot_info *si,
                              s16 slot_num,
                              s16 node_num);
 
-/* Use the slot information we've collected to create a map of mounted
- * nodes. Should be holding an EX on super block. assumes slot info is
- * up to date. Note that we call this *after* we find a slot, so our
- * own node should be set in the map too... */
-void ocfs2_populate_mounted_map(struct ocfs2_super *osb)
-{
-       int i;
-       struct ocfs2_slot_info *si = osb->slot_info;
-
-       spin_lock(&si->si_lock);
-
-       for (i = 0; i < si->si_size; i++)
-               if (si->si_global_node_nums[i] != OCFS2_INVALID_SLOT)
-                       ocfs2_node_map_set_bit(osb, &osb->mounted_map,
-                                             si->si_global_node_nums[i]);
-
-       spin_unlock(&si->si_lock);
-}
-
 /* post the slot information on disk into our slot_info struct. */
 void ocfs2_update_slot_info(struct ocfs2_slot_info *si)
 {
index d8c8ceed031b4733fd6ec0b9ae0f6f22d3fc5fc2..1025872aaade6cac6ede633418576dc96f0215e6 100644 (file)
@@ -52,8 +52,6 @@ s16 ocfs2_node_num_to_slot(struct ocfs2_slot_info *si,
 void ocfs2_clear_slot(struct ocfs2_slot_info *si,
                      s16 slot_num);
 
-void ocfs2_populate_mounted_map(struct ocfs2_super *osb);
-
 static inline int ocfs2_is_empty_slot(struct ocfs2_slot_info *si,
                                      int slot_num)
 {
index 8f09f5235e3a68651ca279ab34598f2f22270cc8..7e397e2c25dd219fd55e3f16c363488fb57223e6 100644 (file)
@@ -101,8 +101,6 @@ static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg
 static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
                                                   u64 bg_blkno,
                                                   u16 bg_bit_off);
-static inline u64 ocfs2_which_cluster_group(struct inode *inode,
-                                           u32 cluster);
 static inline void ocfs2_block_to_cluster_group(struct inode *inode,
                                                u64 data_blkno,
                                                u64 *bg_blkno,
@@ -114,7 +112,7 @@ void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
 
        if (inode) {
                if (ac->ac_which != OCFS2_AC_USE_LOCAL)
-                       ocfs2_meta_unlock(inode, 1);
+                       ocfs2_inode_unlock(inode, 1);
 
                mutex_unlock(&inode->i_mutex);
 
@@ -131,9 +129,9 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl)
 }
 
 /* somewhat more expensive than our other checks, so use sparingly. */
-static int ocfs2_check_group_descriptor(struct super_block *sb,
-                                       struct ocfs2_dinode *di,
-                                       struct ocfs2_group_desc *gd)
+int ocfs2_check_group_descriptor(struct super_block *sb,
+                                struct ocfs2_dinode *di,
+                                struct ocfs2_group_desc *gd)
 {
        unsigned int max_bits;
 
@@ -412,7 +410,7 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
 
        mutex_lock(&alloc_inode->i_mutex);
 
-       status = ocfs2_meta_lock(alloc_inode, &bh, 1);
+       status = ocfs2_inode_lock(alloc_inode, &bh, 1);
        if (status < 0) {
                mutex_unlock(&alloc_inode->i_mutex);
                iput(alloc_inode);
@@ -1443,8 +1441,7 @@ static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
 
 /* given a cluster offset, calculate which block group it belongs to
  * and return that block offset. */
-static inline u64 ocfs2_which_cluster_group(struct inode *inode,
-                                           u32 cluster)
+u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster)
 {
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        u32 group_no;
@@ -1519,8 +1516,9 @@ int __ocfs2_claim_clusters(struct ocfs2_super *osb,
                if (min_clusters > (osb->bitmap_cpg - 1)) {
                        /* The only paths asking for contiguousness
                         * should know about this already. */
-                       mlog(ML_ERROR, "minimum allocation requested exceeds "
-                                      "group bitmap size!");
+                       mlog(ML_ERROR, "minimum allocation requested %u exceeds "
+                            "group bitmap size %u!\n", min_clusters,
+                            osb->bitmap_cpg);
                        status = -ENOSPC;
                        goto bail;
                }
index cafe93703095f187a5fadf825a6415c9d1837bad..8799033bb459d9adc4b558d0e50c1b4a52562b61 100644 (file)
@@ -147,4 +147,12 @@ static inline int ocfs2_is_cluster_bitmap(struct inode *inode)
 int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
                                      struct ocfs2_alloc_context *ac);
 
+/* given a cluster offset, calculate which block group it belongs to
+ * and return that block offset. */
+u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster);
+
+/* somewhat more expensive than our other checks, so use sparingly. */
+int ocfs2_check_group_descriptor(struct super_block *sb,
+                                struct ocfs2_dinode *di,
+                                struct ocfs2_group_desc *gd);
 #endif /* _CHAINALLOC_H_ */
index 5ee7754206651baceff8735e57b4b7382e2617e9..01fe40ee5ea943e2a47ae1a96987eed12673a847 100644 (file)
@@ -65,7 +65,6 @@
 #include "sysfile.h"
 #include "uptodate.h"
 #include "ver.h"
-#include "vote.h"
 
 #include "buffer_head_io.h"
 
@@ -84,9 +83,11 @@ MODULE_LICENSE("GPL");
 
 struct mount_options
 {
+       unsigned long   commit_interval;
        unsigned long   mount_opt;
        unsigned int    atime_quantum;
        signed short    slot;
+       unsigned int    localalloc_opt;
 };
 
 static int ocfs2_parse_options(struct super_block *sb, char *options,
@@ -150,6 +151,9 @@ enum {
        Opt_data_writeback,
        Opt_atime_quantum,
        Opt_slot,
+       Opt_commit,
+       Opt_localalloc,
+       Opt_localflocks,
        Opt_err,
 };
 
@@ -165,6 +169,9 @@ static match_table_t tokens = {
        {Opt_data_writeback, "data=writeback"},
        {Opt_atime_quantum, "atime_quantum=%u"},
        {Opt_slot, "preferred_slot=%u"},
+       {Opt_commit, "commit=%u"},
+       {Opt_localalloc, "localalloc=%d"},
+       {Opt_localflocks, "localflocks"},
        {Opt_err, NULL}
 };
 
@@ -213,7 +220,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
-       new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE);
+       new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
        if (IS_ERR(new)) {
                status = PTR_ERR(new);
                mlog_errno(status);
@@ -221,7 +228,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
        }
        osb->root_inode = new;
 
-       new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE);
+       new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
        if (IS_ERR(new)) {
                status = PTR_ERR(new);
                mlog_errno(status);
@@ -443,6 +450,8 @@ unlock_osb:
                osb->s_mount_opt = parsed_options.mount_opt;
                osb->s_atime_quantum = parsed_options.atime_quantum;
                osb->preferred_slot = parsed_options.slot;
+               if (parsed_options.commit_interval)
+                       osb->osb_commit_interval = parsed_options.commit_interval;
 
                if (!ocfs2_is_hard_readonly(osb))
                        ocfs2_set_journal_params(osb);
@@ -597,6 +606,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        osb->s_mount_opt = parsed_options.mount_opt;
        osb->s_atime_quantum = parsed_options.atime_quantum;
        osb->preferred_slot = parsed_options.slot;
+       osb->osb_commit_interval = parsed_options.commit_interval;
+       osb->local_alloc_size = parsed_options.localalloc_opt;
 
        sb->s_magic = OCFS2_SUPER_MAGIC;
 
@@ -747,9 +758,11 @@ static int ocfs2_parse_options(struct super_block *sb,
        mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
                   options ? options : "(none)");
 
+       mopt->commit_interval = 0;
        mopt->mount_opt = 0;
        mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
        mopt->slot = OCFS2_INVALID_SLOT;
+       mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
 
        if (!options) {
                status = 1;
@@ -816,6 +829,41 @@ static int ocfs2_parse_options(struct super_block *sb,
                        if (option)
                                mopt->slot = (s16)option;
                        break;
+               case Opt_commit:
+                       option = 0;
+                       if (match_int(&args[0], &option)) {
+                               status = 0;
+                               goto bail;
+                       }
+                       if (option < 0)
+                               return 0;
+                       if (option == 0)
+                               option = JBD_DEFAULT_MAX_COMMIT_AGE;
+                       mopt->commit_interval = HZ * option;
+                       break;
+               case Opt_localalloc:
+                       option = 0;
+                       if (match_int(&args[0], &option)) {
+                               status = 0;
+                               goto bail;
+                       }
+                       if (option >= 0 && (option <= ocfs2_local_alloc_size(sb) * 8))
+                               mopt->localalloc_opt = option;
+                       break;
+               case Opt_localflocks:
+                       /*
+                        * Changing this during remount could race
+                        * flock() requests, or "unbalance" existing
+                        * ones (e.g., a lock is taken in one mode but
+                        * dropped in the other). If users care enough
+                        * to flip locking modes during remount, we
+                        * could add a "local" flag to individual
+                        * flock structures for proper tracking of
+                        * state.
+                        */
+                       if (!is_remount)
+                               mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
+                       break;
                default:
                        mlog(ML_ERROR,
                             "Unrecognized mount option \"%s\" "
@@ -864,6 +912,16 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
        if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
                seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
 
+       if (osb->osb_commit_interval)
+               seq_printf(s, ",commit=%u",
+                          (unsigned) (osb->osb_commit_interval / HZ));
+
+       if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
+               seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
+
+       if (opts & OCFS2_MOUNT_LOCALFLOCKS)
+               seq_printf(s, ",localflocks,");
+
        return 0;
 }
 
@@ -965,7 +1023,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
                goto bail;
        }
 
-       status = ocfs2_meta_lock(inode, &bh, 0);
+       status = ocfs2_inode_lock(inode, &bh, 0);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -989,7 +1047,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
 
        brelse(bh);
 
-       ocfs2_meta_unlock(inode, 0);
+       ocfs2_inode_unlock(inode, 0);
        status = 0;
 bail:
        if (inode)
@@ -1020,8 +1078,7 @@ static void ocfs2_inode_init_once(struct kmem_cache *cachep, void *data)
        oi->ip_clusters = 0;
 
        ocfs2_lock_res_init_once(&oi->ip_rw_lockres);
-       ocfs2_lock_res_init_once(&oi->ip_meta_lockres);
-       ocfs2_lock_res_init_once(&oi->ip_data_lockres);
+       ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
        ocfs2_lock_res_init_once(&oi->ip_open_lockres);
 
        ocfs2_metadata_cache_init(&oi->vfs_inode);
@@ -1117,25 +1174,12 @@ static int ocfs2_mount_volume(struct super_block *sb)
                goto leave;
        }
 
-       status = ocfs2_register_hb_callbacks(osb);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
-
        status = ocfs2_dlm_init(osb);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
        }
 
-       /* requires vote_thread to be running. */
-       status = ocfs2_register_net_handlers(osb);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
-
        status = ocfs2_super_lock(osb, 1);
        if (status < 0) {
                mlog_errno(status);
@@ -1150,8 +1194,6 @@ static int ocfs2_mount_volume(struct super_block *sb)
                goto leave;
        }
 
-       ocfs2_populate_mounted_map(osb);
-
        /* load all node-local system inodes */
        status = ocfs2_init_local_system_inodes(osb);
        if (status < 0) {
@@ -1174,15 +1216,6 @@ static int ocfs2_mount_volume(struct super_block *sb)
        if (ocfs2_mount_local(osb))
                goto leave;
 
-       /* This should be sent *after* we recovered our journal as it
-        * will cause other nodes to unmark us as needing
-        * recovery. However, we need to send it *before* dropping the
-        * super block lock as otherwise their recovery threads might
-        * try to clean us up while we're live! */
-       status = ocfs2_request_mount_vote(osb);
-       if (status < 0)
-               mlog_errno(status);
-
 leave:
        if (unlock_super)
                ocfs2_super_unlock(osb, 1);
@@ -1240,10 +1273,6 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
                        mlog_errno(tmp);
                        return;
                }
-
-               tmp = ocfs2_request_umount_vote(osb);
-               if (tmp < 0)
-                       mlog_errno(tmp);
        }
 
        if (osb->slot_num != OCFS2_INVALID_SLOT)
@@ -1254,13 +1283,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        ocfs2_release_system_inodes(osb);
 
-       if (osb->dlm) {
-               ocfs2_unregister_net_handlers(osb);
-
+       if (osb->dlm)
                ocfs2_dlm_shutdown(osb);
-       }
-
-       ocfs2_clear_hb_callbacks(osb);
 
        debugfs_remove(osb->osb_debug_root);
 
@@ -1315,7 +1339,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
        int i, cbits, bbits;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
        struct inode *inode = NULL;
-       struct buffer_head *bitmap_bh = NULL;
        struct ocfs2_journal *journal;
        __le32 uuid_net_key;
        struct ocfs2_super *osb;
@@ -1344,19 +1367,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
        osb->s_sectsize_bits = blksize_bits(sector_size);
        BUG_ON(!osb->s_sectsize_bits);
 
-       osb->net_response_ids = 0;
-       spin_lock_init(&osb->net_response_lock);
-       INIT_LIST_HEAD(&osb->net_response_list);
-
-       INIT_LIST_HEAD(&osb->osb_net_handlers);
        init_waitqueue_head(&osb->recovery_event);
-       spin_lock_init(&osb->vote_task_lock);
-       init_waitqueue_head(&osb->vote_event);
-       osb->vote_work_sequence = 0;
-       osb->vote_wake_sequence = 0;
+       spin_lock_init(&osb->dc_task_lock);
+       init_waitqueue_head(&osb->dc_event);
+       osb->dc_work_sequence = 0;
+       osb->dc_wake_sequence = 0;
        INIT_LIST_HEAD(&osb->blocked_lock_list);
        osb->blocked_lock_count = 0;
-       INIT_LIST_HEAD(&osb->vote_list);
        spin_lock_init(&osb->osb_lock);
 
        atomic_set(&osb->alloc_stats.moves, 0);
@@ -1496,7 +1513,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
        }
 
        memcpy(&uuid_net_key, di->id2.i_super.s_uuid, sizeof(uuid_net_key));
-       osb->net_key = le32_to_cpu(uuid_net_key);
 
        strncpy(osb->vol_label, di->id2.i_super.s_label, 63);
        osb->vol_label[63] = '\0';
@@ -1539,25 +1555,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
        }
 
        osb->bitmap_blkno = OCFS2_I(inode)->ip_blkno;
-
-       /* We don't have a cluster lock on the bitmap here because
-        * we're only interested in static information and the extra
-        * complexity at mount time isn't worht it. Don't pass the
-        * inode in to the read function though as we don't want it to
-        * be put in the cache. */
-       status = ocfs2_read_block(osb, osb->bitmap_blkno, &bitmap_bh, 0,
-                                 NULL);
        iput(inode);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
 
-       di = (struct ocfs2_dinode *) bitmap_bh->b_data;
-       osb->bitmap_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
-       brelse(bitmap_bh);
-       mlog(0, "cluster bitmap inode: %llu, clusters per group: %u\n",
-            (unsigned long long)osb->bitmap_blkno, osb->bitmap_cpg);
+       osb->bitmap_cpg = ocfs2_group_bitmap_size(sb) * 8;
 
        status = ocfs2_init_slot_info(osb);
        if (status < 0) {
index fd2e846e3e6f6a76ec5c84f0d8eb8f91d751a9ba..ab713ebdd5468222899654f706c4b80955a9bfe8 100644 (file)
@@ -112,7 +112,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
                goto bail;
        }
 
-       inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE);
+       inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE, type);
        if (IS_ERR(inode)) {
                mlog_errno(PTR_ERR(inode));
                inode = NULL;
index 5405ce121c99ce10d446a33eae85d3dd5dd14003..e2488f4128a20f563459ba936cf263160e7350b2 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "ver.h"
 
-#define OCFS2_BUILD_VERSION "1.3.3"
+#define OCFS2_BUILD_VERSION "1.5.0"
 
 #define VERSION_STR "OCFS2 " OCFS2_BUILD_VERSION
 
diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
deleted file mode 100644 (file)
index c053585..0000000
+++ /dev/null
@@ -1,756 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * vote.c
- *
- * description here
- *
- * Copyright (C) 2003, 2004 Oracle.  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.
- *
- * 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 021110-1307, USA.
- */
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/highmem.h>
-#include <linux/kthread.h>
-
-#include <cluster/heartbeat.h>
-#include <cluster/nodemanager.h>
-#include <cluster/tcp.h>
-
-#include <dlm/dlmapi.h>
-
-#define MLOG_MASK_PREFIX ML_VOTE
-#include <cluster/masklog.h>
-
-#include "ocfs2.h"
-
-#include "alloc.h"
-#include "dlmglue.h"
-#include "extent_map.h"
-#include "heartbeat.h"
-#include "inode.h"
-#include "journal.h"
-#include "slot_map.h"
-#include "vote.h"
-
-#include "buffer_head_io.h"
-
-#define OCFS2_MESSAGE_TYPE_VOTE     (0x1)
-#define OCFS2_MESSAGE_TYPE_RESPONSE (0x2)
-struct ocfs2_msg_hdr
-{
-       __be32 h_response_id; /* used to lookup message handle on sending
-                           * node. */
-       __be32 h_request;
-       __be64 h_blkno;
-       __be32 h_generation;
-       __be32 h_node_num;    /* node sending this particular message. */
-};
-
-struct ocfs2_vote_msg
-{
-       struct ocfs2_msg_hdr v_hdr;
-       __be32 v_reserved1;
-} __attribute__ ((packed));
-
-/* Responses are given these values to maintain backwards
- * compatibility with older ocfs2 versions */
-#define OCFS2_RESPONSE_OK              (0)
-#define OCFS2_RESPONSE_BUSY            (-16)
-#define OCFS2_RESPONSE_BAD_MSG         (-22)
-
-struct ocfs2_response_msg
-{
-       struct ocfs2_msg_hdr r_hdr;
-       __be32 r_response;
-} __attribute__ ((packed));
-
-struct ocfs2_vote_work {
-       struct list_head   w_list;
-       struct ocfs2_vote_msg w_msg;
-};
-
-enum ocfs2_vote_request {
-       OCFS2_VOTE_REQ_INVALID = 0,
-       OCFS2_VOTE_REQ_MOUNT,
-       OCFS2_VOTE_REQ_UMOUNT,
-       OCFS2_VOTE_REQ_LAST
-};
-
-static inline int ocfs2_is_valid_vote_request(int request)
-{
-       return OCFS2_VOTE_REQ_INVALID < request &&
-               request < OCFS2_VOTE_REQ_LAST;
-}
-
-typedef void (*ocfs2_net_response_callback)(void *priv,
-                                           struct ocfs2_response_msg *resp);
-struct ocfs2_net_response_cb {
-       ocfs2_net_response_callback     rc_cb;
-       void                            *rc_priv;
-};
-
-struct ocfs2_net_wait_ctxt {
-       struct list_head        n_list;
-       u32                     n_response_id;
-       wait_queue_head_t       n_event;
-       struct ocfs2_node_map   n_node_map;
-       int                     n_response; /* an agreggate response. 0 if
-                                            * all nodes are go, < 0 on any
-                                            * negative response from any
-                                            * node or network error. */
-       struct ocfs2_net_response_cb *n_callback;
-};
-
-static void ocfs2_process_mount_request(struct ocfs2_super *osb,
-                                       unsigned int node_num)
-{
-       mlog(0, "MOUNT vote from node %u\n", node_num);
-       /* The other node only sends us this message when he has an EX
-        * on the superblock, so our recovery threads (if having been
-        * launched) are waiting on it.*/
-       ocfs2_recovery_map_clear(osb, node_num);
-       ocfs2_node_map_set_bit(osb, &osb->mounted_map, node_num);
-
-       /* We clear the umount map here because a node may have been
-        * previously mounted, safely unmounted but never stopped
-        * heartbeating - in which case we'd have a stale entry. */
-       ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
-}
-
-static void ocfs2_process_umount_request(struct ocfs2_super *osb,
-                                        unsigned int node_num)
-{
-       mlog(0, "UMOUNT vote from node %u\n", node_num);
-       ocfs2_node_map_clear_bit(osb, &osb->mounted_map, node_num);
-       ocfs2_node_map_set_bit(osb, &osb->umount_map, node_num);
-}
-
-static void ocfs2_process_vote(struct ocfs2_super *osb,
-                              struct ocfs2_vote_msg *msg)
-{
-       int net_status, vote_response;
-       unsigned int node_num;
-       u64 blkno;
-       enum ocfs2_vote_request request;
-       struct ocfs2_msg_hdr *hdr = &msg->v_hdr;
-       struct ocfs2_response_msg response;
-
-       /* decode the network mumbo jumbo into local variables. */
-       request = be32_to_cpu(hdr->h_request);
-       blkno = be64_to_cpu(hdr->h_blkno);
-       node_num = be32_to_cpu(hdr->h_node_num);
-
-       mlog(0, "processing vote: request = %u, blkno = %llu, node_num = %u\n",
-            request, (unsigned long long)blkno, node_num);
-
-       if (!ocfs2_is_valid_vote_request(request)) {
-               mlog(ML_ERROR, "Invalid vote request %d from node %u\n",
-                    request, node_num);
-               vote_response = OCFS2_RESPONSE_BAD_MSG;
-               goto respond;
-       }
-
-       vote_response = OCFS2_RESPONSE_OK;
-
-       switch (request) {
-       case OCFS2_VOTE_REQ_UMOUNT:
-               ocfs2_process_umount_request(osb, node_num);
-               goto respond;
-       case OCFS2_VOTE_REQ_MOUNT:
-               ocfs2_process_mount_request(osb, node_num);
-               goto respond;
-       default:
-               /* avoids a gcc warning */
-               break;
-       }
-
-respond:
-       /* Response struture is small so we just put it on the stack
-        * and stuff it inline. */
-       memset(&response, 0, sizeof(struct ocfs2_response_msg));
-       response.r_hdr.h_response_id = hdr->h_response_id;
-       response.r_hdr.h_blkno = hdr->h_blkno;
-       response.r_hdr.h_generation = hdr->h_generation;
-       response.r_hdr.h_node_num = cpu_to_be32(osb->node_num);
-       response.r_response = cpu_to_be32(vote_response);
-
-       net_status = o2net_send_message(OCFS2_MESSAGE_TYPE_RESPONSE,
-                                       osb->net_key,
-                                       &response,
-                                       sizeof(struct ocfs2_response_msg),
-                                       node_num,
-                                       NULL);
-       /* We still want to error print for ENOPROTOOPT here. The
-        * sending node shouldn't have unregistered his net handler
-        * without sending an unmount vote 1st */
-       if (net_status < 0
-           && net_status != -ETIMEDOUT
-           && net_status != -ENOTCONN)
-               mlog(ML_ERROR, "message to node %u fails with error %d!\n",
-                    node_num, net_status);
-}
-
-static void ocfs2_vote_thread_do_work(struct ocfs2_super *osb)
-{
-       unsigned long processed;
-       struct ocfs2_lock_res *lockres;
-       struct ocfs2_vote_work *work;
-
-       mlog_entry_void();
-
-       spin_lock(&osb->vote_task_lock);
-       /* grab this early so we know to try again if a state change and
-        * wake happens part-way through our work  */
-       osb->vote_work_sequence = osb->vote_wake_sequence;
-
-       processed = osb->blocked_lock_count;
-       while (processed) {
-               BUG_ON(list_empty(&osb->blocked_lock_list));
-
-               lockres = list_entry(osb->blocked_lock_list.next,
-                                    struct ocfs2_lock_res, l_blocked_list);
-               list_del_init(&lockres->l_blocked_list);
-               osb->blocked_lock_count--;
-               spin_unlock(&osb->vote_task_lock);
-
-               BUG_ON(!processed);
-               processed--;
-
-               ocfs2_process_blocked_lock(osb, lockres);
-
-               spin_lock(&osb->vote_task_lock);
-       }
-
-       while (osb->vote_count) {
-               BUG_ON(list_empty(&osb->vote_list));
-               work = list_entry(osb->vote_list.next,
-                                 struct ocfs2_vote_work, w_list);
-               list_del(&work->w_list);
-               osb->vote_count--;
-               spin_unlock(&osb->vote_task_lock);
-
-               ocfs2_process_vote(osb, &work->w_msg);
-               kfree(work);
-
-               spin_lock(&osb->vote_task_lock);
-       }
-       spin_unlock(&osb->vote_task_lock);
-
-       mlog_exit_void();
-}
-
-static int ocfs2_vote_thread_lists_empty(struct ocfs2_super *osb)
-{
-       int empty = 0;
-
-       spin_lock(&osb->vote_task_lock);
-       if (list_empty(&osb->blocked_lock_list) &&
-           list_empty(&osb->vote_list))
-               empty = 1;
-
-       spin_unlock(&osb->vote_task_lock);
-       return empty;
-}
-
-static int ocfs2_vote_thread_should_wake(struct ocfs2_super *osb)
-{
-       int should_wake = 0;
-
-       spin_lock(&osb->vote_task_lock);
-       if (osb->vote_work_sequence != osb->vote_wake_sequence)
-               should_wake = 1;
-       spin_unlock(&osb->vote_task_lock);
-
-       return should_wake;
-}
-
-int ocfs2_vote_thread(void *arg)
-{
-       int status = 0;
-       struct ocfs2_super *osb = arg;
-
-       /* only quit once we've been asked to stop and there is no more
-        * work available */
-       while (!(kthread_should_stop() &&
-                ocfs2_vote_thread_lists_empty(osb))) {
-
-               wait_event_interruptible(osb->vote_event,
-                                        ocfs2_vote_thread_should_wake(osb) ||
-                                        kthread_should_stop());
-
-               mlog(0, "vote_thread: awoken\n");
-
-               ocfs2_vote_thread_do_work(osb);
-       }
-
-       osb->vote_task = NULL;
-       return status;
-}
-
-static struct ocfs2_net_wait_ctxt *ocfs2_new_net_wait_ctxt(unsigned int response_id)
-{
-       struct ocfs2_net_wait_ctxt *w;
-
-       w = kzalloc(sizeof(*w), GFP_NOFS);
-       if (!w) {
-               mlog_errno(-ENOMEM);
-               goto bail;
-       }
-
-       INIT_LIST_HEAD(&w->n_list);
-       init_waitqueue_head(&w->n_event);
-       ocfs2_node_map_init(&w->n_node_map);
-       w->n_response_id = response_id;
-       w->n_callback = NULL;
-bail:
-       return w;
-}
-
-static unsigned int ocfs2_new_response_id(struct ocfs2_super *osb)
-{
-       unsigned int ret;
-
-       spin_lock(&osb->net_response_lock);
-       ret = ++osb->net_response_ids;
-       spin_unlock(&osb->net_response_lock);
-
-       return ret;
-}
-
-static void ocfs2_dequeue_net_wait_ctxt(struct ocfs2_super *osb,
-                                       struct ocfs2_net_wait_ctxt *w)
-{
-       spin_lock(&osb->net_response_lock);
-       list_del(&w->n_list);
-       spin_unlock(&osb->net_response_lock);
-}
-
-static void ocfs2_queue_net_wait_ctxt(struct ocfs2_super *osb,
-                                     struct ocfs2_net_wait_ctxt *w)
-{
-       spin_lock(&osb->net_response_lock);
-       list_add_tail(&w->n_list,
-                     &osb->net_response_list);
-       spin_unlock(&osb->net_response_lock);
-}
-
-static void __ocfs2_mark_node_responded(struct ocfs2_super *osb,
-                                       struct ocfs2_net_wait_ctxt *w,
-                                       int node_num)
-{
-       assert_spin_locked(&osb->net_response_lock);
-
-       ocfs2_node_map_clear_bit(osb, &w->n_node_map, node_num);
-       if (ocfs2_node_map_is_empty(osb, &w->n_node_map))
-               wake_up(&w->n_event);
-}
-
-/* Intended to be called from the node down callback, we fake remove
- * the node from all our response contexts */
-void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
-                                       int node_num)
-{
-       struct list_head *p;
-       struct ocfs2_net_wait_ctxt *w = NULL;
-
-       spin_lock(&osb->net_response_lock);
-
-       list_for_each(p, &osb->net_response_list) {
-               w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list);
-
-               __ocfs2_mark_node_responded(osb, w, node_num);
-       }
-
-       spin_unlock(&osb->net_response_lock);
-}
-
-static int ocfs2_broadcast_vote(struct ocfs2_super *osb,
-                               struct ocfs2_vote_msg *request,
-                               unsigned int response_id,
-                               int *response,
-                               struct ocfs2_net_response_cb *callback)
-{
-       int status, i, remote_err;
-       struct ocfs2_net_wait_ctxt *w = NULL;
-       int dequeued = 0;
-
-       mlog_entry_void();
-
-       w = ocfs2_new_net_wait_ctxt(response_id);
-       if (!w) {
-               status = -ENOMEM;
-               mlog_errno(status);
-               goto bail;
-       }
-       w->n_callback = callback;
-
-       /* we're pretty much ready to go at this point, and this fills
-        * in n_response which we need anyway... */
-       ocfs2_queue_net_wait_ctxt(osb, w);
-
-       i = ocfs2_node_map_iterate(osb, &osb->mounted_map, 0);
-
-       while (i != O2NM_INVALID_NODE_NUM) {
-               if (i != osb->node_num) {
-                       mlog(0, "trying to send request to node %i\n", i);
-                       ocfs2_node_map_set_bit(osb, &w->n_node_map, i);
-
-                       remote_err = 0;
-                       status = o2net_send_message(OCFS2_MESSAGE_TYPE_VOTE,
-                                                   osb->net_key,
-                                                   request,
-                                                   sizeof(*request),
-                                                   i,
-                                                   &remote_err);
-                       if (status == -ETIMEDOUT) {
-                               mlog(0, "remote node %d timed out!\n", i);
-                               status = -EAGAIN;
-                               goto bail;
-                       }
-                       if (remote_err < 0) {
-                               status = remote_err;
-                               mlog(0, "remote error %d on node %d!\n",
-                                    remote_err, i);
-                               mlog_errno(status);
-                               goto bail;
-                       }
-                       if (status < 0) {
-                               mlog_errno(status);
-                               goto bail;
-                       }
-               }
-               i++;
-               i = ocfs2_node_map_iterate(osb, &osb->mounted_map, i);
-               mlog(0, "next is %d, i am %d\n", i, osb->node_num);
-       }
-       mlog(0, "done sending, now waiting on responses...\n");
-
-       wait_event(w->n_event, ocfs2_node_map_is_empty(osb, &w->n_node_map));
-
-       ocfs2_dequeue_net_wait_ctxt(osb, w);
-       dequeued = 1;
-
-       *response = w->n_response;
-       status = 0;
-bail:
-       if (w) {
-               if (!dequeued)
-                       ocfs2_dequeue_net_wait_ctxt(osb, w);
-               kfree(w);
-       }
-
-       mlog_exit(status);
-       return status;
-}
-
-static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb,
-                                                     u64 blkno,
-                                                     unsigned int generation,
-                                                     enum ocfs2_vote_request type)
-{
-       struct ocfs2_vote_msg *request;
-       struct ocfs2_msg_hdr *hdr;
-
-       BUG_ON(!ocfs2_is_valid_vote_request(type));
-
-       request = kzalloc(sizeof(*request), GFP_NOFS);
-       if (!request) {
-               mlog_errno(-ENOMEM);
-       } else {
-               hdr = &request->v_hdr;
-               hdr->h_node_num = cpu_to_be32(osb->node_num);
-               hdr->h_request = cpu_to_be32(type);
-               hdr->h_blkno = cpu_to_be64(blkno);
-               hdr->h_generation = cpu_to_be32(generation);
-       }
-
-       return request;
-}
-
-/* Complete the buildup of a new vote request and process the
- * broadcast return value. */
-static int ocfs2_do_request_vote(struct ocfs2_super *osb,
-                                struct ocfs2_vote_msg *request,
-                                struct ocfs2_net_response_cb *callback)
-{
-       int status, response = -EBUSY;
-       unsigned int response_id;
-       struct ocfs2_msg_hdr *hdr;
-
-       response_id = ocfs2_new_response_id(osb);
-
-       hdr = &request->v_hdr;
-       hdr->h_response_id = cpu_to_be32(response_id);
-
-       status = ocfs2_broadcast_vote(osb, request, response_id, &response,
-                                     callback);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       status = response;
-bail:
-
-       return status;
-}
-
-int ocfs2_request_mount_vote(struct ocfs2_super *osb)
-{
-       int status;
-       struct ocfs2_vote_msg *request = NULL;
-
-       request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_MOUNT);
-       if (!request) {
-               status = -ENOMEM;
-               goto bail;
-       }
-
-       status = -EAGAIN;
-       while (status == -EAGAIN) {
-               if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) &&
-                   signal_pending(current)) {
-                       status = -ERESTARTSYS;
-                       goto bail;
-               }
-
-               if (ocfs2_node_map_is_only(osb, &osb->mounted_map,
-                                          osb->node_num)) {
-                       status = 0;
-                       goto bail;
-               }
-
-               status = ocfs2_do_request_vote(osb, request, NULL);
-       }
-
-bail:
-       kfree(request);
-       return status;
-}
-
-int ocfs2_request_umount_vote(struct ocfs2_super *osb)
-{
-       int status;
-       struct ocfs2_vote_msg *request = NULL;
-
-       request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_UMOUNT);
-       if (!request) {
-               status = -ENOMEM;
-               goto bail;
-       }
-
-       status = -EAGAIN;
-       while (status == -EAGAIN) {
-               /* Do not check signals on this vote... We really want
-                * this one to go all the way through. */
-
-               if (ocfs2_node_map_is_only(osb, &osb->mounted_map,
-                                          osb->node_num)) {
-                       status = 0;
-                       goto bail;
-               }
-
-               status = ocfs2_do_request_vote(osb, request, NULL);
-       }
-
-bail:
-       kfree(request);
-       return status;
-}
-
-/* TODO: This should eventually be a hash table! */
-static struct ocfs2_net_wait_ctxt * __ocfs2_find_net_wait_ctxt(struct ocfs2_super *osb,
-                                                              u32 response_id)
-{
-       struct list_head *p;
-       struct ocfs2_net_wait_ctxt *w = NULL;
-
-       list_for_each(p, &osb->net_response_list) {
-               w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list);
-               if (response_id == w->n_response_id)
-                       break;
-               w = NULL;
-       }
-
-       return w;
-}
-
-/* Translate response codes into local node errno values */
-static inline int ocfs2_translate_response(int response)
-{
-       int ret;
-
-       switch (response) {
-       case OCFS2_RESPONSE_OK:
-               ret = 0;
-               break;
-
-       case OCFS2_RESPONSE_BUSY:
-               ret = -EBUSY;
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static int ocfs2_handle_response_message(struct o2net_msg *msg,
-                                        u32 len,
-                                        void *data, void **ret_data)
-{
-       unsigned int response_id, node_num;
-       int response_status;
-       struct ocfs2_super *osb = data;
-       struct ocfs2_response_msg *resp;
-       struct ocfs2_net_wait_ctxt * w;
-       struct ocfs2_net_response_cb *resp_cb;
-
-       resp = (struct ocfs2_response_msg *) msg->buf;
-
-       response_id = be32_to_cpu(resp->r_hdr.h_response_id);
-       node_num = be32_to_cpu(resp->r_hdr.h_node_num);
-       response_status = 
-               ocfs2_translate_response(be32_to_cpu(resp->r_response));
-
-       mlog(0, "received response message:\n");
-       mlog(0, "h_response_id = %u\n", response_id);
-       mlog(0, "h_request = %u\n", be32_to_cpu(resp->r_hdr.h_request));
-       mlog(0, "h_blkno = %llu\n",
-            (unsigned long long)be64_to_cpu(resp->r_hdr.h_blkno));
-       mlog(0, "h_generation = %u\n", be32_to_cpu(resp->r_hdr.h_generation));
-       mlog(0, "h_node_num = %u\n", node_num);
-       mlog(0, "r_response = %d\n", response_status);
-
-       spin_lock(&osb->net_response_lock);
-       w = __ocfs2_find_net_wait_ctxt(osb, response_id);
-       if (!w) {
-               mlog(0, "request not found!\n");
-               goto bail;
-       }
-       resp_cb = w->n_callback;
-
-       if (response_status && (!w->n_response)) {
-               /* we only really need one negative response so don't
-                * set it twice. */
-               w->n_response = response_status;
-       }
-
-       if (resp_cb) {
-               spin_unlock(&osb->net_response_lock);
-
-               resp_cb->rc_cb(resp_cb->rc_priv, resp);
-
-               spin_lock(&osb->net_response_lock);
-       }
-
-       __ocfs2_mark_node_responded(osb, w, node_num);
-bail:
-       spin_unlock(&osb->net_response_lock);
-
-       return 0;
-}
-
-static int ocfs2_handle_vote_message(struct o2net_msg *msg,
-                                    u32 len,
-                                    void *data, void **ret_data)
-{
-       int status;
-       struct ocfs2_super *osb = data;
-       struct ocfs2_vote_work *work;
-
-       work = kmalloc(sizeof(struct ocfs2_vote_work), GFP_NOFS);
-       if (!work) {
-               status = -ENOMEM;
-               mlog_errno(status);
-               goto bail;
-       }
-
-       INIT_LIST_HEAD(&work->w_list);
-       memcpy(&work->w_msg, msg->buf, sizeof(struct ocfs2_vote_msg));
-
-       mlog(0, "scheduling vote request:\n");
-       mlog(0, "h_response_id = %u\n",
-            be32_to_cpu(work->w_msg.v_hdr.h_response_id));
-       mlog(0, "h_request = %u\n", be32_to_cpu(work->w_msg.v_hdr.h_request));
-       mlog(0, "h_blkno = %llu\n",
-            (unsigned long long)be64_to_cpu(work->w_msg.v_hdr.h_blkno));
-       mlog(0, "h_generation = %u\n",
-            be32_to_cpu(work->w_msg.v_hdr.h_generation));
-       mlog(0, "h_node_num = %u\n",
-            be32_to_cpu(work->w_msg.v_hdr.h_node_num));
-
-       spin_lock(&osb->vote_task_lock);
-       list_add_tail(&work->w_list, &osb->vote_list);
-       osb->vote_count++;
-       spin_unlock(&osb->vote_task_lock);
-
-       ocfs2_kick_vote_thread(osb);
-
-       status = 0;
-bail:
-       return status;
-}
-
-void ocfs2_unregister_net_handlers(struct ocfs2_super *osb)
-{
-       if (!osb->net_key)
-               return;
-
-       o2net_unregister_handler_list(&osb->osb_net_handlers);
-
-       if (!list_empty(&osb->net_response_list))
-               mlog(ML_ERROR, "net response list not empty!\n");
-
-       osb->net_key = 0;
-}
-
-int ocfs2_register_net_handlers(struct ocfs2_super *osb)
-{
-       int status = 0;
-
-       if (ocfs2_mount_local(osb))
-               return 0;
-
-       status = o2net_register_handler(OCFS2_MESSAGE_TYPE_RESPONSE,
-                                       osb->net_key,
-                                       sizeof(struct ocfs2_response_msg),
-                                       ocfs2_handle_response_message,
-                                       osb, NULL, &osb->osb_net_handlers);
-       if (status) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       status = o2net_register_handler(OCFS2_MESSAGE_TYPE_VOTE,
-                                       osb->net_key,
-                                       sizeof(struct ocfs2_vote_msg),
-                                       ocfs2_handle_vote_message,
-                                       osb, NULL, &osb->osb_net_handlers);
-       if (status) {
-               mlog_errno(status);
-               goto bail;
-       }
-bail:
-       if (status < 0)
-               ocfs2_unregister_net_handlers(osb);
-
-       return status;
-}
diff --git a/fs/ocfs2/vote.h b/fs/ocfs2/vote.h
deleted file mode 100644 (file)
index 9ea46f6..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * vote.h
- *
- * description here
- *
- * Copyright (C) 2002, 2004 Oracle.  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.
- *
- * 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 021110-1307, USA.
- */
-
-
-#ifndef VOTE_H
-#define VOTE_H
-
-int ocfs2_vote_thread(void *arg);
-static inline void ocfs2_kick_vote_thread(struct ocfs2_super *osb)
-{
-       spin_lock(&osb->vote_task_lock);
-       /* make sure the voting thread gets a swipe at whatever changes
-        * the caller may have made to the voting state */
-       osb->vote_wake_sequence++;
-       spin_unlock(&osb->vote_task_lock);
-       wake_up(&osb->vote_event);
-}
-
-int ocfs2_request_mount_vote(struct ocfs2_super *osb);
-int ocfs2_request_umount_vote(struct ocfs2_super *osb);
-int ocfs2_register_net_handlers(struct ocfs2_super *osb);
-void ocfs2_unregister_net_handlers(struct ocfs2_super *osb);
-
-void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
-                                       int node_num);
-#endif
index d88173840082aad76ab84a2c086c3d06bb73bef9..6b7ff16189450b972374bfa0689f52e24a51405a 100644 (file)
@@ -131,7 +131,7 @@ static void property_stop(struct seq_file *f, void *v)
        /* Nothing to do */
 }
 
-static struct seq_operations property_op = {
+static const struct seq_operations property_op = {
        .start          = property_start,
        .next           = property_next,
        .stop           = property_stop,
index 722e12e5acc71e9b90051da29f5611b5e3182f9c..739da701ae7b8fec52d10f48392a85509208e286 100644 (file)
@@ -195,96 +195,45 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
        return ERR_PTR(res);
 }
 
-/*
- * sysfs bindings for partitions
- */
-
-struct part_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct hd_struct *,char *);
-       ssize_t (*store)(struct hd_struct *,const char *, size_t);
-};
-
-static ssize_t 
-part_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
+static ssize_t part_start_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
 {
-       struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
-       struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
-       ssize_t ret = 0;
-       if (part_attr->show)
-               ret = part_attr->show(p, page);
-       return ret;
-}
-static ssize_t
-part_attr_store(struct kobject * kobj, struct attribute * attr,
-               const char *page, size_t count)
-{
-       struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
-       struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
-       ssize_t ret = 0;
+       struct hd_struct *p = dev_to_part(dev);
 
-       if (part_attr->store)
-               ret = part_attr->store(p, page, count);
-       return ret;
+       return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
 }
 
-static struct sysfs_ops part_sysfs_ops = {
-       .show   =       part_attr_show,
-       .store  =       part_attr_store,
-};
-
-static ssize_t part_uevent_store(struct hd_struct * p,
-                                const char *page, size_t count)
+static ssize_t part_size_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
-       kobject_uevent(&p->kobj, KOBJ_ADD);
-       return count;
+       struct hd_struct *p = dev_to_part(dev);
+       return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
 }
-static ssize_t part_dev_read(struct hd_struct * p, char *page)
-{
-       struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
-       dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); 
-       return print_dev_t(page, dev);
-}
-static ssize_t part_start_read(struct hd_struct * p, char *page)
-{
-       return sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
-}
-static ssize_t part_size_read(struct hd_struct * p, char *page)
-{
-       return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
-}
-static ssize_t part_stat_read(struct hd_struct * p, char *page)
+
+static ssize_t part_stat_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
-       return sprintf(page, "%8u %8llu %8u %8llu\n",
+       struct hd_struct *p = dev_to_part(dev);
+
+       return sprintf(buf, "%8u %8llu %8u %8llu\n",
                       p->ios[0], (unsigned long long)p->sectors[0],
                       p->ios[1], (unsigned long long)p->sectors[1]);
 }
-static struct part_attribute part_attr_uevent = {
-       .attr = {.name = "uevent", .mode = S_IWUSR },
-       .store  = part_uevent_store
-};
-static struct part_attribute part_attr_dev = {
-       .attr = {.name = "dev", .mode = S_IRUGO },
-       .show   = part_dev_read
-};
-static struct part_attribute part_attr_start = {
-       .attr = {.name = "start", .mode = S_IRUGO },
-       .show   = part_start_read
-};
-static struct part_attribute part_attr_size = {
-       .attr = {.name = "size", .mode = S_IRUGO },
-       .show   = part_size_read
-};
-static struct part_attribute part_attr_stat = {
-       .attr = {.name = "stat", .mode = S_IRUGO },
-       .show   = part_stat_read
-};
 
 #ifdef CONFIG_FAIL_MAKE_REQUEST
+static ssize_t part_fail_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
 
-static ssize_t part_fail_store(struct hd_struct * p,
+       return sprintf(buf, "%d\n", p->make_it_fail);
+}
+
+static ssize_t part_fail_store(struct device *dev,
+                              struct device_attribute *attr,
                               const char *buf, size_t count)
 {
+       struct hd_struct *p = dev_to_part(dev);
        int i;
 
        if (count > 0 && sscanf(buf, "%d", &i) > 0)
@@ -292,50 +241,53 @@ static ssize_t part_fail_store(struct hd_struct * p,
 
        return count;
 }
-static ssize_t part_fail_read(struct hd_struct * p, char *page)
-{
-       return sprintf(page, "%d\n", p->make_it_fail);
-}
-static struct part_attribute part_attr_fail = {
-       .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
-       .store  = part_fail_store,
-       .show   = part_fail_read
-};
+#endif
 
+static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
+static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
+static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+static struct device_attribute dev_attr_fail =
+       __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
 #endif
 
-static struct attribute * default_attrs[] = {
-       &part_attr_uevent.attr,
-       &part_attr_dev.attr,
-       &part_attr_start.attr,
-       &part_attr_size.attr,
-       &part_attr_stat.attr,
+static struct attribute *part_attrs[] = {
+       &dev_attr_start.attr,
+       &dev_attr_size.attr,
+       &dev_attr_stat.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
-       &part_attr_fail.attr,
+       &dev_attr_fail.attr,
 #endif
-       NULL,
+       NULL
 };
 
-extern struct kset block_subsys;
+static struct attribute_group part_attr_group = {
+       .attrs = part_attrs,
+};
 
-static void part_release(struct kobject *kobj)
+static struct attribute_group *part_attr_groups[] = {
+       &part_attr_group,
+       NULL
+};
+
+static void part_release(struct device *dev)
 {
-       struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
+       struct hd_struct *p = dev_to_part(dev);
        kfree(p);
 }
 
-struct kobj_type ktype_part = {
+struct device_type part_type = {
+       .name           = "partition",
+       .groups         = part_attr_groups,
        .release        = part_release,
-       .default_attrs  = default_attrs,
-       .sysfs_ops      = &part_sysfs_ops,
 };
 
 static inline void partition_sysfs_add_subdir(struct hd_struct *p)
 {
        struct kobject *k;
 
-       k = kobject_get(&p->kobj);
-       p->holder_dir = kobject_add_dir(k, "holders");
+       k = kobject_get(&p->dev.kobj);
+       p->holder_dir = kobject_create_and_add("holders", k);
        kobject_put(k);
 }
 
@@ -343,15 +295,16 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
 {
        struct kobject *k;
 
-       k = kobject_get(&disk->kobj);
-       disk->holder_dir = kobject_add_dir(k, "holders");
-       disk->slave_dir = kobject_add_dir(k, "slaves");
+       k = kobject_get(&disk->dev.kobj);
+       disk->holder_dir = kobject_create_and_add("holders", k);
+       disk->slave_dir = kobject_create_and_add("slaves", k);
        kobject_put(k);
 }
 
 void delete_partition(struct gendisk *disk, int part)
 {
        struct hd_struct *p = disk->part[part-1];
+
        if (!p)
                return;
        if (!p->nr_sects)
@@ -361,113 +314,55 @@ void delete_partition(struct gendisk *disk, int part)
        p->nr_sects = 0;
        p->ios[0] = p->ios[1] = 0;
        p->sectors[0] = p->sectors[1] = 0;
-       sysfs_remove_link(&p->kobj, "subsystem");
-       kobject_unregister(p->holder_dir);
-       kobject_uevent(&p->kobj, KOBJ_REMOVE);
-       kobject_del(&p->kobj);
-       kobject_put(&p->kobj);
+       kobject_put(p->holder_dir);
+       device_del(&p->dev);
+       put_device(&p->dev);
 }
 
 void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags)
 {
        struct hd_struct *p;
+       int err;
 
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
                return;
-       
+
        p->start_sect = start;
        p->nr_sects = len;
        p->partno = part;
        p->policy = disk->policy;
 
-       if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1]))
-               kobject_set_name(&p->kobj, "%sp%d",
-                                kobject_name(&disk->kobj), part);
+       if (isdigit(disk->dev.bus_id[strlen(disk->dev.bus_id)-1]))
+               snprintf(p->dev.bus_id, BUS_ID_SIZE,
+               "%sp%d", disk->dev.bus_id, part);
        else
-               kobject_set_name(&p->kobj, "%s%d",
-                                kobject_name(&disk->kobj),part);
-       p->kobj.parent = &disk->kobj;
-       p->kobj.ktype = &ktype_part;
-       kobject_init(&p->kobj);
-       kobject_add(&p->kobj);
-       if (!disk->part_uevent_suppress)
-               kobject_uevent(&p->kobj, KOBJ_ADD);
-       sysfs_create_link(&p->kobj, &block_subsys.kobj, "subsystem");
+               snprintf(p->dev.bus_id, BUS_ID_SIZE,
+                        "%s%d", disk->dev.bus_id, part);
+
+       device_initialize(&p->dev);
+       p->dev.devt = MKDEV(disk->major, disk->first_minor + part);
+       p->dev.class = &block_class;
+       p->dev.type = &part_type;
+       p->dev.parent = &disk->dev;
+       disk->part[part-1] = p;
+
+       /* delay uevent until 'holders' subdir is created */
+       p->dev.uevent_suppress = 1;
+       device_add(&p->dev);
+       partition_sysfs_add_subdir(p);
+       p->dev.uevent_suppress = 0;
        if (flags & ADDPART_FLAG_WHOLEDISK) {
                static struct attribute addpartattr = {
                        .name = "whole_disk",
                        .mode = S_IRUSR | S_IRGRP | S_IROTH,
                };
-
-               sysfs_create_file(&p->kobj, &addpartattr);
+               err = sysfs_create_file(&p->dev.kobj, &addpartattr);
        }
-       partition_sysfs_add_subdir(p);
-       disk->part[part-1] = p;
-}
 
-static char *make_block_name(struct gendisk *disk)
-{
-       char *name;
-       static char *block_str = "block:";
-       int size;
-       char *s;
-
-       size = strlen(block_str) + strlen(disk->disk_name) + 1;
-       name = kmalloc(size, GFP_KERNEL);
-       if (!name)
-               return NULL;
-       strcpy(name, block_str);
-       strcat(name, disk->disk_name);
-       /* ewww... some of these buggers have / in name... */
-       s = strchr(name, '/');
-       if (s)
-               *s = '!';
-       return name;
-}
-
-static int disk_sysfs_symlinks(struct gendisk *disk)
-{
-       struct device *target = get_device(disk->driverfs_dev);
-       int err;
-       char *disk_name = NULL;
-
-       if (target) {
-               disk_name = make_block_name(disk);
-               if (!disk_name) {
-                       err = -ENOMEM;
-                       goto err_out;
-               }
-
-               err = sysfs_create_link(&disk->kobj, &target->kobj, "device");
-               if (err)
-                       goto err_out_disk_name;
-
-               err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);
-               if (err)
-                       goto err_out_dev_link;
-       }
-
-       err = sysfs_create_link(&disk->kobj, &block_subsys.kobj,
-                               "subsystem");
-       if (err)
-               goto err_out_disk_name_lnk;
-
-       kfree(disk_name);
-
-       return 0;
-
-err_out_disk_name_lnk:
-       if (target) {
-               sysfs_remove_link(&target->kobj, disk_name);
-err_out_dev_link:
-               sysfs_remove_link(&disk->kobj, "device");
-err_out_disk_name:
-               kfree(disk_name);
-err_out:
-               put_device(target);
-       }
-       return err;
+       /* suppress uevent if the disk supresses it */
+       if (!disk->dev.uevent_suppress)
+               kobject_uevent(&p->dev.kobj, KOBJ_ADD);
 }
 
 /* Not exported, helper to add_disk(). */
@@ -479,19 +374,29 @@ void register_disk(struct gendisk *disk)
        struct hd_struct *p;
        int err;
 
-       kobject_set_name(&disk->kobj, "%s", disk->disk_name);
-       /* ewww... some of these buggers have / in name... */
-       s = strchr(disk->kobj.k_name, '/');
+       disk->dev.parent = disk->driverfs_dev;
+       disk->dev.devt = MKDEV(disk->major, disk->first_minor);
+
+       strlcpy(disk->dev.bus_id, disk->disk_name, KOBJ_NAME_LEN);
+       /* ewww... some of these buggers have / in the name... */
+       s = strchr(disk->dev.bus_id, '/');
        if (s)
                *s = '!';
-       if ((err = kobject_add(&disk->kobj)))
+
+       /* delay uevents, until we scanned partition table */
+       disk->dev.uevent_suppress = 1;
+
+       if (device_add(&disk->dev))
                return;
-       err = disk_sysfs_symlinks(disk);
+#ifndef CONFIG_SYSFS_DEPRECATED
+       err = sysfs_create_link(block_depr, &disk->dev.kobj,
+                               kobject_name(&disk->dev.kobj));
        if (err) {
-               kobject_del(&disk->kobj);
+               device_del(&disk->dev);
                return;
        }
-       disk_sysfs_add_subdirs(disk);
+#endif
+       disk_sysfs_add_subdirs(disk);
 
        /* No minors to use for partitions */
        if (disk->minors == 1)
@@ -505,25 +410,23 @@ void register_disk(struct gendisk *disk)
        if (!bdev)
                goto exit;
 
-       /* scan partition table, but suppress uevents */
        bdev->bd_invalidated = 1;
-       disk->part_uevent_suppress = 1;
        err = blkdev_get(bdev, FMODE_READ, 0);
-       disk->part_uevent_suppress = 0;
        if (err < 0)
                goto exit;
        blkdev_put(bdev);
 
 exit:
-       /* announce disk after possible partitions are already created */
-       kobject_uevent(&disk->kobj, KOBJ_ADD);
+       /* announce disk after possible partitions are created */
+       disk->dev.uevent_suppress = 0;
+       kobject_uevent(&disk->dev.kobj, KOBJ_ADD);
 
        /* announce possible partitions */
        for (i = 1; i < disk->minors; i++) {
                p = disk->part[i-1];
                if (!p || !p->nr_sects)
                        continue;
-               kobject_uevent(&p->kobj, KOBJ_ADD);
+               kobject_uevent(&p->dev.kobj, KOBJ_ADD);
        }
 }
 
@@ -602,19 +505,11 @@ void del_gendisk(struct gendisk *disk)
        disk_stat_set_all(disk, 0);
        disk->stamp = 0;
 
-       kobject_uevent(&disk->kobj, KOBJ_REMOVE);
-       kobject_unregister(disk->holder_dir);
-       kobject_unregister(disk->slave_dir);
-       if (disk->driverfs_dev) {
-               char *disk_name = make_block_name(disk);
-               sysfs_remove_link(&disk->kobj, "device");
-               if (disk_name) {
-                       sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name);
-                       kfree(disk_name);
-               }
-               put_device(disk->driverfs_dev);
-               disk->driverfs_dev = NULL;
-       }
-       sysfs_remove_link(&disk->kobj, "subsystem");
-       kobject_del(&disk->kobj);
+       kobject_put(disk->holder_dir);
+       kobject_put(disk->slave_dir);
+       disk->driverfs_dev = NULL;
+#ifndef CONFIG_SYSFS_DEPRECATED
+       sysfs_remove_link(block_depr, disk->dev.bus_id);
+#endif
+       device_del(&disk->dev);
 }
index 65c62e1bfd6f6cb6170c53a55c90473fe10d5e6b..eb97f2897e2b50724046446be149951c1685c650 100644 (file)
@@ -169,7 +169,7 @@ static inline char *task_state(struct task_struct *p, char *buffer)
        ppid = pid_alive(p) ?
                task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0;
        tpid = pid_alive(p) && p->ptrace ?
-               task_ppid_nr_ns(rcu_dereference(p->parent), ns) : 0;
+               task_pid_nr_ns(rcu_dereference(p->parent), ns) : 0;
        buffer += sprintf(buffer,
                "State:\t%s\n"
                "Tgid:\t%d\n"
@@ -464,8 +464,8 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
                }
 
                sid = task_session_nr_ns(task, ns);
+               ppid = task_tgid_nr_ns(task->real_parent, ns);
                pgid = task_pgrp_nr_ns(task, ns);
-               ppid = task_ppid_nr_ns(task, ns);
 
                unlock_task_sighand(task, &flags);
        }
index 02a63ac04178e64c8f7e2a3bddee2fcadeaf8254..91fa8e6ce8ad6591cb496ca54731ab5531cef521 100644 (file)
@@ -202,6 +202,26 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
         (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
         security_ptrace(current,task) == 0))
 
+struct mm_struct *mm_for_maps(struct task_struct *task)
+{
+       struct mm_struct *mm = get_task_mm(task);
+       if (!mm)
+               return NULL;
+       down_read(&mm->mmap_sem);
+       task_lock(task);
+       if (task->mm != mm)
+               goto out;
+       if (task->mm != current->mm && __ptrace_may_attach(task) < 0)
+               goto out;
+       task_unlock(task);
+       return mm;
+out:
+       task_unlock(task);
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+       return NULL;
+}
+
 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
 {
        int res = 0;
@@ -290,6 +310,77 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
 }
 #endif
 
+#ifdef CONFIG_LATENCYTOP
+static int lstats_show_proc(struct seq_file *m, void *v)
+{
+       int i;
+       struct task_struct *task = m->private;
+       seq_puts(m, "Latency Top version : v0.1\n");
+
+       for (i = 0; i < 32; i++) {
+               if (task->latency_record[i].backtrace[0]) {
+                       int q;
+                       seq_printf(m, "%i %li %li ",
+                               task->latency_record[i].count,
+                               task->latency_record[i].time,
+                               task->latency_record[i].max);
+                       for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
+                               char sym[KSYM_NAME_LEN];
+                               char *c;
+                               if (!task->latency_record[i].backtrace[q])
+                                       break;
+                               if (task->latency_record[i].backtrace[q] == ULONG_MAX)
+                                       break;
+                               sprint_symbol(sym, task->latency_record[i].backtrace[q]);
+                               c = strchr(sym, '+');
+                               if (c)
+                                       *c = 0;
+                               seq_printf(m, "%s ", sym);
+                       }
+                       seq_printf(m, "\n");
+               }
+
+       }
+       return 0;
+}
+
+static int lstats_open(struct inode *inode, struct file *file)
+{
+       int ret;
+       struct seq_file *m;
+       struct task_struct *task = get_proc_task(inode);
+
+       ret = single_open(file, lstats_show_proc, NULL);
+       if (!ret) {
+               m = file->private_data;
+               m->private = task;
+       }
+       return ret;
+}
+
+static ssize_t lstats_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *offs)
+{
+       struct seq_file *m;
+       struct task_struct *task;
+
+       m = file->private_data;
+       task = m->private;
+       clear_all_latency_tracing(task);
+
+       return count;
+}
+
+static const struct file_operations proc_lstats_operations = {
+       .open           = lstats_open,
+       .read           = seq_read,
+       .write          = lstats_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+#endif
+
 /* The badness from the OOM killer */
 unsigned long badness(struct task_struct *p, unsigned long uptime);
 static int proc_oom_score(struct task_struct *task, char *buffer)
@@ -1000,6 +1091,7 @@ static const struct file_operations proc_fault_inject_operations = {
 };
 #endif
 
+
 #ifdef CONFIG_SCHED_DEBUG
 /*
  * Print out various scheduling related per-task fields:
@@ -2210,6 +2302,9 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat",  S_IRUGO, pid_schedstat),
 #endif
+#ifdef CONFIG_LATENCYTOP
+       REG("latency",  S_IRUGO, lstats),
+#endif
 #ifdef CONFIG_PROC_PID_CPUSET
        REG("cpuset",     S_IRUGO, cpuset),
 #endif
@@ -2535,6 +2630,9 @@ static const struct pid_entry tid_base_stuff[] = {
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat", S_IRUGO, pid_schedstat),
 #endif
+#ifdef CONFIG_LATENCYTOP
+       REG("latency",  S_IRUGO, lstats),
+#endif
 #ifdef CONFIG_PROC_PID_CPUSET
        REG("cpuset",    S_IRUGO, cpuset),
 #endif
index 1820eb2ef7623a2c222e9be9b61d0e749f259187..05b3e9006262c49145f640e482062bbd0b6d14ad 100644 (file)
@@ -27,6 +27,8 @@ struct vmalloc_info {
        unsigned long   largest_chunk;
 };
 
+extern struct mm_struct *mm_for_maps(struct task_struct *);
+
 #ifdef CONFIG_MMU
 #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
 extern void get_vmalloc_info(struct vmalloc_info *vmi);
index e0d064e9764ef55422cf79119b7624b3e6b87373..3462bfde89f68224a4ec48629e26c81feee0e44b 100644 (file)
@@ -410,7 +410,7 @@ static const struct file_operations proc_modules_operations = {
 };
 #endif
 
-#ifdef CONFIG_SLAB
+#ifdef CONFIG_SLABINFO
 static int slabinfo_open(struct inode *inode, struct file *file)
 {
        return seq_open(file, &slabinfo_op);
@@ -728,7 +728,7 @@ void __init proc_misc_init(void)
 #endif
        create_seq_entry("stat", 0, &proc_stat_operations);
        create_seq_entry("interrupts", 0, &proc_interrupts_operations);
-#ifdef CONFIG_SLAB
+#ifdef CONFIG_SLABINFO
        create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
 #ifdef CONFIG_DEBUG_SLAB_LEAK
        create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations);
index c24d81a5a040e2a91825673434339e3c2f1dcdda..8043a3eab52ce49f14f0b23f863b8fb77c6916ba 100644 (file)
@@ -397,12 +397,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
        if (!priv->task)
                return NULL;
 
-       mm = get_task_mm(priv->task);
+       mm = mm_for_maps(priv->task);
        if (!mm)
                return NULL;
 
        priv->tail_vma = tail_vma = get_gate_vma(priv->task);
-       down_read(&mm->mmap_sem);
 
        /* Start with last addr hint */
        if (last_addr && (vma = find_vma(mm, last_addr))) {
index d8b8c7183c243d86455390f1246da6c12891d396..1932c2ca345729580c60f5a0a2b8187779b9c450 100644 (file)
@@ -165,15 +165,13 @@ static void *m_start(struct seq_file *m, loff_t *pos)
        if (!priv->task)
                return NULL;
 
-       mm = get_task_mm(priv->task);
+       mm = mm_for_maps(priv->task);
        if (!mm) {
                put_task_struct(priv->task);
                priv->task = NULL;
                return NULL;
        }
 
-       down_read(&mm->mmap_sem);
-
        /* start from the Nth VMA */
        for (vml = mm->context.vmlist; vml; vml = vml->next)
                if (n-- == 0)
index ea1f94cc722e0c942111b9849cedf8b1aef1d86a..c4d3d17923f155004fec85fd04f836a06aa585f3 100644 (file)
@@ -197,25 +197,27 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
 {
        struct inode *inode;
        loff_t pos;
+       int retval = -EINVAL;
 
        inode = file->f_path.dentry->d_inode;
        if (unlikely((ssize_t) count < 0))
-               goto Einval;
+               return retval;
        pos = *ppos;
        if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
-               goto Einval;
+               return retval;
 
        if (unlikely(inode->i_flock && mandatory_lock(inode))) {
-               int retval = locks_mandatory_area(
+               retval = locks_mandatory_area(
                        read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
                        inode, file, pos, count);
                if (retval < 0)
                        return retval;
        }
+       retval = security_file_permission(file,
+                               read_write == READ ? MAY_READ : MAY_WRITE);
+       if (retval)
+               return retval;
        return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
-
-Einval:
-       return -EINVAL;
 }
 
 static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
@@ -267,18 +269,15 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
        ret = rw_verify_area(READ, file, pos, count);
        if (ret >= 0) {
                count = ret;
-               ret = security_file_permission (file, MAY_READ);
-               if (!ret) {
-                       if (file->f_op->read)
-                               ret = file->f_op->read(file, buf, count, pos);
-                       else
-                               ret = do_sync_read(file, buf, count, pos);
-                       if (ret > 0) {
-                               fsnotify_access(file->f_path.dentry);
-                               add_rchar(current, ret);
-                       }
-                       inc_syscr(current);
+               if (file->f_op->read)
+                       ret = file->f_op->read(file, buf, count, pos);
+               else
+                       ret = do_sync_read(file, buf, count, pos);
+               if (ret > 0) {
+                       fsnotify_access(file->f_path.dentry);
+                       add_rchar(current, ret);
                }
+               inc_syscr(current);
        }
 
        return ret;
@@ -325,18 +324,15 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
        ret = rw_verify_area(WRITE, file, pos, count);
        if (ret >= 0) {
                count = ret;
-               ret = security_file_permission (file, MAY_WRITE);
-               if (!ret) {
-                       if (file->f_op->write)
-                               ret = file->f_op->write(file, buf, count, pos);
-                       else
-                               ret = do_sync_write(file, buf, count, pos);
-                       if (ret > 0) {
-                               fsnotify_modify(file->f_path.dentry);
-                               add_wchar(current, ret);
-                       }
-                       inc_syscw(current);
+               if (file->f_op->write)
+                       ret = file->f_op->write(file, buf, count, pos);
+               else
+                       ret = do_sync_write(file, buf, count, pos);
+               if (ret > 0) {
+                       fsnotify_modify(file->f_path.dentry);
+                       add_wchar(current, ret);
                }
+               inc_syscw(current);
        }
 
        return ret;
@@ -603,9 +599,6 @@ static ssize_t do_readv_writev(int type, struct file *file,
        ret = rw_verify_area(type, file, pos, tot_len);
        if (ret < 0)
                goto out;
-       ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
-       if (ret)
-               goto out;
 
        fnv = NULL;
        if (type == READ) {
@@ -737,10 +730,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                goto fput_in;
        count = retval;
 
-       retval = security_file_permission (in_file, MAY_READ);
-       if (retval)
-               goto fput_in;
-
        /*
         * Get output file, and verify that it is ok..
         */
@@ -759,10 +748,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                goto fput_out;
        count = retval;
 
-       retval = security_file_permission (out_file, MAY_WRITE);
-       if (retval)
-               goto fput_out;
-
        if (!max)
                max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
 
index 6bdcb6107bc3c55b58199537e2eb5537133cd460..56b802bfbfa4879021cc2af03f175e69cec621d8 100644 (file)
@@ -908,10 +908,6 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
        if (unlikely(ret < 0))
                return ret;
 
-       ret = security_file_permission(out, MAY_WRITE);
-       if (unlikely(ret < 0))
-               return ret;
-
        return out->f_op->splice_write(pipe, out, ppos, len, flags);
 }
 
@@ -934,10 +930,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
        if (unlikely(ret < 0))
                return ret;
 
-       ret = security_file_permission(in, MAY_READ);
-       if (unlikely(ret < 0))
-               return ret;
-
        return in->f_op->splice_read(in, ppos, pipe, len, flags);
 }
 
index 337162935d2173964538a190b7ed6e8433823f35..4948d9bc405dfbdb23f30dcd5ad47d103f4e5514 100644 (file)
@@ -440,7 +440,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 /**
  *     sysfs_remove_one - remove sysfs_dirent from parent
  *     @acxt: addrm context to use
- *     @sd: sysfs_dirent to be added
+ *     @sd: sysfs_dirent to be removed
  *
  *     Mark @sd removed and drop nlink of parent inode if @sd is a
  *     directory.  @sd is unlinked from the children list.
@@ -678,8 +678,10 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
        sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
 
        /* no such entry */
-       if (!sd)
+       if (!sd) {
+               ret = ERR_PTR(-ENOENT);
                goto out_unlock;
+       }
 
        /* attach dentry and inode */
        inode = sysfs_get_inode(sd);
@@ -781,6 +783,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
        old_dentry = sysfs_get_dentry(sd);
        if (IS_ERR(old_dentry)) {
                error = PTR_ERR(old_dentry);
+               old_dentry = NULL;
                goto out;
        }
 
@@ -848,6 +851,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
        old_dentry = sysfs_get_dentry(sd);
        if (IS_ERR(old_dentry)) {
                error = PTR_ERR(old_dentry);
+               old_dentry = NULL;
                goto out;
        }
        old_parent = old_dentry->d_parent;
@@ -855,6 +859,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
        new_parent = sysfs_get_dentry(new_parent_sd);
        if (IS_ERR(new_parent)) {
                error = PTR_ERR(new_parent);
+               new_parent = NULL;
                goto out;
        }
 
@@ -878,7 +883,6 @@ again:
        error = 0;
        d_add(new_dentry, NULL);
        d_move(old_dentry, new_dentry);
-       dput(new_dentry);
 
        /* Remove from old parent's list and insert into new parent's list. */
        sysfs_unlink_sibling(sd);
index 4045bdcc4b331dbf7f4cdd7c6d781f16021ffbf2..a271c87c4472d530bee00c35da17a06606dfc97c 100644 (file)
 
 #include "sysfs.h"
 
-#define to_sattr(a) container_of(a,struct subsys_attribute, attr)
-
-/*
- * Subsystem file operations.
- * These operations allow subsystems to have files that can be 
- * read/written. 
- */
-static ssize_t 
-subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
-{
-       struct kset *kset = to_kset(kobj);
-       struct subsys_attribute * sattr = to_sattr(attr);
-       ssize_t ret = -EIO;
-
-       if (sattr->show)
-               ret = sattr->show(kset, page);
-       return ret;
-}
-
-static ssize_t 
-subsys_attr_store(struct kobject * kobj, struct attribute * attr, 
-                 const char * page, size_t count)
-{
-       struct kset *kset = to_kset(kobj);
-       struct subsys_attribute * sattr = to_sattr(attr);
-       ssize_t ret = -EIO;
-
-       if (sattr->store)
-               ret = sattr->store(kset, page, count);
-       return ret;
-}
-
-static struct sysfs_ops subsys_sysfs_ops = {
-       .show   = subsys_attr_show,
-       .store  = subsys_attr_store,
-};
-
 /*
  * There's one sysfs_buffer for each open file and one
  * sysfs_open_dirent for each sysfs_dirent with one or more open
@@ -66,7 +29,7 @@ static struct sysfs_ops subsys_sysfs_ops = {
  * sysfs_dirent->s_attr.open points to sysfs_open_dirent.  s_attr.open
  * is protected by sysfs_open_dirent_lock.
  */
-static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sysfs_open_dirent_lock);
 
 struct sysfs_open_dirent {
        atomic_t                refcnt;
@@ -354,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
 {
        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
-       struct sysfs_buffer * buffer;
-       struct sysfs_ops * ops = NULL;
-       int error;
+       struct sysfs_buffer *buffer;
+       struct sysfs_ops *ops;
+       int error = -EACCES;
 
        /* need attr_sd for attr and ops, its parent for kobj */
        if (!sysfs_get_active_two(attr_sd))
                return -ENODEV;
 
-       /* if the kobject has no ktype, then we assume that it is a subsystem
-        * itself, and use ops for it.
-        */
-       if (kobj->kset && kobj->kset->ktype)
-               ops = kobj->kset->ktype->sysfs_ops;
-       else if (kobj->ktype)
+       /* every kobject with an attribute needs a ktype assigned */
+       if (kobj->ktype && kobj->ktype->sysfs_ops)
                ops = kobj->ktype->sysfs_ops;
-       else
-               ops = &subsys_sysfs_ops;
-
-       error = -EACCES;
-
-       /* No sysfs operations, either from having no subsystem,
-        * or the subsystem have no operations.
-        */
-       if (!ops)
+       else {
+               printk(KERN_ERR "missing sysfs attribute operations for "
+                      "kobject: %s\n", kobject_name(kobj));
+               WARN_ON(1);
                goto err_out;
+       }
 
        /* File needs write support.
         * The inode's perms must say it's ok, 
@@ -568,7 +523,11 @@ int sysfs_add_file_to_group(struct kobject *kobj,
        struct sysfs_dirent *dir_sd;
        int error;
 
-       dir_sd = sysfs_get_dirent(kobj->sd, group);
+       if (group)
+               dir_sd = sysfs_get_dirent(kobj->sd, group);
+       else
+               dir_sd = sysfs_get(kobj->sd);
+
        if (!dir_sd)
                return -ENOENT;
 
@@ -656,7 +615,10 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
 {
        struct sysfs_dirent *dir_sd;
 
-       dir_sd = sysfs_get_dirent(kobj->sd, group);
+       if (group)
+               dir_sd = sysfs_get_dirent(kobj->sd, group);
+       else
+               dir_sd = sysfs_get(kobj->sd);
        if (dir_sd) {
                sysfs_hash_and_remove(dir_sd, attr->name);
                sysfs_put(dir_sd);
index d1972374655a22377e94186b62564aaa83f2299f..0871c3dadce1c4a16d469b9a03b511f3eadbb937 100644 (file)
 #include "sysfs.h"
 
 
-static void remove_files(struct sysfs_dirent *dir_sd,
+static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
                         const struct attribute_group *grp)
 {
        struct attribute *const* attr;
+       int i;
 
-       for (attr = grp->attrs; *attr; attr++)
-               sysfs_hash_and_remove(dir_sd, (*attr)->name);
+       for (i = 0, attr = grp->attrs; *attr; i++, attr++)
+               if (!grp->is_visible ||
+                   grp->is_visible(kobj, *attr, i))
+                       sysfs_hash_and_remove(dir_sd, (*attr)->name);
 }
 
-static int create_files(struct sysfs_dirent *dir_sd,
+static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
                        const struct attribute_group *grp)
 {
        struct attribute *const* attr;
-       int error = 0;
+       int error = 0, i;
 
-       for (attr = grp->attrs; *attr && !error; attr++)
-               error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
+       for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++)
+               if (!grp->is_visible ||
+                   grp->is_visible(kobj, *attr, i))
+                       error |=
+                               sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
        if (error)
-               remove_files(dir_sd, grp);
+               remove_files(dir_sd, kobj, grp);
        return error;
 }
 
@@ -54,7 +60,7 @@ int sysfs_create_group(struct kobject * kobj,
        } else
                sd = kobj->sd;
        sysfs_get(sd);
-       error = create_files(sd, grp);
+       error = create_files(sd, kobj, grp);
        if (error) {
                if (grp->name)
                        sysfs_remove_subdir(sd);
@@ -75,7 +81,7 @@ void sysfs_remove_group(struct kobject * kobj,
        } else
                sd = sysfs_get(dir_sd);
 
-       remove_files(sd, grp);
+       remove_files(sd, kobj, grp);
        if (grp->name)
                sysfs_remove_subdir(sd);
 
index 3eac20c63c419d45cc666a53251be208ebf1296a..5f66c446615176eff46e1864a7343f228bac19e6 100644 (file)
 
 #include "sysfs.h"
 
-static int object_depth(struct sysfs_dirent *sd)
-{
-       int depth = 0;
-
-       for (; sd->s_parent; sd = sd->s_parent)
-               depth++;
-
-       return depth;
-}
-
-static int object_path_length(struct sysfs_dirent * sd)
-{
-       int length = 1;
-
-       for (; sd->s_parent; sd = sd->s_parent)
-               length += strlen(sd->s_name) + 1;
-
-       return length;
-}
-
-static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
-{
-       --length;
-       for (; sd->s_parent; sd = sd->s_parent) {
-               int cur = strlen(sd->s_name);
-
-               /* back up enough to print this bus id with '/' */
-               length -= cur;
-               strncpy(buffer + length, sd->s_name, cur);
-               *(buffer + --length) = '/';
-       }
-}
-
 /**
  *     sysfs_create_link - create symlink between two objects.
  *     @kobj:  object whose directory we're creating the link in.
@@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
        return error;
 }
 
-
 /**
  *     sysfs_remove_link - remove symlink in object's directory.
  *     @kobj:  object we're acting for.
@@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
        sysfs_hash_and_remove(kobj->sd, name);
 }
 
-static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
-                                struct sysfs_dirent * target_sd, char *path)
+static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
+                                struct sysfs_dirent *target_sd, char *path)
 {
-       char * s;
-       int depth, size;
+       struct sysfs_dirent *base, *sd;
+       char *s = path;
+       int len = 0;
+
+       /* go up to the root, stop at the base */
+       base = parent_sd;
+       while (base->s_parent) {
+               sd = target_sd->s_parent;
+               while (sd->s_parent && base != sd)
+                       sd = sd->s_parent;
+
+               if (base == sd)
+                       break;
+
+               strcpy(s, "../");
+               s += 3;
+               base = base->s_parent;
+       }
+
+       /* determine end of target string for reverse fillup */
+       sd = target_sd;
+       while (sd->s_parent && sd != base) {
+               len += strlen(sd->s_name) + 1;
+               sd = sd->s_parent;
+       }
 
-       depth = object_depth(parent_sd);
-       size = object_path_length(target_sd) + depth * 3 - 1;
-       if (size > PATH_MAX)
+       /* check limits */
+       if (len < 2)
+               return -EINVAL;
+       len--;
+       if ((s - path) + len > PATH_MAX)
                return -ENAMETOOLONG;
 
-       pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
+       /* reverse fillup of target string from target to base */
+       sd = target_sd;
+       while (sd->s_parent && sd != base) {
+               int slen = strlen(sd->s_name);
 
-       for (s = path; depth--; s += 3)
-               strcpy(s,"../");
+               len -= slen;
+               strncpy(s + len, sd->s_name, slen);
+               if (len)
+                       s[--len] = '/';
 
-       fill_object_path(target_sd, path, size);
-       pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
+               sd = sd->s_parent;
+       }
 
        return 0;
 }
index 4847eb83fc180868f9af080cf0f9a1b2696a8b19..21a1c2b1c5fcf716b779fb973ef31fa5acb6114c 100644 (file)
@@ -261,9 +261,9 @@ xfs_file_readdir(
 #else
 
 struct hack_dirent {
-       int             namlen;
-       loff_t          offset;
        u64             ino;
+       loff_t          offset;
+       int             namlen;
        unsigned int    d_type;
        char            name[];
 };
@@ -285,8 +285,10 @@ xfs_hack_filldir(
 {
        struct hack_callback *buf = __buf;
        struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used);
+       unsigned int reclen;
 
-       if (buf->used + sizeof(struct hack_dirent) + namlen > buf->len)
+       reclen = ALIGN(sizeof(struct hack_dirent) + namlen, sizeof(u64));
+       if (buf->used + reclen > buf->len)
                return -EINVAL;
 
        de->namlen = namlen;
@@ -294,7 +296,7 @@ xfs_hack_filldir(
        de->ino = ino;
        de->d_type = d_type;
        memcpy(de->name, name, namlen);
-       buf->used += sizeof(struct hack_dirent) + namlen;
+       buf->used += reclen;
        return 0;
 }
 
@@ -334,7 +336,8 @@ xfs_file_readdir(
                offset = filp->f_pos;
 
        while (!eof) {
-               int reclen;
+               unsigned int reclen;
+
                start_offset = offset;
 
                buf.used = 0;
@@ -355,7 +358,8 @@ xfs_file_readdir(
                                goto done;
                        }
 
-                       reclen = sizeof(struct hack_dirent) + de->namlen;
+                       reclen = ALIGN(sizeof(struct hack_dirent) + de->namlen,
+                                      sizeof(u64));
                        size -= reclen;
                        de = (struct hack_dirent *)((char *)de + reclen);
                        curr_offset = de->offset /* & 0x7fffffff */;
index 19c3ead2a90bb768f98e077ff91c050ae290e737..fb7171b1bd22e900349126212f8fceb4f997d8e8 100644 (file)
@@ -168,7 +168,8 @@ struct acpi_device_flags {
        u32 power_manageable:1;
        u32 performance_manageable:1;
        u32 wake_capable:1;     /* Wakeup(_PRW) supported? */
-       u32 reserved:20;
+       u32 force_power_state:1;
+       u32 reserved:19;
 };
 
 /* File System */
@@ -318,7 +319,7 @@ struct acpi_bus_event {
        u32 data;
 };
 
-extern struct kset acpi_subsys;
+extern struct kobject *acpi_kobj;
 extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
 /*
  * External Functions
index ab2d963e742a46c26185c7358e8ad28a0438ee51..e25558faa5a480f7b2c2fa78d444244e071e9ae6 100644 (file)
 
 #define cpu_is_pxa21x()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa21x(id);                    \
+               __cpu_is_pxa21x(read_cpuid_id());       \
        })
 
 #define cpu_is_pxa25x()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa25x(id);                    \
+               __cpu_is_pxa25x(read_cpuid_id());       \
        })
 
 #define cpu_is_pxa27x()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa27x(id);                    \
+               __cpu_is_pxa27x(read_cpuid_id());       \
        })
 
 #define cpu_is_pxa300()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa300(id);                    \
+               __cpu_is_pxa300(read_cpuid_id());       \
         })
 
 #define cpu_is_pxa310()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa310(id);                    \
+               __cpu_is_pxa310(read_cpuid_id());       \
         })
 
 #define cpu_is_pxa320()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa320(id);                    \
+               __cpu_is_pxa320(read_cpuid_id());       \
         })
 
 /*
 
 #define cpu_is_pxa2xx()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa2xx(id);                    \
+               __cpu_is_pxa2xx(read_cpuid_id());       \
         })
 
 #define cpu_is_pxa3xx()                                        \
        ({                                              \
-               unsigned int id = read_cpuid(CPUID_ID); \
-               __cpu_is_pxa3xx(id);                    \
+               __cpu_is_pxa3xx(read_cpuid_id());       \
         })
 
 /*
index 94ea8c6dc1a4485014fd9bb8fbd7c29078e69696..28425c473e71c72c7a959f6650fc6707a89d6b0e 100644 (file)
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
+#include <linux/stringify.h>
 #include <linux/irqflags.h>
 
+/*
+ * The CPU ID never changes at run time, so we might as well tell the
+ * compiler that it's constant.  Use this function to read the CPU ID
+ * rather than directly reading processor_id or read_cpuid() directly.
+ */
+static inline unsigned int read_cpuid_id(void) __attribute_const__;
+
+static inline unsigned int read_cpuid_id(void)
+{
+       return read_cpuid(CPUID_ID);
+}
+
 #define __exception    __attribute__((section(".exception.text")))
 
 struct thread_info;
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
deleted file mode 100644 (file)
index 3914d7b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Pin definitions for AT32AP7000.
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_AT32AP7000_H__
-#define __ASM_ARCH_AT32AP7000_H__
-
-#define GPIO_PERIPH_A  0
-#define GPIO_PERIPH_B  1
-
-#define NR_GPIO_CONTROLLERS    4
-
-/*
- * Pin numbers identifying specific GPIO pins on the chip. They can
- * also be converted to IRQ numbers by passing them through
- * gpio_to_irq().
- */
-#define GPIO_PIOA_BASE (0)
-#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
-#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
-#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
-#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32)
-
-#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
-#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
-#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
-#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
-#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N))
-
-#endif /* __ASM_ARCH_AT32AP7000_H__ */
diff --git a/include/asm-avr32/arch-at32ap/at32ap700x.h b/include/asm-avr32/arch-at32ap/at32ap700x.h
new file mode 100644 (file)
index 0000000..99684d6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Pin definitions for AT32AP7000.
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARCH_AT32AP700X_H__
+#define __ASM_ARCH_AT32AP700X_H__
+
+#define GPIO_PERIPH_A  0
+#define GPIO_PERIPH_B  1
+
+#define NR_GPIO_CONTROLLERS    4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be converted to IRQ numbers by passing them through
+ * gpio_to_irq().
+ */
+#define GPIO_PIOA_BASE (0)
+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
+#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32)
+
+#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
+#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
+#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
+#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
+#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N))
+
+#endif /* __ASM_ARCH_AT32AP700X_H__ */
index a762f42cbb71538d0eb5d0f484ccda952aa2132d..0dc20261c1ea2d8a02ef094f28afb59b6550d7cf 100644 (file)
@@ -14,7 +14,7 @@
  * Only AT32AP7000 is defined for now. We can identify the specific
  * chip at runtime, but I'm not sure if it's really worth it.
  */
-#ifdef CONFIG_CPU_AT32AP7000
+#ifdef CONFIG_CPU_AT32AP700X
 # define cpu_is_at32ap7000()   (1)
 #else
 # define cpu_is_at32ap7000()   (0)
index ee59e401f041569af2a7077540f371add0362160..4ec6abc68ea38084fae0a1d269f5fd53ebe34589 100644 (file)
@@ -4,7 +4,7 @@
 /* For "bizarre" halfword swapping */
 #include <linux/byteorder/swabb.h>
 
-#if defined(CONFIG_AP7000_32_BIT_SMC)
+#if defined(CONFIG_AP700X_32_BIT_SMC)
 # define __swizzle_addr_b(addr)        (addr ^ 3UL)
 # define __swizzle_addr_w(addr)        (addr ^ 2UL)
 # define __swizzle_addr_l(addr)        (addr)
@@ -14,7 +14,7 @@
 # define __mem_ioswabb(a, x)   (x)
 # define __mem_ioswabw(a, x)   swab16(x)
 # define __mem_ioswabl(a, x)   swab32(x)
-#elif defined(CONFIG_AP7000_16_BIT_SMC)
+#elif defined(CONFIG_AP700X_16_BIT_SMC)
 # define __swizzle_addr_b(addr)        (addr ^ 1UL)
 # define __swizzle_addr_w(addr)        (addr)
 # define __swizzle_addr_l(addr)        (addr)
index 83e6549d7783f0ab2bff22b1a4a94f822ccb16e7..9315724c059675d7bdcda46007c63c9260afda7c 100644 (file)
@@ -11,4 +11,9 @@
 
 #define irq_canonicalize(i)    (i)
 
+#ifndef __ASSEMBLER__
+int nmi_enable(void);
+void nmi_disable(void);
+#endif
+
 #endif /* __ASM_AVR32_IOCTLS_H */
index fd7e99046b2f366be239078692c957381c223bc6..ca4f9542365afdd27a061ca22e12448afd0a6a46 100644 (file)
@@ -5,6 +5,7 @@
 enum die_val {
        DIE_BREAKPOINT,
        DIE_SSTEP,
+       DIE_NMI,
 };
 
 #endif /* __ASM_AVR32_KDEBUG_H */
index 996405e0393f8e999289d503d2902d9e50a47e6e..6bef094902353b80364766a438a852b3346a02b5 100644 (file)
@@ -533,6 +533,11 @@ static inline void __ocd_write(unsigned int reg, unsigned long value)
 #define ocd_read(reg)                  __ocd_read(OCD_##reg)
 #define ocd_write(reg, value)          __ocd_write(OCD_##reg, value)
 
+struct task_struct;
+
+void ocd_enable(struct task_struct *child);
+void ocd_disable(struct task_struct *child);
+
 #endif /* !__ASSEMBLER__ */
 
 #endif /* __ASM_AVR32_OCD_H */
index a52576b25afe9a47af07c9d9b27d6cea4ae1e889..4212551c1cd9962d81268ed0e40e23e4ebefd0aa 100644 (file)
@@ -57,11 +57,25 @@ struct avr32_cpuinfo {
        unsigned short cpu_revision;
        enum tlb_config tlb_config;
        unsigned long features;
+       u32 device_id;
 
        struct cache_info icache;
        struct cache_info dcache;
 };
 
+static inline unsigned int avr32_get_manufacturer_id(struct avr32_cpuinfo *cpu)
+{
+       return (cpu->device_id >> 1) & 0x7f;
+}
+static inline unsigned int avr32_get_product_number(struct avr32_cpuinfo *cpu)
+{
+       return (cpu->device_id >> 12) & 0xffff;
+}
+static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
+{
+       return (cpu->device_id >> 28) & 0x0f;
+}
+
 extern struct avr32_cpuinfo boot_cpu_data;
 
 #ifdef CONFIG_SMP
index 8c5dba5e33dfd396e6b67b61b1454e4c7d70e20b..9e2d44f4e0fe9f7b358758d9babfc7443cea2e7b 100644 (file)
@@ -121,7 +121,15 @@ struct pt_regs {
 };
 
 #ifdef __KERNEL__
-# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
+
+#include <asm/ocd.h>
+
+#define arch_ptrace_attach(child)       ocd_enable(child)
+
+#define user_mode(regs)                 (((regs)->sr & MODE_MASK) == MODE_USER)
+#define instruction_pointer(regs)       ((regs)->pc)
+#define profile_pc(regs)                instruction_pointer(regs)
+
 extern void show_regs (struct pt_regs *);
 
 static __inline__ int valid_user_regs(struct pt_regs *regs)
@@ -141,9 +149,6 @@ static __inline__ int valid_user_regs(struct pt_regs *regs)
        return 0;
 }
 
-#define instruction_pointer(regs) ((regs)->pc)
-
-#define profile_pc(regs) instruction_pointer(regs)
 
 #endif /* __KERNEL__ */
 
index 184b574289b431ba8f5981ee572a3a1ce7ce5c80..07049f6c0d41a168ba057eae80247a0f8727b03e 100644 (file)
@@ -88,6 +88,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             6
 #define TIF_RESTORE_SIGMASK    7       /* restore signal mask in do_signal */
 #define TIF_CPU_GOING_TO_SLEEP 8       /* CPU is entering sleep 0 mode */
+#define TIF_DEBUG              30      /* debugging enabled */
 #define TIF_USERSPACE          31      /* true if FS sets userspace */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
index 78b301ed7b126961fe4554f6a16a3d81e70596e3..ea34e0d0a3884690a3e66ff7fd1bdeb6a24f596e 100644 (file)
@@ -89,11 +89,6 @@ static inline void ide_init_default_hwifs(void)
        }
 }
 
-/* some configuration options we don't need */
-
-#undef SUPPORT_VLB_SYNC
-#define SUPPORT_VLB_SYNC 0
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMCRIS_IDE_H */
index 11296170d057cf96abcced2b328874f963239f33..fb9c3627a5b4eac13c71f7fc3d919d456a18fcf1 100644 (file)
@@ -48,11 +48,6 @@ static inline unsigned long ide_default_io_base(int index)
        return REG_TYPE_CONV(unsigned long, reg_ata_rw_ctrl2, ctrl2);
 }
 
-/* some configuration options we don't need */
-
-#undef SUPPORT_VLB_SYNC
-#define SUPPORT_VLB_SYNC 0
-
 #define IDE_ARCH_ACK_INTR
 #define ide_ack_intr(hwif)     ((hwif)->ack_intr(hwif))
 
index 0648e3153f81f2d1f49d8633d5b72d59aa3ba117..b84353ef6998459ccf3b40da3777254cadcfe1fe 100644 (file)
@@ -4,14 +4,11 @@
 #ifdef __KERNEL__
 
 #include <asm/arch/page.h>
+#include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     13
-#ifndef __ASSEMBLY__
-#define PAGE_SIZE      (1UL << PAGE_SHIFT)
-#else
-#define PAGE_SIZE      (1 << PAGE_SHIFT)
-#endif
+#define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
index 6f2d924f4fd6d0f1421a46666ae81ad9c418b52f..bd57a794917057c20f7312f1661a97a9cfd473c8 100644 (file)
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 /*
  * "Conditional" syscalls
index f0bd2cb250c110ca64c353dfae02f054a22d9395..8c9a540d434431138deb74ee9f7558b660e9b197 100644 (file)
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS 0
-
-#undef SUPPORT_VLB_SYNC
-#define SUPPORT_VLB_SYNC 0
-
 #ifndef MAX_HWIFS
 #define MAX_HWIFS 8
 #endif
index a4a22cc358987c86999ef602301b2ca189526dfe..587566f95f6ccd61eb3931097542b37a9c769138 100644 (file)
@@ -44,8 +44,8 @@
 #define RLIMIT_NICE            13      /* max nice prio allowed to raise to
                                           0-39 for nice level 19 .. -20 */
 #define RLIMIT_RTPRIO          14      /* maximum realtime priority */
-
-#define RLIM_NLIMITS           15
+#define RLIMIT_RTTIME          15      /* timeout for RT tasks in us */
+#define RLIM_NLIMITS           16
 
 /*
  * SuS says limits have to be unsigned.
@@ -86,6 +86,7 @@
        [RLIMIT_MSGQUEUE]       = {   MQ_BYTES_MAX,   MQ_BYTES_MAX },   \
        [RLIMIT_NICE]           = { 0, 0 },                             \
        [RLIMIT_RTPRIO]         = { 0, 0 },                             \
+       [RLIMIT_RTTIME]         = {  RLIM_INFINITY,  RLIM_INFINITY },   \
 }
 
 #endif /* __KERNEL__ */
index 8e5d7de9c63217d4518847670ab5466022f2a44c..3c0900ab8003172b4d41f1dcd8f2139a1c1a6013 100644 (file)
@@ -1211,11 +1211,13 @@ xpc_IPI_init(int index)
 static inline enum xpc_retval
 xpc_map_bte_errors(bte_result_t error)
 {
+       if (error == BTE_SUCCESS)
+               return xpcSuccess;
+
        if (is_shub2()) {
                if (BTE_VALID_SH2_ERROR(error))
                        return xpcBteSh2Start + error;
-               else
-                       return xpcBteUnmappedError;
+               return xpcBteUnmappedError;
        }
        switch (error) {
        case BTE_SUCCESS:       return xpcSuccess;
index df7f2deb3b56cee5361629380c7c619fc8e52187..256ad2cc6eb8f8a4bb242ae383f50266eea47270 100644 (file)
@@ -64,7 +64,7 @@
 #define Page_Invalidate_T      0x16
 
 /*
- * R1000-specific cacheops
+ * R10000-specific cacheops
  *
  * Cacheops 0x02, 0x06, 0x0a, 0x0c-0x0e, 0x16, 0x1a and 0x1e are unused.
  * Most of the _S cacheops are identical to the R4000SC _SD cacheops.
index e09131a6127de1bbd723ad0452db211b7bea4ea4..8ce51757434051d6daa0af76a5a8dd5680304096 100644 (file)
@@ -49,7 +49,7 @@ struct smtc_ipi_q {
 
 static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p)
 {
-       long flags;
+       unsigned long flags;
 
        spin_lock_irqsave(&q->lock, flags);
        if (q->head == NULL)
@@ -98,7 +98,7 @@ static inline struct smtc_ipi *smtc_ipi_dq(struct smtc_ipi_q *q)
 
 static inline void smtc_ipi_req(struct smtc_ipi_q *q, struct smtc_ipi *p)
 {
-       long flags;
+       unsigned long flags;
 
        spin_lock_irqsave(&q->lock, flags);
        if (q->head == NULL) {
@@ -114,7 +114,7 @@ static inline void smtc_ipi_req(struct smtc_ipi_q *q, struct smtc_ipi *p)
 
 static inline int smtc_ipi_qdepth(struct smtc_ipi_q *q)
 {
-       long flags;
+       unsigned long flags;
        int retval;
 
        spin_lock_irqsave(&q->lock, flags);
index fd7f5a430f0afdc91e934b0ebf54102e7559efcc..6d50310ecaea558b8ee9f93ecae44478c266bd56 100644 (file)
@@ -42,9 +42,6 @@ struct ide_machdep_calls {
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-#undef SUPPORT_SLOW_DATA_PORTS
-#define        SUPPORT_SLOW_DATA_PORTS 0
-
 #define IDE_ARCH_OBSOLETE_DEFAULTS
 
 static __inline__ int ide_default_irq(unsigned long base)
diff --git a/include/asm-s390/airq.h b/include/asm-s390/airq.h
new file mode 100644 (file)
index 0000000..41d028c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  include/asm-s390/airq.h
+ *
+ *    Copyright IBM Corp. 2002,2007
+ *    Author(s): Ingo Adlung <adlung@de.ibm.com>
+ *              Cornelia Huck <cornelia.huck@de.ibm.com>
+ *              Arnd Bergmann <arndb@de.ibm.com>
+ *              Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_AIRQ_H
+#define _ASM_S390_AIRQ_H
+
+typedef void (*adapter_int_handler_t)(void *, void *);
+
+void *s390_register_adapter_interrupt(adapter_int_handler_t, void *);
+void s390_unregister_adapter_interrupt(void *);
+
+#endif /* _ASM_S390_AIRQ_H */
index 2f08c16e44adf649b2596cf5fff833a48dbb4208..123b557c3ff4d19c29b42bd1dec2f570787cef36 100644 (file)
@@ -24,8 +24,8 @@
  * @fmt: format
  * @pfch: prefetch
  * @isic: initial-status interruption control
- * @alcc: adress-limit checking control
- * @ssi: supress-suspended interruption
+ * @alcc: address-limit checking control
+ * @ssi: suppress-suspended interruption
  * @zcc: zero condition code
  * @ectl: extended control
  * @pno: path not operational
index 604f68fa6f56d0c3974a46aa47ad34d4bccc1f2e..3f002e13d024ee5bf4481ffb4c63698fdcd2ee60 100644 (file)
@@ -105,7 +105,7 @@ typedef struct dasd_information_t {
 } dasd_information_t;
 
 /*
- * Read Subsystem Data - Perfomance Statistics
+ * Read Subsystem Data - Performance Statistics
  */ 
 typedef struct dasd_rssd_perf_stats_t {
        unsigned char  invalid:1;
index 2c40fd3a137f304afd985a58c8155abadd7dcf70..c1b2e50392bb095dcba90a0b797133eb4583e2c1 100644 (file)
@@ -83,6 +83,8 @@ extern u32 dump_prefix_page;
 extern unsigned int zfcpdump_prefix_array[];
 
 extern void do_reipl(void);
+extern void do_halt(void);
+extern void do_poff(void);
 extern void ipl_save_parameters(void);
 
 enum {
@@ -118,7 +120,7 @@ struct ipl_info
 };
 
 extern struct ipl_info ipl_info;
-extern void setup_ipl_info(void);
+extern void setup_ipl(void);
 
 /*
  * DIAG 308 support
@@ -141,6 +143,10 @@ enum diag308_opt {
        DIAG308_IPL_OPT_DUMP    = 0x20,
 };
 
+enum diag308_flags {
+       DIAG308_FLAGS_LP_VALID  = 0x80,
+};
+
 enum diag308_rc {
        DIAG308_RC_OK   = 1,
 };
index 05b842126b993295d95912c8f057f5cb182c5397..a77d4ba3c8ebc5c63ef4fbaa60104ffa6d296fc3 100644 (file)
 #include <asm/pgalloc.h>
 #include <asm-generic/mm_hooks.h>
 
-/*
- * get a new mmu context.. S390 don't know about contexts.
- */
-#define init_new_context(tsk,mm)        0
+static inline int init_new_context(struct task_struct *tsk,
+                                  struct mm_struct *mm)
+{
+       mm->context = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
+#ifdef CONFIG_64BIT
+       mm->context |= _ASCE_TYPE_REGION3;
+#endif
+       return 0;
+}
 
 #define destroy_context(mm)             do { } while (0)
 
 
 static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
 {
-       pgd_t *pgd = mm->pgd;
-       unsigned long asce_bits;
-
-       /* Calculate asce bits from the first pgd table entry. */
-       asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
-#ifdef CONFIG_64BIT
-       asce_bits |= _ASCE_TYPE_REGION3;
-#endif
-       S390_lowcore.user_asce = asce_bits | __pa(pgd);
+       S390_lowcore.user_asce = mm->context | __pa(mm->pgd);
        if (switch_amode) {
                /* Load primary space page table origin. */
-               pgd_t *shadow_pgd = get_shadow_table(pgd) ? : pgd;
-               S390_lowcore.user_exec_asce = asce_bits | __pa(shadow_pgd);
+               pgd_t *shadow_pgd = get_shadow_table(mm->pgd) ? : mm->pgd;
+               S390_lowcore.user_exec_asce = mm->context | __pa(shadow_pgd);
                asm volatile(LCTL_OPCODE" 1,1,%0\n"
                             : : "m" (S390_lowcore.user_exec_asce) );
        } else
index 1f530f8a628022f8add003100e26b25d87396f0f..79b9eab1a0c71bc25ffbee10582c1267e2aecb3e 100644 (file)
@@ -104,41 +104,27 @@ extern char empty_zero_page[PAGE_SIZE];
 
 #ifndef __ASSEMBLY__
 /*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- * vmalloc area starts at 4GB to prevent syscall table entry exchanging
- * from modules.
- */
-extern unsigned long vmalloc_end;
-
-#ifdef CONFIG_64BIT
-#define VMALLOC_ADDR   (max(0x100000000UL, (unsigned long) high_memory))
-#else
-#define VMALLOC_ADDR   ((unsigned long) high_memory)
-#endif
-#define VMALLOC_OFFSET (8*1024*1024)
-#define VMALLOC_START  ((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_END    vmalloc_end
-
-/*
- * We need some free virtual space to be able to do vmalloc.
- * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
- * area. On a machine with 2GB memory we make sure that we
- * have at least 128MB free space for vmalloc. On a machine
- * with 4TB we make sure we have at least 128GB.
+ * The vmalloc area will always be on the topmost area of the kernel
+ * mapping. We reserve 96MB (31bit) / 1GB (64bit) for vmalloc,
+ * which should be enough for any sane case.
+ * By putting vmalloc at the top, we maximise the gap between physical
+ * memory and vmalloc to catch misplaced memory accesses. As a side
+ * effect, this also makes sure that 64 bit module code cannot be used
+ * as system call address.
  */
 #ifndef __s390x__
-#define VMALLOC_MIN_SIZE       0x8000000UL
-#define VMALLOC_END_INIT       0x80000000UL
+#define VMALLOC_START  0x78000000UL
+#define VMALLOC_END    0x7e000000UL
+#define VMEM_MAP_MAX   0x80000000UL
 #else /* __s390x__ */
-#define VMALLOC_MIN_SIZE       0x2000000000UL
-#define VMALLOC_END_INIT       0x40000000000UL
+#define VMALLOC_START  0x3e000000000UL
+#define VMALLOC_END    0x3e040000000UL
+#define VMEM_MAP_MAX   0x40000000000UL
 #endif /* __s390x__ */
 
+#define VMEM_MAP       ((struct page *) VMALLOC_END)
+#define VMEM_MAP_SIZE  ((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
+
 /*
  * A 31 bit pagetable entry of S390 has following format:
  *  |   PFRA          |    |  OS  |
index 21d40a19355e75a2f1117f1ae5b47a25d94686b8..c86b982aef5a6bb9ebce57a008617443555084f8 100644 (file)
@@ -59,9 +59,6 @@ extern void s390_adjust_jiffies(void);
 extern void print_cpu_info(struct cpuinfo_S390 *);
 extern int get_cpu_capability(unsigned int *);
 
-/* Lazy FPU handling on uni-processor */
-extern struct task_struct *last_task_used_math;
-
 /*
  * User space process size: 2GB for 31 bit, 4TB for 64 bit.
  */
@@ -95,7 +92,6 @@ struct thread_struct {
         unsigned long ksp;              /* kernel stack pointer             */
        mm_segment_t mm_segment;
         unsigned long prot_addr;        /* address of protection-excep.     */
-        unsigned int error_code;        /* error-code of last prog-excep.   */
         unsigned int trap_no;
         per_struct per_info;
        /* Used to give failing instruction back to user for ieee exceptions */
index 332ee73688fc183ab5fbd60cd722a90b5b3ed50a..61f6952f2e357e2b76f442994b91aa55c55e596f 100644 (file)
@@ -465,6 +465,14 @@ struct user_regs_struct
 #ifdef __KERNEL__
 #define __ARCH_SYS_PTRACE      1
 
+/*
+ * These are defined as per linux/ptrace.h, which see.
+ */
+#define arch_has_single_step() (1)
+struct task_struct;
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
 #define regs_return_value(regs)((regs)->gprs[2])
index 74db1dc10a7d60043a182333a5c815a3187a9000..4b8ff55f680e4d6e26183d2da148c545054116d6 100644 (file)
@@ -184,7 +184,7 @@ struct qdr {
 #endif /* QDIO_32_BIT */
        unsigned long qiba;             /* queue-information-block address */
        unsigned int  res8;             /* reserved */
-       unsigned int  qkey    :  4;     /* queue-informatio-block key */
+       unsigned int  qkey    :  4;     /* queue-information-block key */
        unsigned int  res9    : 28;     /* reserved */
 /*     union _qd {*/ /* why this? */
                struct qdesfmt0 qdf0[126];
index 90f4eccaa290eb936de85dca4a6e96825f5e20bf..9d2a179718056758304a194ff67766be5a5b72ce 100644 (file)
@@ -91,8 +91,8 @@ struct rw_semaphore {
 #endif
 
 #define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
-  __RWSEM_DEP_MAP_INIT(name) }
+ { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
+   LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
 
 #define DECLARE_RWSEM(name) \
        struct rw_semaphore name = __RWSEM_INITIALIZER(name)
index cb9faf1ea5cfd5db60a602e45af058bceddc06f2..b5f2843013a346902741fe2cfa8031ff4f3e8ea7 100644 (file)
@@ -27,7 +27,25 @@ struct sclp_ipl_info {
        char loadparm[LOADPARM_LEN];
 };
 
-void sclp_readinfo_early(void);
+struct sclp_cpu_entry {
+       u8 address;
+       u8 reserved0[13];
+       u8 type;
+       u8 reserved1;
+} __attribute__((packed));
+
+struct sclp_cpu_info {
+       unsigned int configured;
+       unsigned int standby;
+       unsigned int combined;
+       int has_cpu_type;
+       struct sclp_cpu_entry cpu[255];
+};
+
+int sclp_get_cpu_info(struct sclp_cpu_info *info);
+int sclp_cpu_configure(u8 cpu);
+int sclp_cpu_deconfigure(u8 cpu);
+void sclp_read_info_early(void);
 void sclp_facilities_detect(void);
 unsigned long long sclp_memory_detect(void);
 int sclp_sdias_blk_count(void);
index 07708c07701e434f9ddaa905864045efe32c07a6..c7b74326a527b15eaa059cca78bdbe1fb4b57d69 100644 (file)
@@ -35,8 +35,6 @@ extern void machine_restart_smp(char *);
 extern void machine_halt_smp(void);
 extern void machine_power_off_smp(void);
 
-extern void smp_setup_cpu_possible_map(void);
-
 #define NO_PROC_ID             0xFF            /* No processor magic marker */
 
 /*
@@ -92,6 +90,8 @@ extern void __cpu_die (unsigned int cpu);
 extern void cpu_die (void) __attribute__ ((noreturn));
 extern int __cpu_up (unsigned int cpu);
 
+extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+       void *info, int wait);
 #endif
 
 #ifndef CONFIG_SMP
@@ -103,7 +103,6 @@ static inline void smp_send_stop(void)
 
 #define hard_smp_processor_id()                0
 #define smp_cpu_not_running(cpu)       1
-#define smp_setup_cpu_possible_map()   do { } while (0)
 #endif
 
 extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
index 3fd43826fd0bf864a94bb307b86354b358d280bd..df84ae96915f5342b4f86a76d0ac09651e12c4bd 100644 (file)
@@ -53,44 +53,48 @@ _raw_compare_and_swap(volatile unsigned int *lock,
  */
 
 #define __raw_spin_is_locked(x) ((x)->owner_cpu != 0)
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
 #define __raw_spin_unlock_wait(lock) \
        do { while (__raw_spin_is_locked(lock)) \
                 _raw_spin_relax(lock); } while (0)
 
-extern void _raw_spin_lock_wait(raw_spinlock_t *, unsigned int pc);
-extern int _raw_spin_trylock_retry(raw_spinlock_t *, unsigned int pc);
+extern void _raw_spin_lock_wait(raw_spinlock_t *);
+extern void _raw_spin_lock_wait_flags(raw_spinlock_t *, unsigned long flags);
+extern int _raw_spin_trylock_retry(raw_spinlock_t *);
 extern void _raw_spin_relax(raw_spinlock_t *lock);
 
 static inline void __raw_spin_lock(raw_spinlock_t *lp)
 {
-       unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
        int old;
 
        old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-       if (likely(old == 0)) {
-               lp->owner_pc = pc;
+       if (likely(old == 0))
                return;
-       }
-       _raw_spin_lock_wait(lp, pc);
+       _raw_spin_lock_wait(lp);
+}
+
+static inline void __raw_spin_lock_flags(raw_spinlock_t *lp,
+                                        unsigned long flags)
+{
+       int old;
+
+       old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
+       if (likely(old == 0))
+               return;
+       _raw_spin_lock_wait_flags(lp, flags);
 }
 
 static inline int __raw_spin_trylock(raw_spinlock_t *lp)
 {
-       unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
        int old;
 
        old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-       if (likely(old == 0)) {
-               lp->owner_pc = pc;
+       if (likely(old == 0))
                return 1;
-       }
-       return _raw_spin_trylock_retry(lp, pc);
+       return _raw_spin_trylock_retry(lp);
 }
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lp)
 {
-       lp->owner_pc = 0;
        _raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
 }
                
index b7ac13f7aa373e0c2c21412579d9e0f5f3215103..654abc40de04a7b7729e3802b9d9b86244982da2 100644 (file)
@@ -7,7 +7,6 @@
 
 typedef struct {
        volatile unsigned int owner_cpu;
-       volatile unsigned int owner_pc;
 } __attribute__ ((aligned (4))) raw_spinlock_t;
 
 #define __RAW_SPIN_LOCK_UNLOCKED       { 0 }
index a69bd2490d52ceeb1af02f94dd0ba40eb958c593..70fa5ae581801b8a112edc0f71dfc9c9770ed83b 100644 (file)
@@ -42,11 +42,11 @@ static inline void __tlb_flush_global(void)
 /*
  * Flush all tlb entries of a page table on all cpus.
  */
-static inline void __tlb_flush_idte(pgd_t *pgd)
+static inline void __tlb_flush_idte(unsigned long asce)
 {
        asm volatile(
                "       .insn   rrf,0xb98e0000,0,%0,%1,0"
-               : : "a" (2048), "a" (__pa(pgd) & PAGE_MASK) : "cc" );
+               : : "a" (2048), "a" (asce) : "cc" );
 }
 
 static inline void __tlb_flush_mm(struct mm_struct * mm)
@@ -61,11 +61,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
         * only ran on the local cpu.
         */
        if (MACHINE_HAS_IDTE) {
-               pgd_t *shadow_pgd = get_shadow_table(mm->pgd);
+               pgd_t *shadow = get_shadow_table(mm->pgd);
 
-               if (shadow_pgd)
-                       __tlb_flush_idte(shadow_pgd);
-               __tlb_flush_idte(mm->pgd);
+               if (shadow)
+                       __tlb_flush_idte((unsigned long) shadow | mm->context);
+               __tlb_flush_idte((unsigned long) mm->pgd | mm->context);
                return;
        }
        preempt_disable();
@@ -106,9 +106,23 @@ static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
  */
 #define flush_tlb()                            do { } while (0)
 #define flush_tlb_all()                                do { } while (0)
-#define flush_tlb_mm(mm)                       __tlb_flush_mm_cond(mm)
 #define flush_tlb_page(vma, addr)              do { } while (0)
-#define flush_tlb_range(vma, start, end)       __tlb_flush_mm_cond(mm)
-#define flush_tlb_kernel_range(start, end)     __tlb_flush_mm(&init_mm)
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       __tlb_flush_mm_cond(mm);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+                                  unsigned long start, unsigned long end)
+{
+       __tlb_flush_mm_cond(vma->vm_mm);
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+                                         unsigned long end)
+{
+       __tlb_flush_mm(&init_mm);
+}
 
 #endif /* _S390_TLBFLUSH_H */
index a5dada6177514fc650ea27a5cdf556d6702e233c..f228f1b86877feabca366cb1db8a8dec1930b6d6 100644 (file)
@@ -117,7 +117,7 @@ struct CPRBX {
        unsigned char   padx004[16 - sizeof (char *)];
        unsigned char * req_extb;       /* request extension block 'addr'*/
        unsigned char   padx005[16 - sizeof (char *)];
-       unsigned char * rpl_extb;       /* reply extension block 'addres'*/
+       unsigned char * rpl_extb;       /* reply extension block 'address'*/
        unsigned short  ccp_rtcode;     /* server return code            */
        unsigned short  ccp_rscode;     /* server reason code            */
        unsigned int    mac_data_len;   /* Mac Data Length               */
index 9d528ada3c148615b6e09371aacaced7fdfcc867..e034c3604111b2ac99ffda62cd05bb6a88831381 100644 (file)
@@ -43,6 +43,12 @@ extern void __flush_purge_region(void *start, int size);
 extern void __flush_invalidate_region(void *start, int size);
 #endif
 
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+static inline void flush_kernel_dcache_page(struct page *page)
+{
+       flush_dcache_page(page);
+}
+
 #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_CACHE_OFF)
 extern void copy_to_user_page(struct vm_area_struct *vma,
        struct page *page, unsigned long vaddr, void *dst, const void *src,
index f18a1a5c95c0ad4856685ab050d71a48b8cf5081..77c391fa93d6380b1f25996a692dc77ca5af66dc 100644 (file)
@@ -73,38 +73,26 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
 /*
  * __access_ok: Check if address with size is OK or not.
  *
- * We do three checks:
- * (1) is it user space?
- * (2) addr + size --> carry?
- * (3) addr + size >= 0x80000000  (PAGE_OFFSET)
+ * Uhhuh, this needs 33-bit arithmetic. We have a carry..
  *
- * (1) (2) (3) | RESULT
- *  0   0   0  |  ok
- *  0   0   1  |  ok
- *  0   1   0  |  bad
- *  0   1   1  |  bad
- *  1   0   0  |  ok
- *  1   0   1  |  bad
- *  1   1   0  |  bad
- *  1   1   1  |  bad
+ * sum := addr + size;  carry? --> flag = true;
+ * if (sum >= addr_limit) flag = true;
  */
 static inline int __access_ok(unsigned long addr, unsigned long size)
 {
-       unsigned long flag, tmp;
-
-       __asm__("stc    r7_bank, %0\n\t"
-               "mov.l  @(8,%0), %0\n\t"
-               "clrt\n\t"
-               "addc   %2, %1\n\t"
-               "and    %1, %0\n\t"
-               "rotcl  %0\n\t"
-               "rotcl  %0\n\t"
-               "and    #3, %0"
-               : "=&z" (flag), "=r" (tmp)
-               : "r" (addr), "1" (size)
-               : "t");
-
+       unsigned long flag, sum;
+
+       __asm__("clrt\n\t"
+               "addc   %3, %1\n\t"
+               "movt   %0\n\t"
+               "cmp/hi %4, %1\n\t"
+               "rotcl  %0"
+               :"=&r" (flag), "=r" (sum)
+               :"1" (addr), "r" (size),
+                "r" (current_thread_info()->addr_limit.seg)
+               :"t");
        return flag == 0;
+
 }
 #endif /* CONFIG_MMU */
 
index 1f2d6d5bf20dd7659b38365982d781534f6e6a8c..fe2f2e5d51baf2bbe66e649c88d5de1713b56c42 100644 (file)
@@ -30,13 +30,13 @@ static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 val)
        } v;
        v.u = val;
 #ifdef CONFIG_X86_BSWAP
-       asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1"
+       __asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1"
            : "=r" (v.s.a), "=r" (v.s.b)
            : "0" (v.s.a), "1" (v.s.b));
 #else
        v.s.a = ___arch__swab32(v.s.a);
        v.s.b = ___arch__swab32(v.s.b);
-       asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b));
+       __asm__("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b));
 #endif
        return v.u;
 }
index ba4b3143212073bdfa1190158b130f63bde9906e..80b027081b3ce54ffc009e104250283cec5efdda 100644 (file)
@@ -3,6 +3,10 @@
 
 #include <asm/msr-index.h>
 
+#ifndef __ASSEMBLY__
+# include <linux/types.h>
+#endif
+
 #ifdef __i386__
 
 #ifdef __KERNEL__
@@ -191,38 +195,6 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
 
 #define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32)
 
-/* wrmsr with exception handling */
-#define wrmsr_safe(msr,a,b) ({ int ret__;                      \
-       asm volatile("2: wrmsr ; xorl %0,%0\n"                  \
-                    "1:\n\t"                                   \
-                    ".section .fixup,\"ax\"\n\t"               \
-                    "3:  movl %4,%0 ; jmp 1b\n\t"              \
-                    ".previous\n\t"                            \
-                    ".section __ex_table,\"a\"\n"              \
-                    "   .align 8\n\t"                          \
-                    "   .quad  2b,3b\n\t"                      \
-                    ".previous"                                \
-                    : "=a" (ret__)                             \
-                    : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \
-       ret__; })
-
-#define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
-
-#define rdmsr_safe(msr,a,b) \
-       ({ int ret__;                                           \
-         asm volatile ("1:       rdmsr\n"                      \
-                       "2:\n"                                  \
-                       ".section .fixup,\"ax\"\n"              \
-                       "3:       movl %4,%0\n"                 \
-                       " jmp 2b\n"                             \
-                       ".previous\n"                           \
-                       ".section __ex_table,\"a\"\n"           \
-                       " .align 8\n"                           \
-                       " .quad 1b,3b\n"                                \
-                       ".previous":"=&bDS" (ret__), "=a"(*(a)), "=d"(*(b)) \
-                       :"c"(msr), "i"(-EIO), "0"(0));                  \
-         ret__; })
-
 #define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
 
@@ -230,17 +202,17 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
      __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
 
 #define rdtscp(low,high,aux) \
-     asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (low), "=d" (high), "=c" (aux))
+     __asm__ __volatile__ (".byte 0x0f,0x01,0xf9" : "=a" (low), "=d" (high), "=c" (aux))
 
 #define rdtscll(val) do { \
      unsigned int __a,__d; \
-     asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
+     __asm__ __volatile__("rdtsc" : "=a" (__a), "=d" (__d)); \
      (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
 } while(0)
 
 #define rdtscpll(val, aux) do { \
      unsigned long __a, __d; \
-     asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (__a), "=d" (__d), "=c" (aux)); \
+     __asm__ __volatile__ (".byte 0x0f,0x01,0xf9" : "=a" (__a), "=d" (__d), "=c" (aux)); \
      (val) = (__d << 32) | __a; \
 } while (0)
 
@@ -253,6 +225,7 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
                          : "=a" (low), "=d" (high) \
                          : "c" (counter))
 
+
 static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx,
                         unsigned int *ecx, unsigned int *edx)
 {
@@ -320,6 +293,40 @@ static inline unsigned int cpuid_edx(unsigned int op)
        return edx;
 }
 
+#ifdef __KERNEL__
+
+/* wrmsr with exception handling */
+#define wrmsr_safe(msr,a,b) ({ int ret__;                      \
+       asm volatile("2: wrmsr ; xorl %0,%0\n"                  \
+                    "1:\n\t"                                   \
+                    ".section .fixup,\"ax\"\n\t"               \
+                    "3:  movl %4,%0 ; jmp 1b\n\t"              \
+                    ".previous\n\t"                            \
+                    ".section __ex_table,\"a\"\n"              \
+                    "   .align 8\n\t"                          \
+                    "   .quad  2b,3b\n\t"                      \
+                    ".previous"                                \
+                    : "=a" (ret__)                             \
+                    : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \
+       ret__; })
+
+#define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
+
+#define rdmsr_safe(msr,a,b) \
+       ({ int ret__;                                           \
+         asm volatile ("1:       rdmsr\n"                      \
+                       "2:\n"                                  \
+                       ".section .fixup,\"ax\"\n"              \
+                       "3:       movl %4,%0\n"                 \
+                       " jmp 2b\n"                             \
+                       ".previous\n"                           \
+                       ".section __ex_table,\"a\"\n"           \
+                       " .align 8\n"                           \
+                       " .quad 1b,3b\n"                                \
+                       ".previous":"=&bDS" (ret__), "=a"(*(a)), "=d"(*(b)) \
+                       :"c"(msr), "i"(-EIO), "0"(0));                  \
+         ret__; })
+
 #ifdef CONFIG_SMP
 void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
@@ -343,6 +350,7 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
        return wrmsr_safe(msr_no, l, h);
 }
 #endif  /* CONFIG_SMP */
+#endif  /* __KERNEL__ */
 #endif  /* __ASSEMBLY__ */
 
 #endif  /* !__i386__ */
index 22a8cbcd35e2f11b8446ef2b71179efbaf8291ab..ef58fd2a6eb089f49086f1dfec56d451af127f8b 100644 (file)
@@ -132,6 +132,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_AUDIT      6       /* syscall auditing active */
 #define TIF_SECCOMP            7       /* secure computing */
 #define TIF_RESTORE_SIGMASK    8       /* restore signal mask in do_signal() */
+#define TIF_HRTICK_RESCHED     9       /* reprogram hrtick timer */
 #define TIF_MEMDIE             16
 #define TIF_DEBUG              17      /* uses debug registers */
 #define TIF_IO_BITMAP          18      /* uses I/O bitmap */
@@ -147,6 +148,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_HRTICK_RESCHED    (1<<TIF_HRTICK_RESCHED)
 #define _TIF_DEBUG             (1<<TIF_DEBUG)
 #define _TIF_IO_BITMAP         (1<<TIF_IO_BITMAP)
 #define _TIF_FREEZE            (1<<TIF_FREEZE)
index beae2bfb62cacdc7aa6705be207a59b11edea1ae..7f6ee68f000203d17a6ee747e6df85a55535053b 100644 (file)
@@ -115,6 +115,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define TIF_SECCOMP            8       /* secure computing */
 #define TIF_RESTORE_SIGMASK    9       /* restore signal mask in do_signal */
 #define TIF_MCE_NOTIFY         10      /* notify userspace of an MCE */
+#define TIF_HRTICK_RESCHED     11      /* reprogram hrtick timer */
 /* 16 free */
 #define TIF_IA32               17      /* 32bit process */ 
 #define TIF_FORK               18      /* ret_from_fork */
@@ -133,6 +134,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_MCE_NOTIFY                (1<<TIF_MCE_NOTIFY)
+#define _TIF_HRTICK_RESCHED    (1<<TIF_HRTICK_RESCHED)
 #define _TIF_IA32              (1<<TIF_IA32)
 #define _TIF_FORK              (1<<TIF_FORK)
 #define _TIF_ABI_PENDING       (1<<TIF_ABI_PENDING)
@@ -146,6 +148,9 @@ static inline struct thread_info *stack_thread_info(void)
 /* work to do on any return to user space */
 #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
 
+#define _TIF_DO_NOTIFY_MASK \
+       (_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY|_TIF_HRTICK_RESCHED)
+
 /* flags to check in __switch_to() */
 #define _TIF_WORK_CTXSW (_TIF_DEBUG|_TIF_IO_BITMAP)
 
diff --git a/include/crypto/aead.h b/include/crypto/aead.h
new file mode 100644 (file)
index 0000000..0edf949
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * AEAD: Authenticated Encryption with Associated Data
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_AEAD_H
+#define _CRYPTO_AEAD_H
+
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+/**
+ *     struct aead_givcrypt_request - AEAD request with IV generation
+ *     @seq: Sequence number for IV generation
+ *     @giv: Space for generated IV
+ *     @areq: The AEAD request itself
+ */
+struct aead_givcrypt_request {
+       u64 seq;
+       u8 *giv;
+
+       struct aead_request areq;
+};
+
+static inline struct crypto_aead *aead_givcrypt_reqtfm(
+       struct aead_givcrypt_request *req)
+{
+       return crypto_aead_reqtfm(&req->areq);
+}
+
+static inline int crypto_aead_givencrypt(struct aead_givcrypt_request *req)
+{
+       struct aead_tfm *crt = crypto_aead_crt(aead_givcrypt_reqtfm(req));
+       return crt->givencrypt(req);
+};
+
+static inline int crypto_aead_givdecrypt(struct aead_givcrypt_request *req)
+{
+       struct aead_tfm *crt = crypto_aead_crt(aead_givcrypt_reqtfm(req));
+       return crt->givdecrypt(req);
+};
+
+static inline void aead_givcrypt_set_tfm(struct aead_givcrypt_request *req,
+                                        struct crypto_aead *tfm)
+{
+       req->areq.base.tfm = crypto_aead_tfm(tfm);
+}
+
+static inline struct aead_givcrypt_request *aead_givcrypt_alloc(
+       struct crypto_aead *tfm, gfp_t gfp)
+{
+       struct aead_givcrypt_request *req;
+
+       req = kmalloc(sizeof(struct aead_givcrypt_request) +
+                     crypto_aead_reqsize(tfm), gfp);
+
+       if (likely(req))
+               aead_givcrypt_set_tfm(req, tfm);
+
+       return req;
+}
+
+static inline void aead_givcrypt_free(struct aead_givcrypt_request *req)
+{
+       kfree(req);
+}
+
+static inline void aead_givcrypt_set_callback(
+       struct aead_givcrypt_request *req, u32 flags,
+       crypto_completion_t complete, void *data)
+{
+       aead_request_set_callback(&req->areq, flags, complete, data);
+}
+
+static inline void aead_givcrypt_set_crypt(struct aead_givcrypt_request *req,
+                                          struct scatterlist *src,
+                                          struct scatterlist *dst,
+                                          unsigned int nbytes, void *iv)
+{
+       aead_request_set_crypt(&req->areq, src, dst, nbytes, iv);
+}
+
+static inline void aead_givcrypt_set_assoc(struct aead_givcrypt_request *req,
+                                          struct scatterlist *assoc,
+                                          unsigned int assoclen)
+{
+       aead_request_set_assoc(&req->areq, assoc, assoclen);
+}
+
+static inline void aead_givcrypt_set_giv(struct aead_givcrypt_request *req,
+                                        u8 *giv, u64 seq)
+{
+       req->giv = giv;
+       req->seq = seq;
+}
+
+#endif /* _CRYPTO_AEAD_H */
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
new file mode 100644 (file)
index 0000000..d480b76
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Common values for AES algorithms
+ */
+
+#ifndef _CRYPTO_AES_H
+#define _CRYPTO_AES_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define AES_MIN_KEY_SIZE       16
+#define AES_MAX_KEY_SIZE       32
+#define AES_KEYSIZE_128                16
+#define AES_KEYSIZE_192                24
+#define AES_KEYSIZE_256                32
+#define AES_BLOCK_SIZE         16
+
+struct crypto_aes_ctx {
+       u32 key_length;
+       u32 key_enc[60];
+       u32 key_dec[60];
+};
+
+extern u32 crypto_ft_tab[4][256];
+extern u32 crypto_fl_tab[4][256];
+extern u32 crypto_it_tab[4][256];
+extern u32 crypto_il_tab[4][256];
+
+int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+               unsigned int key_len);
+#endif
index b9b05d399d2b49bbbe304fbb608336db94d58784..60d06e784be3aa54464c0263e4611c087cc0a17c 100644 (file)
@@ -111,8 +111,15 @@ void crypto_drop_spawn(struct crypto_spawn *spawn);
 struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
                                    u32 mask);
 
+static inline void crypto_set_spawn(struct crypto_spawn *spawn,
+                                   struct crypto_instance *inst)
+{
+       spawn->inst = inst;
+}
+
 struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
 int crypto_check_attr_type(struct rtattr **tb, u32 type);
+const char *crypto_attr_alg_name(struct rtattr *rta);
 struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask);
 int crypto_attr_u32(struct rtattr *rta, u32 *num);
 struct crypto_instance *crypto_alloc_instance(const char *name,
@@ -124,6 +131,10 @@ int crypto_enqueue_request(struct crypto_queue *queue,
 struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
 int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);
 
+/* These functions require the input/output to be aligned as u32. */
+void crypto_inc(u8 *a, unsigned int size);
+void crypto_xor(u8 *dst, const u8 *src, unsigned int size);
+
 int blkcipher_walk_done(struct blkcipher_desc *desc,
                        struct blkcipher_walk *walk, int err);
 int blkcipher_walk_virt(struct blkcipher_desc *desc,
@@ -187,20 +198,11 @@ static inline struct crypto_instance *crypto_aead_alg_instance(
        return crypto_tfm_alg_instance(&aead->base);
 }
 
-static inline struct crypto_ablkcipher *crypto_spawn_ablkcipher(
-       struct crypto_spawn *spawn)
-{
-       u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
-       u32 mask = CRYPTO_ALG_TYPE_MASK;
-
-       return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
-}
-
 static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
        struct crypto_spawn *spawn)
 {
        u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
-       u32 mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+       u32 mask = CRYPTO_ALG_TYPE_MASK;
 
        return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
 }
@@ -303,5 +305,14 @@ static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb,
        return crypto_attr_alg(tb[1], type, mask);
 }
 
+/*
+ * Returns CRYPTO_ALG_ASYNC if type/mask requires the use of sync algorithms.
+ * Otherwise returns zero.
+ */
+static inline int crypto_requires_sync(u32 type, u32 mask)
+{
+       return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC;
+}
+
 #endif /* _CRYPTO_ALGAPI_H */
 
diff --git a/include/crypto/authenc.h b/include/crypto/authenc.h
new file mode 100644 (file)
index 0000000..e47b044
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Authenc: Simple AEAD wrapper for IPsec
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#ifndef _CRYPTO_AUTHENC_H
+#define _CRYPTO_AUTHENC_H
+
+#include <linux/types.h>
+
+enum {
+       CRYPTO_AUTHENC_KEYA_UNSPEC,
+       CRYPTO_AUTHENC_KEYA_PARAM,
+};
+
+struct crypto_authenc_key_param {
+       __be32 enckeylen;
+};
+
+#endif /* _CRYPTO_AUTHENC_H */
+
diff --git a/include/crypto/ctr.h b/include/crypto/ctr.h
new file mode 100644 (file)
index 0000000..4180fc0
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * CTR: Counter mode
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_CTR_H
+#define _CRYPTO_CTR_H
+
+#define CTR_RFC3686_NONCE_SIZE 4
+#define CTR_RFC3686_IV_SIZE 8
+#define CTR_RFC3686_BLOCK_SIZE 16
+
+#endif  /* _CRYPTO_CTR_H */
diff --git a/include/crypto/des.h b/include/crypto/des.h
new file mode 100644 (file)
index 0000000..2971c63
--- /dev/null
@@ -0,0 +1,19 @@
+/* 
+ * DES & Triple DES EDE Cipher Algorithms.
+ */
+
+#ifndef __CRYPTO_DES_H
+#define __CRYPTO_DES_H
+
+#define DES_KEY_SIZE           8
+#define DES_EXPKEY_WORDS       32
+#define DES_BLOCK_SIZE         8
+
+#define DES3_EDE_KEY_SIZE      (3 * DES_KEY_SIZE)
+#define DES3_EDE_EXPKEY_WORDS  (3 * DES_EXPKEY_WORDS)
+#define DES3_EDE_BLOCK_SIZE    DES_BLOCK_SIZE
+
+
+extern unsigned long des_ekey(u32 *pe, const u8 *k);
+
+#endif /* __CRYPTO_DES_H */
diff --git a/include/crypto/internal/aead.h b/include/crypto/internal/aead.h
new file mode 100644 (file)
index 0000000..d838c94
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * AEAD: Authenticated Encryption with Associated Data
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_INTERNAL_AEAD_H
+#define _CRYPTO_INTERNAL_AEAD_H
+
+#include <crypto/aead.h>
+#include <crypto/algapi.h>
+#include <linux/types.h>
+
+struct rtattr;
+
+struct crypto_aead_spawn {
+       struct crypto_spawn base;
+};
+
+extern const struct crypto_type crypto_nivaead_type;
+
+static inline void crypto_set_aead_spawn(
+       struct crypto_aead_spawn *spawn, struct crypto_instance *inst)
+{
+       crypto_set_spawn(&spawn->base, inst);
+}
+
+int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
+                    u32 type, u32 mask);
+
+static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn)
+{
+       crypto_drop_spawn(&spawn->base);
+}
+
+static inline struct crypto_alg *crypto_aead_spawn_alg(
+       struct crypto_aead_spawn *spawn)
+{
+       return spawn->base.alg;
+}
+
+static inline struct crypto_aead *crypto_spawn_aead(
+       struct crypto_aead_spawn *spawn)
+{
+       return __crypto_aead_cast(
+               crypto_spawn_tfm(&spawn->base, CRYPTO_ALG_TYPE_AEAD,
+                                CRYPTO_ALG_TYPE_MASK));
+}
+
+struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
+                                        struct rtattr **tb, u32 type,
+                                        u32 mask);
+void aead_geniv_free(struct crypto_instance *inst);
+int aead_geniv_init(struct crypto_tfm *tfm);
+void aead_geniv_exit(struct crypto_tfm *tfm);
+
+static inline struct crypto_aead *aead_geniv_base(struct crypto_aead *geniv)
+{
+       return crypto_aead_crt(geniv)->base;
+}
+
+static inline void *aead_givcrypt_reqctx(struct aead_givcrypt_request *req)
+{
+       return aead_request_ctx(&req->areq);
+}
+
+static inline void aead_givcrypt_complete(struct aead_givcrypt_request *req,
+                                         int err)
+{
+       aead_request_complete(&req->areq, err);
+}
+
+#endif /* _CRYPTO_INTERNAL_AEAD_H */
+
diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
new file mode 100644 (file)
index 0000000..2ba42cd
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Symmetric key ciphers.
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_INTERNAL_SKCIPHER_H
+#define _CRYPTO_INTERNAL_SKCIPHER_H
+
+#include <crypto/algapi.h>
+#include <crypto/skcipher.h>
+#include <linux/types.h>
+
+struct rtattr;
+
+struct crypto_skcipher_spawn {
+       struct crypto_spawn base;
+};
+
+extern const struct crypto_type crypto_givcipher_type;
+
+static inline void crypto_set_skcipher_spawn(
+       struct crypto_skcipher_spawn *spawn, struct crypto_instance *inst)
+{
+       crypto_set_spawn(&spawn->base, inst);
+}
+
+int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
+                        u32 type, u32 mask);
+
+static inline void crypto_drop_skcipher(struct crypto_skcipher_spawn *spawn)
+{
+       crypto_drop_spawn(&spawn->base);
+}
+
+static inline struct crypto_alg *crypto_skcipher_spawn_alg(
+       struct crypto_skcipher_spawn *spawn)
+{
+       return spawn->base.alg;
+}
+
+static inline struct crypto_ablkcipher *crypto_spawn_skcipher(
+       struct crypto_skcipher_spawn *spawn)
+{
+       return __crypto_ablkcipher_cast(
+               crypto_spawn_tfm(&spawn->base, crypto_skcipher_type(0),
+                                crypto_skcipher_mask(0)));
+}
+
+int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req);
+int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req);
+const char *crypto_default_geniv(const struct crypto_alg *alg);
+
+struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl,
+                                            struct rtattr **tb, u32 type,
+                                            u32 mask);
+void skcipher_geniv_free(struct crypto_instance *inst);
+int skcipher_geniv_init(struct crypto_tfm *tfm);
+void skcipher_geniv_exit(struct crypto_tfm *tfm);
+
+static inline struct crypto_ablkcipher *skcipher_geniv_cipher(
+       struct crypto_ablkcipher *geniv)
+{
+       return crypto_ablkcipher_crt(geniv)->base;
+}
+
+static inline int skcipher_enqueue_givcrypt(
+       struct crypto_queue *queue, struct skcipher_givcrypt_request *request)
+{
+       return ablkcipher_enqueue_request(queue, &request->creq);
+}
+
+static inline struct skcipher_givcrypt_request *skcipher_dequeue_givcrypt(
+       struct crypto_queue *queue)
+{
+       return container_of(ablkcipher_dequeue_request(queue),
+                           struct skcipher_givcrypt_request, creq);
+}
+
+static inline void *skcipher_givcrypt_reqctx(
+       struct skcipher_givcrypt_request *req)
+{
+       return ablkcipher_request_ctx(&req->creq);
+}
+
+static inline void ablkcipher_request_complete(struct ablkcipher_request *req,
+                                              int err)
+{
+       req->base.complete(&req->base, err);
+}
+
+static inline void skcipher_givcrypt_complete(
+       struct skcipher_givcrypt_request *req, int err)
+{
+       ablkcipher_request_complete(&req->creq, err);
+}
+
+static inline u32 ablkcipher_request_flags(struct ablkcipher_request *req)
+{
+       return req->base.flags;
+}
+
+#endif /* _CRYPTO_INTERNAL_SKCIPHER_H */
+
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
new file mode 100644 (file)
index 0000000..224658b
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Cryptographic scatter and gather helpers.
+ *
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com>
+ * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_SCATTERWALK_H
+#define _CRYPTO_SCATTERWALK_H
+
+#include <asm/kmap_types.h>
+#include <crypto/algapi.h>
+#include <linux/hardirq.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+
+static inline enum km_type crypto_kmap_type(int out)
+{
+       enum km_type type;
+
+       if (in_softirq())
+               type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0;
+       else
+               type = out * (KM_USER1 - KM_USER0) + KM_USER0;
+
+       return type;
+}
+
+static inline void *crypto_kmap(struct page *page, int out)
+{
+       return kmap_atomic(page, crypto_kmap_type(out));
+}
+
+static inline void crypto_kunmap(void *vaddr, int out)
+{
+       kunmap_atomic(vaddr, crypto_kmap_type(out));
+}
+
+static inline void crypto_yield(u32 flags)
+{
+       if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
+               cond_resched();
+}
+
+static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num,
+                                       struct scatterlist *sg2)
+{
+       sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
+}
+
+static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
+{
+       return (++sg)->length ? sg : (void *)sg_page(sg);
+}
+
+static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
+                                               struct scatter_walk *walk_out)
+{
+       return !(((sg_page(walk_in->sg) - sg_page(walk_out->sg)) << PAGE_SHIFT) +
+                (int)(walk_in->offset - walk_out->offset));
+}
+
+static inline unsigned int scatterwalk_pagelen(struct scatter_walk *walk)
+{
+       unsigned int len = walk->sg->offset + walk->sg->length - walk->offset;
+       unsigned int len_this_page = offset_in_page(~walk->offset) + 1;
+       return len_this_page > len ? len : len_this_page;
+}
+
+static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk,
+                                            unsigned int nbytes)
+{
+       unsigned int len_this_page = scatterwalk_pagelen(walk);
+       return nbytes > len_this_page ? len_this_page : nbytes;
+}
+
+static inline void scatterwalk_advance(struct scatter_walk *walk,
+                                      unsigned int nbytes)
+{
+       walk->offset += nbytes;
+}
+
+static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk,
+                                              unsigned int alignmask)
+{
+       return !(walk->offset & alignmask);
+}
+
+static inline struct page *scatterwalk_page(struct scatter_walk *walk)
+{
+       return sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
+}
+
+static inline void scatterwalk_unmap(void *vaddr, int out)
+{
+       crypto_kunmap(vaddr, out);
+}
+
+void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
+void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
+                           size_t nbytes, int out);
+void *scatterwalk_map(struct scatter_walk *walk, int out);
+void scatterwalk_done(struct scatter_walk *walk, int out, int more);
+
+void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
+                             unsigned int start, unsigned int nbytes, int out);
+
+#endif  /* _CRYPTO_SCATTERWALK_H */
index 0686e1f7a24b0375a421af0cf79da7288f56fdee..c0ccc2b1a2d82eb21d2b34cfa2eb292297c2dd56 100644 (file)
@@ -8,6 +8,9 @@
 #define SHA1_DIGEST_SIZE        20
 #define SHA1_BLOCK_SIZE         64
 
+#define SHA224_DIGEST_SIZE     28
+#define SHA224_BLOCK_SIZE      64
+
 #define SHA256_DIGEST_SIZE      32
 #define SHA256_BLOCK_SIZE       64
 
 #define SHA1_H3                0x10325476UL
 #define SHA1_H4                0xc3d2e1f0UL
 
+#define SHA224_H0      0xc1059ed8UL
+#define SHA224_H1      0x367cd507UL
+#define SHA224_H2      0x3070dd17UL
+#define SHA224_H3      0xf70e5939UL
+#define SHA224_H4      0xffc00b31UL
+#define SHA224_H5      0x68581511UL
+#define SHA224_H6      0x64f98fa7UL
+#define SHA224_H7      0xbefa4fa4UL
+
 #define SHA256_H0      0x6a09e667UL
 #define SHA256_H1      0xbb67ae85UL
 #define SHA256_H2      0x3c6ef372UL
diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h
new file mode 100644 (file)
index 0000000..25fd612
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Symmetric key ciphers.
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_SKCIPHER_H
+#define _CRYPTO_SKCIPHER_H
+
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+/**
+ *     struct skcipher_givcrypt_request - Crypto request with IV generation
+ *     @seq: Sequence number for IV generation
+ *     @giv: Space for generated IV
+ *     @creq: The crypto request itself
+ */
+struct skcipher_givcrypt_request {
+       u64 seq;
+       u8 *giv;
+
+       struct ablkcipher_request creq;
+};
+
+static inline struct crypto_ablkcipher *skcipher_givcrypt_reqtfm(
+       struct skcipher_givcrypt_request *req)
+{
+       return crypto_ablkcipher_reqtfm(&req->creq);
+}
+
+static inline int crypto_skcipher_givencrypt(
+       struct skcipher_givcrypt_request *req)
+{
+       struct ablkcipher_tfm *crt =
+               crypto_ablkcipher_crt(skcipher_givcrypt_reqtfm(req));
+       return crt->givencrypt(req);
+};
+
+static inline int crypto_skcipher_givdecrypt(
+       struct skcipher_givcrypt_request *req)
+{
+       struct ablkcipher_tfm *crt =
+               crypto_ablkcipher_crt(skcipher_givcrypt_reqtfm(req));
+       return crt->givdecrypt(req);
+};
+
+static inline void skcipher_givcrypt_set_tfm(
+       struct skcipher_givcrypt_request *req, struct crypto_ablkcipher *tfm)
+{
+       req->creq.base.tfm = crypto_ablkcipher_tfm(tfm);
+}
+
+static inline struct skcipher_givcrypt_request *skcipher_givcrypt_cast(
+       struct crypto_async_request *req)
+{
+       return container_of(ablkcipher_request_cast(req),
+                           struct skcipher_givcrypt_request, creq);
+}
+
+static inline struct skcipher_givcrypt_request *skcipher_givcrypt_alloc(
+       struct crypto_ablkcipher *tfm, gfp_t gfp)
+{
+       struct skcipher_givcrypt_request *req;
+
+       req = kmalloc(sizeof(struct skcipher_givcrypt_request) +
+                     crypto_ablkcipher_reqsize(tfm), gfp);
+
+       if (likely(req))
+               skcipher_givcrypt_set_tfm(req, tfm);
+
+       return req;
+}
+
+static inline void skcipher_givcrypt_free(struct skcipher_givcrypt_request *req)
+{
+       kfree(req);
+}
+
+static inline void skcipher_givcrypt_set_callback(
+       struct skcipher_givcrypt_request *req, u32 flags,
+       crypto_completion_t complete, void *data)
+{
+       ablkcipher_request_set_callback(&req->creq, flags, complete, data);
+}
+
+static inline void skcipher_givcrypt_set_crypt(
+       struct skcipher_givcrypt_request *req,
+       struct scatterlist *src, struct scatterlist *dst,
+       unsigned int nbytes, void *iv)
+{
+       ablkcipher_request_set_crypt(&req->creq, src, dst, nbytes, iv);
+}
+
+static inline void skcipher_givcrypt_set_giv(
+       struct skcipher_givcrypt_request *req, u8 *giv, u64 seq)
+{
+       req->giv = giv;
+       req->seq = seq;
+}
+
+#endif /* _CRYPTO_SKCIPHER_H */
+
index f30fa92a44a1ef951771050d0fa5378fdf812522..bd694f779346687e787a61b6547f15a9af28f0c7 100644 (file)
@@ -49,6 +49,7 @@ header-y += comstats.h
 header-y += const.h
 header-y += cgroupstats.h
 header-y += cycx_cfm.h
+header-y += dlmconstants.h
 header-y += dlm_device.h
 header-y += dlm_netlink.h
 header-y += dm-ioctl.h
index e3c16c981e4627beca2b3bd2240d51e67b64918a..63f2e6ed698f5ba471efab1f7f5af1cc4942fb96 100644 (file)
@@ -40,6 +40,7 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_numa.h>
 #include <asm/acpi.h>
+#include <linux/dmi.h>
 
 
 #ifdef CONFIG_ACPI
@@ -192,7 +193,9 @@ extern int ec_transaction(u8 command,
 #endif /*CONFIG_ACPI_EC*/
 
 extern int acpi_blacklisted(void);
-extern void acpi_bios_year(char *s);
+#ifdef CONFIG_DMI
+extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
+#endif
 
 #ifdef CONFIG_ACPI_NUMA
 int acpi_get_pxm(acpi_handle handle);
@@ -226,5 +229,5 @@ static inline int acpi_boot_table_init(void)
        return 0;
 }
 
-#endif /* CONFIG_ACPI */
+#endif /* !CONFIG_ACPI */
 #endif /*_LINUX_ACPI_H*/
index 72ab80801ef61d3f82c3a3cb7e980a2ca6c0f275..78bbacaed8c4a4f2521f552432d2b4baf2dfc226 100644 (file)
@@ -286,9 +286,10 @@ enum {
        ATA_CBL_NONE            = 0,
        ATA_CBL_PATA40          = 1,
        ATA_CBL_PATA80          = 2,
-       ATA_CBL_PATA40_SHORT    = 3,            /* 40 wire cable to high UDMA spec */
-       ATA_CBL_PATA_UNK        = 4,
-       ATA_CBL_SATA            = 5,
+       ATA_CBL_PATA40_SHORT    = 3,    /* 40 wire cable to high UDMA spec */
+       ATA_CBL_PATA_UNK        = 4,    /* don't know, maybe 80c? */
+       ATA_CBL_PATA_IGN        = 5,    /* don't know, ignore cable handling */
+       ATA_CBL_SATA            = 6,
 
        /* SATA Status and Control Registers */
        SCR_STATUS              = 0,
@@ -324,6 +325,13 @@ enum {
        ATA_TFLAG_LBA           = (1 << 4), /* enable LBA */
        ATA_TFLAG_FUA           = (1 << 5), /* enable FUA */
        ATA_TFLAG_POLLING       = (1 << 6), /* set nIEN to 1 and use polling */
+
+       /* protocol flags */
+       ATA_PROT_FLAG_PIO       = (1 << 0), /* is PIO */
+       ATA_PROT_FLAG_DMA       = (1 << 1), /* is DMA */
+       ATA_PROT_FLAG_DATA      = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
+       ATA_PROT_FLAG_NCQ       = (1 << 2), /* is NCQ */
+       ATA_PROT_FLAG_ATAPI     = (1 << 3), /* is ATAPI */
 };
 
 enum ata_tf_protocols {
@@ -333,9 +341,9 @@ enum ata_tf_protocols {
        ATA_PROT_PIO,           /* PIO data xfer */
        ATA_PROT_DMA,           /* DMA */
        ATA_PROT_NCQ,           /* NCQ */
-       ATA_PROT_ATAPI,         /* packet command, PIO data xfer*/
-       ATA_PROT_ATAPI_NODATA,  /* packet command, no data */
-       ATA_PROT_ATAPI_DMA,     /* packet command with special DMA sauce */
+       ATAPI_PROT_NODATA,      /* packet command, no data */
+       ATAPI_PROT_PIO,         /* packet command, PIO data xfer*/
+       ATAPI_PROT_DMA,         /* packet command with special DMA sauce */
 };
 
 enum ata_ioctls {
@@ -346,8 +354,8 @@ enum ata_ioctls {
 /* core structures */
 
 struct ata_prd {
-       u32                     addr;
-       u32                     flags_len;
+       __le32                  addr;
+       __le32                  flags_len;
 };
 
 struct ata_taskfile {
@@ -373,13 +381,69 @@ struct ata_taskfile {
        u8                      command;        /* IO operation */
 };
 
+/*
+ * protocol tests
+ */
+static inline unsigned int ata_prot_flags(u8 prot)
+{
+       switch (prot) {
+       case ATA_PROT_NODATA:
+               return 0;
+       case ATA_PROT_PIO:
+               return ATA_PROT_FLAG_PIO;
+       case ATA_PROT_DMA:
+               return ATA_PROT_FLAG_DMA;
+       case ATA_PROT_NCQ:
+               return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
+       case ATAPI_PROT_NODATA:
+               return ATA_PROT_FLAG_ATAPI;
+       case ATAPI_PROT_PIO:
+               return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
+       case ATAPI_PROT_DMA:
+               return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
+       }
+       return 0;
+}
+
+static inline int ata_is_atapi(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
+}
+
+static inline int ata_is_nodata(u8 prot)
+{
+       return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
+}
+
+static inline int ata_is_pio(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
+}
+
+static inline int ata_is_dma(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
+}
+
+static inline int ata_is_ncq(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
+}
+
+static inline int ata_is_data(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
+}
+
+/*
+ * id tests
+ */
 #define ata_id_is_ata(id)      (((id)[0] & (1 << 15)) == 0)
 #define ata_id_has_lba(id)     ((id)[49] & (1 << 9))
 #define ata_id_has_dma(id)     ((id)[49] & (1 << 8))
 #define ata_id_has_ncq(id)     ((id)[76] & (1 << 8))
 #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
 #define ata_id_removeable(id)  ((id)[0] & (1 << 7))
-#define ata_id_has_dword_io(id)        ((id)[48] & (1 << 0))
 #define ata_id_has_atapi_AN(id)        \
        ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
          ((id)[78] & (1 << 5)) )
@@ -415,6 +479,7 @@ static inline bool ata_id_has_dipm(const u16 *id)
        return val & (1 << 3);
 }
 
+
 static inline int ata_id_has_fua(const u16 *id)
 {
        if ((id[84] & 0xC000) != 0x4000)
@@ -519,6 +584,26 @@ static inline int ata_id_is_sata(const u16 *id)
        return ata_id_major_version(id) >= 5 && id[93] == 0;
 }
 
+static inline int ata_id_has_tpm(const u16 *id)
+{
+       /* The TPM bits are only valid on ATA8 */
+       if (ata_id_major_version(id) < 8)
+               return 0;
+       if ((id[48] & 0xC000) != 0x4000)
+               return 0;
+       return id[48] & (1 << 0);
+}
+
+static inline int ata_id_has_dword_io(const u16 *id)
+{
+       /* ATA 8 reuses this flag for "trusted" computing */
+       if (ata_id_major_version(id) > 7)
+               return 0;
+       if (id[48] & (1 << 0))
+               return 1;
+       return 0;
+}
+
 static inline int ata_id_current_chs_valid(const u16 *id)
 {
        /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
@@ -554,8 +639,6 @@ static inline int ata_drive_40wire(const u16 *dev_id)
 
 static inline int ata_drive_40wire_relaxed(const u16 *dev_id)
 {
-       if (ata_id_is_sata(dev_id))
-               return 0;       /* SATA */
        if ((dev_id[93] & 0x2000) == 0x2000)
                return 0;       /* 80 wire */
        return 1;
@@ -576,13 +659,6 @@ static inline int atapi_command_packet_set(const u16 *dev_id)
        return (dev_id[0] >> 8) & 0x1f;
 }
 
-static inline int is_atapi_taskfile(const struct ata_taskfile *tf)
-{
-       return (tf->protocol == ATA_PROT_ATAPI) ||
-              (tf->protocol == ATA_PROT_ATAPI_NODATA) ||
-              (tf->protocol == ATA_PROT_ATAPI_DMA);
-}
-
 static inline int is_multi_taskfile(struct ata_taskfile *tf)
 {
        return (tf->command == ATA_CMD_READ_MULTI) ||
index 8ff2749339484fdddd066bab4ab971916a510b93..f5582332af046d4cb00ea31b3beeebccd7da2384 100644 (file)
@@ -17,6 +17,7 @@ struct attribute_container {
        struct list_head        node;
        struct klist            containers;
        struct class            *class;
+       struct attribute_group  *grp;
        struct class_device_attribute **attrs;
        int (*match)(struct attribute_container *, struct device *);
 #define        ATTRIBUTE_CONTAINER_NO_CLASSDEVS        0x01
index d18ee67b40f8198118e93336aee272324d9c30db..49b7a4c31a6d5d35af9c3e11e24791afe86faaf4 100644 (file)
@@ -143,8 +143,6 @@ enum rq_cmd_type_bits {
         * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver
         * private REQ_LB opcodes to differentiate what type of request this is
         */
-       REQ_TYPE_ATA_CMD,
-       REQ_TYPE_ATA_TASK,
        REQ_TYPE_ATA_TASKFILE,
        REQ_TYPE_ATA_PC,
 };
@@ -766,6 +764,7 @@ extern void blk_queue_segment_boundary(struct request_queue *, unsigned long);
 extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
+extern void blk_queue_update_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
index c6d3e22c0624235e4d1db94d852f6baf5f11d2c7..fcdc11b9609b7c2efc4318811375a30574d7c586 100644 (file)
@@ -451,6 +451,7 @@ struct cdrom_generic_command
 #define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL  0x1e
 #define GPCMD_READ_10                      0x28
 #define GPCMD_READ_12                      0xa8
+#define GPCMD_READ_BUFFER                  0x3c
 #define GPCMD_READ_BUFFER_CAPACITY         0x5c
 #define GPCMD_READ_CDVD_CAPACITY           0x25
 #define GPCMD_READ_CD                      0xbe
@@ -480,7 +481,9 @@ struct cdrom_generic_command
 #define GPCMD_TEST_UNIT_READY              0x00
 #define GPCMD_VERIFY_10                            0x2f
 #define GPCMD_WRITE_10                     0x2a
+#define GPCMD_WRITE_12                     0xaa
 #define GPCMD_WRITE_AND_VERIFY_10          0x2e
+#define GPCMD_WRITE_BUFFER                 0x3b
 /* This is listed as optional in ATAPI 2.6, but is (curiously) 
  * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
  * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
index b79c5756936728ca8a576c3ea13142f71f333f4c..0be8d65bc3c8538b62c2f5493dcc8c4008b96a54 100644 (file)
@@ -71,18 +71,27 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb)
 
 int cpu_up(unsigned int cpu);
 
+extern void cpu_hotplug_init(void);
+
 #else
 
 static inline int register_cpu_notifier(struct notifier_block *nb)
 {
        return 0;
 }
+
 static inline void unregister_cpu_notifier(struct notifier_block *nb)
 {
 }
 
+static inline void cpu_hotplug_init(void)
+{
+}
+
 #endif /* CONFIG_SMP */
 extern struct sysdev_class cpu_sysdev_class;
+extern void cpu_maps_update_begin(void);
+extern void cpu_maps_update_done(void);
 
 #ifdef CONFIG_HOTPLUG_CPU
 /* Stop CPUs going up and down. */
@@ -97,8 +106,8 @@ static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
        mutex_unlock(cpu_hp_mutex);
 }
 
-extern void lock_cpu_hotplug(void);
-extern void unlock_cpu_hotplug(void);
+extern void get_online_cpus(void);
+extern void put_online_cpus(void);
 #define hotcpu_notifier(fn, pri) {                             \
        static struct notifier_block fn##_nb =                  \
                { .notifier_call = fn, .priority = pri };       \
@@ -107,7 +116,6 @@ extern void unlock_cpu_hotplug(void);
 #define register_hotcpu_notifier(nb)   register_cpu_notifier(nb)
 #define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
 int cpu_down(unsigned int cpu);
-#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 
 #else          /* CONFIG_HOTPLUG_CPU */
 
@@ -116,15 +124,12 @@ static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex)
 static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
 { }
 
-#define lock_cpu_hotplug()     do { } while (0)
-#define unlock_cpu_hotplug()   do { } while (0)
+#define get_online_cpus()      do { } while (0)
+#define put_online_cpus()      do { } while (0)
 #define hotcpu_notifier(fn, pri)       do { (void)(fn); } while (0)
 /* These aren't inline functions due to a GCC bug. */
 #define register_hotcpu_notifier(nb)   ({ (void)(nb); 0; })
 #define unregister_hotcpu_notifier(nb) ({ (void)(nb); })
-
-/* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */
-static inline int cpu_is_offline(int cpu) { return 0; }
 #endif         /* CONFIG_HOTPLUG_CPU */
 
 #ifdef CONFIG_PM_SLEEP_SMP
index 23f55140ccd570fd45c321b8275ce04edc451288..85bd790c201eeaafb62da1b03006c13b29e61598 100644 (file)
@@ -397,6 +397,8 @@ extern cpumask_t cpu_present_map;
 #define cpu_present(cpu)       ((cpu) == 0)
 #endif
 
+#define cpu_is_offline(cpu)    unlikely(!cpu_online(cpu))
+
 #ifdef CONFIG_SMP
 extern int nr_cpu_ids;
 #define any_online_cpu(mask) __any_online_cpu(&(mask))
index f3110ebe894a090254ac4b48f0d9ef98205c5eaf..5e02d1b46370c4a9b496359bbbe98eca883b6229 100644 (file)
 #define CRYPTO_ALG_TYPE_DIGEST         0x00000002
 #define CRYPTO_ALG_TYPE_HASH           0x00000003
 #define CRYPTO_ALG_TYPE_BLKCIPHER      0x00000004
-#define CRYPTO_ALG_TYPE_COMPRESS       0x00000005
-#define CRYPTO_ALG_TYPE_AEAD           0x00000006
+#define CRYPTO_ALG_TYPE_ABLKCIPHER     0x00000005
+#define CRYPTO_ALG_TYPE_GIVCIPHER      0x00000006
+#define CRYPTO_ALG_TYPE_COMPRESS       0x00000008
+#define CRYPTO_ALG_TYPE_AEAD           0x00000009
 
 #define CRYPTO_ALG_TYPE_HASH_MASK      0x0000000e
+#define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c
 
 #define CRYPTO_ALG_LARVAL              0x00000010
 #define CRYPTO_ALG_DEAD                        0x00000020
  */
 #define CRYPTO_ALG_NEED_FALLBACK       0x00000100
 
+/*
+ * This bit is set for symmetric key ciphers that have already been wrapped
+ * with a generic IV generator to prevent them from being wrapped again.
+ */
+#define CRYPTO_ALG_GENIV               0x00000200
+
 /*
  * Transform masks and values (for crt_flags).
  */
 #define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN
 #elif defined(ARCH_SLAB_MINALIGN)
 #define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN
+#else
+#define CRYPTO_MINALIGN __alignof__(unsigned long long)
 #endif
 
-#ifdef CRYPTO_MINALIGN
 #define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN)))
-#else
-#define CRYPTO_MINALIGN_ATTR
-#endif
 
 struct scatterlist;
 struct crypto_ablkcipher;
@@ -97,6 +104,8 @@ struct crypto_blkcipher;
 struct crypto_hash;
 struct crypto_tfm;
 struct crypto_type;
+struct aead_givcrypt_request;
+struct skcipher_givcrypt_request;
 
 typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err);
 
@@ -176,6 +185,10 @@ struct ablkcipher_alg {
                      unsigned int keylen);
        int (*encrypt)(struct ablkcipher_request *req);
        int (*decrypt)(struct ablkcipher_request *req);
+       int (*givencrypt)(struct skcipher_givcrypt_request *req);
+       int (*givdecrypt)(struct skcipher_givcrypt_request *req);
+
+       const char *geniv;
 
        unsigned int min_keysize;
        unsigned int max_keysize;
@@ -185,11 +198,16 @@ struct ablkcipher_alg {
 struct aead_alg {
        int (*setkey)(struct crypto_aead *tfm, const u8 *key,
                      unsigned int keylen);
+       int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize);
        int (*encrypt)(struct aead_request *req);
        int (*decrypt)(struct aead_request *req);
+       int (*givencrypt)(struct aead_givcrypt_request *req);
+       int (*givdecrypt)(struct aead_givcrypt_request *req);
+
+       const char *geniv;
 
        unsigned int ivsize;
-       unsigned int authsize;
+       unsigned int maxauthsize;
 };
 
 struct blkcipher_alg {
@@ -202,6 +220,8 @@ struct blkcipher_alg {
                       struct scatterlist *dst, struct scatterlist *src,
                       unsigned int nbytes);
 
+       const char *geniv;
+
        unsigned int min_keysize;
        unsigned int max_keysize;
        unsigned int ivsize;
@@ -317,6 +337,11 @@ struct ablkcipher_tfm {
                      unsigned int keylen);
        int (*encrypt)(struct ablkcipher_request *req);
        int (*decrypt)(struct ablkcipher_request *req);
+       int (*givencrypt)(struct skcipher_givcrypt_request *req);
+       int (*givdecrypt)(struct skcipher_givcrypt_request *req);
+
+       struct crypto_ablkcipher *base;
+
        unsigned int ivsize;
        unsigned int reqsize;
 };
@@ -326,6 +351,11 @@ struct aead_tfm {
                      unsigned int keylen);
        int (*encrypt)(struct aead_request *req);
        int (*decrypt)(struct aead_request *req);
+       int (*givencrypt)(struct aead_givcrypt_request *req);
+       int (*givdecrypt)(struct aead_givcrypt_request *req);
+
+       struct crypto_aead *base;
+
        unsigned int ivsize;
        unsigned int authsize;
        unsigned int reqsize;
@@ -525,17 +555,23 @@ static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast(
        return (struct crypto_ablkcipher *)tfm;
 }
 
-static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher(
-       const char *alg_name, u32 type, u32 mask)
+static inline u32 crypto_skcipher_type(u32 type)
 {
-       type &= ~CRYPTO_ALG_TYPE_MASK;
+       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
        type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-       mask |= CRYPTO_ALG_TYPE_MASK;
+       return type;
+}
 
-       return __crypto_ablkcipher_cast(
-               crypto_alloc_base(alg_name, type, mask));
+static inline u32 crypto_skcipher_mask(u32 mask)
+{
+       mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK;
+       return mask;
 }
 
+struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name,
+                                                 u32 type, u32 mask);
+
 static inline struct crypto_tfm *crypto_ablkcipher_tfm(
        struct crypto_ablkcipher *tfm)
 {
@@ -550,11 +586,8 @@ static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm)
 static inline int crypto_has_ablkcipher(const char *alg_name, u32 type,
                                        u32 mask)
 {
-       type &= ~CRYPTO_ALG_TYPE_MASK;
-       type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-       mask |= CRYPTO_ALG_TYPE_MASK;
-
-       return crypto_has_alg(alg_name, type, mask);
+       return crypto_has_alg(alg_name, crypto_skcipher_type(type),
+                             crypto_skcipher_mask(mask));
 }
 
 static inline struct ablkcipher_tfm *crypto_ablkcipher_crt(
@@ -601,7 +634,9 @@ static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm,
 static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
                                           const u8 *key, unsigned int keylen)
 {
-       return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen);
+       struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(tfm);
+
+       return crt->setkey(crt->base, key, keylen);
 }
 
 static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm(
@@ -633,7 +668,7 @@ static inline unsigned int crypto_ablkcipher_reqsize(
 static inline void ablkcipher_request_set_tfm(
        struct ablkcipher_request *req, struct crypto_ablkcipher *tfm)
 {
-       req->base.tfm = crypto_ablkcipher_tfm(tfm);
+       req->base.tfm = crypto_ablkcipher_tfm(crypto_ablkcipher_crt(tfm)->base);
 }
 
 static inline struct ablkcipher_request *ablkcipher_request_cast(
@@ -686,15 +721,7 @@ static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm)
        return (struct crypto_aead *)tfm;
 }
 
-static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name,
-                                                   u32 type, u32 mask)
-{
-       type &= ~CRYPTO_ALG_TYPE_MASK;
-       type |= CRYPTO_ALG_TYPE_AEAD;
-       mask |= CRYPTO_ALG_TYPE_MASK;
-
-       return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask));
-}
+struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask);
 
 static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm)
 {
@@ -749,9 +776,13 @@ static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags)
 static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
                                     unsigned int keylen)
 {
-       return crypto_aead_crt(tfm)->setkey(tfm, key, keylen);
+       struct aead_tfm *crt = crypto_aead_crt(tfm);
+
+       return crt->setkey(crt->base, key, keylen);
 }
 
+int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize);
+
 static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req)
 {
        return __crypto_aead_cast(req->base.tfm);
@@ -775,7 +806,7 @@ static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)
 static inline void aead_request_set_tfm(struct aead_request *req,
                                        struct crypto_aead *tfm)
 {
-       req->base.tfm = crypto_aead_tfm(tfm);
+       req->base.tfm = crypto_aead_tfm(crypto_aead_crt(tfm)->base);
 }
 
 static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm,
@@ -841,9 +872,9 @@ static inline struct crypto_blkcipher *crypto_blkcipher_cast(
 static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
        const char *alg_name, u32 type, u32 mask)
 {
-       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+       type &= ~CRYPTO_ALG_TYPE_MASK;
        type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-       mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+       mask |= CRYPTO_ALG_TYPE_MASK;
 
        return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
 }
@@ -861,9 +892,9 @@ static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm)
 
 static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask)
 {
-       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+       type &= ~CRYPTO_ALG_TYPE_MASK;
        type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-       mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+       mask |= CRYPTO_ALG_TYPE_MASK;
 
        return crypto_has_alg(alg_name, type, mask);
 }
@@ -1081,6 +1112,7 @@ static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name,
                                                    u32 type, u32 mask)
 {
        type &= ~CRYPTO_ALG_TYPE_MASK;
+       mask &= ~CRYPTO_ALG_TYPE_MASK;
        type |= CRYPTO_ALG_TYPE_HASH;
        mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 
@@ -1100,6 +1132,7 @@ static inline void crypto_free_hash(struct crypto_hash *tfm)
 static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask)
 {
        type &= ~CRYPTO_ALG_TYPE_MASK;
+       mask &= ~CRYPTO_ALG_TYPE_MASK;
        type |= CRYPTO_ALG_TYPE_HASH;
        mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 
index 1678a5de7013a91f08f3f352a773ff90166240f1..f4a5871767f534ef6b8a2a950c70372ef7c27ca7 100644 (file)
@@ -47,6 +47,7 @@ struct task_struct;
 
 #ifdef CONFIG_LOCKDEP
 extern void debug_show_all_locks(void);
+extern void __debug_show_held_locks(struct task_struct *task);
 extern void debug_show_held_locks(struct task_struct *task);
 extern void debug_check_no_locks_freed(const void *from, unsigned long len);
 extern void debug_check_no_locks_held(struct task_struct *task);
@@ -55,6 +56,10 @@ static inline void debug_show_all_locks(void)
 {
 }
 
+static inline void __debug_show_held_locks(struct task_struct *task)
+{
+}
+
 static inline void debug_show_held_locks(struct task_struct *task)
 {
 }
index 2e15822fe40931cb88eb627971f1a5db41f9c892..1880208964d6c9a4a75d332927a0ef3e23b19191 100644 (file)
 #include <asm/device.h>
 
 #define DEVICE_NAME_SIZE       50
-#define DEVICE_NAME_HALF       __stringify(20) /* Less than half to accommodate slop */
+/* DEVICE_NAME_HALF is really less than half to accommodate slop */
+#define DEVICE_NAME_HALF       __stringify(20)
 #define DEVICE_ID_SIZE         32
 #define BUS_ID_SIZE            KOBJ_NAME_LEN
 
 
 struct device;
 struct device_driver;
+struct driver_private;
 struct class;
 struct class_device;
 struct bus_type;
+struct bus_type_private;
 
 struct bus_attribute {
        struct attribute        attr;
-       ssize_t (*show)(struct bus_type *, char * buf);
-       ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+       ssize_t (*show)(struct bus_type *bus, char *buf);
+       ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
 };
 
-#define BUS_ATTR(_name,_mode,_show,_store)     \
-struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
+#define BUS_ATTR(_name, _mode, _show, _store)  \
+struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
 extern int __must_check bus_create_file(struct bus_type *,
                                        struct bus_attribute *);
 extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
 
 struct bus_type {
-       const char              * name;
-       struct module           * owner;
+       const char              *name;
+       struct bus_attribute    *bus_attrs;
+       struct device_attribute *dev_attrs;
+       struct driver_attribute *drv_attrs;
 
-       struct kset             subsys;
-       struct kset             drivers;
-       struct kset             devices;
-       struct klist            klist_devices;
-       struct klist            klist_drivers;
-
-       struct blocking_notifier_head bus_notifier;
-
-       struct bus_attribute    * bus_attrs;
-       struct device_attribute * dev_attrs;
-       struct driver_attribute * drv_attrs;
-
-       int             (*match)(struct device * dev, struct device_driver * drv);
-       int             (*uevent)(struct device *dev, struct kobj_uevent_env *env);
-       int             (*probe)(struct device * dev);
-       int             (*remove)(struct device * dev);
-       void            (*shutdown)(struct device * dev);
+       int (*match)(struct device *dev, struct device_driver *drv);
+       int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
+       int (*probe)(struct device *dev);
+       int (*remove)(struct device *dev);
+       void (*shutdown)(struct device *dev);
 
-       int (*suspend)(struct device * dev, pm_message_t state);
-       int (*suspend_late)(struct device * dev, pm_message_t state);
-       int (*resume_early)(struct device * dev);
-       int (*resume)(struct device * dev);
+       int (*suspend)(struct device *dev, pm_message_t state);
+       int (*suspend_late)(struct device *dev, pm_message_t state);
+       int (*resume_early)(struct device *dev);
+       int (*resume)(struct device *dev);
 
-       unsigned int drivers_autoprobe:1;
+       struct bus_type_private *p;
 };
 
-extern int __must_check bus_register(struct bus_type * bus);
-extern void bus_unregister(struct bus_type * bus);
+extern int __must_check bus_register(struct bus_type *bus);
+extern void bus_unregister(struct bus_type *bus);
 
-extern int __must_check bus_rescan_devices(struct bus_type * bus);
+extern int __must_check bus_rescan_devices(struct bus_type *bus);
 
 /* iterator helpers for buses */
 
-int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
-                    int (*fn)(struct device *, void *));
-struct device * bus_find_device(struct bus_type *bus, struct device *start,
-                               void *data, int (*match)(struct device *, void *));
+int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data,
+                    int (*fn)(struct device *dev, void *data));
+struct device *bus_find_device(struct bus_type *bus, struct device *start,
+                              void *data,
+                              int (*match)(struct device *dev, void *data));
 
 int __must_check bus_for_each_drv(struct bus_type *bus,
-               struct device_driver *start, void *data,
-               int (*fn)(struct device_driver *, void *));
+                                 struct device_driver *start, void *data,
+                                 int (*fn)(struct device_driver *, void *));
 
 /*
  * Bus notifiers: Get notified of addition/removal of devices
@@ -118,111 +112,128 @@ extern int bus_unregister_notifier(struct bus_type *bus,
 #define BUS_NOTIFY_UNBIND_DRIVER       0x00000004 /* driver about to be
                                                      unbound */
 
+extern struct kset *bus_get_kset(struct bus_type *bus);
+extern struct klist *bus_get_device_klist(struct bus_type *bus);
+
 struct device_driver {
-       const char              * name;
-       struct bus_type         * bus;
+       const char              *name;
+       struct bus_type         *bus;
 
-       struct kobject          kobj;
-       struct klist            klist_devices;
-       struct klist_node       knode_bus;
+       struct module           *owner;
+       const char              *mod_name;      /* used for built-in modules */
 
-       struct module           * owner;
-       const char              * mod_name;     /* used for built-in modules */
-       struct module_kobject   * mkobj;
+       int (*probe) (struct device *dev);
+       int (*remove) (struct device *dev);
+       void (*shutdown) (struct device *dev);
+       int (*suspend) (struct device *dev, pm_message_t state);
+       int (*resume) (struct device *dev);
+       struct attribute_group **groups;
 
-       int     (*probe)        (struct device * dev);
-       int     (*remove)       (struct device * dev);
-       void    (*shutdown)     (struct device * dev);
-       int     (*suspend)      (struct device * dev, pm_message_t state);
-       int     (*resume)       (struct device * dev);
+       struct driver_private *p;
 };
 
 
-extern int __must_check driver_register(struct device_driver * drv);
-extern void driver_unregister(struct device_driver * drv);
+extern int __must_check driver_register(struct device_driver *drv);
+extern void driver_unregister(struct device_driver *drv);
 
-extern struct device_driver * get_driver(struct device_driver * drv);
-extern void put_driver(struct device_driver * drv);
-extern struct device_driver *driver_find(const char *name, struct bus_type *bus);
+extern struct device_driver *get_driver(struct device_driver *drv);
+extern void put_driver(struct device_driver *drv);
+extern struct device_driver *driver_find(const char *name,
+                                        struct bus_type *bus);
 extern int driver_probe_done(void);
 
 /* sysfs interface for exporting driver attributes */
 
 struct driver_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(struct device_driver *, char * buf);
-       ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
+       struct attribute attr;
+       ssize_t (*show)(struct device_driver *driver, char *buf);
+       ssize_t (*store)(struct device_driver *driver, const char *buf,
+                        size_t count);
 };
 
-#define DRIVER_ATTR(_name,_mode,_show,_store)  \
-struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store)
+#define DRIVER_ATTR(_name, _mode, _show, _store)       \
+struct driver_attribute driver_attr_##_name =          \
+       __ATTR(_name, _mode, _show, _store)
 
-extern int __must_check driver_create_file(struct device_driver *,
-                                       struct driver_attribute *);
-extern void driver_remove_file(struct device_driver *, struct driver_attribute *);
+extern int __must_check driver_create_file(struct device_driver *driver,
+                                          struct driver_attribute *attr);
+extern void driver_remove_file(struct device_driver *driver,
+                              struct driver_attribute *attr);
 
-extern int __must_check driver_for_each_device(struct device_driver * drv,
-               struct device *start, void *data,
-               int (*fn)(struct device *, void *));
-struct device * driver_find_device(struct device_driver *drv,
-                                  struct device *start, void *data,
-                                  int (*match)(struct device *, void *));
+extern int __must_check driver_add_kobj(struct device_driver *drv,
+                                       struct kobject *kobj,
+                                       const char *fmt, ...);
+
+extern int __must_check driver_for_each_device(struct device_driver *drv,
+                                              struct device *start,
+                                              void *data,
+                                              int (*fn)(struct device *dev,
+                                                        void *));
+struct device *driver_find_device(struct device_driver *drv,
+                                 struct device *start, void *data,
+                                 int (*match)(struct device *dev, void *data));
 
 /*
  * device classes
  */
 struct class {
-       const char              * name;
-       struct module           * owner;
+       const char              *name;
+       struct module           *owner;
 
        struct kset             subsys;
        struct list_head        children;
        struct list_head        devices;
        struct list_head        interfaces;
        struct kset             class_dirs;
-       struct semaphore        sem;    /* locks both the children and interfaces lists */
-
-       struct class_attribute          * class_attrs;
-       struct class_device_attribute   * class_dev_attrs;
-       struct device_attribute         * dev_attrs;
+       struct semaphore        sem; /* locks children, devices, interfaces */
+       struct class_attribute          *class_attrs;
+       struct class_device_attribute   *class_dev_attrs;
+       struct device_attribute         *dev_attrs;
 
-       int     (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
-       int     (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
+       int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
+       int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
 
-       void    (*release)(struct class_device *dev);
-       void    (*class_release)(struct class *class);
-       void    (*dev_release)(struct device *dev);
+       void (*release)(struct class_device *dev);
+       void (*class_release)(struct class *class);
+       void (*dev_release)(struct device *dev);
 
-       int     (*suspend)(struct device *, pm_message_t state);
-       int     (*resume)(struct device *);
+       int (*suspend)(struct device *dev, pm_message_t state);
+       int (*resume)(struct device *dev);
 };
 
-extern int __must_check class_register(struct class *);
-extern void class_unregister(struct class *);
+extern int __must_check class_register(struct class *class);
+extern void class_unregister(struct class *class);
+extern int class_for_each_device(struct class *class, void *data,
+                                int (*fn)(struct device *dev, void *data));
+extern struct device *class_find_device(struct class *class, void *data,
+                                       int (*match)(struct device *, void *));
+extern struct class_device *class_find_child(struct class *class, void *data,
+                                  int (*match)(struct class_device *, void *));
 
 
 struct class_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(struct class *, char * buf);
-       ssize_t (*store)(struct class *, const char * buf, size_t count);
+       struct attribute attr;
+       ssize_t (*show)(struct class *class, char *buf);
+       ssize_t (*store)(struct class *class, const char *buf, size_t count);
 };
 
-#define CLASS_ATTR(_name,_mode,_show,_store)                   \
-struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) 
+#define CLASS_ATTR(_name, _mode, _show, _store)                        \
+struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
-extern int __must_check class_create_file(struct class *,
-                                       const struct class_attribute *);
-extern void class_remove_file(struct class *, const struct class_attribute *);
+extern int __must_check class_create_file(struct class *class,
+                                         const struct class_attribute *attr);
+extern void class_remove_file(struct class *class,
+                             const struct class_attribute *attr);
 
 struct class_device_attribute {
-       struct attribute        attr;
-       ssize_t (*show)(struct class_device *, char * buf);
-       ssize_t (*store)(struct class_device *, const char * buf, size_t count);
+       struct attribute attr;
+       ssize_t (*show)(struct class_device *, char *buf);
+       ssize_t (*store)(struct class_device *, const char *buf, size_t count);
 };
 
-#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store)            \
+#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store)         \
 struct class_device_attribute class_device_attr_##_name =      \
-       __ATTR(_name,_mode,_show,_store)
+       __ATTR(_name, _mode, _show, _store)
 
 extern int __must_check class_device_create_file(struct class_device *,
                                    const struct class_device_attribute *);
@@ -255,26 +266,24 @@ struct class_device {
        struct list_head        node;
 
        struct kobject          kobj;
-       struct class            * class;        /* required */
-       dev_t                   devt;           /* dev_t, creates the sysfs "dev" */
-       struct device           * dev;          /* not necessary, but nice to have */
-       void                    * class_data;   /* class-specific data */
-       struct class_device     *parent;        /* parent of this child device, if there is one */
-       struct attribute_group  ** groups;      /* optional groups */
-
-       void    (*release)(struct class_device *dev);
-       int     (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
-       char    class_id[BUS_ID_SIZE];  /* unique to this class */
+       struct class            *class;
+       dev_t                   devt;
+       struct device           *dev;
+       void                    *class_data;
+       struct class_device     *parent;
+       struct attribute_group  **groups;
+
+       void (*release)(struct class_device *dev);
+       int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
+       char class_id[BUS_ID_SIZE];
 };
 
-static inline void *
-class_get_devdata (struct class_device *dev)
+static inline void *class_get_devdata(struct class_device *dev)
 {
        return dev->class_data;
 }
 
-static inline void
-class_set_devdata (struct class_device *dev, void *data)
+static inline void class_set_devdata(struct class_device *dev, void *data)
 {
        dev->class_data = data;
 }
@@ -286,10 +295,10 @@ extern void class_device_initialize(struct class_device *);
 extern int __must_check class_device_add(struct class_device *);
 extern void class_device_del(struct class_device *);
 
-extern struct class_device * class_device_get(struct class_device *);
+extern struct class_device *class_device_get(struct class_device *);
 extern void class_device_put(struct class_device *);
 
-extern void class_device_remove_file(struct class_device *, 
+extern void class_device_remove_file(struct class_device *,
                                     const struct class_device_attribute *);
 extern int __must_check class_device_create_bin_file(struct class_device *,
                                        struct bin_attribute *);
@@ -316,7 +325,7 @@ extern struct class_device *class_device_create(struct class *cls,
                                                dev_t devt,
                                                struct device *device,
                                                const char *fmt, ...)
-                                       __attribute__((format(printf,5,6)));
+                                       __attribute__((format(printf, 5, 6)));
 extern void class_device_destroy(struct class *cls, dev_t devt);
 
 /*
@@ -333,8 +342,8 @@ struct device_type {
        struct attribute_group **groups;
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        void (*release)(struct device *dev);
-       int (*suspend)(struct device * dev, pm_message_t state);
-       int (*resume)(struct device * dev);
+       int (*suspend)(struct device *dev, pm_message_t state);
+       int (*resume)(struct device *dev);
 };
 
 /* interface for exporting device attributes */
@@ -346,18 +355,19 @@ struct device_attribute {
                         const char *buf, size_t count);
 };
 
-#define DEVICE_ATTR(_name,_mode,_show,_store) \
-struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
 extern int __must_check device_create_file(struct device *device,
-                                       struct device_attribute * entry);
-extern void device_remove_file(struct device * dev, struct device_attribute * attr);
+                                          struct device_attribute *entry);
+extern void device_remove_file(struct device *dev,
+                              struct device_attribute *attr);
 extern int __must_check device_create_bin_file(struct device *dev,
                                               struct bin_attribute *attr);
 extern void device_remove_bin_file(struct device *dev,
                                   struct bin_attribute *attr);
 extern int device_schedule_callback_owner(struct device *dev,
-               void (*func)(struct device *), struct module *owner);
+               void (*func)(struct device *dev), struct module *owner);
 
 /* This is a macro to avoid include problems with THIS_MODULE */
 #define device_schedule_callback(dev, func)                    \
@@ -368,21 +378,21 @@ typedef void (*dr_release_t)(struct device *dev, void *res);
 typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data);
 
 #ifdef CONFIG_DEBUG_DEVRES
-extern void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+extern void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
                             const char *name);
 #define devres_alloc(release, size, gfp) \
        __devres_alloc(release, size, gfp, #release)
 #else
-extern void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
+extern void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
 #endif
 extern void devres_free(void *res);
 extern void devres_add(struct device *dev, void *res);
-extern void * devres_find(struct device *dev, dr_release_t release,
-                         dr_match_t match, void *match_data);
-extern void * devres_get(struct device *dev, void *new_res,
+extern void *devres_find(struct device *dev, dr_release_t release,
                         dr_match_t match, void *match_data);
-extern void * devres_remove(struct device *dev, dr_release_t release,
-                           dr_match_t match, void *match_data);
+extern void *devres_get(struct device *dev, void *new_res,
+                       dr_match_t match, void *match_data);
+extern void *devres_remove(struct device *dev, dr_release_t release,
+                          dr_match_t match, void *match_data);
 extern int devres_destroy(struct device *dev, dr_release_t release,
                          dr_match_t match, void *match_data);
 
@@ -399,7 +409,7 @@ extern void devm_kfree(struct device *dev, void *p);
 
 struct device {
        struct klist            klist_children;
-       struct klist_node       knode_parent;           /* node in sibling list */
+       struct klist_node       knode_parent;   /* node in sibling list */
        struct klist_node       knode_driver;
        struct klist_node       knode_bus;
        struct device           *parent;
@@ -414,7 +424,7 @@ struct device {
                                         * its driver.
                                         */
 
-       struct bus_type * bus;          /* type of bus device is on */
+       struct bus_type *bus;           /* type of bus device is on */
        struct device_driver *driver;   /* which driver has allocated this
                                           device */
        void            *driver_data;   /* data private to the driver */
@@ -445,10 +455,10 @@ struct device {
        /* class_device migration path */
        struct list_head        node;
        struct class            *class;
-       dev_t                   devt;           /* dev_t, creates the sysfs "dev" */
+       dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
        struct attribute_group  **groups;       /* optional groups */
 
-       void    (*release)(struct device * dev);
+       void    (*release)(struct device *dev);
 };
 
 #ifdef CONFIG_NUMA
@@ -470,14 +480,12 @@ static inline void set_dev_node(struct device *dev, int node)
 }
 #endif
 
-static inline void *
-dev_get_drvdata (struct device *dev)
+static inline void *dev_get_drvdata(struct device *dev)
 {
        return dev->driver_data;
 }
 
-static inline void
-dev_set_drvdata (struct device *dev, void *data)
+static inline void dev_set_drvdata(struct device *dev, void *data)
 {
        dev->driver_data = data;
 }
@@ -492,15 +500,15 @@ void driver_init(void);
 /*
  * High level routines for use by the bus drivers
  */
-extern int __must_check device_register(struct device * dev);
-extern void device_unregister(struct device * dev);
-extern void device_initialize(struct device * dev);
-extern int __must_check device_add(struct device * dev);
-extern void device_del(struct device * dev);
-extern int device_for_each_child(struct device *, void *,
-                    int (*fn)(struct device *, void *));
-extern struct device *device_find_child(struct device *, void *data,
-                                       int (*match)(struct device *, void *));
+extern int __must_check device_register(struct device *dev);
+extern void device_unregister(struct device *dev);
+extern void device_initialize(struct device *dev);
+extern int __must_check device_add(struct device *dev);
+extern void device_del(struct device *dev);
+extern int device_for_each_child(struct device *dev, void *data,
+                    int (*fn)(struct device *dev, void *data));
+extern struct device *device_find_child(struct device *dev, void *data,
+                               int (*match)(struct device *dev, void *data));
 extern int device_rename(struct device *dev, char *new_name);
 extern int device_move(struct device *dev, struct device *new_parent);
 
@@ -509,8 +517,8 @@ extern int device_move(struct device *dev, struct device *new_parent);
  * for information on use.
  */
 extern int __must_check device_bind_driver(struct device *dev);
-extern void device_release_driver(struct device * dev);
-extern int  __must_check device_attach(struct device * dev);
+extern void device_release_driver(struct device *dev);
+extern int  __must_check device_attach(struct device *dev);
 extern int __must_check driver_attach(struct device_driver *drv);
 extern int __must_check device_reprobe(struct device *dev);
 
@@ -519,8 +527,16 @@ extern int __must_check device_reprobe(struct device *dev);
  */
 extern struct device *device_create(struct class *cls, struct device *parent,
                                    dev_t devt, const char *fmt, ...)
-                                   __attribute__((format(printf,4,5)));
+                                   __attribute__((format(printf, 4, 5)));
 extern void device_destroy(struct class *cls, dev_t devt);
+#ifdef CONFIG_PM_SLEEP
+extern void destroy_suspended_device(struct class *cls, dev_t devt);
+#else /* !CONFIG_PM_SLEEP */
+static inline void destroy_suspended_device(struct class *cls, dev_t devt)
+{
+       device_destroy(cls, devt);
+}
+#endif /* !CONFIG_PM_SLEEP */
 
 /*
  * Platform "fixup" functions - allow the platform to have their say
@@ -528,17 +544,17 @@ extern void device_destroy(struct class *cls, dev_t devt);
  * know about.
  */
 /* Notify platform of device discovery */
-extern int (*platform_notify)(struct device * dev);
+extern int (*platform_notify)(struct device *dev);
 
-extern int (*platform_notify_remove)(struct device * dev);
+extern int (*platform_notify_remove)(struct device *dev);
 
 
 /**
  * get_device - atomically increment the reference count for the device.
  *
  */
-extern struct device * get_device(struct device * dev);
-extern void put_device(struct device * dev);
+extern struct device *get_device(struct device *dev);
+extern void put_device(struct device *dev);
 
 
 /* drivers/base/power/shutdown.c */
@@ -547,22 +563,33 @@ extern void device_shutdown(void);
 /* drivers/base/sys.c */
 extern void sysdev_shutdown(void);
 
-
-/* drivers/base/firmware.c */
-extern int __must_check firmware_register(struct kset *);
-extern void firmware_unregister(struct kset *);
-
 /* debugging and troubleshooting/diagnostic helpers. */
 extern const char *dev_driver_string(struct device *dev);
 #define dev_printk(level, dev, format, arg...) \
-       printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg)
+       printk(level "%s %s: " format , dev_driver_string(dev) , \
+              (dev)->bus_id , ## arg)
+
+#define dev_emerg(dev, format, arg...)         \
+       dev_printk(KERN_EMERG , dev , format , ## arg)
+#define dev_alert(dev, format, arg...)         \
+       dev_printk(KERN_ALERT , dev , format , ## arg)
+#define dev_crit(dev, format, arg...)          \
+       dev_printk(KERN_CRIT , dev , format , ## arg)
+#define dev_err(dev, format, arg...)           \
+       dev_printk(KERN_ERR , dev , format , ## arg)
+#define dev_warn(dev, format, arg...)          \
+       dev_printk(KERN_WARNING , dev , format , ## arg)
+#define dev_notice(dev, format, arg...)                \
+       dev_printk(KERN_NOTICE , dev , format , ## arg)
+#define dev_info(dev, format, arg...)          \
+       dev_printk(KERN_INFO , dev , format , ## arg)
 
 #ifdef DEBUG
 #define dev_dbg(dev, format, arg...)           \
        dev_printk(KERN_DEBUG , dev , format , ## arg)
 #else
 static inline int __attribute__ ((format (printf, 2, 3)))
-dev_dbg(struct device * dev, const char * fmt, ...)
+dev_dbg(struct device *dev, const char *fmt, ...)
 {
        return 0;
 }
@@ -572,21 +599,12 @@ dev_dbg(struct device * dev, const char * fmt, ...)
 #define dev_vdbg       dev_dbg
 #else
 static inline int __attribute__ ((format (printf, 2, 3)))
-dev_vdbg(struct device * dev, const char * fmt, ...)
+dev_vdbg(struct device *dev, const char *fmt, ...)
 {
        return 0;
 }
 #endif
 
-#define dev_err(dev, format, arg...)           \
-       dev_printk(KERN_ERR , dev , format , ## arg)
-#define dev_info(dev, format, arg...)          \
-       dev_printk(KERN_INFO , dev , format , ## arg)
-#define dev_warn(dev, format, arg...)          \
-       dev_printk(KERN_WARNING , dev , format , ## arg)
-#define dev_notice(dev, format, arg...)                \
-       dev_printk(KERN_NOTICE , dev , format , ## arg)
-
 /* Create alias, so I can be autoloaded. */
 #define MODULE_ALIAS_CHARDEV(major,minor) \
        MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
index be9d278761e0ed5ddbb87653d64f34e9108956cb..c743fbc769dbb19905773828ca69f2f2a89722d7 100644 (file)
  * routines and structures to use DLM lockspaces
  */
 
-/*
- * Lock Modes
- */
+/* Lock levels and flags are here */
+#include <linux/dlmconstants.h>
 
-#define DLM_LOCK_IV            -1      /* invalid */
-#define DLM_LOCK_NL            0       /* null */
-#define DLM_LOCK_CR            1       /* concurrent read */
-#define DLM_LOCK_CW            2       /* concurrent write */
-#define DLM_LOCK_PR            3       /* protected read */
-#define DLM_LOCK_PW            4       /* protected write */
-#define DLM_LOCK_EX            5       /* exclusive */
-
-/*
- * Maximum size in bytes of a dlm_lock name
- */
 
 #define DLM_RESNAME_MAXLEN     64
 
-/*
- * Flags to dlm_lock
- *
- * DLM_LKF_NOQUEUE
- *
- * Do not queue the lock request on the wait queue if it cannot be granted
- * immediately.  If the lock cannot be granted because of this flag, DLM will
- * either return -EAGAIN from the dlm_lock call or will return 0 from
- * dlm_lock and -EAGAIN in the lock status block when the AST is executed.
- *
- * DLM_LKF_CANCEL
- *
- * Used to cancel a pending lock request or conversion.  A converting lock is
- * returned to its previously granted mode.
- *
- * DLM_LKF_CONVERT
- *
- * Indicates a lock conversion request.  For conversions the name and namelen
- * are ignored and the lock ID in the LKSB is used to identify the lock.
- *
- * DLM_LKF_VALBLK
- *
- * Requests DLM to return the current contents of the lock value block in the
- * lock status block.  When this flag is set in a lock conversion from PW or EX
- * modes, DLM assigns the value specified in the lock status block to the lock
- * value block of the lock resource.  The LVB is a DLM_LVB_LEN size array
- * containing application-specific information.
- *
- * DLM_LKF_QUECVT
- *
- * Force a conversion request to be queued, even if it is compatible with
- * the granted modes of other locks on the same resource.
- *
- * DLM_LKF_IVVALBLK
- *
- * Invalidate the lock value block.
- *
- * DLM_LKF_CONVDEADLK
- *
- * Allows the dlm to resolve conversion deadlocks internally by demoting the
- * granted mode of a converting lock to NL.  The DLM_SBF_DEMOTED flag is
- * returned for a conversion that's been effected by this.
- *
- * DLM_LKF_PERSISTENT
- *
- * Only relevant to locks originating in userspace.  A persistent lock will not
- * be removed if the process holding the lock exits.
- *
- * DLM_LKF_NODLCKWT
- *
- * Do not cancel the lock if it gets into conversion deadlock.
- * Exclude this lock from being monitored due to DLM_LSFL_TIMEWARN.
- *
- * DLM_LKF_NODLCKBLK
- *
- * net yet implemented
- *
- * DLM_LKF_EXPEDITE
- *
- * Used only with new requests for NL mode locks.  Tells the lock manager
- * to grant the lock, ignoring other locks in convert and wait queues.
- *
- * DLM_LKF_NOQUEUEBAST
- *
- * Send blocking AST's before returning -EAGAIN to the caller.  It is only
- * used along with the NOQUEUE flag.  Blocking AST's are not sent for failed
- * NOQUEUE requests otherwise.
- *
- * DLM_LKF_HEADQUE
- *
- * Add a lock to the head of the convert or wait queue rather than the tail.
- *
- * DLM_LKF_NOORDER
- *
- * Disregard the standard grant order rules and grant a lock as soon as it
- * is compatible with other granted locks.
- *
- * DLM_LKF_ORPHAN
- *
- * not yet implemented
- *
- * DLM_LKF_ALTPR
- *
- * If the requested mode cannot be granted immediately, try to grant the lock
- * in PR mode instead.  If this alternate mode is granted instead of the
- * requested mode, DLM_SBF_ALTMODE is returned in the lksb.
- *
- * DLM_LKF_ALTCW
- *
- * The same as ALTPR, but the alternate mode is CW.
- *
- * DLM_LKF_FORCEUNLOCK
- *
- * Unlock the lock even if it is converting or waiting or has sublocks.
- * Only really for use by the userland device.c code.
- *
- */
-
-#define DLM_LKF_NOQUEUE                0x00000001
-#define DLM_LKF_CANCEL         0x00000002
-#define DLM_LKF_CONVERT                0x00000004
-#define DLM_LKF_VALBLK         0x00000008
-#define DLM_LKF_QUECVT         0x00000010
-#define DLM_LKF_IVVALBLK       0x00000020
-#define DLM_LKF_CONVDEADLK     0x00000040
-#define DLM_LKF_PERSISTENT     0x00000080
-#define DLM_LKF_NODLCKWT       0x00000100
-#define DLM_LKF_NODLCKBLK      0x00000200
-#define DLM_LKF_EXPEDITE       0x00000400
-#define DLM_LKF_NOQUEUEBAST    0x00000800
-#define DLM_LKF_HEADQUE                0x00001000
-#define DLM_LKF_NOORDER                0x00002000
-#define DLM_LKF_ORPHAN         0x00004000
-#define DLM_LKF_ALTPR          0x00008000
-#define DLM_LKF_ALTCW          0x00010000
-#define DLM_LKF_FORCEUNLOCK    0x00020000
-#define DLM_LKF_TIMEOUT                0x00040000
-
-/*
- * Some return codes that are not in errno.h
- */
-
-#define DLM_ECANCEL            0x10001
-#define DLM_EUNLOCK            0x10002
 
 typedef void dlm_lockspace_t;
 
diff --git a/include/linux/dlmconstants.h b/include/linux/dlmconstants.h
new file mode 100644 (file)
index 0000000..fddb3d3
--- /dev/null
@@ -0,0 +1,159 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLMCONSTANTS_DOT_H__
+#define __DLMCONSTANTS_DOT_H__
+
+/*
+ * Constants used by DLM interface.
+ */
+
+/*
+ * Lock Modes
+ */
+
+#define DLM_LOCK_IV            (-1)    /* invalid */
+#define DLM_LOCK_NL            0       /* null */
+#define DLM_LOCK_CR            1       /* concurrent read */
+#define DLM_LOCK_CW            2       /* concurrent write */
+#define DLM_LOCK_PR            3       /* protected read */
+#define DLM_LOCK_PW            4       /* protected write */
+#define DLM_LOCK_EX            5       /* exclusive */
+
+
+/*
+ * Flags to dlm_lock
+ *
+ * DLM_LKF_NOQUEUE
+ *
+ * Do not queue the lock request on the wait queue if it cannot be granted
+ * immediately.  If the lock cannot be granted because of this flag, DLM will
+ * either return -EAGAIN from the dlm_lock call or will return 0 from
+ * dlm_lock and -EAGAIN in the lock status block when the AST is executed.
+ *
+ * DLM_LKF_CANCEL
+ *
+ * Used to cancel a pending lock request or conversion.  A converting lock is
+ * returned to its previously granted mode.
+ *
+ * DLM_LKF_CONVERT
+ *
+ * Indicates a lock conversion request.  For conversions the name and namelen
+ * are ignored and the lock ID in the LKSB is used to identify the lock.
+ *
+ * DLM_LKF_VALBLK
+ *
+ * Requests DLM to return the current contents of the lock value block in the
+ * lock status block.  When this flag is set in a lock conversion from PW or EX
+ * modes, DLM assigns the value specified in the lock status block to the lock
+ * value block of the lock resource.  The LVB is a DLM_LVB_LEN size array
+ * containing application-specific information.
+ *
+ * DLM_LKF_QUECVT
+ *
+ * Force a conversion request to be queued, even if it is compatible with
+ * the granted modes of other locks on the same resource.
+ *
+ * DLM_LKF_IVVALBLK
+ *
+ * Invalidate the lock value block.
+ *
+ * DLM_LKF_CONVDEADLK
+ *
+ * Allows the dlm to resolve conversion deadlocks internally by demoting the
+ * granted mode of a converting lock to NL.  The DLM_SBF_DEMOTED flag is
+ * returned for a conversion that's been effected by this.
+ *
+ * DLM_LKF_PERSISTENT
+ *
+ * Only relevant to locks originating in userspace.  A persistent lock will not
+ * be removed if the process holding the lock exits.
+ *
+ * DLM_LKF_NODLCKWT
+ *
+ * Do not cancel the lock if it gets into conversion deadlock.
+ * Exclude this lock from being monitored due to DLM_LSFL_TIMEWARN.
+ *
+ * DLM_LKF_NODLCKBLK
+ *
+ * net yet implemented
+ *
+ * DLM_LKF_EXPEDITE
+ *
+ * Used only with new requests for NL mode locks.  Tells the lock manager
+ * to grant the lock, ignoring other locks in convert and wait queues.
+ *
+ * DLM_LKF_NOQUEUEBAST
+ *
+ * Send blocking AST's before returning -EAGAIN to the caller.  It is only
+ * used along with the NOQUEUE flag.  Blocking AST's are not sent for failed
+ * NOQUEUE requests otherwise.
+ *
+ * DLM_LKF_HEADQUE
+ *
+ * Add a lock to the head of the convert or wait queue rather than the tail.
+ *
+ * DLM_LKF_NOORDER
+ *
+ * Disregard the standard grant order rules and grant a lock as soon as it
+ * is compatible with other granted locks.
+ *
+ * DLM_LKF_ORPHAN
+ *
+ * not yet implemented
+ *
+ * DLM_LKF_ALTPR
+ *
+ * If the requested mode cannot be granted immediately, try to grant the lock
+ * in PR mode instead.  If this alternate mode is granted instead of the
+ * requested mode, DLM_SBF_ALTMODE is returned in the lksb.
+ *
+ * DLM_LKF_ALTCW
+ *
+ * The same as ALTPR, but the alternate mode is CW.
+ *
+ * DLM_LKF_FORCEUNLOCK
+ *
+ * Unlock the lock even if it is converting or waiting or has sublocks.
+ * Only really for use by the userland device.c code.
+ *
+ */
+
+#define DLM_LKF_NOQUEUE                0x00000001
+#define DLM_LKF_CANCEL         0x00000002
+#define DLM_LKF_CONVERT                0x00000004
+#define DLM_LKF_VALBLK         0x00000008
+#define DLM_LKF_QUECVT         0x00000010
+#define DLM_LKF_IVVALBLK       0x00000020
+#define DLM_LKF_CONVDEADLK     0x00000040
+#define DLM_LKF_PERSISTENT     0x00000080
+#define DLM_LKF_NODLCKWT       0x00000100
+#define DLM_LKF_NODLCKBLK      0x00000200
+#define DLM_LKF_EXPEDITE       0x00000400
+#define DLM_LKF_NOQUEUEBAST    0x00000800
+#define DLM_LKF_HEADQUE                0x00001000
+#define DLM_LKF_NOORDER                0x00002000
+#define DLM_LKF_ORPHAN         0x00004000
+#define DLM_LKF_ALTPR          0x00008000
+#define DLM_LKF_ALTCW          0x00010000
+#define DLM_LKF_FORCEUNLOCK    0x00020000
+#define DLM_LKF_TIMEOUT                0x00040000
+
+/*
+ * Some return codes that are not in errno.h
+ */
+
+#define DLM_ECANCEL            0x10001
+#define DLM_EUNLOCK            0x10002
+
+#endif  /* __DLMCONSTANTS_DOT_H__ */
index a3b6035b6c860c506c7c5c2d923cdc8444901ad6..55c9a6952f447c6284a5b75b88ac9696ddc89214 100644 (file)
@@ -132,7 +132,7 @@ struct dma_chan {
 
        /* sysfs */
        int chan_id;
-       struct class_device class_dev;
+       struct device dev;
 
        struct kref refcount;
        int slow_ref;
@@ -142,6 +142,7 @@ struct dma_chan {
        struct dma_chan_percpu *local;
 };
 
+#define to_dma_chan(p) container_of(p, struct dma_chan, dev)
 
 void dma_chan_cleanup(struct kref *kref);
 
index 00fc7a9c35eccdbb2b0b577e0e110fafb0b96668..5b42a659a308d046a886ca86fd05e260822a77b4 100644 (file)
@@ -78,6 +78,8 @@ extern const struct dmi_device * dmi_find_device(int type, const char *name,
 extern void dmi_scan_machine(void);
 extern int dmi_get_year(int field);
 extern int dmi_name_in_vendors(const char *str);
+extern int dmi_available;
+extern char *dmi_get_slot(int slot);
 
 #else
 
@@ -87,6 +89,8 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na
        const struct dmi_device *from) { return NULL; }
 static inline int dmi_get_year(int year) { return 0; }
 static inline int dmi_name_in_vendors(const char *s) { return 0; }
+#define dmi_available 0
+static inline char *dmi_get_slot(int slot) { return NULL; }
 
 #endif
 
index b3ec4a496d64faa3a380827abed7b54d9d8bd7da..21398a5d688d3e188325822c781ae19e8c67d6b9 100644 (file)
@@ -1476,7 +1476,7 @@ extern void drop_collected_mounts(struct vfsmount *);
 extern int vfs_statfs(struct dentry *, struct kstatfs *);
 
 /* /sys/fs */
-extern struct kset fs_subsys;
+extern struct kobject *fs_kobj;
 
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
index 92d420fe03f8173d072b1d8d03a7c51fdcef2125..1a15f8e237a7cf2404b1aa5bf16ccbb4f52214b4 100644 (file)
@@ -1,8 +1,12 @@
 #ifndef _LINUX_FUTEX_H
 #define _LINUX_FUTEX_H
 
-#include <linux/sched.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
 
+struct inode;
+struct mm_struct;
+struct task_struct;
 union ktime;
 
 /* Second argument to futex syscall */
index a47b8025d39935c18a66db9cc975a58fe8f85dda..1dbea0ac5693049885c7c8ec33ec158dad1cb4bc 100644 (file)
  */
 
 #include <linux/types.h>
+#include <linux/kdev_t.h>
 
 #ifdef CONFIG_BLOCK
 
+#define kobj_to_dev(k) container_of(k, struct device, kobj)
+#define dev_to_disk(device) container_of(device, struct gendisk, dev)
+#define dev_to_part(device) container_of(device, struct hd_struct, dev)
+
+extern struct device_type disk_type;
+extern struct device_type part_type;
+extern struct kobject *block_depr;
+extern struct class block_class;
+
 enum {
 /* These three have identical behaviour; use the second one if DOS FDISK gets
    confused about extended/logical partitions starting past cylinder 1023. */
@@ -84,7 +94,7 @@ struct partition {
 struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
-       struct kobject kobj;
+       struct device dev;
        struct kobject *holder_dir;
        unsigned ios[2], sectors[2];    /* READs and WRITEs */
        int policy, partno;
@@ -117,15 +127,14 @@ struct gendisk {
                                          * disks that can't be partitioned. */
        char disk_name[32];             /* name of major driver */
        struct hd_struct **part;        /* [indexed by minor] */
-       int part_uevent_suppress;
        struct block_device_operations *fops;
        struct request_queue *queue;
        void *private_data;
        sector_t capacity;
 
        int flags;
-       struct device *driverfs_dev;
-       struct kobject kobj;
+       struct device *driverfs_dev;  // FIXME: remove
+       struct device dev;
        struct kobject *holder_dir;
        struct kobject *slave_dir;
 
@@ -143,13 +152,6 @@ struct gendisk {
        struct work_struct async_notify;
 };
 
-/* Structure for sysfs attributes on block devices */
-struct disk_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct gendisk *, char *);
-       ssize_t (*store)(struct gendisk *, const char *, size_t);
-};
-
 /* 
  * Macros to operate on percpu disk statistics:
  *
@@ -411,7 +413,8 @@ struct unixware_disklabel {
 #define ADDPART_FLAG_RAID      1
 #define ADDPART_FLAG_WHOLEDISK 2
 
-char *disk_name (struct gendisk *hd, int part, char *buf);
+extern dev_t blk_lookup_devt(const char *name);
+extern char *disk_name (struct gendisk *hd, int part, char *buf);
 
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
 extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);
@@ -423,12 +426,12 @@ extern struct gendisk *alloc_disk(int minors);
 extern struct kobject *get_disk(struct gendisk *disk);
 extern void put_disk(struct gendisk *disk);
 extern void genhd_media_change_notify(struct gendisk *disk);
-extern void blk_register_region(dev_t dev, unsigned long range,
+extern void blk_register_region(dev_t devt, unsigned long range,
                        struct module *module,
                        struct kobject *(*probe)(dev_t, int *, void *),
                        int (*lock)(dev_t, void *),
                        void *data);
-extern void blk_unregister_region(dev_t dev, unsigned long range);
+extern void blk_unregister_region(dev_t devt, unsigned long range);
 
 static inline struct block_device *bdget_disk(struct gendisk *disk, int index)
 {
@@ -441,6 +444,12 @@ static inline struct block_device *bdget_disk(struct gendisk *disk, int index)
 
 static inline void printk_all_partitions(void) { }
 
+static inline dev_t blk_lookup_devt(const char *name)
+{
+       dev_t devt = MKDEV(0, 0);
+       return devt;
+}
+
 #endif /* CONFIG_BLOCK */
 
 #endif
index 8d302298a161941ce40c6ed47411627d5f0229f8..2961ec788046627c823feb291d7d522f15982fbf 100644 (file)
 #define in_softirq()           (softirq_count())
 #define in_interrupt()         (irq_count())
 
-#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL)
-# define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
-#else
-# define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != 0)
-#endif
+#define in_atomic()            ((preempt_count() & ~PREEMPT_ACTIVE) != 0)
 
 #ifdef CONFIG_PREEMPT
 # define PREEMPT_CHECK_OFFSET 1
index 818c6afc109190affc2d592ea66fb120efdd139f..ff43f8d6b5b330379ef301dc8276088a1d59de20 100644 (file)
@@ -44,7 +44,9 @@
 
 /* Bits for HD_ERROR */
 #define MARK_ERR               0x01    /* Bad address mark */
+#define ILI_ERR                        0x01    /* Illegal Length Indication (ATAPI) */
 #define TRK0_ERR               0x02    /* couldn't find track 0 */
+#define EOM_ERR                        0x02    /* End Of Media (ATAPI) */
 #define ABRT_ERR               0x04    /* Command aborted */
 #define MCR_ERR                        0x08    /* media change request */
 #define ID_ERR                 0x10    /* ID field not found */
@@ -52,6 +54,7 @@
 #define ECC_ERR                        0x40    /* Uncorrectable ECC error */
 #define BBD_ERR                        0x80    /* pre-EIDE meaning:  block marked bad */
 #define ICRC_ERR               0x80    /* new meaning:  CRC error during transfer */
+#define LFS_ERR                        0xf0    /* Last Failed Sense (ATAPI) */
 
 /* Bits of HD_NSECTOR */
 #define CD                     0x01
 #define HDIO_DRIVE_HOB_HDR_SIZE                (8 * sizeof(__u8))
 #define HDIO_DRIVE_TASK_HDR_SIZE       (8 * sizeof(__u8))
 
-#define IDE_DRIVE_TASK_INVALID         -1
 #define IDE_DRIVE_TASK_NO_DATA         0
+#ifndef __KERNEL__
+#define IDE_DRIVE_TASK_INVALID         -1
 #define IDE_DRIVE_TASK_SET_XFER                1
-
 #define IDE_DRIVE_TASK_IN              2
-
 #define IDE_DRIVE_TASK_OUT             3
+#endif
 #define IDE_DRIVE_TASK_RAW_WRITE       4
 
 /*
 #ifndef __KERNEL__
 #define IDE_TASKFILE_STD_OUT_FLAGS     0xFE
 #define IDE_HOB_STD_OUT_FLAGS          0x3C
-#endif
 
 typedef unsigned char task_ioreg_t;
 typedef unsigned long sata_ioreg_t;
+#endif
 
 typedef union ide_reg_valid_s {
        unsigned all                            : 16;
@@ -116,8 +119,8 @@ typedef union ide_reg_valid_s {
 } ide_reg_valid_t;
 
 typedef struct ide_task_request_s {
-       task_ioreg_t    io_ports[8];
-       task_ioreg_t    hob_ports[8];
+       __u8            io_ports[8];
+       __u8            hob_ports[8]; /* bytes 6 and 7 are unused */
        ide_reg_valid_t out_flags;
        ide_reg_valid_t in_flags;
        int             data_phase;
@@ -133,36 +136,35 @@ typedef struct ide_ioctl_request_s {
 } ide_ioctl_request_t;
 
 struct hd_drive_cmd_hdr {
-       task_ioreg_t command;
-       task_ioreg_t sector_number;
-       task_ioreg_t feature;
-       task_ioreg_t sector_count;
+       __u8 command;
+       __u8 sector_number;
+       __u8 feature;
+       __u8 sector_count;
 };
 
+#ifndef __KERNEL__
 typedef struct hd_drive_task_hdr {
-       task_ioreg_t data;
-       task_ioreg_t feature;
-       task_ioreg_t sector_count;
-       task_ioreg_t sector_number;
-       task_ioreg_t low_cylinder;
-       task_ioreg_t high_cylinder;
-       task_ioreg_t device_head;
-       task_ioreg_t command;
+       __u8 data;
+       __u8 feature;
+       __u8 sector_count;
+       __u8 sector_number;
+       __u8 low_cylinder;
+       __u8 high_cylinder;
+       __u8 device_head;
+       __u8 command;
 } task_struct_t;
 
 typedef struct hd_drive_hob_hdr {
-       task_ioreg_t data;
-       task_ioreg_t feature;
-       task_ioreg_t sector_count;
-       task_ioreg_t sector_number;
-       task_ioreg_t low_cylinder;
-       task_ioreg_t high_cylinder;
-       task_ioreg_t device_head;
-       task_ioreg_t control;
+       __u8 data;
+       __u8 feature;
+       __u8 sector_count;
+       __u8 sector_number;
+       __u8 low_cylinder;
+       __u8 high_cylinder;
+       __u8 device_head;
+       __u8 control;
 } hob_struct_t;
-
-#define TASKFILE_INVALID               0x7fff
-#define TASKFILE_48                    0x8000
+#endif
 
 #define TASKFILE_NO_DATA               0x0000
 
@@ -178,12 +180,16 @@ typedef struct hd_drive_hob_hdr {
 #define TASKFILE_IN_DMAQ               0x0080
 #define TASKFILE_OUT_DMAQ              0x0100
 
+#ifndef __KERNEL__
 #define TASKFILE_P_IN                  0x0200
 #define TASKFILE_P_OUT                 0x0400
 #define TASKFILE_P_IN_DMA              0x0800
 #define TASKFILE_P_OUT_DMA             0x1000
 #define TASKFILE_P_IN_DMAQ             0x2000
 #define TASKFILE_P_OUT_DMAQ            0x4000
+#define TASKFILE_48                    0x8000
+#define TASKFILE_INVALID               0x7fff
+#endif
 
 /* ATA/ATAPI Commands pre T13 Spec */
 #define WIN_NOP                                0x00
index 7a9398e1970432a500f5a660bf458c26f0158554..49067f14fac190ea7bb492fceb1befdcf46aadce 100644 (file)
@@ -115,10 +115,8 @@ struct hrtimer {
        enum hrtimer_restart            (*function)(struct hrtimer *);
        struct hrtimer_clock_base       *base;
        unsigned long                   state;
-#ifdef CONFIG_HIGH_RES_TIMERS
        enum hrtimer_cb_mode            cb_mode;
        struct list_head                cb_entry;
-#endif
 #ifdef CONFIG_TIMER_STATS
        void                            *start_site;
        char                            start_comm[16];
@@ -194,10 +192,10 @@ struct hrtimer_cpu_base {
        spinlock_t                      lock;
        struct lock_class_key           lock_key;
        struct hrtimer_clock_base       clock_base[HRTIMER_MAX_CLOCK_BASES];
+       struct list_head                cb_pending;
 #ifdef CONFIG_HIGH_RES_TIMERS
        ktime_t                         expires_next;
        int                             hres_active;
-       struct list_head                cb_pending;
        unsigned long                   nr_events;
 #endif
 };
@@ -217,6 +215,11 @@ static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer)
        return timer->base->get_time();
 }
 
+static inline int hrtimer_is_hres_active(struct hrtimer *timer)
+{
+       return timer->base->cpu_base->hres_active;
+}
+
 /*
  * The resolution of the clocks. The resolution value is returned in
  * the clock_getres() system call to give application programmers an
@@ -248,6 +251,10 @@ static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer)
        return timer->base->softirq_time;
 }
 
+static inline int hrtimer_is_hres_active(struct hrtimer *timer)
+{
+       return 0;
+}
 #endif
 
 extern ktime_t ktime_get(void);
@@ -310,6 +317,7 @@ extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
 
 /* Soft interrupt function to run the hrtimer queues: */
 extern void hrtimer_run_queues(void);
+extern void hrtimer_run_pending(void);
 
 /* Bootup initialization: */
 extern void __init hrtimers_init(void);
index 21ea7610e1775ae4be3015f36f956d19f88e8b73..85d11916e9ea48a878f54eb3aff5045a8ec2b2c7 100644 (file)
@@ -33,7 +33,7 @@ struct hwrng {
        const char *name;
        int (*init)(struct hwrng *rng);
        void (*cleanup)(struct hwrng *rng);
-       int (*data_present)(struct hwrng *rng);
+       int (*data_present)(struct hwrng *rng, int wait);
        int (*data_read)(struct hwrng *rng, u32 *data);
        unsigned long priv;
 
index 88c81403eb3ff8dbb4804e72c0fa65d28afe0691..c7a51a196f5107438beb47417bfa889bdbffd509 100644 (file)
 #ifndef LINUX_I2C_ID_H
 #define LINUX_I2C_ID_H
 
+/* Please note that I2C driver IDs are optional. They are only needed if a
+   legacy chip driver needs to identify a bus or a bus driver needs to
+   identify a legacy client. If you don't need them, just don't set them. */
+
 /*
  * ---- Driver types -----------------------------------------------------
  */
 #define I2C_DRIVERID_LM4857    92      /* LM4857 Audio Amplifier */
 #define I2C_DRIVERID_VP27SMPX  93      /* Panasonic VP27s tuner internal MPX */
 #define I2C_DRIVERID_CS4270    94      /* Cirrus Logic 4270 audio codec */
+#define I2C_DRIVERID_M52790    95      /* Mitsubishi M52790SP/FP AV switch */
+#define I2C_DRIVERID_CS5345    96      /* cs5345 audio processor       */
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
index 9a6a41e7079ff942ec4d204ae20011ee7987d6a2..27cb39de2ae2e5ed8daa2ecc49cfe61731651e19 100644 (file)
 #include <asm/semaphore.h>
 #include <asm/mutex.h>
 
-/******************************************************************************
- * IDE driver configuration options (play with these as desired):
- *
- * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
- */
-#define INITIAL_MULT_COUNT     0       /* off=0; on=2,4,8,16,32, etc.. */
-
-#ifndef SUPPORT_SLOW_DATA_PORTS                /* 1 to support slow data ports */
-#define SUPPORT_SLOW_DATA_PORTS        1       /* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_VLB_SYNC               /* 1 to support weird 32-bit chips */
-#define SUPPORT_VLB_SYNC       1       /* 0 to reduce kernel size */
-#endif
-#ifndef OK_TO_RESET_CONTROLLER         /* 1 needed for good error recovery */
-#define OK_TO_RESET_CONTROLLER 1       /* 0 for use with AH2372A/B interface */
-#endif
-
-#ifndef DISABLE_IRQ_NOSYNC
-#define DISABLE_IRQ_NOSYNC     0
+#if defined(CRIS) || defined(FRV)
+# define SUPPORT_VLB_SYNC 0
+#else
+# define SUPPORT_VLB_SYNC 1
 #endif
 
 /*
  
 #define IDE_NO_IRQ             (-1)
 
-/*
- *  "No user-serviceable parts" beyond this point  :)
- *****************************************************************************/
-
 typedef unsigned char  byte;   /* used everywhere */
 
 /*
@@ -103,8 +84,6 @@ typedef unsigned char        byte;   /* used everywhere */
 #define IDE_FEATURE_OFFSET     IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET     IDE_STATUS_OFFSET
 
-#define IDE_CONTROL_OFFSET_HOB (7)
-
 #define IDE_DATA_REG           (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
 #define IDE_ERROR_REG          (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
 #define IDE_NSECTOR_REG                (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
@@ -128,7 +107,6 @@ typedef unsigned char       byte;   /* used everywhere */
 #define BAD_W_STAT             (BAD_R_STAT  | WRERR_STAT)
 #define BAD_STAT               (BAD_R_STAT  | DRQ_STAT)
 #define DRIVE_READY            (READY_STAT  | SEEK_STAT)
-#define DATA_READY             (DRQ_STAT)
 
 #define BAD_CRC                        (ABRT_ERR    | ICRC_ERR)
 
@@ -219,8 +197,11 @@ typedef struct hw_regs_s {
 } hw_regs_t;
 
 struct hwif_s * ide_find_port(unsigned long);
+void ide_init_port_data(struct hwif_s *, unsigned int);
+void ide_init_port_hw(struct hwif_s *, hw_regs_t *);
 
-int ide_register_hw(hw_regs_t *, void (*)(struct hwif_s *), int,
+struct ide_drive_s;
+int ide_register_hw(hw_regs_t *, void (*)(struct ide_drive_s *),
                    struct hwif_s **);
 
 void ide_setup_ports(  hw_regs_t *hw,
@@ -327,46 +308,15 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw,
 typedef union {
        unsigned all                    : 8;
        struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
                unsigned set_geometry   : 1;
                unsigned recalibrate    : 1;
                unsigned set_multmode   : 1;
                unsigned set_tune       : 1;
                unsigned serviced       : 1;
                unsigned reserved       : 3;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned reserved       : 3;
-               unsigned serviced       : 1;
-               unsigned set_tune       : 1;
-               unsigned set_multmode   : 1;
-               unsigned recalibrate    : 1;
-               unsigned set_geometry   : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
        } b;
 } special_t;
 
-/*
- * ATA DATA Register Special.
- * ATA NSECTOR Count Register().
- * ATAPI Byte Count Register.
- */
-typedef union {
-       unsigned all                    :16;
-       struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-               unsigned low            :8;     /* LSB */
-               unsigned high           :8;     /* MSB */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned high           :8;     /* MSB */
-               unsigned low            :8;     /* LSB */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       } b;
-} ata_nsector_t, ata_data_t, atapi_bcount_t;
-
 /*
  * ATA-IDE Select Register, aka Device-Head
  *
@@ -397,131 +347,6 @@ typedef union {
        } b;
 } select_t, ata_select_t;
 
-/*
- * The ATA-IDE Status Register.
- * The ATAPI Status Register.
- *
- * check       : Error occurred
- * idx         : Index Error
- * corr                : Correctable error occurred
- * drq         : Data is request by the device
- * dsc         : Disk Seek Complete                    : ata
- *             : Media access command finished         : atapi
- * df          : Device Fault                          : ata
- *             : Reserved                              : atapi
- * drdy                : Ready, Command Mode Capable           : ata
- *             : Ignored for ATAPI commands            : atapi
- * bsy         : Disk is Busy
- *             : The device has access to the command block
- */
-typedef union {
-       unsigned all                    :8;
-       struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-               unsigned check          :1;
-               unsigned idx            :1;
-               unsigned corr           :1;
-               unsigned drq            :1;
-               unsigned dsc            :1;
-               unsigned df             :1;
-               unsigned drdy           :1;
-               unsigned bsy            :1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned bsy            :1;
-               unsigned drdy           :1;
-               unsigned df             :1;
-               unsigned dsc            :1;
-               unsigned drq            :1;
-               unsigned corr           :1;
-               unsigned idx            :1;
-               unsigned check          :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       } b;
-} ata_status_t, atapi_status_t;
-
-/*
- * ATAPI Feature Register
- *
- * dma         : Using DMA or PIO
- * reserved321 : Reserved
- * reserved654 : Reserved (Tag Type)
- * reserved7   : Reserved
- */
-typedef union {
-       unsigned all                    :8;
-       struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-               unsigned dma            :1;
-               unsigned reserved321    :3;
-               unsigned reserved654    :3;
-               unsigned reserved7      :1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned reserved7      :1;
-               unsigned reserved654    :3;
-               unsigned reserved321    :3;
-               unsigned dma            :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       } b;
-} atapi_feature_t;
-
-/*
- * ATAPI Interrupt Reason Register.
- *
- * cod         : Information transferred is command (1) or data (0)
- * io          : The device requests us to read (1) or write (0)
- * reserved    : Reserved
- */
-typedef union {
-       unsigned all                    :8;
-       struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-               unsigned cod            :1;
-               unsigned io             :1;
-               unsigned reserved       :6;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned reserved       :6;
-               unsigned io             :1;
-               unsigned cod            :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       } b;
-} atapi_ireason_t;
-
-/*
- * The ATAPI error register.
- *
- * ili         : Illegal Length Indication
- * eom         : End Of Media Detected
- * abrt                : Aborted command - As defined by ATA
- * mcr         : Media Change Requested - As defined by ATA
- * sense_key   : Sense key of the last failed packet command
- */
-typedef union {
-       unsigned all                    :8;
-       struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-               unsigned ili            :1;
-               unsigned eom            :1;
-               unsigned abrt           :1;
-               unsigned mcr            :1;
-               unsigned sense_key      :4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned sense_key      :4;
-               unsigned mcr            :1;
-               unsigned abrt           :1;
-               unsigned eom            :1;
-               unsigned ili            :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       } b;
-} atapi_error_t;
-
 /*
  * Status returned from various ide_ functions
  */
@@ -568,7 +393,6 @@ typedef struct ide_drive_s {
        u8      state;                  /* retry state */
        u8      waiting_for_dma;        /* dma currently in progress */
        u8      unmask;                 /* okay to unmask other irqs */
-       u8      bswap;                  /* byte swap data */
        u8      noflush;                /* don't attempt flushes */
        u8      dsc_overlap;            /* DSC overlap */
        u8      nice1;                  /* give potential excess bandwidth */
@@ -701,36 +525,29 @@ typedef struct hwif_s {
        void    (*pre_reset)(ide_drive_t *);
        /* routine to reset controller after a disk reset */
        void    (*resetproc)(ide_drive_t *);
-       /* special interrupt handling for shared pci interrupts */
-       void    (*intrproc)(ide_drive_t *);
        /* special host masking for drive selection */
        void    (*maskproc)(ide_drive_t *, int);
        /* check host's drive quirk list */
-       int     (*quirkproc)(ide_drive_t *);
+       void    (*quirkproc)(ide_drive_t *);
        /* driver soft-power interface */
        int     (*busproc)(ide_drive_t *, int);
 #endif
        u8 (*mdma_filter)(ide_drive_t *);
        u8 (*udma_filter)(ide_drive_t *);
 
-       void (*fixup)(struct hwif_s *);
-
        void (*ata_input_data)(ide_drive_t *, void *, u32);
        void (*ata_output_data)(ide_drive_t *, void *, u32);
 
        void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
        void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
 
+       void (*dma_host_set)(ide_drive_t *, int);
        int (*dma_setup)(ide_drive_t *);
        void (*dma_exec_cmd)(ide_drive_t *, u8);
        void (*dma_start)(ide_drive_t *);
        int (*ide_dma_end)(ide_drive_t *drive);
-       int (*ide_dma_on)(ide_drive_t *drive);
-       void (*dma_off_quietly)(ide_drive_t *drive);
        int (*ide_dma_test_irq)(ide_drive_t *drive);
        void (*ide_dma_clear_irq)(ide_drive_t *drive);
-       void (*dma_host_on)(ide_drive_t *drive);
-       void (*dma_host_off)(ide_drive_t *drive);
        void (*dma_lost_irq)(ide_drive_t *drive);
        void (*dma_timeout)(ide_drive_t *drive);
 
@@ -766,7 +583,6 @@ typedef struct hwif_s {
        int             rqsize;         /* max sectors per request */
        int             irq;            /* our irq number */
 
-       unsigned long   dma_master;     /* reference base addr dmabase */
        unsigned long   dma_base;       /* base addr for dma ports */
        unsigned long   dma_command;    /* dma command register */
        unsigned long   dma_vendor1;    /* dma vendor 1 register */
@@ -806,7 +622,6 @@ typedef struct hwif_s {
 /*
  *  internal ide interrupt handler type
  */
-typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 typedef int (ide_expiry_t)(ide_drive_t *);
 
@@ -1020,7 +835,8 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
 
 extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
 
-extern void ide_execute_command(ide_drive_t *, task_ioreg_t cmd, ide_handler_t *, unsigned int, ide_expiry_t *);
+void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int,
+                        ide_expiry_t *);
 
 ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8);
 
@@ -1054,60 +870,126 @@ extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
 
 extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
-/*
- * Issue ATA command and wait for completion.
- * Use for implementing commands in kernel
- *
- *  (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
- */
-extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *);
+enum {
+       IDE_TFLAG_LBA48                 = (1 << 0),
+       IDE_TFLAG_NO_SELECT_MASK        = (1 << 1),
+       IDE_TFLAG_FLAGGED               = (1 << 2),
+       IDE_TFLAG_OUT_DATA              = (1 << 3),
+       IDE_TFLAG_OUT_HOB_FEATURE       = (1 << 4),
+       IDE_TFLAG_OUT_HOB_NSECT         = (1 << 5),
+       IDE_TFLAG_OUT_HOB_LBAL          = (1 << 6),
+       IDE_TFLAG_OUT_HOB_LBAM          = (1 << 7),
+       IDE_TFLAG_OUT_HOB_LBAH          = (1 << 8),
+       IDE_TFLAG_OUT_HOB               = IDE_TFLAG_OUT_HOB_FEATURE |
+                                         IDE_TFLAG_OUT_HOB_NSECT |
+                                         IDE_TFLAG_OUT_HOB_LBAL |
+                                         IDE_TFLAG_OUT_HOB_LBAM |
+                                         IDE_TFLAG_OUT_HOB_LBAH,
+       IDE_TFLAG_OUT_FEATURE           = (1 << 9),
+       IDE_TFLAG_OUT_NSECT             = (1 << 10),
+       IDE_TFLAG_OUT_LBAL              = (1 << 11),
+       IDE_TFLAG_OUT_LBAM              = (1 << 12),
+       IDE_TFLAG_OUT_LBAH              = (1 << 13),
+       IDE_TFLAG_OUT_TF                = IDE_TFLAG_OUT_FEATURE |
+                                         IDE_TFLAG_OUT_NSECT |
+                                         IDE_TFLAG_OUT_LBAL |
+                                         IDE_TFLAG_OUT_LBAM |
+                                         IDE_TFLAG_OUT_LBAH,
+       IDE_TFLAG_OUT_DEVICE            = (1 << 14),
+       IDE_TFLAG_WRITE                 = (1 << 15),
+       IDE_TFLAG_FLAGGED_SET_IN_FLAGS  = (1 << 16),
+       IDE_TFLAG_IN_DATA               = (1 << 17),
+       IDE_TFLAG_CUSTOM_HANDLER        = (1 << 18),
+       IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 19),
+       IDE_TFLAG_IN_HOB_FEATURE        = (1 << 20),
+       IDE_TFLAG_IN_HOB_NSECT          = (1 << 21),
+       IDE_TFLAG_IN_HOB_LBAL           = (1 << 22),
+       IDE_TFLAG_IN_HOB_LBAM           = (1 << 23),
+       IDE_TFLAG_IN_HOB_LBAH           = (1 << 24),
+       IDE_TFLAG_IN_HOB_LBA            = IDE_TFLAG_IN_HOB_LBAL |
+                                         IDE_TFLAG_IN_HOB_LBAM |
+                                         IDE_TFLAG_IN_HOB_LBAH,
+       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_FEATURE |
+                                         IDE_TFLAG_IN_HOB_NSECT |
+                                         IDE_TFLAG_IN_HOB_LBA,
+       IDE_TFLAG_IN_NSECT              = (1 << 25),
+       IDE_TFLAG_IN_LBAL               = (1 << 26),
+       IDE_TFLAG_IN_LBAM               = (1 << 27),
+       IDE_TFLAG_IN_LBAH               = (1 << 28),
+       IDE_TFLAG_IN_LBA                = IDE_TFLAG_IN_LBAL |
+                                         IDE_TFLAG_IN_LBAM |
+                                         IDE_TFLAG_IN_LBAH,
+       IDE_TFLAG_IN_TF                 = IDE_TFLAG_IN_NSECT |
+                                         IDE_TFLAG_IN_LBA,
+       IDE_TFLAG_IN_DEVICE             = (1 << 29),
+       IDE_TFLAG_HOB                   = IDE_TFLAG_OUT_HOB |
+                                         IDE_TFLAG_IN_HOB,
+       IDE_TFLAG_TF                    = IDE_TFLAG_OUT_TF |
+                                         IDE_TFLAG_IN_TF,
+       IDE_TFLAG_DEVICE                = IDE_TFLAG_OUT_DEVICE |
+                                         IDE_TFLAG_IN_DEVICE,
+       /* force 16-bit I/O operations */
+       IDE_TFLAG_IO_16BIT              = (1 << 30),
+};
+
+struct ide_taskfile {
+       u8      hob_data;       /*  0: high data byte (for TASKFILE IOCTL) */
+
+       u8      hob_feature;    /*  1-5: additional data to support LBA48 */
+       u8      hob_nsect;
+       u8      hob_lbal;
+       u8      hob_lbam;
+       u8      hob_lbah;
+
+       u8      data;           /*  6: low data byte (for TASKFILE IOCTL) */
+
+       union {                 /*  7: */
+               u8 error;       /*   read:  error */
+               u8 feature;     /*  write: feature */
+       };
+
+       u8      nsect;          /*  8: number of sectors */
+       u8      lbal;           /*  9: LBA low */
+       u8      lbam;           /* 10: LBA mid */
+       u8      lbah;           /* 11: LBA high */
+
+       u8      device;         /* 12: device select */
+
+       union {                 /* 13: */
+               u8 status;      /*  read: status  */
+               u8 command;     /* write: command */
+       };
+};
 
 typedef struct ide_task_s {
-/*
- *     struct hd_drive_task_hdr        tf;
- *     task_struct_t           tf;
- *     struct hd_drive_hob_hdr         hobf;
- *     hob_struct_t            hobf;
- */
-       task_ioreg_t            tfRegister[8];
-       task_ioreg_t            hobRegister[8];
-       ide_reg_valid_t         tf_out_flags;
-       ide_reg_valid_t         tf_in_flags;
+       union {
+               struct ide_taskfile     tf;
+               u8                      tf_array[14];
+       };
+       u32                     tf_flags;
        int                     data_phase;
-       int                     command_type;
-       ide_pre_handler_t       *prehandler;
-       ide_handler_t           *handler;
        struct request          *rq;            /* copy of request */
        void                    *special;       /* valid_t generally */
 } ide_task_t;
 
-extern u32 ide_read_24(ide_drive_t *);
+void ide_tf_load(ide_drive_t *, ide_task_t *);
+void ide_tf_read(ide_drive_t *, ide_task_t *);
 
 extern void SELECT_DRIVE(ide_drive_t *);
-extern void SELECT_INTERRUPT(ide_drive_t *);
 extern void SELECT_MASK(ide_drive_t *, int);
-extern void QUIRK_LIST(ide_drive_t *);
 
 extern int drive_is_ready(ide_drive_t *);
 
-/*
- * taskfile io for disks for now...and builds request from ide_ioctl
- */
-extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
+void ide_pktcmd_tf_load(ide_drive_t *, u32, u16, u8);
 
-/*
- * Special Flagged Register Validation Caller
- */
-extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
+
+void task_end_request(ide_drive_t *, struct request *, u8);
 
-extern ide_startstop_t set_multmode_intr(ide_drive_t *);
-extern ide_startstop_t set_geometry_intr(ide_drive_t *);
-extern ide_startstop_t recal_intr(ide_drive_t *);
-extern ide_startstop_t task_no_data_intr(ide_drive_t *);
-extern ide_startstop_t task_in_intr(ide_drive_t *);
-extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+u8 wait_drive_not_busy(ide_drive_t *);
 
-extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
+int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16);
+int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
 
 int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
 int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long);
@@ -1133,10 +1015,9 @@ extern void do_ide_request(struct request_queue *);
 
 void ide_init_disk(struct gendisk *, ide_drive_t *);
 
-extern int ideprobe_init(void);
-
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-extern void ide_scan_pcibus(int scan_direction) __init;
+extern int ide_scan_direction;
+int __init ide_scan_pcibus(void);
 extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
 #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
 #else
@@ -1212,6 +1093,9 @@ enum {
        IDE_HFLAG_IO_32BIT              = (1 << 24),
        /* unmask IRQs */
        IDE_HFLAG_UNMASK_IRQS           = (1 << 25),
+       IDE_HFLAG_ABUSE_SET_DMA_MODE    = (1 << 26),
+       /* host is CY82C693 */
+       IDE_HFLAG_CY82C693              = (1 << 27),
 };
 
 #ifdef CONFIG_BLK_DEV_OFFBOARD
@@ -1226,10 +1110,9 @@ struct ide_port_info {
        void                    (*init_iops)(ide_hwif_t *);
        void                    (*init_hwif)(ide_hwif_t *);
        void                    (*init_dma)(ide_hwif_t *, unsigned long);
-       void                    (*fixup)(ide_hwif_t *);
        ide_pci_enablebit_t     enablebits[2];
        hwif_chipset_t          chipset;
-       unsigned int            extra;
+       u8                      extra;
        u32                     host_flags;
        u8                      pio_mask;
        u8                      swdma_mask;
@@ -1264,7 +1147,9 @@ static inline u8 ide_max_dma_mode(ide_drive_t *drive)
        return ide_find_dma_mode(drive, XFER_UDMA_6);
 }
 
+void ide_dma_off_quietly(ide_drive_t *);
 void ide_dma_off(ide_drive_t *);
+void ide_dma_on(ide_drive_t *);
 int ide_set_dma(ide_drive_t *);
 ide_startstop_t ide_dma_intr(ide_drive_t *);
 
@@ -1275,10 +1160,7 @@ extern void ide_destroy_dmatable(ide_drive_t *);
 extern int ide_release_dma(ide_hwif_t *);
 extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
 
-void ide_dma_host_off(ide_drive_t *);
-void ide_dma_off_quietly(ide_drive_t *);
-void ide_dma_host_on(ide_drive_t *);
-extern int __ide_dma_on(ide_drive_t *);
+void ide_dma_host_set(ide_drive_t *, int);
 extern int ide_dma_setup(ide_drive_t *);
 extern void ide_dma_start(ide_drive_t *);
 extern int __ide_dma_end(ide_drive_t *);
@@ -1290,7 +1172,9 @@ extern void ide_dma_timeout(ide_drive_t *);
 static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
 static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
 static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
+static inline void ide_dma_off_quietly(ide_drive_t *drive) { ; }
 static inline void ide_dma_off(ide_drive_t *drive) { ; }
+static inline void ide_dma_on(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -1320,8 +1204,9 @@ extern void ide_unregister (unsigned int index);
 void ide_register_region(struct gendisk *);
 void ide_unregister_region(struct gendisk *);
 
-void ide_undecoded_slave(ide_hwif_t *);
+void ide_undecoded_slave(ide_drive_t *);
 
+int ide_device_add_all(u8 *idx);
 int ide_device_add(u8 idx[4]);
 
 static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
@@ -1356,6 +1241,7 @@ static inline int ide_dev_is_sata(struct hd_driveid *id)
        return 0;
 }
 
+u64 ide_get_lba_addr(struct ide_taskfile *, int);
 u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
 typedef struct ide_pio_timings_s {
@@ -1418,4 +1304,9 @@ static inline ide_drive_t *ide_get_paired_drive(ide_drive_t *drive)
        return &hwif->drives[(drive->dn ^ 1) & 1];
 }
 
+static inline void ide_set_irq(ide_drive_t *drive, int on)
+{
+       drive->hwif->OUTB(drive->ctl | (on ? 0 : 2), IDE_CONTROL_REG);
+}
+
 #endif /* _IDE_H */
index cae35b6b9aecf9a849085a3c67a56da6c57d69cb..796019b22b6ff5c549c609530e454d37d162b1d4 100644 (file)
@@ -132,9 +132,12 @@ extern struct group_info init_groups;
        .cpus_allowed   = CPU_MASK_ALL,                                 \
        .mm             = NULL,                                         \
        .active_mm      = &init_mm,                                     \
-       .run_list       = LIST_HEAD_INIT(tsk.run_list),                 \
+       .rt             = {                                             \
+               .run_list       = LIST_HEAD_INIT(tsk.rt.run_list),      \
+               .time_slice     = HZ,                                   \
+               .nr_cpus_allowed = NR_CPUS,                             \
+       },                                                              \
        .ioprio         = 0,                                            \
-       .time_slice     = HZ,                                           \
        .tasks          = LIST_HEAD_INIT(tsk.tasks),                    \
        .ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),          \
        .ptrace_list    = LIST_HEAD_INIT(tsk.ptrace_list),              \
index 2306920fa38811bf1bdae40343217e8c497362d5..c3db4a00f1fab50cbabe3002d8b7041179471ee2 100644 (file)
@@ -256,6 +256,7 @@ enum
 #ifdef CONFIG_HIGH_RES_TIMERS
        HRTIMER_SOFTIRQ,
 #endif
+       RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
 };
 
 /* softirq mask and active fields moved to irq_cpustat_t in
index 8b080024bbc1fe649770c44b8df540da8ec87d39..7ba9e47bf061588b03556a4aaa767a087cc45c16 100644 (file)
 # define SHIFT_HZ      9
 #elif HZ >= 768 && HZ < 1536
 # define SHIFT_HZ      10
+#elif HZ >= 1536 && HZ < 3072
+# define SHIFT_HZ      11
+#elif HZ >= 3072 && HZ < 6144
+# define SHIFT_HZ      12
+#elif HZ >= 6144 && HZ < 12288
+# define SHIFT_HZ      13
 #else
 # error You lose.
 #endif
index 94bc99656963ac5ad78cada2c608b2d93db4e8c0..a7283c9beadff498968eb1ff506b5369077ae96c 100644 (file)
@@ -105,8 +105,8 @@ struct user;
  * supposed to.
  */
 #ifdef CONFIG_PREEMPT_VOLUNTARY
-extern int cond_resched(void);
-# define might_resched() cond_resched()
+extern int _cond_resched(void);
+# define might_resched() _cond_resched()
 #else
 # define might_resched() do { } while (0)
 #endif
index fcdbd5ed227b56ce486b09fb76f3ef1052f364b6..a70b8a8f20058c60a5bc6916deeaceda5040ea6e 100644 (file)
@@ -290,7 +290,7 @@ extern void key_init(void);
 #define key_get(k)                     ({ NULL; })
 #define key_put(k)                     do { } while(0)
 #define key_ref_put(k)                 do { } while(0)
-#define make_key_ref(k)                        ({ NULL; })
+#define make_key_ref(k, p)                     ({ NULL; })
 #define key_ref_to_ptr(k)              ({ NULL; })
 #define is_key_possessed(k)            0
 #define alloc_uid_keyring(u,c)         0
index 4a0d27f475d7485ba13ee691b9b3978b7a3ed9a8..caa3f411f15d0c48958e40d5369b4e16b9456b15 100644 (file)
@@ -3,15 +3,14 @@
  *
  * Copyright (c) 2002-2003 Patrick Mochel
  * Copyright (c) 2002-2003 Open Source Development Labs
- * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (c) 2006-2007 Novell Inc.
+ * Copyright (c) 2006-2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2008 Novell Inc.
  *
  * This file is released under the GPLv2.
  *
- * 
  * Please read Documentation/kobject.txt before using the kobject
  * interface, ESPECIALLY the parts about reference counts and object
- * destructors. 
+ * destructors.
  */
 
 #ifndef _KOBJECT_H_
@@ -61,48 +60,54 @@ enum kobject_action {
 };
 
 struct kobject {
-       const char              * k_name;
+       const char              *name;
        struct kref             kref;
        struct list_head        entry;
-       struct kobject          * parent;
-       struct kset             * kset;
-       struct kobj_type        * ktype;
-       struct sysfs_dirent     * sd;
+       struct kobject          *parent;
+       struct kset             *kset;
+       struct kobj_type        *ktype;
+       struct sysfs_dirent     *sd;
+       unsigned int state_initialized:1;
+       unsigned int state_in_sysfs:1;
+       unsigned int state_add_uevent_sent:1;
+       unsigned int state_remove_uevent_sent:1;
 };
 
-extern int kobject_set_name(struct kobject *, const char *, ...)
-       __attribute__((format(printf,2,3)));
+extern int kobject_set_name(struct kobject *kobj, const char *name, ...)
+                           __attribute__((format(printf, 2, 3)));
 
-static inline const char * kobject_name(const struct kobject * kobj)
+static inline const char *kobject_name(const struct kobject *kobj)
 {
-       return kobj->k_name;
+       return kobj->name;
 }
 
-extern void kobject_init(struct kobject *);
-extern void kobject_cleanup(struct kobject *);
+extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
+extern int __must_check kobject_add(struct kobject *kobj,
+                                   struct kobject *parent,
+                                   const char *fmt, ...);
+extern int __must_check kobject_init_and_add(struct kobject *kobj,
+                                            struct kobj_type *ktype,
+                                            struct kobject *parent,
+                                            const char *fmt, ...);
+
+extern void kobject_del(struct kobject *kobj);
 
-extern int __must_check kobject_add(struct kobject *);
-extern void kobject_del(struct kobject *);
+extern struct kobject * __must_check kobject_create(void);
+extern struct kobject * __must_check kobject_create_and_add(const char *name,
+                                               struct kobject *parent);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
-extern int __must_check kobject_register(struct kobject *);
-extern void kobject_unregister(struct kobject *);
-
-extern struct kobject * kobject_get(struct kobject *);
-extern void kobject_put(struct kobject *);
-
-extern struct kobject *kobject_kset_add_dir(struct kset *kset,
-                                           struct kobject *, const char *);
-extern struct kobject *kobject_add_dir(struct kobject *, const char *);
+extern struct kobject *kobject_get(struct kobject *kobj);
+extern void kobject_put(struct kobject *kobj);
 
-extern char * kobject_get_path(struct kobject *, gfp_t);
+extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);
 
 struct kobj_type {
-       void (*release)(struct kobject *);
-       struct sysfs_ops        * sysfs_ops;
-       struct attribute        ** default_attrs;
+       void (*release)(struct kobject *kobj);
+       struct sysfs_ops *sysfs_ops;
+       struct attribute **default_attrs;
 };
 
 struct kobj_uevent_env {
@@ -119,6 +124,16 @@ struct kset_uevent_ops {
                      struct kobj_uevent_env *env);
 };
 
+struct kobj_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
+                        const char *buf, size_t count);
+};
+
+extern struct sysfs_ops kobj_sysfs_ops;
+
 /**
  * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  *
@@ -128,7 +143,6 @@ struct kset_uevent_ops {
  * define the attribute callbacks and other common events that happen to
  * a kobject.
  *
- * @ktype: the struct kobj_type for this specific kset
  * @list: the list of all kobjects for this kset
  * @list_lock: a lock for iterating over the kobjects
  * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
@@ -138,99 +152,49 @@ struct kset_uevent_ops {
  * desired.
  */
 struct kset {
-       struct kobj_type        *ktype;
-       struct list_head        list;
-       spinlock_t              list_lock;
-       struct kobject          kobj;
-       struct kset_uevent_ops  *uevent_ops;
+       struct list_head list;
+       spinlock_t list_lock;
+       struct kobject kobj;
+       struct kset_uevent_ops *uevent_ops;
 };
 
+extern void kset_init(struct kset *kset);
+extern int __must_check kset_register(struct kset *kset);
+extern void kset_unregister(struct kset *kset);
+extern struct kset * __must_check kset_create_and_add(const char *name,
+                                               struct kset_uevent_ops *u,
+                                               struct kobject *parent_kobj);
 
-extern void kset_init(struct kset * k);
-extern int __must_check kset_add(struct kset * k);
-extern int __must_check kset_register(struct kset * k);
-extern void kset_unregister(struct kset * k);
-
-static inline struct kset * to_kset(struct kobject * kobj)
+static inline struct kset *to_kset(struct kobject *kobj)
 {
-       return kobj ? container_of(kobj,struct kset,kobj) : NULL;
+       return kobj ? container_of(kobj, struct kset, kobj) : NULL;
 }
 
-static inline struct kset * kset_get(struct kset * k)
+static inline struct kset *kset_get(struct kset *k)
 {
        return k ? to_kset(kobject_get(&k->kobj)) : NULL;
 }
 
-static inline void kset_put(struct kset * k)
+static inline void kset_put(struct kset *k)
 {
        kobject_put(&k->kobj);
 }
 
-static inline struct kobj_type * get_ktype(struct kobject * k)
+static inline struct kobj_type *get_ktype(struct kobject *kobj)
 {
-       if (k->kset && k->kset->ktype)
-               return k->kset->ktype;
-       else 
-               return k->ktype;
+       return kobj->ktype;
 }
 
-extern struct kobject * kset_find_obj(struct kset *, const char *);
-
-
-/*
- * Use this when initializing an embedded kset with no other 
- * fields to initialize.
- */
-#define set_kset_name(str)     .kset = { .kobj = { .k_name = str } }
-
-
-#define decl_subsys(_name,_type,_uevent_ops) \
-struct kset _name##_subsys = { \
-       .kobj = { .k_name = __stringify(_name) }, \
-       .ktype = _type, \
-       .uevent_ops =_uevent_ops, \
-}
-#define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
-struct kset _varname##_subsys = { \
-       .kobj = { .k_name = __stringify(_name) }, \
-       .ktype = _type, \
-       .uevent_ops =_uevent_ops, \
-}
-
-/* The global /sys/kernel/ subsystem for people to chain off of */
-extern struct kset kernel_subsys;
-/* The global /sys/hypervisor/ subsystem  */
-extern struct kset hypervisor_subsys;
-
-/*
- * Helpers for setting the kset of registered objects.
- * Often, a registered object belongs to a kset embedded in a 
- * subsystem. These do no magic, just make the resulting code
- * easier to follow. 
- */
-
-/**
- *     kobj_set_kset_s(obj,subsys) - set kset for embedded kobject.
- *     @obj:           ptr to some object type.
- *     @subsys:        a subsystem object (not a ptr).
- *
- *     Can be used for any object type with an embedded ->kobj.
- */
-
-#define kobj_set_kset_s(obj,subsys) \
-       (obj)->kobj.kset = &(subsys)
-
-extern int __must_check subsystem_register(struct kset *);
-extern void subsystem_unregister(struct kset *);
-
-struct subsys_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct kset *, char *);
-       ssize_t (*store)(struct kset *, const char *, size_t);
-};
+extern struct kobject *kset_find_obj(struct kset *, const char *);
 
-extern int __must_check subsys_create_file(struct kset *,
-                                       struct subsys_attribute *);
+/* The global /sys/kernel/ kobject for people to chain off of */
+extern struct kobject *kernel_kobj;
+/* The global /sys/hypervisor/ kobject for people to chain off of */
+extern struct kobject *hypervisor_kobj;
+/* The global /sys/power/ kobject for people to chain off of */
+extern struct kobject *power_kobj;
+/* The global /sys/firmware/ kobject for people to chain off of */
+extern struct kobject *firmware_kobj;
 
 #if defined(CONFIG_HOTPLUG)
 int kobject_uevent(struct kobject *kobj, enum kobject_action action);
@@ -243,18 +207,20 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
 int kobject_action_type(const char *buf, size_t count,
                        enum kobject_action *type);
 #else
-static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
+static inline int kobject_uevent(struct kobject *kobj,
+                                enum kobject_action action)
 { return 0; }
 static inline int kobject_uevent_env(struct kobject *kobj,
                                      enum kobject_action action,
                                      char *envp[])
 { return 0; }
 
-static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
+static inline int add_uevent_var(struct kobj_uevent_env *env,
+                                const char *format, ...)
 { return 0; }
 
 static inline int kobject_action_type(const char *buf, size_t count,
-                       enum kobject_action *type)
+                                     enum kobject_action *type)
 { return -EINVAL; }
 #endif
 
index 6fee3539893f6f93d5634ec099f5741e4d1ccb95..5d185635786e129a35c28f475fdbb879cf78558b 100644 (file)
@@ -24,6 +24,7 @@ struct kref {
        atomic_t refcount;
 };
 
+void kref_set(struct kref *kref, int num);
 void kref_init(struct kref *kref);
 void kref_get(struct kref *kref);
 int kref_put(struct kref *kref, void (*release) (struct kref *kref));
diff --git a/include/linux/latencytop.h b/include/linux/latencytop.h
new file mode 100644 (file)
index 0000000..901c2d6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * latencytop.h: Infrastructure for displaying latency
+ *
+ * (C) Copyright 2008 Intel Corporation
+ * Author: Arjan van de Ven <arjan@linux.intel.com>
+ *
+ */
+
+#ifndef _INCLUDE_GUARD_LATENCYTOP_H_
+#define _INCLUDE_GUARD_LATENCYTOP_H_
+
+#ifdef CONFIG_LATENCYTOP
+
+#define LT_SAVECOUNT           32
+#define LT_BACKTRACEDEPTH      12
+
+struct latency_record {
+       unsigned long   backtrace[LT_BACKTRACEDEPTH];
+       unsigned int    count;
+       unsigned long   time;
+       unsigned long   max;
+};
+
+
+struct task_struct;
+
+void account_scheduler_latency(struct task_struct *task, int usecs, int inter);
+
+void clear_all_latency_tracing(struct task_struct *p);
+
+#else
+
+static inline void
+account_scheduler_latency(struct task_struct *task, int usecs, int inter)
+{
+}
+
+static inline void clear_all_latency_tracing(struct task_struct *p)
+{
+}
+
+#endif
+
+#endif
index 124033cb5e9bf6c6540a83f7b696852912d75913..4374c427778081d0a4e13fbfd3449dd488a7c0ed 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/workqueue.h>
 #include <scsi/scsi_host.h>
 #include <linux/acpi.h>
+#include <linux/cdrom.h>
 
 /*
  * Define if arch has non-standard setup.  This is a _PCI_ standard
@@ -143,10 +144,11 @@ enum {
        ATA_DFLAG_NCQ_OFF       = (1 << 13), /* device limited to non-NCQ mode */
        ATA_DFLAG_SPUNDOWN      = (1 << 14), /* XXX: for spindown_compat */
        ATA_DFLAG_SLEEPING      = (1 << 15), /* device is sleeping */
-       ATA_DFLAG_INIT_MASK     = (1 << 16) - 1,
+       ATA_DFLAG_DUBIOUS_XFER  = (1 << 16), /* data transfer not verified */
+       ATA_DFLAG_INIT_MASK     = (1 << 24) - 1,
 
-       ATA_DFLAG_DETACH        = (1 << 16),
-       ATA_DFLAG_DETACHED      = (1 << 17),
+       ATA_DFLAG_DETACH        = (1 << 24),
+       ATA_DFLAG_DETACHED      = (1 << 25),
 
        ATA_DEV_UNKNOWN         = 0,    /* unknown device */
        ATA_DEV_ATA             = 1,    /* ATA device */
@@ -217,9 +219,7 @@ enum {
 
        /* struct ata_queued_cmd flags */
        ATA_QCFLAG_ACTIVE       = (1 << 0), /* cmd not yet ack'd to scsi lyer */
-       ATA_QCFLAG_SG           = (1 << 1), /* have s/g table? */
-       ATA_QCFLAG_SINGLE       = (1 << 2), /* no s/g, just a single buffer */
-       ATA_QCFLAG_DMAMAP       = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
+       ATA_QCFLAG_DMAMAP       = (1 << 1), /* SG table is DMA mapped */
        ATA_QCFLAG_IO           = (1 << 3), /* standard IO command */
        ATA_QCFLAG_RESULT_TF    = (1 << 4), /* result TF requested */
        ATA_QCFLAG_CLEAR_EXCL   = (1 << 5), /* clear excl_link on completion */
@@ -266,19 +266,15 @@ enum {
        PORT_DISABLED           = 2,
 
        /* encoding various smaller bitmaps into a single
-        * unsigned int bitmap
+        * unsigned long bitmap
         */
-       ATA_BITS_PIO            = 7,
-       ATA_BITS_MWDMA          = 5,
-       ATA_BITS_UDMA           = 8,
+       ATA_NR_PIO_MODES        = 7,
+       ATA_NR_MWDMA_MODES      = 5,
+       ATA_NR_UDMA_MODES       = 8,
 
        ATA_SHIFT_PIO           = 0,
-       ATA_SHIFT_MWDMA         = ATA_SHIFT_PIO + ATA_BITS_PIO,
-       ATA_SHIFT_UDMA          = ATA_SHIFT_MWDMA + ATA_BITS_MWDMA,
-
-       ATA_MASK_PIO            = ((1 << ATA_BITS_PIO) - 1) << ATA_SHIFT_PIO,
-       ATA_MASK_MWDMA          = ((1 << ATA_BITS_MWDMA) - 1) << ATA_SHIFT_MWDMA,
-       ATA_MASK_UDMA           = ((1 << ATA_BITS_UDMA) - 1) << ATA_SHIFT_UDMA,
+       ATA_SHIFT_MWDMA         = ATA_SHIFT_PIO + ATA_NR_PIO_MODES,
+       ATA_SHIFT_UDMA          = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES,
 
        /* size of buffer to pad xfers ending on unaligned boundaries */
        ATA_DMA_PAD_SZ          = 4,
@@ -349,6 +345,21 @@ enum {
        ATA_DMA_MASK_ATA        = (1 << 0),     /* DMA on ATA Disk */
        ATA_DMA_MASK_ATAPI      = (1 << 1),     /* DMA on ATAPI */
        ATA_DMA_MASK_CFA        = (1 << 2),     /* DMA on CF Card */
+
+       /* ATAPI command types */
+       ATAPI_READ              = 0,            /* READs */
+       ATAPI_WRITE             = 1,            /* WRITEs */
+       ATAPI_READ_CD           = 2,            /* READ CD [MSF] */
+       ATAPI_MISC              = 3,            /* the rest */
+};
+
+enum ata_xfer_mask {
+       ATA_MASK_PIO            = ((1LU << ATA_NR_PIO_MODES) - 1)
+                                       << ATA_SHIFT_PIO,
+       ATA_MASK_MWDMA          = ((1LU << ATA_NR_MWDMA_MODES) - 1)
+                                       << ATA_SHIFT_MWDMA,
+       ATA_MASK_UDMA           = ((1LU << ATA_NR_UDMA_MODES) - 1)
+                                       << ATA_SHIFT_UDMA,
 };
 
 enum hsm_task_states {
@@ -447,7 +458,7 @@ struct ata_queued_cmd {
        unsigned int            tag;
        unsigned int            n_elem;
        unsigned int            n_iter;
-       unsigned int            orig_n_elem;
+       unsigned int            mapped_n_elem;
 
        int                     dma_dir;
 
@@ -455,17 +466,18 @@ struct ata_queued_cmd {
        unsigned int            sect_size;
 
        unsigned int            nbytes;
+       unsigned int            raw_nbytes;
        unsigned int            curbytes;
 
        struct scatterlist      *cursg;
        unsigned int            cursg_ofs;
 
+       struct scatterlist      *last_sg;
+       struct scatterlist      saved_last_sg;
        struct scatterlist      sgent;
-       struct scatterlist      pad_sgent;
-       void                    *buf_virt;
+       struct scatterlist      extra_sg[2];
 
-       /* DO NOT iterate over __sg manually, use ata_for_each_sg() */
-       struct scatterlist      *__sg;
+       struct scatterlist      *sg;
 
        unsigned int            err_mask;
        struct ata_taskfile     result_tf;
@@ -482,7 +494,7 @@ struct ata_port_stats {
 };
 
 struct ata_ering_entry {
-       int                     is_io;
+       unsigned int            eflags;
        unsigned int            err_mask;
        u64                     timestamp;
 };
@@ -522,9 +534,9 @@ struct ata_device {
        unsigned int            cdb_len;
 
        /* per-dev xfer mask */
-       unsigned int            pio_mask;
-       unsigned int            mwdma_mask;
-       unsigned int            udma_mask;
+       unsigned long           pio_mask;
+       unsigned long           mwdma_mask;
+       unsigned long           udma_mask;
 
        /* for CHS addressing */
        u16                     cylinders;      /* Number of cylinders */
@@ -560,6 +572,8 @@ struct ata_eh_context {
        int                     tries[ATA_MAX_DEVICES];
        unsigned int            classes[ATA_MAX_DEVICES];
        unsigned int            did_probe_mask;
+       unsigned int            saved_ncq_enabled;
+       u8                      saved_xfer_mode[ATA_MAX_DEVICES];
 };
 
 struct ata_acpi_drive
@@ -686,7 +700,8 @@ struct ata_port_operations {
        void (*bmdma_setup) (struct ata_queued_cmd *qc);
        void (*bmdma_start) (struct ata_queued_cmd *qc);
 
-       void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+       unsigned int (*data_xfer) (struct ata_device *dev, unsigned char *buf,
+                                  unsigned int buflen, int rw);
 
        int (*qc_defer) (struct ata_queued_cmd *qc);
        void (*qc_prep) (struct ata_queued_cmd *qc);
@@ -832,8 +847,6 @@ extern int ata_busy_sleep(struct ata_port *ap,
                          unsigned long timeout_pat, unsigned long timeout);
 extern void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline);
 extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline);
-extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn,
-                               void *data, unsigned long delay);
 extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
                             unsigned long interval_msec,
                             unsigned long timeout_msec);
@@ -848,6 +861,16 @@ extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 extern void ata_tf_to_fis(const struct ata_taskfile *tf,
                          u8 pmp, int is_cmd, u8 *fis);
 extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
+extern unsigned long ata_pack_xfermask(unsigned long pio_mask,
+                       unsigned long mwdma_mask, unsigned long udma_mask);
+extern void ata_unpack_xfermask(unsigned long xfer_mask,
+                       unsigned long *pio_mask, unsigned long *mwdma_mask,
+                       unsigned long *udma_mask);
+extern u8 ata_xfer_mask2mode(unsigned long xfer_mask);
+extern unsigned long ata_xfer_mode2mask(u8 xfer_mode);
+extern int ata_xfer_mode2shift(unsigned long xfer_mode);
+extern const char *ata_mode_string(unsigned long xfer_mask);
+extern unsigned long ata_id_xfermask(const u16 *id);
 extern void ata_noop_dev_select(struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select(struct ata_port *ap, unsigned int device);
 extern u8 ata_check_status(struct ata_port *ap);
@@ -856,17 +879,15 @@ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
 extern int ata_port_start(struct ata_port *ap);
 extern int ata_sff_port_start(struct ata_port *ap);
 extern irqreturn_t ata_interrupt(int irq, void *dev_instance);
-extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
-                         unsigned int buflen, int write_data);
-extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
-                               unsigned int buflen, int write_data);
+extern unsigned int ata_data_xfer(struct ata_device *dev,
+                       unsigned char *buf, unsigned int buflen, int rw);
+extern unsigned int ata_data_xfer_noirq(struct ata_device *dev,
+                       unsigned char *buf, unsigned int buflen, int rw);
 extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
 extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
 extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
 extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
-extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf,
-               unsigned int buflen);
 extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
                 unsigned int n_elem);
 extern unsigned int ata_dev_classify(const struct ata_taskfile *tf);
@@ -875,7 +896,6 @@ extern void ata_id_string(const u16 *id, unsigned char *s,
                          unsigned int ofs, unsigned int len);
 extern void ata_id_c_string(const u16 *id, unsigned char *s,
                            unsigned int ofs, unsigned int len);
-extern void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown);
 extern void ata_bmdma_setup(struct ata_queued_cmd *qc);
 extern void ata_bmdma_start(struct ata_queued_cmd *qc);
 extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
@@ -910,6 +930,7 @@ extern u8 ata_irq_on(struct ata_port *ap);
 extern int ata_cable_40wire(struct ata_port *ap);
 extern int ata_cable_80wire(struct ata_port *ap);
 extern int ata_cable_sata(struct ata_port *ap);
+extern int ata_cable_ignore(struct ata_port *ap);
 extern int ata_cable_unknown(struct ata_port *ap);
 
 /*
@@ -917,11 +938,13 @@ extern int ata_cable_unknown(struct ata_port *ap);
  */
 
 extern unsigned int ata_pio_need_iordy(const struct ata_device *);
+extern const struct ata_timing *ata_timing_find_mode(u8 xfer_mode);
 extern int ata_timing_compute(struct ata_device *, unsigned short,
                              struct ata_timing *, int, int);
 extern void ata_timing_merge(const struct ata_timing *,
                             const struct ata_timing *, struct ata_timing *,
                             unsigned int);
+extern u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle);
 
 enum {
        ATA_TIMING_SETUP        = (1 << 0),
@@ -948,15 +971,40 @@ static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap)
                return &ap->__acpi_init_gtm;
        return NULL;
 }
-extern int ata_acpi_cbl_80wire(struct ata_port *ap);
 int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm);
 int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm);
+unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev,
+                                   const struct ata_acpi_gtm *gtm);
+int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm);
 #else
 static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap)
 {
        return NULL;
 }
-static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; }
+
+static inline int ata_acpi_stm(const struct ata_port *ap,
+                              struct ata_acpi_gtm *stm)
+{
+       return -ENOSYS;
+}
+
+static inline int ata_acpi_gtm(const struct ata_port *ap,
+                              struct ata_acpi_gtm *stm)
+{
+       return -ENOSYS;
+}
+
+static inline unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev,
+                                       const struct ata_acpi_gtm *gtm)
+{
+       return 0;
+}
+
+static inline int ata_acpi_cbl_80wire(struct ata_port *ap,
+                                     const struct ata_acpi_gtm *gtm)
+{
+       return 0;
+}
 #endif
 
 #ifdef CONFIG_PCI
@@ -985,8 +1033,12 @@ extern int ata_pci_init_bmdma(struct ata_host *host);
 extern int ata_pci_prepare_sff_host(struct pci_dev *pdev,
                                    const struct ata_port_info * const * ppi,
                                    struct ata_host **r_host);
+extern int ata_pci_activate_sff_host(struct ata_host *host,
+                                    irq_handler_t irq_handler,
+                                    struct scsi_host_template *sht);
 extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
-extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
+extern unsigned long ata_pci_default_filter(struct ata_device *dev,
+                                           unsigned long xfer_mask);
 #endif /* CONFIG_PCI */
 
 /*
@@ -1074,35 +1126,6 @@ extern void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
                               const char *name);
 #endif
 
-/*
- * qc helpers
- */
-static inline struct scatterlist *
-ata_qc_first_sg(struct ata_queued_cmd *qc)
-{
-       qc->n_iter = 0;
-       if (qc->n_elem)
-               return qc->__sg;
-       if (qc->pad_len)
-               return &qc->pad_sgent;
-       return NULL;
-}
-
-static inline struct scatterlist *
-ata_qc_next_sg(struct scatterlist *sg, struct ata_queued_cmd *qc)
-{
-       if (sg == &qc->pad_sgent)
-               return NULL;
-       if (++qc->n_iter < qc->n_elem)
-               return sg_next(sg);
-       if (qc->pad_len)
-               return &qc->pad_sgent;
-       return NULL;
-}
-
-#define ata_for_each_sg(sg, qc) \
-       for (sg = ata_qc_first_sg(qc); sg; sg = ata_qc_next_sg(sg, qc))
-
 static inline unsigned int ata_tag_valid(unsigned int tag)
 {
        return (tag < ATA_MAX_QUEUE) ? 1 : 0;
@@ -1337,15 +1360,17 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
 static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
 {
        qc->dma_dir = DMA_NONE;
-       qc->__sg = NULL;
+       qc->sg = NULL;
        qc->flags = 0;
        qc->cursg = NULL;
        qc->cursg_ofs = 0;
-       qc->nbytes = qc->curbytes = 0;
+       qc->nbytes = qc->raw_nbytes = qc->curbytes = 0;
        qc->n_elem = 0;
+       qc->mapped_n_elem = 0;
        qc->n_iter = 0;
        qc->err_mask = 0;
        qc->pad_len = 0;
+       qc->last_sg = NULL;
        qc->sect_size = ATA_SECT_SIZE;
 
        ata_tf_init(qc->dev, &qc->tf);
@@ -1362,6 +1387,27 @@ static inline int ata_try_flush_cache(const struct ata_device *dev)
               ata_id_has_flush_ext(dev->id);
 }
 
+static inline int atapi_cmd_type(u8 opcode)
+{
+       switch (opcode) {
+       case GPCMD_READ_10:
+       case GPCMD_READ_12:
+               return ATAPI_READ;
+
+       case GPCMD_WRITE_10:
+       case GPCMD_WRITE_12:
+       case GPCMD_WRITE_AND_VERIFY_10:
+               return ATAPI_WRITE;
+
+       case GPCMD_READ_CD:
+       case GPCMD_READ_CD_MSF:
+               return ATAPI_READ_CD;
+
+       default:
+               return ATAPI_MISC;
+       }
+}
+
 static inline unsigned int ac_err_mask(u8 status)
 {
        if (status & (ATA_BUSY | ATA_DRQ))
index 1b7b95c67acaf5df2fd9cb860599931119ddc029..1897ca223eca99c402523994c04e64287b769cbd 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/prio_tree.h>
 #include <linux/debug_locks.h>
 #include <linux/mm_types.h>
-#include <linux/security.h>
 
 struct mempolicy;
 struct anon_vma;
@@ -34,6 +33,8 @@ extern int sysctl_legacy_va_layout;
 #define sysctl_legacy_va_layout 0
 #endif
 
+extern unsigned long mmap_min_addr;
+
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
index 2cbc0b87e329d30d0ec72b03c83f5d7f123b8a05..c97bdb7eb957cdd71e625ac9cf66862132d153da 100644 (file)
@@ -574,7 +574,9 @@ struct device_driver;
 #ifdef CONFIG_SYSFS
 struct module;
 
-extern struct kset module_subsys;
+extern struct kset *module_kset;
+extern struct kobj_type module_ktype;
+extern int module_sysfs_initialized;
 
 int mod_sysfs_init(struct module *mod);
 int mod_sysfs_setup(struct module *mod,
@@ -607,21 +609,6 @@ static inline void module_remove_modinfo_attrs(struct module *mod)
 
 #endif /* CONFIG_SYSFS */
 
-#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES)
-
-void module_add_driver(struct module *mod, struct device_driver *drv);
-void module_remove_driver(struct device_driver *drv);
-
-#else /* not both CONFIG_SYSFS && CONFIG_MODULES */
-
-static inline void module_add_driver(struct module *mod, struct device_driver *drv)
-{ }
-
-static inline void module_remove_driver(struct device_driver *drv)
-{ }
-
-#endif
-
 #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
 
 /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */
index 1e6af4f174b6cd5affaf7baf75597490e6915fce..b0813c3286b1bbfd035415c86cf592f39a52245b 100644 (file)
@@ -319,21 +319,29 @@ struct napi_struct {
 enum
 {
        NAPI_STATE_SCHED,       /* Poll is scheduled */
+       NAPI_STATE_DISABLE,     /* Disable pending */
 };
 
 extern void FASTCALL(__napi_schedule(struct napi_struct *n));
 
+static inline int napi_disable_pending(struct napi_struct *n)
+{
+       return test_bit(NAPI_STATE_DISABLE, &n->state);
+}
+
 /**
  *     napi_schedule_prep - check if napi can be scheduled
  *     @n: napi context
  *
  * Test if NAPI routine is already running, and if not mark
  * it as running.  This is used as a condition variable
- * insure only one NAPI poll instance runs
+ * insure only one NAPI poll instance runs.  We also make
+ * sure there is no pending NAPI disable.
  */
 static inline int napi_schedule_prep(struct napi_struct *n)
 {
-       return !test_and_set_bit(NAPI_STATE_SCHED, &n->state);
+       return !napi_disable_pending(n) &&
+               !test_and_set_bit(NAPI_STATE_SCHED, &n->state);
 }
 
 /**
@@ -389,8 +397,10 @@ static inline void napi_complete(struct napi_struct *n)
  */
 static inline void napi_disable(struct napi_struct *n)
 {
+       set_bit(NAPI_STATE_DISABLE, &n->state);
        while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
                msleep(1);
+       clear_bit(NAPI_STATE_DISABLE, &n->state);
 }
 
 /**
@@ -1268,7 +1278,7 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
 static inline int netif_rx_schedule_prep(struct net_device *dev,
                                         struct napi_struct *napi)
 {
-       return netif_running(dev) && napi_schedule_prep(napi);
+       return napi_schedule_prep(napi);
 }
 
 /* Add interface to tail of rx poll list. This assumes that _prep has
@@ -1277,7 +1287,6 @@ static inline int netif_rx_schedule_prep(struct net_device *dev,
 static inline void __netif_rx_schedule(struct net_device *dev,
                                       struct napi_struct *napi)
 {
-       dev_hold(dev);
        __napi_schedule(napi);
 }
 
@@ -1308,7 +1317,6 @@ static inline void __netif_rx_complete(struct net_device *dev,
                                       struct napi_struct *napi)
 {
        __napi_complete(napi);
-       dev_put(dev);
 }
 
 /* Remove interface from poll list: it must be in the poll list
index 0c40cc0b4a362034fbe444a929ab1d9a0ecdb749..5dfbc684ce7daab792ca9ddf40e842fe5a5cc1c7 100644 (file)
@@ -207,9 +207,7 @@ static inline int notifier_to_errno(int ret)
 #define CPU_DOWN_PREPARE       0x0005 /* CPU (unsigned)v going down */
 #define CPU_DOWN_FAILED                0x0006 /* CPU (unsigned)v NOT going down */
 #define CPU_DEAD               0x0007 /* CPU (unsigned)v dead */
-#define CPU_LOCK_ACQUIRE       0x0008 /* Acquire all hotcpu locks */
-#define CPU_LOCK_RELEASE       0x0009 /* Release all hotcpu locks */
-#define CPU_DYING              0x000A /* CPU (unsigned)v not running any task,
+#define CPU_DYING              0x0008 /* CPU (unsigned)v not running any task,
                                        * not handling interrupts, soon dead */
 
 /* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
index ab4cb6ecd47c3132c2393db1b290ea9965f3d96a..8f67e8f2a3cc0c0e24d32ebd77cde24bb94281a5 100644 (file)
@@ -174,7 +174,7 @@ extern int pci_hp_register          (struct hotplug_slot *slot);
 extern int pci_hp_deregister           (struct hotplug_slot *slot);
 extern int __must_check pci_hp_change_slot_info        (struct hotplug_slot *slot,
                                                 struct hotplug_slot_info *info);
-extern struct kset pci_hotplug_slots_subsys;
+extern struct kset *pci_hotplug_slots_kset;
 
 /* PCI Setting Record (Type 0) */
 struct hpp_type0 {
index 023656d2f1da02202c30def116d4ff4fd1424237..1fbd0256e86b6f0b0da7c1dfb1b287a83a43a749 100644 (file)
 #define PCI_VENDOR_ID_NETCELL          0x169c
 #define PCI_DEVICE_ID_REVOLUTION       0x0044
 
+#define PCI_VENDOR_ID_CENATEK          0x16CA
+#define PCI_DEVICE_ID_CENATEK_IDE      0x0001
+
 #define PCI_VENDOR_ID_VITESSE          0x1725
 #define PCI_DEVICE_ID_VITESSE_VSC7174  0x7174
 
 #define PCI_DEVICE_ID_INTEL_ICH9_4     0x2914
 #define PCI_DEVICE_ID_INTEL_ICH9_5     0x2919
 #define PCI_DEVICE_ID_INTEL_ICH9_6     0x2930
+#define PCI_DEVICE_ID_INTEL_ICH9_7     0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9_8     0x2918
 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
 #define PCI_DEVICE_ID_INTEL_82830_HB   0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC  0x3577
index 5ea4f05683f6c838df23f48c2b8381a054ae7938..04b4d7330e6db16dab77d2317a8754fded181dce 100644 (file)
@@ -290,7 +290,7 @@ struct pktcdvd_device
        int                     write_congestion_off;
        int                     write_congestion_on;
 
-       struct class_device     *clsdev;        /* sysfs pktcdvd[0-7] class dev */
+       struct device           *dev;           /* sysfs pktcdvd[0-7] dev */
        struct pktcdvd_kobj     *kobj_stat;     /* sysfs pktcdvd[0-7]/stat/     */
        struct pktcdvd_kobj     *kobj_wqueue;   /* sysfs pktcdvd[0-7]/write_queue/ */
 
index e80804316cdb2e9c78c3ec15ab26435e056bd6bb..3261681c82a45bb4ec68551bd6bb40bbef1935e3 100644 (file)
@@ -35,7 +35,7 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u
 extern int platform_get_irq_byname(struct platform_device *, char *);
 extern int platform_add_devices(struct platform_device **, int);
 
-extern struct platform_device *platform_device_register_simple(char *, int id,
+extern struct platform_device *platform_device_register_simple(const char *, int id,
                                        struct resource *, unsigned int);
 
 extern struct platform_device *platform_device_alloc(const char *name, int id);
index 09a309b7b5d2d4565b48b1eb5f59acd5c13265fe..b78e0295adf4342732b42d8ffd588a48771e2b79 100644 (file)
@@ -246,6 +246,15 @@ static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
                device_set_wakeup_enable(dev,val); \
        } while(0)
 
+/*
+ * Global Power Management flags
+ * Used to keep APM and ACPI from both being active
+ */
+extern unsigned int    pm_flags;
+
+#define PM_APM 1
+#define PM_ACPI        2
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_PM_H */
index 514729a446888e21dee4289db2ea4e71f80f6eaa..446f4f42b952894b3ffe1c2cb2cf91780e86ee33 100644 (file)
@@ -4,10 +4,6 @@
 
 #ifdef CONFIG_PM_LEGACY
 
-extern int pm_active;
-
-#define PM_IS_ACTIVE() (pm_active != 0)
-
 /*
  * Register a device with power management
  */
@@ -21,8 +17,6 @@ int __deprecated pm_send_all(pm_request_t rqst, void *data);
 
 #else /* CONFIG_PM_LEGACY */
 
-#define PM_IS_ACTIVE() 0
-
 static inline struct pm_dev *pm_register(pm_dev_t type,
                                         unsigned long id,
                                         pm_callback callback)
index 0a0426c2867d7f03bbf257887d588db4ea0be7af..2a6d62c7d2d1a5d8f58baad15d82e9a198eb4993 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/errno.h>
 #include <linux/mod_devicetable.h>
 
-#define PNP_MAX_PORT           24
+#define PNP_MAX_PORT           40
 #define PNP_MAX_MEM            12
 #define PNP_MAX_IRQ            2
 #define PNP_MAX_DMA            2
index ae8146abd7463b694f0690353a13545c840890fd..3ea5750a0f7e2ac74c1c90e1aecd4910b7a74bc7 100644 (file)
@@ -97,6 +97,7 @@ extern void __ptrace_link(struct task_struct *child,
 extern void __ptrace_unlink(struct task_struct *child);
 extern void ptrace_untrace(struct task_struct *child);
 extern int ptrace_may_attach(struct task_struct *task);
+extern int __ptrace_may_attach(struct task_struct *task);
 
 static inline void ptrace_link(struct task_struct *child,
                               struct task_struct *new_parent)
diff --git a/include/linux/rcuclassic.h b/include/linux/rcuclassic.h
new file mode 100644 (file)
index 0000000..4d66242
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (classic version)
+ *
+ * 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.
+ *
+ * Copyright IBM Corporation, 2001
+ *
+ * Author: Dipankar Sarma <dipankar@in.ibm.com>
+ *
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *             Documentation/RCU
+ *
+ */
+
+#ifndef __LINUX_RCUCLASSIC_H
+#define __LINUX_RCUCLASSIC_H
+
+#ifdef __KERNEL__
+
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/percpu.h>
+#include <linux/cpumask.h>
+#include <linux/seqlock.h>
+
+
+/* Global control variables for rcupdate callback mechanism. */
+struct rcu_ctrlblk {
+       long    cur;            /* Current batch number.                      */
+       long    completed;      /* Number of the last completed batch         */
+       int     next_pending;   /* Is the next batch already waiting?         */
+
+       int     signaled;
+
+       spinlock_t      lock    ____cacheline_internodealigned_in_smp;
+       cpumask_t       cpumask; /* CPUs that need to switch in order    */
+                                /* for current batch to proceed.        */
+} ____cacheline_internodealigned_in_smp;
+
+/* Is batch a before batch b ? */
+static inline int rcu_batch_before(long a, long b)
+{
+       return (a - b) < 0;
+}
+
+/* Is batch a after batch b ? */
+static inline int rcu_batch_after(long a, long b)
+{
+       return (a - b) > 0;
+}
+
+/*
+ * Per-CPU data for Read-Copy UPdate.
+ * nxtlist - new callbacks are added here
+ * curlist - current batch for which quiescent cycle started if any
+ */
+struct rcu_data {
+       /* 1) quiescent state handling : */
+       long            quiescbatch;     /* Batch # for grace period */
+       int             passed_quiesc;   /* User-mode/idle loop etc. */
+       int             qs_pending;      /* core waits for quiesc state */
+
+       /* 2) batch handling */
+       long            batch;           /* Batch # for current RCU batch */
+       struct rcu_head *nxtlist;
+       struct rcu_head **nxttail;
+       long            qlen;            /* # of queued callbacks */
+       struct rcu_head *curlist;
+       struct rcu_head **curtail;
+       struct rcu_head *donelist;
+       struct rcu_head **donetail;
+       long            blimit;          /* Upper limit on a processed batch */
+       int cpu;
+       struct rcu_head barrier;
+};
+
+DECLARE_PER_CPU(struct rcu_data, rcu_data);
+DECLARE_PER_CPU(struct rcu_data, rcu_bh_data);
+
+/*
+ * Increment the quiescent state counter.
+ * The counter is a bit degenerated: We do not need to know
+ * how many quiescent states passed, just if there was at least
+ * one since the start of the grace period. Thus just a flag.
+ */
+static inline void rcu_qsctr_inc(int cpu)
+{
+       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
+       rdp->passed_quiesc = 1;
+}
+static inline void rcu_bh_qsctr_inc(int cpu)
+{
+       struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
+       rdp->passed_quiesc = 1;
+}
+
+extern int rcu_pending(int cpu);
+extern int rcu_needs_cpu(int cpu);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern struct lockdep_map rcu_lock_map;
+# define rcu_read_acquire()    \
+                       lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_)
+# define rcu_read_release()    lock_release(&rcu_lock_map, 1, _THIS_IP_)
+#else
+# define rcu_read_acquire()    do { } while (0)
+# define rcu_read_release()    do { } while (0)
+#endif
+
+#define __rcu_read_lock() \
+       do { \
+               preempt_disable(); \
+               __acquire(RCU); \
+               rcu_read_acquire(); \
+       } while (0)
+#define __rcu_read_unlock() \
+       do { \
+               rcu_read_release(); \
+               __release(RCU); \
+               preempt_enable(); \
+       } while (0)
+#define __rcu_read_lock_bh() \
+       do { \
+               local_bh_disable(); \
+               __acquire(RCU_BH); \
+               rcu_read_acquire(); \
+       } while (0)
+#define __rcu_read_unlock_bh() \
+       do { \
+               rcu_read_release(); \
+               __release(RCU_BH); \
+               local_bh_enable(); \
+       } while (0)
+
+#define __synchronize_sched() synchronize_rcu()
+
+extern void __rcu_init(void);
+extern void rcu_check_callbacks(int cpu, int user);
+extern void rcu_restart_cpu(int cpu);
+
+extern long rcu_batches_completed(void);
+extern long rcu_batches_completed_bh(void);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_RCUCLASSIC_H */
index cc24a01df940a67a18bce50a666d5a9080c7b387..d32c14de270ea28a1490c3241fe71057a1b0f582 100644 (file)
@@ -15,7 +15,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Copyright (C) IBM Corporation, 2001
+ * Copyright IBM Corporation, 2001
  *
  * Author: Dipankar Sarma <dipankar@in.ibm.com>
  * 
@@ -53,96 +53,18 @@ struct rcu_head {
        void (*func)(struct rcu_head *head);
 };
 
+#ifdef CONFIG_CLASSIC_RCU
+#include <linux/rcuclassic.h>
+#else /* #ifdef CONFIG_CLASSIC_RCU */
+#include <linux/rcupreempt.h>
+#endif /* #else #ifdef CONFIG_CLASSIC_RCU */
+
 #define RCU_HEAD_INIT  { .next = NULL, .func = NULL }
 #define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT
 #define INIT_RCU_HEAD(ptr) do { \
        (ptr)->next = NULL; (ptr)->func = NULL; \
 } while (0)
 
-
-
-/* Global control variables for rcupdate callback mechanism. */
-struct rcu_ctrlblk {
-       long    cur;            /* Current batch number.                      */
-       long    completed;      /* Number of the last completed batch         */
-       int     next_pending;   /* Is the next batch already waiting?         */
-
-       int     signaled;
-
-       spinlock_t      lock    ____cacheline_internodealigned_in_smp;
-       cpumask_t       cpumask; /* CPUs that need to switch in order    */
-                                /* for current batch to proceed.        */
-} ____cacheline_internodealigned_in_smp;
-
-/* Is batch a before batch b ? */
-static inline int rcu_batch_before(long a, long b)
-{
-        return (a - b) < 0;
-}
-
-/* Is batch a after batch b ? */
-static inline int rcu_batch_after(long a, long b)
-{
-        return (a - b) > 0;
-}
-
-/*
- * Per-CPU data for Read-Copy UPdate.
- * nxtlist - new callbacks are added here
- * curlist - current batch for which quiescent cycle started if any
- */
-struct rcu_data {
-       /* 1) quiescent state handling : */
-       long            quiescbatch;     /* Batch # for grace period */
-       int             passed_quiesc;   /* User-mode/idle loop etc. */
-       int             qs_pending;      /* core waits for quiesc state */
-
-       /* 2) batch handling */
-       long            batch;           /* Batch # for current RCU batch */
-       struct rcu_head *nxtlist;
-       struct rcu_head **nxttail;
-       long            qlen;            /* # of queued callbacks */
-       struct rcu_head *curlist;
-       struct rcu_head **curtail;
-       struct rcu_head *donelist;
-       struct rcu_head **donetail;
-       long            blimit;          /* Upper limit on a processed batch */
-       int cpu;
-       struct rcu_head barrier;
-};
-
-DECLARE_PER_CPU(struct rcu_data, rcu_data);
-DECLARE_PER_CPU(struct rcu_data, rcu_bh_data);
-
-/*
- * Increment the quiescent state counter.
- * The counter is a bit degenerated: We do not need to know
- * how many quiescent states passed, just if there was at least
- * one since the start of the grace period. Thus just a flag.
- */
-static inline void rcu_qsctr_inc(int cpu)
-{
-       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
-       rdp->passed_quiesc = 1;
-}
-static inline void rcu_bh_qsctr_inc(int cpu)
-{
-       struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
-       rdp->passed_quiesc = 1;
-}
-
-extern int rcu_pending(int cpu);
-extern int rcu_needs_cpu(int cpu);
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-extern struct lockdep_map rcu_lock_map;
-# define rcu_read_acquire()    lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_)
-# define rcu_read_release()    lock_release(&rcu_lock_map, 1, _THIS_IP_)
-#else
-# define rcu_read_acquire()    do { } while (0)
-# define rcu_read_release()    do { } while (0)
-#endif
-
 /**
  * rcu_read_lock - mark the beginning of an RCU read-side critical section.
  *
@@ -172,24 +94,13 @@ extern struct lockdep_map rcu_lock_map;
  *
  * It is illegal to block while in an RCU read-side critical section.
  */
-#define rcu_read_lock() \
-       do { \
-               preempt_disable(); \
-               __acquire(RCU); \
-               rcu_read_acquire(); \
-       } while(0)
+#define rcu_read_lock() __rcu_read_lock()
 
 /**
  * rcu_read_unlock - marks the end of an RCU read-side critical section.
  *
  * See rcu_read_lock() for more information.
  */
-#define rcu_read_unlock() \
-       do { \
-               rcu_read_release(); \
-               __release(RCU); \
-               preempt_enable(); \
-       } while(0)
 
 /*
  * So where is rcu_write_lock()?  It does not exist, as there is no
@@ -200,6 +111,7 @@ extern struct lockdep_map rcu_lock_map;
  * used as well.  RCU does not care how the writers keep out of each
  * others' way, as long as they do so.
  */
+#define rcu_read_unlock() __rcu_read_unlock()
 
 /**
  * rcu_read_lock_bh - mark the beginning of a softirq-only RCU critical section
@@ -212,24 +124,14 @@ extern struct lockdep_map rcu_lock_map;
  * can use just rcu_read_lock().
  *
  */
-#define rcu_read_lock_bh() \
-       do { \
-               local_bh_disable(); \
-               __acquire(RCU_BH); \
-               rcu_read_acquire(); \
-       } while(0)
+#define rcu_read_lock_bh() __rcu_read_lock_bh()
 
 /*
  * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section
  *
  * See rcu_read_lock_bh() for more information.
  */
-#define rcu_read_unlock_bh() \
-       do { \
-               rcu_read_release(); \
-               __release(RCU_BH); \
-               local_bh_enable(); \
-       } while(0)
+#define rcu_read_unlock_bh() __rcu_read_unlock_bh()
 
 /*
  * Prevent the compiler from merging or refetching accesses.  The compiler
@@ -293,21 +195,52 @@ extern struct lockdep_map rcu_lock_map;
  * In "classic RCU", these two guarantees happen to be one and
  * the same, but can differ in realtime RCU implementations.
  */
-#define synchronize_sched() synchronize_rcu()
+#define synchronize_sched() __synchronize_sched()
 
-extern void rcu_init(void);
-extern void rcu_check_callbacks(int cpu, int user);
-extern void rcu_restart_cpu(int cpu);
-extern long rcu_batches_completed(void);
-extern long rcu_batches_completed_bh(void);
+/**
+ * call_rcu - Queue an RCU callback for invocation after a grace period.
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual update function to be invoked after the grace period
+ *
+ * The update function will be invoked some time after a full grace
+ * period elapses, in other words after all currently executing RCU
+ * read-side critical sections have completed.  RCU read-side critical
+ * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
+ * and may be nested.
+ */
+extern void call_rcu(struct rcu_head *head,
+                             void (*func)(struct rcu_head *head));
 
-/* Exported interfaces */
-extern void FASTCALL(call_rcu(struct rcu_head *head, 
-                               void (*func)(struct rcu_head *head)));
-extern void FASTCALL(call_rcu_bh(struct rcu_head *head,
-                               void (*func)(struct rcu_head *head)));
+/**
+ * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual update function to be invoked after the grace period
+ *
+ * The update function will be invoked some time after a full grace
+ * period elapses, in other words after all currently executing RCU
+ * read-side critical sections have completed. call_rcu_bh() assumes
+ * that the read-side critical sections end on completion of a softirq
+ * handler. This means that read-side critical sections in process
+ * context must not be interrupted by softirqs. This interface is to be
+ * used when most of the read-side critical sections are in softirq context.
+ * RCU read-side critical sections are delimited by :
+ *  - rcu_read_lock() and  rcu_read_unlock(), if in interrupt context.
+ *  OR
+ *  - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context.
+ *  These may be nested.
+ */
+extern void call_rcu_bh(struct rcu_head *head,
+                       void (*func)(struct rcu_head *head));
+
+/* Exported common interfaces */
 extern void synchronize_rcu(void);
 extern void rcu_barrier(void);
+extern long rcu_batches_completed(void);
+extern long rcu_batches_completed_bh(void);
+
+/* Internal to kernel */
+extern void rcu_init(void);
+extern int rcu_needs_cpu(int cpu);
 
 #endif /* __KERNEL__ */
 #endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h
new file mode 100644 (file)
index 0000000..ece8eb3
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (RT implementation)
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author:  Paul McKenney <paulmck@us.ibm.com>
+ *
+ * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *             Documentation/RCU
+ *
+ */
+
+#ifndef __LINUX_RCUPREEMPT_H
+#define __LINUX_RCUPREEMPT_H
+
+#ifdef __KERNEL__
+
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/percpu.h>
+#include <linux/cpumask.h>
+#include <linux/seqlock.h>
+
+#define rcu_qsctr_inc(cpu)
+#define rcu_bh_qsctr_inc(cpu)
+#define call_rcu_bh(head, rcu) call_rcu(head, rcu)
+
+extern void __rcu_read_lock(void);
+extern void __rcu_read_unlock(void);
+extern int rcu_pending(int cpu);
+extern int rcu_needs_cpu(int cpu);
+
+#define __rcu_read_lock_bh()   { rcu_read_lock(); local_bh_disable(); }
+#define __rcu_read_unlock_bh() { local_bh_enable(); rcu_read_unlock(); }
+
+extern void __synchronize_sched(void);
+
+extern void __rcu_init(void);
+extern void rcu_check_callbacks(int cpu, int user);
+extern void rcu_restart_cpu(int cpu);
+extern long rcu_batches_completed(void);
+
+/*
+ * Return the number of RCU batches processed thus far. Useful for debug
+ * and statistic. The _bh variant is identifcal to straight RCU
+ */
+static inline long rcu_batches_completed_bh(void)
+{
+       return rcu_batches_completed();
+}
+
+#ifdef CONFIG_RCU_TRACE
+struct rcupreempt_trace;
+extern long *rcupreempt_flipctr(int cpu);
+extern long rcupreempt_data_completed(void);
+extern int rcupreempt_flip_flag(int cpu);
+extern int rcupreempt_mb_flag(int cpu);
+extern char *rcupreempt_try_flip_state_name(void);
+extern struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu);
+#endif
+
+struct softirq_action;
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_RCUPREEMPT_H */
diff --git a/include/linux/rcupreempt_trace.h b/include/linux/rcupreempt_trace.h
new file mode 100644 (file)
index 0000000..21cd6b2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (RT implementation)
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author:  Paul McKenney <paulmck@us.ibm.com>
+ *
+ * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
+ *
+ * For detailed explanation of the Preemptible Read-Copy Update mechanism see -
+ *              http://lwn.net/Articles/253651/
+ */
+
+#ifndef __LINUX_RCUPREEMPT_TRACE_H
+#define __LINUX_RCUPREEMPT_TRACE_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <asm/atomic.h>
+
+/*
+ * PREEMPT_RCU data structures.
+ */
+
+struct rcupreempt_trace {
+       long            next_length;
+       long            next_add;
+       long            wait_length;
+       long            wait_add;
+       long            done_length;
+       long            done_add;
+       long            done_remove;
+       atomic_t        done_invoked;
+       long            rcu_check_callbacks;
+       atomic_t        rcu_try_flip_1;
+       atomic_t        rcu_try_flip_e1;
+       long            rcu_try_flip_i1;
+       long            rcu_try_flip_ie1;
+       long            rcu_try_flip_g1;
+       long            rcu_try_flip_a1;
+       long            rcu_try_flip_ae1;
+       long            rcu_try_flip_a2;
+       long            rcu_try_flip_z1;
+       long            rcu_try_flip_ze1;
+       long            rcu_try_flip_z2;
+       long            rcu_try_flip_m1;
+       long            rcu_try_flip_me1;
+       long            rcu_try_flip_m2;
+};
+
+#ifdef CONFIG_RCU_TRACE
+#define RCU_TRACE(fn, arg)     fn(arg);
+#else
+#define RCU_TRACE(fn, arg)
+#endif
+
+extern void rcupreempt_trace_move2done(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace);
+extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_RCUPREEMPT_TRACE_H */
index 416e000dfe81c0febed74c4f8aef8bcd979565db..e3ff21dbac536f11d7f62be1dae027d37466b465 100644 (file)
@@ -191,8 +191,8 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
        /*
         * offset and length are unused for chain entry.  Clear them.
         */
-       prv->offset = 0;
-       prv->length = 0;
+       prv[prv_nents - 1].offset = 0;
+       prv[prv_nents - 1].length = 0;
 
        /*
         * Set lowest bit to indicate a link pointer, and make sure to clear
index ac3d496fbd20266ad6ef88848f967eb8a550047a..df5b24ee80b307044bb5292404d1fc41686c8a6d 100644 (file)
@@ -78,7 +78,6 @@ struct sched_param {
 #include <linux/proportions.h>
 #include <linux/seccomp.h>
 #include <linux/rcupdate.h>
-#include <linux/futex.h>
 #include <linux/rtmutex.h>
 
 #include <linux/time.h>
@@ -88,11 +87,13 @@ struct sched_param {
 #include <linux/hrtimer.h>
 #include <linux/task_io_accounting.h>
 #include <linux/kobject.h>
+#include <linux/latencytop.h>
 
 #include <asm/processor.h>
 
 struct exec_domain;
 struct futex_pi_state;
+struct robust_list_head;
 struct bio;
 
 /*
@@ -230,6 +231,8 @@ static inline int select_nohz_load_balancer(int cpu)
 }
 #endif
 
+extern unsigned long rt_needs_cpu(int cpu);
+
 /*
  * Only dump TASK_* tasks. (0 for all tasks)
  */
@@ -257,13 +260,19 @@ extern void trap_init(void);
 extern void account_process_tick(struct task_struct *task, int user);
 extern void update_process_times(int user);
 extern void scheduler_tick(void);
+extern void hrtick_resched(void);
+
+extern void sched_show_task(struct task_struct *p);
 
 #ifdef CONFIG_DETECT_SOFTLOCKUP
 extern void softlockup_tick(void);
 extern void spawn_softlockup_task(void);
 extern void touch_softlockup_watchdog(void);
 extern void touch_all_softlockup_watchdogs(void);
-extern int softlockup_thresh;
+extern unsigned long  softlockup_thresh;
+extern unsigned long sysctl_hung_task_check_count;
+extern unsigned long sysctl_hung_task_timeout_secs;
+extern unsigned long sysctl_hung_task_warnings;
 #else
 static inline void softlockup_tick(void)
 {
@@ -552,18 +561,13 @@ struct user_struct {
 #ifdef CONFIG_FAIR_USER_SCHED
        struct task_group *tg;
 #ifdef CONFIG_SYSFS
-       struct kset kset;
-       struct subsys_attribute user_attr;
+       struct kobject kobj;
        struct work_struct work;
 #endif
 #endif
 };
 
-#ifdef CONFIG_FAIR_USER_SCHED
-extern int uids_kobject_init(void);
-#else
-static inline int uids_kobject_init(void) { return 0; }
-#endif
+extern int uids_sysfs_init(void);
 
 extern struct user_struct *find_user(uid_t);
 
@@ -827,6 +831,7 @@ struct sched_class {
        void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
        void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
        void (*yield_task) (struct rq *rq);
+       int  (*select_task_rq)(struct task_struct *p, int sync);
 
        void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
 
@@ -842,11 +847,25 @@ struct sched_class {
        int (*move_one_task) (struct rq *this_rq, int this_cpu,
                              struct rq *busiest, struct sched_domain *sd,
                              enum cpu_idle_type idle);
+       void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
+       void (*post_schedule) (struct rq *this_rq);
+       void (*task_wake_up) (struct rq *this_rq, struct task_struct *task);
 #endif
 
        void (*set_curr_task) (struct rq *rq);
-       void (*task_tick) (struct rq *rq, struct task_struct *p);
+       void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
        void (*task_new) (struct rq *rq, struct task_struct *p);
+       void (*set_cpus_allowed)(struct task_struct *p, cpumask_t *newmask);
+
+       void (*join_domain)(struct rq *rq);
+       void (*leave_domain)(struct rq *rq);
+
+       void (*switched_from) (struct rq *this_rq, struct task_struct *task,
+                              int running);
+       void (*switched_to) (struct rq *this_rq, struct task_struct *task,
+                            int running);
+       void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
+                            int oldprio, int running);
 };
 
 struct load_weight {
@@ -876,6 +895,8 @@ struct sched_entity {
 #ifdef CONFIG_SCHEDSTATS
        u64                     wait_start;
        u64                     wait_max;
+       u64                     wait_count;
+       u64                     wait_sum;
 
        u64                     sleep_start;
        u64                     sleep_max;
@@ -914,6 +935,21 @@ struct sched_entity {
 #endif
 };
 
+struct sched_rt_entity {
+       struct list_head run_list;
+       unsigned int time_slice;
+       unsigned long timeout;
+       int nr_cpus_allowed;
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       struct sched_rt_entity  *parent;
+       /* rq on which this entity is (to be) queued: */
+       struct rt_rq            *rt_rq;
+       /* rq "owned" by this entity/group: */
+       struct rt_rq            *my_q;
+#endif
+};
+
 struct task_struct {
        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
        void *stack;
@@ -930,9 +966,9 @@ struct task_struct {
 #endif
 
        int prio, static_prio, normal_prio;
-       struct list_head run_list;
        const struct sched_class *sched_class;
        struct sched_entity se;
+       struct sched_rt_entity rt;
 
 #ifdef CONFIG_PREEMPT_NOTIFIERS
        /* list of struct preempt_notifier: */
@@ -956,7 +992,11 @@ struct task_struct {
 
        unsigned int policy;
        cpumask_t cpus_allowed;
-       unsigned int time_slice;
+
+#ifdef CONFIG_PREEMPT_RCU
+       int rcu_read_lock_nesting;
+       int rcu_flipctr_idx;
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
        struct sched_info sched_info;
@@ -1046,6 +1086,11 @@ struct task_struct {
 /* ipc stuff */
        struct sysv_sem sysvsem;
 #endif
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+/* hung task detection */
+       unsigned long last_switch_timestamp;
+       unsigned long last_switch_count;
+#endif
 /* CPU-specific state of this task */
        struct thread_struct thread;
 /* filesystem information */
@@ -1178,6 +1223,10 @@ struct task_struct {
        int make_it_fail;
 #endif
        struct prop_local_single dirties;
+#ifdef CONFIG_LATENCYTOP
+       int latency_record_count;
+       struct latency_record latency_record[LT_SAVECOUNT];
+#endif
 };
 
 /*
@@ -1255,13 +1304,6 @@ struct pid_namespace;
  *
  * set_task_vxid()   : assigns a virtual id to a task;
  *
- * task_ppid_nr_ns() : the parent's id as seen from the namespace specified.
- *                     the result depends on the namespace and whether the
- *                     task in question is the namespace's init. e.g. for the
- *                     namespace's init this will return 0 when called from
- *                     the namespace of this init, or appropriate id otherwise.
- *
- *
  * see also pid_nr() etc in include/linux/pid.h
  */
 
@@ -1317,12 +1359,6 @@ static inline pid_t task_session_vnr(struct task_struct *tsk)
 }
 
 
-static inline pid_t task_ppid_nr_ns(struct task_struct *tsk,
-               struct pid_namespace *ns)
-{
-       return pid_nr_ns(task_pid(rcu_dereference(tsk->real_parent)), ns);
-}
-
 /**
  * pid_alive - check that a task structure is not stale
  * @p: Task structure to be checked.
@@ -1471,6 +1507,12 @@ extern unsigned int sysctl_sched_child_runs_first;
 extern unsigned int sysctl_sched_features;
 extern unsigned int sysctl_sched_migration_cost;
 extern unsigned int sysctl_sched_nr_migrate;
+extern unsigned int sysctl_sched_rt_period;
+extern unsigned int sysctl_sched_rt_ratio;
+#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP)
+extern unsigned int sysctl_sched_min_bal_int_shares;
+extern unsigned int sysctl_sched_max_bal_int_shares;
+#endif
 
 int sched_nr_latency_handler(struct ctl_table *table, int write,
                struct file *file, void __user *buffer, size_t *length,
@@ -1863,7 +1905,18 @@ static inline int need_resched(void)
  * cond_resched_lock() will drop the spinlock before scheduling,
  * cond_resched_softirq() will enable bhs before scheduling.
  */
-extern int cond_resched(void);
+#ifdef CONFIG_PREEMPT
+static inline int cond_resched(void)
+{
+       return 0;
+}
+#else
+extern int _cond_resched(void);
+static inline int cond_resched(void)
+{
+       return _cond_resched();
+}
+#endif
 extern int cond_resched_lock(spinlock_t * lock);
 extern int cond_resched_softirq(void);
 
index ac050830a873b044ba1d23144c88fb99a975c934..d24974262dc62a9376e6c6ffd1a4e7f42ca0196a 100644 (file)
 #include <linux/xfrm.h>
 #include <net/flow.h>
 
+/* only a char in selinux superblock security struct flags */
+#define FSCONTEXT_MNT          0x01
+#define CONTEXT_MNT            0x02
+#define ROOTCONTEXT_MNT                0x04
+#define DEFCONTEXT_MNT         0x08
+
 /*
  * Bounding set
  */
@@ -243,9 +249,6 @@ struct request_sock;
  *     @mnt contains the mounted file system.
  *     @flags contains the new filesystem flags.
  *     @data contains the filesystem-specific data.
- * @sb_post_mountroot:
- *     Update the security module's state when the root filesystem is mounted.
- *     This hook is only called if the mount was successful.
  * @sb_post_addmount:
  *     Update the security module's state when a filesystem is mounted.
  *     This hook is called any time a mount is successfully grafetd to
@@ -261,6 +264,22 @@ struct request_sock;
  *     Update module state after a successful pivot.
  *     @old_nd contains the nameidata structure for the old root.
  *      @new_nd contains the nameidata structure for the new root.
+ * @sb_get_mnt_opts:
+ *     Get the security relevant mount options used for a superblock
+ *     @sb the superblock to get security mount options from
+ *     @mount_options array for pointers to mount options
+ *     @mount_flags array of ints specifying what each mount options is
+ *     @num_opts number of options in the arrays
+ * @sb_set_mnt_opts:
+ *     Set the security relevant mount options used for a superblock
+ *     @sb the superblock to set security mount options for
+ *     @mount_options array for pointers to mount options
+ *     @mount_flags array of ints specifying what each mount options is
+ *     @num_opts number of options in the arrays
+ * @sb_clone_mnt_opts:
+ *     Copy all security options from a given superblock to another
+ *     @oldsb old superblock which contain information to clone
+ *     @newsb new superblock which needs filled in
  *
  * Security hooks for inode operations.
  *
@@ -1183,6 +1202,10 @@ struct request_sock;
  *     Convert secid to security context.
  *     @secid contains the security ID.
  *     @secdata contains the pointer that stores the converted security context.
+ * @secctx_to_secid:
+ *      Convert security context to secid.
+ *      @secid contains the pointer to the generated security ID.
+ *      @secdata contains the security context.
  *
  * @release_secctx:
  *     Release the security context.
@@ -1235,13 +1258,19 @@ struct security_operations {
        void (*sb_umount_busy) (struct vfsmount * mnt);
        void (*sb_post_remount) (struct vfsmount * mnt,
                                 unsigned long flags, void *data);
-       void (*sb_post_mountroot) (void);
        void (*sb_post_addmount) (struct vfsmount * mnt,
                                  struct nameidata * mountpoint_nd);
        int (*sb_pivotroot) (struct nameidata * old_nd,
                             struct nameidata * new_nd);
        void (*sb_post_pivotroot) (struct nameidata * old_nd,
                                   struct nameidata * new_nd);
+       int (*sb_get_mnt_opts) (const struct super_block *sb,
+                               char ***mount_options, int **flags,
+                               int *num_opts);
+       int (*sb_set_mnt_opts) (struct super_block *sb, char **mount_options,
+                               int *flags, int num_opts);
+       void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
+                                  struct super_block *newsb);
 
        int (*inode_alloc_security) (struct inode *inode);      
        void (*inode_free_security) (struct inode *inode);
@@ -1371,6 +1400,7 @@ struct security_operations {
        int (*getprocattr)(struct task_struct *p, char *name, char **value);
        int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size);
        int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
+       int (*secctx_to_secid)(char *secdata, u32 seclen, u32 *secid);
        void (*release_secctx)(char *secdata, u32 seclen);
 
 #ifdef CONFIG_SECURITY_NETWORK
@@ -1495,10 +1525,16 @@ int security_sb_umount(struct vfsmount *mnt, int flags);
 void security_sb_umount_close(struct vfsmount *mnt);
 void security_sb_umount_busy(struct vfsmount *mnt);
 void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data);
-void security_sb_post_mountroot(void);
 void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd);
 int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd);
 void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd);
+int security_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options,
+                            int **flags, int *num_opts);
+int security_sb_set_mnt_opts(struct super_block *sb, char **mount_options,
+                            int *flags, int num_opts);
+void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+                               struct super_block *newsb);
+
 int security_inode_alloc(struct inode *inode);
 void security_inode_free(struct inode *inode);
 int security_inode_init_security(struct inode *inode, struct inode *dir,
@@ -1603,6 +1639,7 @@ int security_setprocattr(struct task_struct *p, char *name, void *value, size_t
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_netlink_recv(struct sk_buff *skb, int cap);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid);
 void security_release_secctx(char *secdata, u32 seclen);
 
 #else /* CONFIG_SECURITY */
@@ -1777,9 +1814,6 @@ static inline void security_sb_post_remount (struct vfsmount *mnt,
                                             unsigned long flags, void *data)
 { }
 
-static inline void security_sb_post_mountroot (void)
-{ }
-
 static inline void security_sb_post_addmount (struct vfsmount *mnt,
                                              struct nameidata *mountpoint_nd)
 { }
@@ -2266,7 +2300,7 @@ static inline struct dentry *securityfs_create_file(const char *name,
                                                mode_t mode,
                                                struct dentry *parent,
                                                void *data,
-                                               struct file_operations *fops)
+                                               const struct file_operations *fops)
 {
        return ERR_PTR(-ENODEV);
 }
@@ -2280,6 +2314,13 @@ static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *secle
        return -EOPNOTSUPP;
 }
 
+static inline int security_secctx_to_secid(char *secdata,
+                                          u32 seclen,
+                                          u32 *secid)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline void security_release_secctx(char *secdata, u32 seclen)
 {
 }
index f3a8eecd99f3c4b5eb68d10389e3b96546699f4d..f62caaad94e00876d7877c8cb738c95f5e61021c 100644 (file)
@@ -271,5 +271,10 @@ static inline void *kzalloc(size_t size, gfp_t flags)
        return kmalloc(size, flags | __GFP_ZERO);
 }
 
+#ifdef CONFIG_SLABINFO
+extern const struct seq_operations slabinfo_op;
+ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SLAB_H */
index 32bdc2ffd7151599c9d6468ee4ad448117f097de..fcc48096ee6406be0200c19ea7d6b1a64609dda5 100644 (file)
@@ -95,7 +95,4 @@ found:
 
 #endif /* CONFIG_NUMA */
 
-extern const struct seq_operations slabinfo_op;
-ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
-
 #endif /* _LINUX_SLAB_DEF_H */
index 58962c51dee108d3f9e5d12a23ce40e6e9387608..aab3a4cff4e13da65a50ec50531ccfd8ed19444d 100644 (file)
@@ -17,22 +17,10 @@ extern void __lockfunc __release_kernel_lock(void);
                __release_kernel_lock();        \
 } while (0)
 
-/*
- * Non-SMP kernels will never block on the kernel lock,
- * so we are better off returning a constant zero from
- * reacquire_kernel_lock() so that the compiler can see
- * it at compile-time.
- */
-#if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_BKL)
-# define return_value_on_smp return
-#else
-# define return_value_on_smp
-#endif
-
 static inline int reacquire_kernel_lock(struct task_struct *task)
 {
        if (unlikely(task->lock_depth >= 0))
-               return_value_on_smp __reacquire_kernel_lock();
+               return __reacquire_kernel_lock();
        return 0;
 }
 
index e7fa657d0c4940c6300a9ce4e516b73f765e31f3..5da9794b2d782d27f3f77fde3418521a6a19a3e8 100644 (file)
@@ -9,10 +9,13 @@ struct stack_trace {
 };
 
 extern void save_stack_trace(struct stack_trace *trace);
+extern void save_stack_trace_tsk(struct task_struct *tsk,
+                               struct stack_trace *trace);
 
 extern void print_stack_trace(struct stack_trace *trace, int spaces);
 #else
 # define save_stack_trace(trace)                       do { } while (0)
+# define save_stack_trace_tsk(tsk, trace)              do { } while (0)
 # define print_stack_trace(trace, spaces)              do { } while (0)
 #endif
 
index e285746588d68baf4dccc894e70768005342e04a..f752e73bf977e98381b95070096522c84e2ed5a1 100644 (file)
@@ -29,6 +29,7 @@
 struct sys_device;
 
 struct sysdev_class {
+       const char *name;
        struct list_head        drivers;
 
        /* Default operations for these types of devices */
index 149ab62329e238aab4ce518c41e4070764a8d32d..802710438a9e8a3b548d9549770268cb1ac2316b 100644 (file)
@@ -32,6 +32,8 @@ struct attribute {
 
 struct attribute_group {
        const char              *name;
+       int                     (*is_visible)(struct kobject *,
+                                             struct attribute *, int);
        struct attribute        **attrs;
 };
 
index 6b3a31805c72ff2e5d450697e15afc5e507d2599..2096b76d0cee68efe8cd91571e69da3c36bffd2c 100644 (file)
@@ -120,7 +120,7 @@ struct tifm_adapter {
        struct completion   *finish_me;
 
        struct work_struct  media_switcher;
-       struct class_device cdev;
+       struct device       dev;
 
        void                (*eject)(struct tifm_adapter *fm,
                                     struct tifm_dev *sock);
index 47729f18bfdf35b7943bd910401cd72a5350bae2..2352f46160d3f3558eb3964646a3c36685470618 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2002, IBM Corp.
  *
- * 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 as published by
        .forkexec_idx           = 0,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_FORK       \
                                | SD_BALANCE_EXEC       \
                                | SD_WAKE_AFFINE        \
                                | SD_WAKE_IDLE          \
        .forkexec_idx           = 1,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_FORK       \
                                | SD_BALANCE_EXEC       \
                                | SD_WAKE_AFFINE        \
                                | SD_WAKE_IDLE          \
        .forkexec_idx           = 1,                    \
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
+                               | SD_BALANCE_FORK       \
                                | SD_BALANCE_EXEC       \
                                | SD_WAKE_AFFINE        \
                                | BALANCE_FOR_PKG_POWER,\
index c555f5442bd7c2c99cad45fb49370bb2280a8629..defd2ab72449d4b9ef91f4def9a9e1cb2635364f 100644 (file)
@@ -319,6 +319,7 @@ extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
 extern void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud);
 extern void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud);
 extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
+extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
 
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
index 44c28e94df505f86b9274904d87f98925d589724..973386d439da24ffef58636347b3463c5aa038b8 100644 (file)
 #include <linux/fs.h>
 #include <linux/interrupt.h>
 
+struct uio_map;
+
 /**
  * struct uio_mem - description of a UIO memory region
- * @kobj:              kobject for this mapping
  * @addr:              address of the device's memory
  * @size:              size of IO
  * @memtype:           type of memory addr points to
  * @internal_addr:     ioremap-ped version of addr, for driver internal use
+ * @map:               for use by the UIO core only.
  */
 struct uio_mem {
-       struct kobject          kobj;
        unsigned long           addr;
        unsigned long           size;
        int                     memtype;
        void __iomem            *internal_addr;
+       struct uio_map          *map;
 };
 
 #define MAX_UIO_MAPS   5
index 7daafdc2514b9657a0e0d9d0325785cc65c934b2..7f28c32d9aca26ebb055fee881c7e28e3fdba2c2 100644 (file)
@@ -149,19 +149,27 @@ struct execute_work {
 
 extern struct workqueue_struct *
 __create_workqueue_key(const char *name, int singlethread,
-                      int freezeable, struct lock_class_key *key);
+                      int freezeable, struct lock_class_key *key,
+                      const char *lock_name);
 
 #ifdef CONFIG_LOCKDEP
 #define __create_workqueue(name, singlethread, freezeable)     \
 ({                                                             \
        static struct lock_class_key __key;                     \
+       const char *__lock_name;                                \
+                                                               \
+       if (__builtin_constant_p(name))                         \
+               __lock_name = (name);                           \
+       else                                                    \
+               __lock_name = #name;                            \
                                                                \
        __create_workqueue_key((name), (singlethread),          \
-                              (freezeable), &__key);           \
+                              (freezeable), &__key,            \
+                              __lock_name);                    \
 })
 #else
 #define __create_workqueue(name, singlethread, freezeable)     \
-       __create_workqueue_key((name), (singlethread), (freezeable), NULL)
+       __create_workqueue_key((name), (singlethread), (freezeable), NULL, NULL)
 #endif
 
 #define create_workqueue(name) __create_workqueue((name), 0, 0)
index bef7d66601cbfc2b52e07b841fceb7fddd77e1cb..c6148bbf1250a37ec4d29ba49732ff87a2019506 100644 (file)
@@ -62,7 +62,6 @@ struct writeback_control {
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
-       unsigned more_io:1;             /* more io to be dispatched */
 };
 
 /*
diff --git a/include/media/cs5345.h b/include/media/cs5345.h
new file mode 100644 (file)
index 0000000..6ccae24
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    cs5345.h - definition for cs5345 inputs and outputs
+
+    Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _CS5345_H_
+#define _CS5345_H_
+
+/* CS5345 HW inputs */
+#define CS5345_IN_MIC 0
+#define CS5345_IN_1   1
+#define CS5345_IN_2   2
+#define CS5345_IN_3   3
+#define CS5345_IN_4   4
+#define CS5345_IN_5   5
+#define CS5345_IN_6   6
+
+#define CS5345_MCLK_1   0x00
+#define CS5345_MCLK_1_5 0x10
+#define CS5345_MCLK_2   0x20
+#define CS5345_MCLK_3   0x30
+#define CS5345_MCLK_4   0x40
+
+#endif
index af8071d7620d1e3405e342a16b2aba9851aa62cb..5f4608e8847647723f8028bc4b488a2b62e060ca 100644 (file)
@@ -83,7 +83,7 @@ struct cx2341x_mpeg_params {
 #define CX2341X_MBOX_MAX_DATA 16
 
 extern const u32 cx2341x_mpeg_ctrls[];
-typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out,
+typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out,
                u32 data[CX2341X_MBOX_MAX_DATA]);
 int cx2341x_update(void *priv, cx2341x_mbox_func func,
                const struct cx2341x_mpeg_params *old,
index 8e7e52d659a0dcc07152c84fe98059a04f1de80e..cd599ad29fb2114b2b7e26ab46e613c8ea5ccff5 100644 (file)
@@ -49,6 +49,25 @@ enum cx25840_video_input {
        CX25840_SVIDEO2 = 0x620,
        CX25840_SVIDEO3 = 0x730,
        CX25840_SVIDEO4 = 0x840,
+
+       /* Allow frames to specify specific input configurations */
+       CX25840_VIN1_CH1  = 0x80000000,
+       CX25840_VIN2_CH1  = 0x80000001,
+       CX25840_VIN3_CH1  = 0x80000002,
+       CX25840_VIN4_CH1  = 0x80000003,
+       CX25840_VIN5_CH1  = 0x80000004,
+       CX25840_VIN6_CH1  = 0x80000005,
+       CX25840_VIN7_CH1  = 0x80000006,
+       CX25840_VIN8_CH1  = 0x80000007,
+       CX25840_VIN4_CH2  = 0x80000000,
+       CX25840_VIN5_CH2  = 0x80000010,
+       CX25840_VIN6_CH2  = 0x80000020,
+       CX25840_NONE_CH2  = 0x80000030,
+       CX25840_VIN7_CH3  = 0x80000000,
+       CX25840_VIN8_CH3  = 0x80000040,
+       CX25840_NONE0_CH3 = 0x80000080,
+       CX25840_NONE1_CH3 = 0x800000c0,
+       CX25840_SVIDEO_ON = 0x80000100,
 };
 
 enum cx25840_audio_input {
index 7a785fa7721262aad3816fef70be06f4cfb46b1a..831547d79683ad23415aa15e7ed9e2e9a6b29bfb 100644 (file)
@@ -97,7 +97,6 @@ int  ir_dump_samples(u32 *samples, int count);
 int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 int  ir_decode_pulsedistance(u32 *samples, int count, int low, int high);
 
-u32 ir_rc5_decode(unsigned int code);
 void ir_rc5_timer_end(unsigned long data);
 void ir_rc5_timer_keyup(unsigned long data);
 
@@ -141,6 +140,8 @@ extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE];
 
 #endif
 
diff --git a/include/media/m52790.h b/include/media/m52790.h
new file mode 100644 (file)
index 0000000..7ddffae
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+    m52790.h - definition for m52790 inputs and outputs
+
+    Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _M52790_H_
+#define _M52790_H_
+
+/* Input routing switch 1 */
+
+#define M52790_SW1_IN_MASK     0x0003
+#define M52790_SW1_IN_TUNER    0x0000
+#define M52790_SW1_IN_V2       0x0001
+#define M52790_SW1_IN_V3       0x0002
+#define M52790_SW1_IN_V4       0x0003
+
+/* Selects component input instead of composite */
+#define M52790_SW1_YCMIX       0x0004
+
+
+/* Input routing switch 2 */
+
+#define M52790_SW2_IN_MASK     0x0300
+#define M52790_SW2_IN_TUNER    0x0000
+#define M52790_SW2_IN_V2       0x0100
+#define M52790_SW2_IN_V3       0x0200
+#define M52790_SW2_IN_V4       0x0300
+
+/* Selects component input instead of composite */
+#define M52790_SW2_YCMIX       0x0400
+
+
+/* Output routing switch 1 */
+
+/* Enable 6dB amplifier for composite out */
+#define M52790_SW1_V_AMP       0x0008
+
+/* Enable 6dB amplifier for component out */
+#define M52790_SW1_YC_AMP      0x0010
+
+/* Audio output mode */
+#define M52790_SW1_AUDIO_MASK  0x00c0
+#define M52790_SW1_AUDIO_MUTE  0x0000
+#define M52790_SW1_AUDIO_R     0x0040
+#define M52790_SW1_AUDIO_L     0x0080
+#define M52790_SW1_AUDIO_STEREO 0x00c0
+
+
+/* Output routing switch 2 */
+
+/* Enable 6dB amplifier for composite out */
+#define M52790_SW2_V_AMP       0x0800
+
+/* Enable 6dB amplifier for component out */
+#define M52790_SW2_YC_AMP      0x1000
+
+/* Audio output mode */
+#define M52790_SW2_AUDIO_MASK  0xc000
+#define M52790_SW2_AUDIO_MUTE  0x0000
+#define M52790_SW2_AUDIO_R     0x4000
+#define M52790_SW2_AUDIO_L     0x8000
+#define M52790_SW2_AUDIO_STEREO 0xc000
+
+
+/* Common values */
+#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER)
+#define M52790_IN_V2    (M52790_SW1_IN_V2 | M52790_SW2_IN_V2)
+#define M52790_IN_V3    (M52790_SW1_IN_V3 | M52790_SW2_IN_V3)
+#define M52790_IN_V4    (M52790_SW1_IN_V4 | M52790_SW2_IN_V4)
+
+#define M52790_OUT_STEREO      (M52790_SW1_AUDIO_STEREO | \
+                                M52790_SW2_AUDIO_STEREO)
+#define M52790_OUT_AMP_STEREO  (M52790_SW1_AUDIO_STEREO | \
+                                M52790_SW1_V_AMP | \
+                                M52790_SW2_AUDIO_STEREO | \
+                                M52790_SW2_V_AMP)
+
+#endif
index e49f7e156061c8dd699060a5b6c1e3edd4c3c268..89c442eb884930b2f5f92de6e2da78ddd7845771 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __SAA7146_VV__
 #define __SAA7146_VV__
 
-#include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/saa7146.h>
 #include <media/videobuf-dma-sg.h>
index c03dceb926051695afbaba9499ce50e56a7c3699..1bf24a6ed8f10e4fbc0bbb25ab04dda09a20fd83 100644 (file)
@@ -24,8 +24,6 @@
 
 #include <linux/videodev2.h>
 
-extern int tuner_debug;
-
 #define ADDR_UNSET (255)
 
 #define TUNER_TEMIC_PAL                        0        /* 4002 FH5 (3X 7756, 9483) */
@@ -117,12 +115,13 @@ extern int tuner_debug;
 #define TUNER_PHILIPS_TUV1236D         68      /* ATI HDTV Wonder */
 #define TUNER_TNF_5335MF                69     /* Sabrent Bt848   */
 #define TUNER_SAMSUNG_TCPN_2121P30A     70     /* Hauppauge PVR-500MCE NTSC */
-#define TUNER_XCEIVE_XC3028            71
+#define TUNER_XC2028                   71
 
 #define TUNER_THOMSON_FE6600           72      /* DViCO FusionHDTV DVB-T Hybrid */
 #define TUNER_SAMSUNG_TCPG_6121P30A     73     /* Hauppauge PVR-500 PAL */
 #define TUNER_TDA9887                   74      /* This tuner should be used only internally */
 #define TUNER_TEA5761                  75      /* Only FM Radio Tuner */
+#define TUNER_XC5000                   76      /* Xceive Silicon Tuner */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
index 8ae42c41dd08d5bb351f3958491f7a442b1659df..032bb75f69c2ea7b92be53f274a52799c20e43eb 100644 (file)
@@ -68,6 +68,9 @@ enum {
        /* module vp27smpx: just ident 2700 */
        V4L2_IDENT_VP27SMPX = 2700,
 
+       /* module cs5345: just ident 5345 */
+       V4L2_IDENT_CS5345 = 5345,
+
        /* module wm8739: just ident 8739 */
        V4L2_IDENT_WM8739 = 8739,
 
@@ -83,6 +86,9 @@ enum {
        /* module upd64083: just ident 64083 */
        V4L2_IDENT_UPD64083 = 64083,
 
+       /* module m52790: just ident 52790 */
+       V4L2_IDENT_M52790 = 52790,
+
        /* module msp34xx: reserved range 34000-34999 */
        V4L2_IDENT_MSP3400B = 34002,
        V4L2_IDENT_MSP3410B = 34102,
index 181a40c46a52d866f5c1d3cb83cdbfeeea0387c1..475d0d8275e001ecb573e5d5e6a1b638db4b400d 100644 (file)
@@ -104,6 +104,17 @@ int v4l2_chip_match_host(u32 id_type, u32 chip_id);
 
 /* ------------------------------------------------------------------------- */
 
+/* Helper function for I2C legacy drivers */
+
+struct i2c_driver;
+struct i2c_adapter;
+struct i2c_client;
+
+int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
+               const char *name, int (*probe)(struct i2c_client *));
+
+/* ------------------------------------------------------------------------- */
+
 /* Internal ioctls */
 
 /* VIDIOC_INT_DECODE_VBI_LINE */
@@ -116,6 +127,11 @@ struct v4l2_decode_vbi_line {
        u32 type;               /* VBI service type (V4L2_SLICED_*). 0 if no service found */
 };
 
+struct v4l2_priv_tun_config {
+       int tuner;
+       void *priv;
+};
+
 /* audio ioctls */
 
 /* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
@@ -131,7 +147,7 @@ struct v4l2_decode_vbi_line {
 #define TUNER_SET_STANDBY            _IOW('d', 91, int)
 
 /* Sets tda9887 specific stuff, like port1, port2 and qss */
-#define TDA9887_SET_CONFIG           _IOW('d', 92, int)
+#define TUNER_SET_CONFIG           _IOW('d', 92, struct v4l2_priv_tun_config)
 
 /* Switch the tuner to a specific tuner mode. Replacement of AUDC_SET_RADIO */
 #define VIDIOC_INT_S_TUNER_MODE             _IOW('d', 93, enum v4l2_tuner_type)
diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h
new file mode 100644 (file)
index 0000000..2418542
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * v4l2-i2c-drv-legacy.h - contains I2C handling code that's identical
+ *                 for all V4L2 I2C drivers. Use this header if the
+ *                 I2C driver is used by both legacy drivers and
+ *                 drivers converted to the bus-based I2C API.
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+struct v4l2_i2c_driver_data {
+       const char * const name;
+       int driverid;
+       int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
+       int (*probe)(struct i2c_client *client);
+       int (*remove)(struct i2c_client *client);
+       int (*suspend)(struct i2c_client *client, pm_message_t state);
+       int (*resume)(struct i2c_client *client);
+       int (*legacy_probe)(struct i2c_adapter *adapter);
+       int legacy_class;
+};
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data;
+static struct i2c_client_address_data addr_data;
+static struct i2c_driver v4l2_i2c_driver_legacy;
+static char v4l2_i2c_drv_name_legacy[32];
+
+static int v4l2_i2c_drv_attach_legacy(struct i2c_adapter *adapter, int address, int kind)
+{
+       return v4l2_i2c_attach(adapter, address, &v4l2_i2c_driver_legacy,
+                       v4l2_i2c_drv_name_legacy, v4l2_i2c_data.probe);
+}
+
+static int v4l2_i2c_drv_probe_legacy(struct i2c_adapter *adapter)
+{
+       if (v4l2_i2c_data.legacy_probe) {
+               if (v4l2_i2c_data.legacy_probe(adapter))
+                       return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy);
+               return 0;
+       }
+       if (adapter->class & v4l2_i2c_data.legacy_class)
+               return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy);
+       return 0;
+}
+
+static int v4l2_i2c_drv_detach_legacy(struct i2c_client *client)
+{
+       int err;
+
+       if (v4l2_i2c_data.remove)
+               v4l2_i2c_data.remove(client);
+
+       err = i2c_detach_client(client);
+       if (err)
+               return err;
+       kfree(client);
+
+       return 0;
+}
+
+static int v4l2_i2c_drv_suspend_helper(struct i2c_client *client, pm_message_t state)
+{
+       return v4l2_i2c_data.suspend ? v4l2_i2c_data.suspend(client, state) : 0;
+}
+
+static int v4l2_i2c_drv_resume_helper(struct i2c_client *client)
+{
+       return v4l2_i2c_data.resume ? v4l2_i2c_data.resume(client) : 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver v4l2_i2c_driver_legacy = {
+       .driver = {
+               .owner = THIS_MODULE,
+       },
+       .attach_adapter = v4l2_i2c_drv_probe_legacy,
+       .detach_client = v4l2_i2c_drv_detach_legacy,
+       .suspend = v4l2_i2c_drv_suspend_helper,
+       .resume  = v4l2_i2c_drv_resume_helper,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver v4l2_i2c_driver = {
+       .suspend        = v4l2_i2c_drv_suspend_helper,
+       .resume         = v4l2_i2c_drv_resume_helper,
+};
+
+static int __init v4l2_i2c_drv_init(void)
+{
+       int err;
+
+       strlcpy(v4l2_i2c_drv_name_legacy, v4l2_i2c_data.name, sizeof(v4l2_i2c_drv_name_legacy));
+       strlcat(v4l2_i2c_drv_name_legacy, "'", sizeof(v4l2_i2c_drv_name_legacy));
+
+       if (v4l2_i2c_data.legacy_class == 0)
+               v4l2_i2c_data.legacy_class = I2C_CLASS_TV_ANALOG;
+
+       v4l2_i2c_driver_legacy.driver.name = v4l2_i2c_drv_name_legacy;
+       v4l2_i2c_driver_legacy.id = v4l2_i2c_data.driverid;
+       v4l2_i2c_driver_legacy.command = v4l2_i2c_data.command;
+       err = i2c_add_driver(&v4l2_i2c_driver_legacy);
+
+       if (err)
+               return err;
+       v4l2_i2c_driver.driver.name = v4l2_i2c_data.name;
+       v4l2_i2c_driver.id = v4l2_i2c_data.driverid;
+       v4l2_i2c_driver.command = v4l2_i2c_data.command;
+       v4l2_i2c_driver.probe = v4l2_i2c_data.probe;
+       v4l2_i2c_driver.remove = v4l2_i2c_data.remove;
+       err = i2c_add_driver(&v4l2_i2c_driver);
+       if (err)
+               i2c_del_driver(&v4l2_i2c_driver_legacy);
+       return err;
+}
+
+static void __exit v4l2_i2c_drv_cleanup(void)
+{
+       i2c_del_driver(&v4l2_i2c_driver_legacy);
+       i2c_del_driver(&v4l2_i2c_driver);
+}
+
+module_init(v4l2_i2c_drv_init);
+module_exit(v4l2_i2c_drv_cleanup);
diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h
new file mode 100644 (file)
index 0000000..9e4bab2
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * v4l2-i2c-drv.h - contains I2C handling code that's identical for
+ *                 all V4L2 I2C drivers. Use this header if the
+ *                 I2C driver is only used by drivers converted
+ *                 to the bus-based I2C API.
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __V4L2_I2C_DRV_H__
+#define __V4L2_I2C_DRV_H__
+
+#include <media/v4l2-common.h>
+
+struct v4l2_i2c_driver_data {
+       const char * const name;
+       int driverid;
+       int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
+       int (*probe)(struct i2c_client *client);
+       int (*remove)(struct i2c_client *client);
+       int (*suspend)(struct i2c_client *client, pm_message_t state);
+       int (*resume)(struct i2c_client *client);
+       int (*legacy_probe)(struct i2c_adapter *adapter);
+       int legacy_class;
+};
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data;
+static struct i2c_driver v4l2_i2c_driver;
+
+
+/* Bus-based I2C implementation for kernels >= 2.6.22 */
+
+static int __init v4l2_i2c_drv_init(void)
+{
+       v4l2_i2c_driver.driver.name = v4l2_i2c_data.name;
+       v4l2_i2c_driver.id = v4l2_i2c_data.driverid;
+       v4l2_i2c_driver.command = v4l2_i2c_data.command;
+       v4l2_i2c_driver.probe = v4l2_i2c_data.probe;
+       v4l2_i2c_driver.remove = v4l2_i2c_data.remove;
+       v4l2_i2c_driver.suspend = v4l2_i2c_data.suspend;
+       v4l2_i2c_driver.resume = v4l2_i2c_data.resume;
+       return i2c_add_driver(&v4l2_i2c_driver);
+}
+
+
+static void __exit v4l2_i2c_drv_cleanup(void)
+{
+       i2c_del_driver(&v4l2_i2c_driver);
+}
+
+module_init(v4l2_i2c_drv_init);
+module_exit(v4l2_i2c_drv_cleanup);
+
+#endif /* __V4L2_I2C_DRV_H__ */
index 066ebfc4f9832e89805b42d0ccbacae6112783c1..c8b80e0f065199e01102933d0ad4074075632782 100644 (file)
@@ -44,9 +44,8 @@ enum v4l2_int_type {
 struct v4l2_int_device;
 
 struct v4l2_int_master {
-       int (*attach)(struct v4l2_int_device *master,
-                     struct v4l2_int_device *slave);
-       void (*detach)(struct v4l2_int_device *master);
+       int (*attach)(struct v4l2_int_device *slave);
+       void (*detach)(struct v4l2_int_device *slave);
 };
 
 typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *);
index 4fd5d0eaa935fba6dab336565f4c70004dd12555..97f14d469595fd03e12adcd01457b266527d8d04 100644 (file)
@@ -56,13 +56,13 @@ struct videobuf_mapping {
 };
 
 enum videobuf_state {
-       STATE_NEEDS_INIT = 0,
-       STATE_PREPARED   = 1,
-       STATE_QUEUED     = 2,
-       STATE_ACTIVE     = 3,
-       STATE_DONE       = 4,
-       STATE_ERROR      = 5,
-       STATE_IDLE       = 6,
+       VIDEOBUF_NEEDS_INIT = 0,
+       VIDEOBUF_PREPARED   = 1,
+       VIDEOBUF_QUEUED     = 2,
+       VIDEOBUF_ACTIVE     = 3,
+       VIDEOBUF_DONE       = 4,
+       VIDEOBUF_ERROR      = 5,
+       VIDEOBUF_IDLE       = 6,
 };
 
 struct videobuf_buffer {
@@ -162,12 +162,14 @@ struct videobuf_queue {
        struct videobuf_queue_ops  *ops;
        struct videobuf_qtype_ops  *int_ops;
 
+       unsigned int               streaming:1;
+       unsigned int               reading:1;
+       unsigned int               is_mmapped:1;
+
        /* capture via mmap() + ioctl(QBUF/DQBUF) */
-       unsigned int               streaming;
        struct list_head           stream;
 
        /* capture via read() */
-       unsigned int               reading;
        unsigned int               read_off;
        struct videobuf_buffer     *read_buf;
 
index 448eccb206384f541a43c530fa5ac3add38eb329..b24508abb8505bff87d1ba1f139f25db0f4a10e6 100644 (file)
@@ -269,18 +269,21 @@ static inline void ipv6_arcnet_mc_map(const struct in6_addr *addr, char *buf)
        buf[0] = 0x00;
 }
 
-static inline void ipv6_ib_mc_map(struct in6_addr *addr, char *buf)
+static inline void ipv6_ib_mc_map(const struct in6_addr *addr,
+                                 const unsigned char *broadcast, char *buf)
 {
+       unsigned char scope = broadcast[5] & 0xF;
+
        buf[0]  = 0;            /* Reserved */
        buf[1]  = 0xff;         /* Multicast QPN */
        buf[2]  = 0xff;
        buf[3]  = 0xff;
        buf[4]  = 0xff;
-       buf[5]  = 0x12;         /* link local scope */
+       buf[5]  = 0x10 | scope; /* scope from broadcast address */
        buf[6]  = 0x60;         /* IPv6 signature */
        buf[7]  = 0x1b;
-       buf[8]  = 0;            /* P_Key */
-       buf[9]  = 0;
+       buf[8]  = broadcast[8]; /* P_Key */
+       buf[9]  = broadcast[9];
        memcpy(buf + 10, addr->s6_addr + 6, 10);
 }
 #endif
index 840dd91b513b0ec5000738af3773eda478bba13b..50c8889b1b8d7e6625cf4580a673c9a516e27bfd 100644 (file)
@@ -266,20 +266,22 @@ static inline void ip_eth_mc_map(__be32 naddr, char *buf)
  *     Leave P_Key as 0 to be filled in by driver.
  */
 
-static inline void ip_ib_mc_map(__be32 naddr, char *buf)
+static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf)
 {
        __u32 addr;
+       unsigned char scope = broadcast[5] & 0xF;
+
        buf[0]  = 0;            /* Reserved */
        buf[1]  = 0xff;         /* Multicast QPN */
        buf[2]  = 0xff;
        buf[3]  = 0xff;
        addr    = ntohl(naddr);
        buf[4]  = 0xff;
-       buf[5]  = 0x12;         /* link local scope */
+       buf[5]  = 0x10 | scope; /* scope from broadcast address */
        buf[6]  = 0x40;         /* IPv4 signature */
        buf[7]  = 0x1b;
-       buf[8]  = 0;            /* P_Key */
-       buf[9]  = 0;
+       buf[8]  = broadcast[8];         /* P_Key */
+       buf[9]  = broadcast[9];
        buf[10] = 0;
        buf[11] = 0;
        buf[12] = 0;
index c9265518a378ac6ca93ab1a74745d8149d8fcf2b..4c3b35153c3722b2a5871cf78ed11023f7fa9e17 100644 (file)
@@ -325,7 +325,6 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask)
                n->tc_verd = SET_TC_VERD(n->tc_verd, 0);
                n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
                n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
-               n->iif = skb->iif;
        }
        return n;
 }
index 00848b641f59d592d933452ee309ab22ee499047..954090b1e354143bd851a384f9b858a844096634 100644 (file)
@@ -450,7 +450,7 @@ enum sctp_sn_type {
        SCTP_SHUTDOWN_EVENT,
        SCTP_PARTIAL_DELIVERY_EVENT,
        SCTP_ADAPTATION_INDICATION,
-       SCTP_AUTHENTICATION_EVENT,
+       SCTP_AUTHENTICATION_INDICATION,
 };
 
 /* Notification error codes used to fill up the error fields in some
index 67e35c7e230c42a08bb718e6508d3826dbbe6cdd..6e1542da33a1ae26ddc93b80a2071401c6f73c09 100644 (file)
@@ -944,7 +944,7 @@ static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
                return err;
        
        rcu_read_lock_bh();
-       filter = sk->sk_filter;
+       filter = rcu_dereference(sk->sk_filter);
        if (filter) {
                unsigned int pkt_len = sk_run_filter(skb, filter->insns,
                                filter->len);
index 58dfa82889aa498be489d11ada7a163f3277f134..1dd20cf17982663b8881f55c76440d7dd096d98d 100644 (file)
@@ -1188,10 +1188,15 @@ static inline int xfrm_aevent_is_on(void)
        return ret;
 }
 
+static inline int xfrm_alg_len(struct xfrm_algo *alg)
+{
+       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
 #ifdef CONFIG_XFRM_MIGRATE
 static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
 {
-       return (struct xfrm_algo *)kmemdup(orig, sizeof(*orig) + orig->alg_key_len, GFP_KERNEL);
+       return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
 }
 
 static inline void xfrm_states_put(struct xfrm_state **states, int n)
index 8ec3799e42e17066dbd2d22e8f90d5069f91c283..7228c056b9e9b3d9f78d05da24ed0b34d1a74e82 100644 (file)
@@ -230,7 +230,9 @@ struct ib_class_port_info
  * @seg_count: The number of RMPP segments allocated for this send.
  * @seg_size: Size of each RMPP segment.
  * @timeout_ms: Time to wait for a response.
- * @retries: Number of times to retry a request for a response.
+ * @retries: Number of times to retry a request for a response.  For MADs
+ *   using RMPP, this applies per window.  On completion, returns the number
+ *   of retries needed to complete the transfer.
  *
  * Users are responsible for initializing the MAD buffer itself, with the
  * exception of any RMPP header.  Additional segment buffer space allocated
index 11f39606e7d94c64c1a63c6e5772dbca944a538c..cfbd38fe299825f7101925860abc70c08d7f8dbb 100644 (file)
@@ -1026,7 +1026,7 @@ struct ib_device {
 
        struct module               *owner;
        struct class_device          class_dev;
-       struct kobject               ports_parent;
+       struct kobject               *ports_parent;
        struct list_head             port_list;
 
        enum {
index 9749c1b34d008e34e353c956bc9ac1f401d92acb..c55705460b87f1f57995798c6f2aa6a63bc71aaf 100644 (file)
@@ -60,7 +60,8 @@ enum {
        RDMA_USER_CM_CMD_SET_OPTION,
        RDMA_USER_CM_CMD_NOTIFY,
        RDMA_USER_CM_CMD_JOIN_MCAST,
-       RDMA_USER_CM_CMD_LEAVE_MCAST
+       RDMA_USER_CM_CMD_LEAVE_MCAST,
+       RDMA_USER_CM_CMD_MIGRATE_ID
 };
 
 /*
@@ -230,4 +231,14 @@ struct rdma_ucm_set_option {
        __u32 optlen;
 };
 
+struct rdma_ucm_migrate_id {
+       __u64 response;
+       __u32 id;
+       __u32 fd;
+};
+
+struct rdma_ucm_migrate_resp {
+       __u32 events_reported;
+};
+
 #endif /* RDMA_USER_CM_H */
index 50e907f4204849177f8e883ced1ec53b3030504f..e19e5842316634699ed5d0763d2d14719e35f7b6 100644 (file)
@@ -49,12 +49,15 @@ enum iscsi_uevent_e {
 
        ISCSI_UEVENT_TGT_DSCVR          = UEVENT_BASE + 15,
        ISCSI_UEVENT_SET_HOST_PARAM     = UEVENT_BASE + 16,
+       ISCSI_UEVENT_UNBIND_SESSION     = UEVENT_BASE + 17,
 
        /* up events */
        ISCSI_KEVENT_RECV_PDU           = KEVENT_BASE + 1,
        ISCSI_KEVENT_CONN_ERROR         = KEVENT_BASE + 2,
        ISCSI_KEVENT_IF_ERROR           = KEVENT_BASE + 3,
        ISCSI_KEVENT_DESTROY_SESSION    = KEVENT_BASE + 4,
+       ISCSI_KEVENT_UNBIND_SESSION     = KEVENT_BASE + 5,
+       ISCSI_KEVENT_CREATE_SESSION     = KEVENT_BASE + 6,
 };
 
 enum iscsi_tgt_dscvr {
@@ -156,6 +159,10 @@ struct iscsi_uevent {
                        uint32_t        sid;
                        uint32_t        cid;
                } c_conn_ret;
+               struct msg_unbind_session {
+                       uint32_t        sid;
+                       uint32_t        host_no;
+               } unbind_session;
                struct msg_recv_req {
                        uint32_t        sid;
                        uint32_t        cid;
@@ -236,6 +243,13 @@ enum iscsi_param {
        ISCSI_PARAM_PASSWORD,
        ISCSI_PARAM_PASSWORD_IN,
 
+       ISCSI_PARAM_FAST_ABORT,
+       ISCSI_PARAM_ABORT_TMO,
+       ISCSI_PARAM_LU_RESET_TMO,
+       ISCSI_PARAM_HOST_RESET_TMO,
+
+       ISCSI_PARAM_PING_TMO,
+       ISCSI_PARAM_RECV_TMO,
        /* must always be last */
        ISCSI_PARAM_MAX,
 };
@@ -266,6 +280,12 @@ enum iscsi_param {
 #define ISCSI_USERNAME_IN              (1 << ISCSI_PARAM_USERNAME_IN)
 #define ISCSI_PASSWORD                 (1 << ISCSI_PARAM_PASSWORD)
 #define ISCSI_PASSWORD_IN              (1 << ISCSI_PARAM_PASSWORD_IN)
+#define ISCSI_FAST_ABORT               (1 << ISCSI_PARAM_FAST_ABORT)
+#define ISCSI_ABORT_TMO                        (1 << ISCSI_PARAM_ABORT_TMO)
+#define ISCSI_LU_RESET_TMO             (1 << ISCSI_PARAM_LU_RESET_TMO)
+#define ISCSI_HOST_RESET_TMO           (1 << ISCSI_PARAM_HOST_RESET_TMO)
+#define ISCSI_PING_TMO                 (1 << ISCSI_PARAM_PING_TMO)
+#define ISCSI_RECV_TMO                 (1 << ISCSI_PARAM_RECV_TMO)
 
 /* iSCSI HBA params */
 enum iscsi_host_param {
index 8d1e4e8026fef0804292aa7d7dcb093a0a5bba11..318a909e7ae15afe3f26d01a4a96be8863192f98 100644 (file)
 #ifndef ISCSI_PROTO_H
 #define ISCSI_PROTO_H
 
+#include <linux/types.h>
+
 #define ISCSI_DRAFT20_VERSION  0x00
 
 /* default iSCSI listen port for incoming connections */
 #define ISCSI_LISTEN_PORT      3260
 
 /* Padding word length */
-#define PAD_WORD_LEN           4
+#define ISCSI_PAD_LEN          4
 
 /*
  * useful common(control and data pathes) macro
@@ -147,6 +149,14 @@ struct iscsi_rlength_ahdr {
        __be32 read_length;
 };
 
+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+       __be16 ahslength;       /* CDB length - 15, including reserved byte */
+       uint8_t ahstype;
+       uint8_t reserved;
+       uint8_t ecdb[260 - 16]; /* 4-byte aligned extended CDB spillover */
+};
+
 /* SCSI Response Header */
 struct iscsi_cmd_rsp {
        uint8_t opcode;
@@ -600,6 +610,8 @@ struct iscsi_reject {
 #define ISCSI_MIN_MAX_BURST_LEN                        512
 #define ISCSI_MAX_MAX_BURST_LEN                        16777215
 
+#define ISCSI_DEF_TIME2WAIT                    2
+
 /************************* RFC 3720 End *****************************/
 
 #endif /* ISCSI_PROTO_H */
index b4b31132618bbeae62699d998beb78bb99b98b23..889f51fabab9edae977c660de18e563a9f5c0982 100644 (file)
@@ -57,11 +57,14 @@ struct iscsi_nopin;
 #define ISCSI_MAX_CMD_PER_LUN          128
 
 /* Task Mgmt states */
-#define TMABORT_INITIAL                        0x0
-#define TMABORT_SUCCESS                        0x1
-#define TMABORT_FAILED                 0x2
-#define TMABORT_TIMEDOUT               0x3
-#define TMABORT_NOT_FOUND              0x4
+enum {
+       TMF_INITIAL,
+       TMF_QUEUED,
+       TMF_SUCCESS,
+       TMF_FAILED,
+       TMF_TIMEDOUT,
+       TMF_NOT_FOUND,
+};
 
 /* Connection suspend "bit" */
 #define ISCSI_SUSPEND_BIT              1
@@ -74,6 +77,13 @@ struct iscsi_nopin;
 
 #define ISCSI_ADDRESS_BUF_LEN          64
 
+enum {
+       /* this is the maximum possible storage for AHSs */
+       ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +
+                               sizeof(struct iscsi_rlength_ahdr),
+       ISCSI_DIGEST_SIZE = sizeof(__u32),
+};
+
 struct iscsi_mgmt_task {
        /*
         * Becuae LLDs allocate their hdr differently, this is a pointer to
@@ -91,15 +101,17 @@ enum {
        ISCSI_TASK_COMPLETED,
        ISCSI_TASK_PENDING,
        ISCSI_TASK_RUNNING,
-       ISCSI_TASK_ABORTING,
 };
 
 struct iscsi_cmd_task {
        /*
-        * Becuae LLDs allocate their hdr differently, this is a pointer to
-        * that storage. It must be setup at session creation time.
+        * Because LLDs allocate their hdr differently, this is a pointer
+        * and length to that storage. It must be setup at session
+        * creation time.
         */
        struct iscsi_cmd        *hdr;
+       unsigned short          hdr_max;
+       unsigned short          hdr_len;        /* accumulated size of hdr used */
        int                     itt;            /* this ITT */
 
        uint32_t                unsol_datasn;
@@ -110,7 +122,6 @@ struct iscsi_cmd_task {
        unsigned                data_count;     /* remaining Data-Out */
        struct scsi_cmnd        *sc;            /* associated SCSI cmd*/
        struct iscsi_conn       *conn;          /* used connection    */
-       struct iscsi_mgmt_task  *mtask;         /* tmf mtask in progr */
 
        /* state set/tested under session->lock */
        int                     state;
@@ -119,6 +130,11 @@ struct iscsi_cmd_task {
        void                    *dd_data;       /* driver/transport data */
 };
 
+static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask)
+{
+       return (void*)ctask->hdr + ctask->hdr_len;
+}
+
 struct iscsi_conn {
        struct iscsi_cls_conn   *cls_conn;      /* ptr to class connection */
        void                    *dd_data;       /* iscsi_transport data */
@@ -132,6 +148,12 @@ struct iscsi_conn {
         * conn_stop() flag: stop to recover, stop to terminate
         */
         int                    stop_stage;
+       struct timer_list       transport_timer;
+       unsigned long           last_recv;
+       unsigned long           last_ping;
+       int                     ping_timeout;
+       int                     recv_timeout;
+       struct iscsi_mgmt_task  *ping_mtask;
 
        /* iSCSI connection-wide sequencing */
        uint32_t                exp_statsn;
@@ -152,10 +174,11 @@ struct iscsi_conn {
        struct iscsi_cmd_task   *ctask;         /* xmit ctask in progress */
 
        /* xmit */
-       struct kfifo            *mgmtqueue;     /* mgmt (control) xmit queue */
+       struct list_head        mgmtqueue;      /* mgmt (control) xmit queue */
        struct list_head        mgmt_run_list;  /* list of control tasks */
        struct list_head        xmitqueue;      /* data-path cmd queue */
        struct list_head        run_list;       /* list of cmds in progress */
+       struct list_head        requeue;        /* tasks needing another run */
        struct work_struct      xmitwork;       /* per-conn. xmit workqueue */
        unsigned long           suspend_tx;     /* suspend Tx */
        unsigned long           suspend_rx;     /* suspend Rx */
@@ -163,8 +186,8 @@ struct iscsi_conn {
        /* abort */
        wait_queue_head_t       ehwait;         /* used in eh_abort() */
        struct iscsi_tm         tmhdr;
-       struct timer_list       tmabort_timer;
-       int                     tmabort_state;  /* see TMABORT_INITIAL, etc.*/
+       struct timer_list       tmf_timer;
+       int                     tmf_state;      /* see TMF_INITIAL, etc.*/
 
        /* negotiated params */
        unsigned                max_recv_dlength; /* initiator_max_recv_dsl*/
@@ -198,7 +221,7 @@ struct iscsi_conn {
        uint32_t                eh_abort_cnt;
 };
 
-struct iscsi_queue {
+struct iscsi_pool {
        struct kfifo            *queue;         /* FIFO Queue */
        void                    **pool;         /* Pool of elements */
        int                     max;            /* Max number of elements */
@@ -221,6 +244,8 @@ struct iscsi_session {
        uint32_t                queued_cmdsn;
 
        /* configuration */
+       int                     abort_timeout;
+       int                     lu_reset_timeout;
        int                     initial_r2t_en;
        unsigned                max_r2t;
        int                     imm_data_en;
@@ -231,6 +256,7 @@ struct iscsi_session {
        int                     pdu_inorder_en;
        int                     dataseq_inorder_en;
        int                     erl;
+       int                     fast_abort;
        int                     tpgt;
        char                    *username;
        char                    *username_in;
@@ -256,10 +282,10 @@ struct iscsi_session {
 
        int                     cmds_max;       /* size of cmds array */
        struct iscsi_cmd_task   **cmds;         /* Original Cmds arr */
-       struct iscsi_queue      cmdpool;        /* PDU's pool */
+       struct iscsi_pool       cmdpool;        /* PDU's pool */
        int                     mgmtpool_max;   /* size of mgmt array */
        struct iscsi_mgmt_task  **mgmt_cmds;    /* Original mgmt arr */
-       struct iscsi_queue      mgmtpool;       /* Mgmt PDU's pool */
+       struct iscsi_pool       mgmtpool;       /* Mgmt PDU's pool */
 };
 
 /*
@@ -268,6 +294,7 @@ struct iscsi_session {
 extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
 extern int iscsi_eh_abort(struct scsi_cmnd *sc);
 extern int iscsi_eh_host_reset(struct scsi_cmnd *sc);
+extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
 extern int iscsi_queuecommand(struct scsi_cmnd *sc,
                              void (*done)(struct scsi_cmnd *));
 
@@ -326,11 +353,32 @@ extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
                                char *, int);
 extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *,
                            uint32_t *);
+extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask);
+extern void iscsi_free_mgmt_task(struct iscsi_conn *conn,
+                                struct iscsi_mgmt_task *mtask);
 
 /*
  * generic helpers
  */
-extern void iscsi_pool_free(struct iscsi_queue *, void **);
-extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int);
+extern void iscsi_pool_free(struct iscsi_pool *);
+extern int iscsi_pool_init(struct iscsi_pool *, int, void ***, int);
+
+/*
+ * inline functions to deal with padding.
+ */
+static inline unsigned int
+iscsi_padded(unsigned int len)
+{
+       return (len + ISCSI_PAD_LEN - 1) & ~(ISCSI_PAD_LEN - 1);
+}
+
+static inline unsigned int
+iscsi_padding(unsigned int len)
+{
+       len &= (ISCSI_PAD_LEN - 1);
+       if (len)
+               len = ISCSI_PAD_LEN - len;
+       return len;
+}
 
 #endif
index a466c2cb8955b5f0955a7a194b44475abfce3e31..3ffd6b582a97144cb37009ef6ef47d1ff4cd8feb 100644 (file)
@@ -91,8 +91,6 @@ enum discover_event {
 
 /* ---------- Expander Devices ---------- */
 
-#define ETASK 0xFA
-
 #define to_dom_device(_obj) container_of(_obj, struct domain_device, dev_obj)
 #define to_dev_attr(_attr)  container_of(_attr, struct domain_dev_attribute,\
                                          attr)
@@ -122,8 +120,8 @@ struct ex_phy {
        u8   attached_sata_dev:1;
        u8   attached_sata_ps:1;
 
-       enum sas_proto attached_tproto;
-       enum sas_proto attached_iproto;
+       enum sas_protocol attached_tproto;
+       enum sas_protocol attached_iproto;
 
        u8   attached_sas_addr[SAS_ADDR_SIZE];
        u8   attached_phy_id;
@@ -191,8 +189,8 @@ struct domain_device {
 
         struct list_head dev_list_node;
 
-        enum sas_proto    iproto;
-        enum sas_proto    tproto;
+        enum sas_protocol    iproto;
+        enum sas_protocol    tproto;
 
         struct sas_rphy *rphy;
 
@@ -245,8 +243,8 @@ struct asd_sas_port {
        enum sas_class   class;
        u8               sas_addr[SAS_ADDR_SIZE];
        u8               attached_sas_addr[SAS_ADDR_SIZE];
-       enum sas_proto   iproto;
-       enum sas_proto   tproto;
+       enum sas_protocol   iproto;
+       enum sas_protocol   tproto;
 
        enum sas_oob_mode oob_mode;
 
@@ -289,8 +287,8 @@ struct asd_sas_phy {
 
        int            id;        /* must be set */
        enum sas_class class;
-       enum sas_proto iproto;
-       enum sas_proto tproto;
+       enum sas_protocol iproto;
+       enum sas_protocol tproto;
 
        enum sas_phy_type  type;
        enum sas_phy_role  role;
@@ -537,7 +535,7 @@ struct sas_task {
        spinlock_t   task_state_lock;
        unsigned     task_state_flags;
 
-       enum   sas_proto      task_proto;
+       enum   sas_protocol      task_proto;
 
        /* Used by the discovery code. */
        struct timer_list     timer;
@@ -563,7 +561,7 @@ struct sas_task {
        struct work_struct abort_work;
 };
 
-
+extern struct kmem_cache *sas_task_cache;
 
 #define SAS_TASK_STATE_PENDING      1
 #define SAS_TASK_STATE_DONE         2
@@ -573,7 +571,6 @@ struct sas_task {
 
 static inline struct sas_task *sas_alloc_task(gfp_t flags)
 {
-       extern struct kmem_cache *sas_task_cache;
        struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags);
 
        if (task) {
@@ -590,7 +587,6 @@ static inline struct sas_task *sas_alloc_task(gfp_t flags)
 static inline void sas_free_task(struct sas_task *task)
 {
        if (task) {
-               extern struct kmem_cache *sas_task_cache;
                BUG_ON(!list_empty(&task->list));
                kmem_cache_free(sas_task_cache, task);
        }
@@ -676,4 +672,8 @@ extern int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
 
 extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                           struct request *req);
+
+extern void sas_ssp_task_response(struct device *dev, struct sas_task *task,
+                                 struct ssp_response_iu *iu);
+
 #endif /* _SASLIB_H_ */
index 2f4b6afa34fc3ae20015c0e18a29aa982a45bfc3..e9fd022813814145726c2296e459909de9ae3676 100644 (file)
@@ -102,13 +102,12 @@ enum sas_dev_type {
        SATA_PM_PORT= 8,
 };
 
-/* Partly from IDENTIFY address frame. */
-enum sas_proto {
-       SATA_PROTO    = 1,
-       SAS_PROTO_SMP = 2,        /* protocol */
-       SAS_PROTO_STP = 4,        /* protocol */
-       SAS_PROTO_SSP = 8,        /* protocol */
-       SAS_PROTO_ALL = 0xE,
+enum sas_protocol {
+       SAS_PROTOCOL_SATA               = 0x01,
+       SAS_PROTOCOL_SMP                = 0x02,
+       SAS_PROTOCOL_STP                = 0x04,
+       SAS_PROTOCOL_SSP                = 0x08,
+       SAS_PROTOCOL_ALL                = 0x0E,
 };
 
 /* From the spec; local phys only */
index 3f47e522a1ec3bedf6c85b9d30145c7208a626b5..abd7479ff45298fbf25bd6d2fb9579531b29f652 100644 (file)
@@ -88,7 +88,7 @@ struct scsi_cmnd {
                                           working on */
 
 #define SCSI_SENSE_BUFFERSIZE  96
-       unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
+       unsigned char *sense_buffer;
                                /* obtained by REQUEST SENSE when
                                 * CHECK CONDITION is received on original
                                 * command (auto-sense) */
index 6c2d80b36aa1b21f0066c284a64df692e375b948..ab7acbe809602b94e693da7fac9bc12a8ad47a89 100644 (file)
@@ -122,9 +122,6 @@ struct scsi_device {
        unsigned tagged_supported:1;    /* Supports SCSI-II tagged queuing */
        unsigned simple_tags:1; /* simple queue tag messages are enabled */
        unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
-       unsigned single_lun:1;  /* Indicates we should only allow I/O to
-                                * one of the luns for the device at a 
-                                * time. */
        unsigned was_reset:1;   /* There was a bus reset on the bus for 
                                 * this device */
        unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
@@ -142,6 +139,7 @@ struct scsi_device {
        unsigned fix_capacity:1;        /* READ_CAPACITY is too high by 1 */
        unsigned guess_capacity:1;      /* READ_CAPACITY might be too high by 1 */
        unsigned retry_hwerror:1;       /* Retry HARDWARE_ERROR */
+       unsigned last_sector_bug:1;     /* Always read last sector in a 1 sector read */
 
        DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
        struct list_head event_list;    /* asserted events */
@@ -202,6 +200,9 @@ struct scsi_target {
        unsigned int            id; /* target id ... replace
                                     * scsi_device.id eventually */
        unsigned int            create:1; /* signal that it needs to be added */
+       unsigned int            single_lun:1;   /* Indicates we should only
+                                                * allow I/O to one of the luns
+                                                * for the device at a time. */
        unsigned int            pdt_1f_for_no_lun;      /* PDT = 0x1f */
                                                /* means no lun present */
 
@@ -295,7 +296,7 @@ extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
                            struct scsi_mode_data *data,
                            struct scsi_sense_hdr *);
 extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
-                               int retries);
+                               int retries, struct scsi_sense_hdr *sshdr);
 extern int scsi_device_set_state(struct scsi_device *sdev,
                                 enum scsi_device_state state);
 extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
@@ -386,6 +387,10 @@ static inline int scsi_device_qas(struct scsi_device *sdev)
                return 0;
        return sdev->inquiry[56] & 0x02;
 }
+static inline int scsi_device_enclosure(struct scsi_device *sdev)
+{
+       return sdev->inquiry[6] & (1<<6);
+}
 
 #define MODULE_ALIAS_SCSI_DEVICE(type) \
        MODULE_ALIAS("scsi:t-" __stringify(type) "*")
index 7ff6199cbd55bef57c55b58b8c5a58f20a5d115a..404f11d331d6e767711a86e860013e63f88b8611 100644 (file)
@@ -118,7 +118,7 @@ struct iscsi_transport {
                         char *data, uint32_t data_size);
        void (*get_stats) (struct iscsi_cls_conn *conn,
                           struct iscsi_stats *stats);
-       void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
+       int (*init_cmd_task) (struct iscsi_cmd_task *ctask);
        void (*init_mgmt_task) (struct iscsi_conn *conn,
                                struct iscsi_mgmt_task *mtask);
        int (*xmit_cmd_task) (struct iscsi_conn *conn,
@@ -176,6 +176,7 @@ struct iscsi_cls_conn {
 #define ISCSI_STATE_TERMINATE          4
 #define ISCSI_STATE_IN_RECOVERY                5
 #define ISCSI_STATE_RECOVERY_FAILED    6
+#define ISCSI_STATE_LOGGING_OUT                7
 
 struct iscsi_cls_session {
        struct list_head sess_list;             /* item in session_list */
@@ -185,6 +186,7 @@ struct iscsi_cls_session {
        /* recovery fields */
        int recovery_tmo;
        struct delayed_work recovery_work;
+       struct work_struct unbind_work;
 
        int target_id;
 
@@ -205,6 +207,8 @@ struct iscsi_cls_session {
 struct iscsi_host {
        struct list_head sessions;
        struct mutex mutex;
+       struct workqueue_struct *unbind_workq;
+       char unbind_workq_name[KOBJ_NAME_LEN];
 };
 
 /*
@@ -214,8 +218,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
                                        struct iscsi_transport *transport);
 extern int iscsi_add_session(struct iscsi_cls_session *session,
                             unsigned int target_id);
-extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn);
-extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn);
+extern int iscsi_session_event(struct iscsi_cls_session *session,
+                              enum iscsi_uevent_e event);
 extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
                                                struct iscsi_transport *t,
                                                unsigned int target_id);
index abdfd2e27dd7dee85993d9199acb099b13a229c2..09125fa95b93a1d834957e7a66cfed67e77e4278 100644 (file)
@@ -4,23 +4,17 @@
 #include <linux/transport_class.h>
 #include <linux/types.h>
 #include <linux/mutex.h>
+#include <scsi/sas.h>
 
 struct scsi_transport_template;
 struct sas_rphy;
 struct request;
 
 enum sas_device_type {
-       SAS_PHY_UNUSED,
-       SAS_END_DEVICE,
-       SAS_EDGE_EXPANDER_DEVICE,
-       SAS_FANOUT_EXPANDER_DEVICE,
-};
-
-enum sas_protocol {
-       SAS_PROTOCOL_SATA               = 0x01,
-       SAS_PROTOCOL_SMP                = 0x02,
-       SAS_PROTOCOL_STP                = 0x04,
-       SAS_PROTOCOL_SSP                = 0x08,
+       SAS_PHY_UNUSED = 0,
+       SAS_END_DEVICE = 1,
+       SAS_EDGE_EXPANDER_DEVICE = 2,
+       SAS_FANOUT_EXPANDER_DEVICE = 3,
 };
 
 static inline int sas_protocol_ata(enum sas_protocol proto)
index f7513313ef0d5d5bdd85194dfb6771ac294cc22d..8ea9f7358ac1dde7a8a28d9442f366304b2e2929 100644 (file)
@@ -41,6 +41,7 @@ struct scsi_disk {
        u32             index;
        u8              media_present;
        u8              write_prot;
+       unsigned        previous_state : 1;
        unsigned        WCE : 1;        /* state of disk WCE bit */
        unsigned        RCD : 1;        /* state of disk RCD bit, unused */
        unsigned        DPOFUA : 1;     /* state of disk DPOFUA bit */
index 404bbf3699becba6bc43dbe9c945506ad1a93d2c..0eda68f0ad540778b7f071bd2f5493adaf29a484 100644 (file)
@@ -363,6 +363,7 @@ config CGROUP_CPUACCT
 
 config SYSFS_DEPRECATED
        bool "Create deprecated sysfs files"
+       depends on SYSFS
        default y
        help
          This option creates deprecated symlinks such as the
@@ -658,6 +659,12 @@ endchoice
 
 endmenu                # General setup
 
+config SLABINFO
+       bool
+       depends on PROC_FS
+       depends on SLAB || SLUB
+       default y
+
 config RT_MUTEXES
        boolean
        select PLIST
@@ -756,3 +763,31 @@ source "block/Kconfig"
 
 config PREEMPT_NOTIFIERS
        bool
+
+choice
+       prompt "RCU implementation type:"
+       default CLASSIC_RCU
+
+config CLASSIC_RCU
+       bool "Classic RCU"
+       help
+         This option selects the classic RCU implementation that is
+         designed for best read-side performance on non-realtime
+         systems.
+
+         Say Y if you are unsure.
+
+config PREEMPT_RCU
+       bool "Preemptible RCU"
+       depends on PREEMPT
+       help
+         This option reduces the latency of the kernel by making certain
+         RCU sections preemptible. Normally RCU code is non-preemptible, if
+         this option is selected then read-only RCU sections become
+         preemptible. This helps latency, but may expose bugs due to
+         now-naive assumptions about each RCU read-side critical section
+         remaining on a given CPU through its execution.
+
+         Say N if you are unsure.
+
+endchoice
index 4efa1e5385e3a1b110b29b46ceccedf36a8c4138..1161dfd7b0d3d23a4f9968c973a5f578b42c341d 100644 (file)
@@ -55,69 +55,6 @@ static int __init readwrite(char *str)
 __setup("ro", readonly);
 __setup("rw", readwrite);
 
-static dev_t try_name(char *name, int part)
-{
-       char path[64];
-       char buf[32];
-       int range;
-       dev_t res;
-       char *s;
-       int len;
-       int fd;
-       unsigned int maj, min;
-
-       /* read device number from .../dev */
-
-       sprintf(path, "/sys/block/%s/dev", name);
-       fd = sys_open(path, 0, 0);
-       if (fd < 0)
-               goto fail;
-       len = sys_read(fd, buf, 32);
-       sys_close(fd);
-       if (len <= 0 || len == 32 || buf[len - 1] != '\n')
-               goto fail;
-       buf[len - 1] = '\0';
-       if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
-               /*
-                * Try the %u:%u format -- see print_dev_t()
-                */
-               res = MKDEV(maj, min);
-               if (maj != MAJOR(res) || min != MINOR(res))
-                       goto fail;
-       } else {
-               /*
-                * Nope.  Try old-style "0321"
-                */
-               res = new_decode_dev(simple_strtoul(buf, &s, 16));
-               if (*s)
-                       goto fail;
-       }
-
-       /* if it's there and we are not looking for a partition - that's it */
-       if (!part)
-               return res;
-
-       /* otherwise read range from .../range */
-       sprintf(path, "/sys/block/%s/range", name);
-       fd = sys_open(path, 0, 0);
-       if (fd < 0)
-               goto fail;
-       len = sys_read(fd, buf, 32);
-       sys_close(fd);
-       if (len <= 0 || len == 32 || buf[len - 1] != '\n')
-               goto fail;
-       buf[len - 1] = '\0';
-       range = simple_strtoul(buf, &s, 10);
-       if (*s)
-               goto fail;
-
-       /* if partition is within range - we got it */
-       if (part < range)
-               return res + part;
-fail:
-       return 0;
-}
-
 /*
  *     Convert a name into device number.  We accept the following variants:
  *
@@ -129,12 +66,10 @@ fail:
  *     5) /dev/<disk_name>p<decimal> - same as the above, that form is
  *        used when disk name of partitioned disk ends on a digit.
  *
- *     If name doesn't have fall into the categories above, we return 0.
- *     Sysfs is used to check if something is a disk name - it has
- *     all known disks under bus/block/devices.  If the disk name
- *     contains slashes, name of sysfs node has them replaced with
- *     bangs.  try_name() does the actual checks, assuming that sysfs
- *     is mounted on rootfs /sys.
+ *     If name doesn't have fall into the categories above, we return (0,0).
+ *     block_class is used to check if something is a disk name. If the disk
+ *     name contains slashes, the device name has them replaced with
+ *     bangs.
  */
 
 dev_t name_to_dev_t(char *name)
@@ -142,13 +77,6 @@ dev_t name_to_dev_t(char *name)
        char s[32];
        char *p;
        dev_t res = 0;
-       int part;
-
-#ifdef CONFIG_SYSFS
-       int mkdir_err = sys_mkdir("/sys", 0700);
-       if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
-               goto out;
-#endif
 
        if (strncmp(name, "/dev/", 5) != 0) {
                unsigned maj, min;
@@ -164,6 +92,7 @@ dev_t name_to_dev_t(char *name)
                }
                goto done;
        }
+
        name += 5;
        res = Root_NFS;
        if (strcmp(name, "nfs") == 0)
@@ -178,35 +107,14 @@ dev_t name_to_dev_t(char *name)
        for (p = s; *p; p++)
                if (*p == '/')
                        *p = '!';
-       res = try_name(s, 0);
+       res = blk_lookup_devt(s);
        if (res)
                goto done;
 
-       while (p > s && isdigit(p[-1]))
-               p--;
-       if (p == s || !*p || *p == '0')
-               goto fail;
-       part = simple_strtoul(p, NULL, 10);
-       *p = '\0';
-       res = try_name(s, part);
-       if (res)
-               goto done;
-
-       if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
-               goto fail;
-       p[-1] = '\0';
-       res = try_name(s, part);
+fail:
+       return 0;
 done:
-#ifdef CONFIG_SYSFS
-       sys_umount("/sys", 0);
-out:
-       if (!mkdir_err)
-               sys_rmdir("/sys");
-#endif
        return res;
-fail:
-       res = 0;
-       goto done;
 }
 
 static int __init root_dev_setup(char *line)
@@ -470,6 +378,5 @@ void __init prepare_namespace(void)
 out:
        sys_mount(".", "/", NULL, MS_MOVE, NULL);
        sys_chroot(".");
-       security_sb_post_mountroot();
 }
 
index 80b04b6c5157c85151669fdfe2864c16f876680e..f287ca5862b9c7e9a8d0f1b1b4ba689a4af7e4e4 100644 (file)
@@ -607,6 +607,7 @@ asmlinkage void __init start_kernel(void)
        vfs_caches_init_early();
        cpuset_init_early();
        mem_init();
+       cpu_hotplug_init();
        kmem_cache_init();
        setup_per_cpu_pageset();
        numa_policy_init();
index 4af15802ccd46e960a857c04db9afe2c0ba49dc3..526128a2e62297630c3207f263e80a4879659003 100644 (file)
@@ -54,3 +54,5 @@ config HZ
        default 300 if HZ_300
        default 1000 if HZ_1000
 
+config SCHED_HRTICK
+       def_bool HIGH_RES_TIMERS && X86
index c64ce9c14207644bfc07c5f2c729f5fe9b66c5b6..0669b70fa6a3af35c4c67599575a8c2a12154fa4 100644 (file)
@@ -52,14 +52,13 @@ config PREEMPT
 
 endchoice
 
-config PREEMPT_BKL
-       bool "Preempt The Big Kernel Lock"
-       depends on SMP || PREEMPT
+config RCU_TRACE
+       bool "Enable tracing for RCU - currently stats in debugfs"
+       select DEBUG_FS
        default y
        help
-         This option reduces the latency of the kernel by making the
-         big kernel lock preemptible.
+         This option provides tracing in RCU which presents stats
+         in debugfs for debugging RCU implementation.
 
-         Say Y here if you are building a kernel for a desktop system.
+         Say Y here if you want to enable RCU tracing
          Say N if you are unsure.
-
index dfa96956dae0869c93f287b4c7348428eacaf8f3..390d421462672af511c09b95f6649590bd1f83c4 100644 (file)
@@ -52,11 +52,17 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
+obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o
+obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o
+ifeq ($(CONFIG_PREEMPT_RCU),y)
+obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o
+endif
 obj-$(CONFIG_RELAY) += relay.o
 obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
 obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
 obj-$(CONFIG_MARKERS) += marker.o
+obj-$(CONFIG_LATENCYTOP) += latencytop.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
index cf19547cc9e42d346c49b0e51e89aa5fb19364d6..521dfa53cb999657ce8971494f1f573d88d55df7 100644 (file)
@@ -482,7 +482,7 @@ static void do_acct_process(struct file *file)
 #endif
 #if ACCT_VERSION==3
        ac.ac_pid = current->tgid;
-       ac.ac_ppid = current->parent->tgid;
+       ac.ac_ppid = current->real_parent->tgid;
 #endif
 
        spin_lock_irq(&current->sighand->siglock);
index 6b3a0c15144f3404294dde422348e17242990e2b..e0d3a4f56ecbddb4a4c87c714bc49991fefa2cc2 100644 (file)
@@ -15,9 +15,8 @@
 #include <linux/stop_machine.h>
 #include <linux/mutex.h>
 
-/* This protects CPUs going up and down... */
+/* Serializes the updates to cpu_online_map, cpu_present_map */
 static DEFINE_MUTEX(cpu_add_remove_lock);
-static DEFINE_MUTEX(cpu_bitmask_lock);
 
 static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
 
@@ -26,52 +25,123 @@ static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
  */
 static int cpu_hotplug_disabled;
 
-#ifdef CONFIG_HOTPLUG_CPU
+static struct {
+       struct task_struct *active_writer;
+       struct mutex lock; /* Synchronizes accesses to refcount, */
+       /*
+        * Also blocks the new readers during
+        * an ongoing cpu hotplug operation.
+        */
+       int refcount;
+       wait_queue_head_t writer_queue;
+} cpu_hotplug;
 
-/* Crappy recursive lock-takers in cpufreq! Complain loudly about idiots */
-static struct task_struct *recursive;
-static int recursive_depth;
+#define writer_exists() (cpu_hotplug.active_writer != NULL)
 
-void lock_cpu_hotplug(void)
+void __init cpu_hotplug_init(void)
 {
-       struct task_struct *tsk = current;
-
-       if (tsk == recursive) {
-               static int warnings = 10;
-               if (warnings) {
-                       printk(KERN_ERR "Lukewarm IQ detected in hotplug locking\n");
-                       WARN_ON(1);
-                       warnings--;
-               }
-               recursive_depth++;
+       cpu_hotplug.active_writer = NULL;
+       mutex_init(&cpu_hotplug.lock);
+       cpu_hotplug.refcount = 0;
+       init_waitqueue_head(&cpu_hotplug.writer_queue);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void get_online_cpus(void)
+{
+       might_sleep();
+       if (cpu_hotplug.active_writer == current)
                return;
-       }
-       mutex_lock(&cpu_bitmask_lock);
-       recursive = tsk;
+       mutex_lock(&cpu_hotplug.lock);
+       cpu_hotplug.refcount++;
+       mutex_unlock(&cpu_hotplug.lock);
+
 }
-EXPORT_SYMBOL_GPL(lock_cpu_hotplug);
+EXPORT_SYMBOL_GPL(get_online_cpus);
 
-void unlock_cpu_hotplug(void)
+void put_online_cpus(void)
 {
-       WARN_ON(recursive != current);
-       if (recursive_depth) {
-               recursive_depth--;
+       if (cpu_hotplug.active_writer == current)
                return;
-       }
-       recursive = NULL;
-       mutex_unlock(&cpu_bitmask_lock);
+       mutex_lock(&cpu_hotplug.lock);
+       cpu_hotplug.refcount--;
+
+       if (unlikely(writer_exists()) && !cpu_hotplug.refcount)
+               wake_up(&cpu_hotplug.writer_queue);
+
+       mutex_unlock(&cpu_hotplug.lock);
+
 }
-EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
+EXPORT_SYMBOL_GPL(put_online_cpus);
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
+/*
+ * The following two API's must be used when attempting
+ * to serialize the updates to cpu_online_map, cpu_present_map.
+ */
+void cpu_maps_update_begin(void)
+{
+       mutex_lock(&cpu_add_remove_lock);
+}
+
+void cpu_maps_update_done(void)
+{
+       mutex_unlock(&cpu_add_remove_lock);
+}
+
+/*
+ * This ensures that the hotplug operation can begin only when the
+ * refcount goes to zero.
+ *
+ * Note that during a cpu-hotplug operation, the new readers, if any,
+ * will be blocked by the cpu_hotplug.lock
+ *
+ * Since cpu_maps_update_begin is always called after invoking
+ * cpu_maps_update_begin, we can be sure that only one writer is active.
+ *
+ * Note that theoretically, there is a possibility of a livelock:
+ * - Refcount goes to zero, last reader wakes up the sleeping
+ *   writer.
+ * - Last reader unlocks the cpu_hotplug.lock.
+ * - A new reader arrives at this moment, bumps up the refcount.
+ * - The writer acquires the cpu_hotplug.lock finds the refcount
+ *   non zero and goes to sleep again.
+ *
+ * However, this is very difficult to achieve in practice since
+ * get_online_cpus() not an api which is called all that often.
+ *
+ */
+static void cpu_hotplug_begin(void)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       mutex_lock(&cpu_hotplug.lock);
+
+       cpu_hotplug.active_writer = current;
+       add_wait_queue_exclusive(&cpu_hotplug.writer_queue, &wait);
+       while (cpu_hotplug.refcount) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               mutex_unlock(&cpu_hotplug.lock);
+               schedule();
+               mutex_lock(&cpu_hotplug.lock);
+       }
+       remove_wait_queue_locked(&cpu_hotplug.writer_queue, &wait);
+}
+
+static void cpu_hotplug_done(void)
+{
+       cpu_hotplug.active_writer = NULL;
+       mutex_unlock(&cpu_hotplug.lock);
+}
 /* Need to know about CPUs going up/down? */
 int __cpuinit register_cpu_notifier(struct notifier_block *nb)
 {
        int ret;
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        ret = raw_notifier_chain_register(&cpu_chain, nb);
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
        return ret;
 }
 
@@ -81,9 +151,9 @@ EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
 {
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        raw_notifier_chain_unregister(&cpu_chain, nb);
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
 }
 EXPORT_SYMBOL(unregister_cpu_notifier);
 
@@ -147,7 +217,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
        if (!cpu_online(cpu))
                return -EINVAL;
 
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+       cpu_hotplug_begin();
        err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
                                        hcpu, -1, &nr_calls);
        if (err == NOTIFY_BAD) {
@@ -166,9 +236,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
        cpu_clear(cpu, tmp);
        set_cpus_allowed(current, tmp);
 
-       mutex_lock(&cpu_bitmask_lock);
        p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
-       mutex_unlock(&cpu_bitmask_lock);
 
        if (IS_ERR(p) || cpu_online(cpu)) {
                /* CPU didn't die: tell everyone.  Can't complain. */
@@ -202,7 +270,7 @@ out_thread:
 out_allowed:
        set_cpus_allowed(current, old_allowed);
 out_release:
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
+       cpu_hotplug_done();
        return err;
 }
 
@@ -210,13 +278,13 @@ int cpu_down(unsigned int cpu)
 {
        int err = 0;
 
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        if (cpu_hotplug_disabled)
                err = -EBUSY;
        else
                err = _cpu_down(cpu, 0);
 
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
        return err;
 }
 #endif /*CONFIG_HOTPLUG_CPU*/
@@ -231,7 +299,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
        if (cpu_online(cpu) || !cpu_present(cpu))
                return -EINVAL;
 
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+       cpu_hotplug_begin();
        ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
                                                        -1, &nr_calls);
        if (ret == NOTIFY_BAD) {
@@ -243,9 +311,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
        }
 
        /* Arch-specific enabling code. */
-       mutex_lock(&cpu_bitmask_lock);
        ret = __cpu_up(cpu);
-       mutex_unlock(&cpu_bitmask_lock);
        if (ret != 0)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
@@ -257,7 +323,7 @@ out_notify:
        if (ret != 0)
                __raw_notifier_call_chain(&cpu_chain,
                                CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
-       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
+       cpu_hotplug_done();
 
        return ret;
 }
@@ -275,13 +341,13 @@ int __cpuinit cpu_up(unsigned int cpu)
                return -EINVAL;
        }
 
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        if (cpu_hotplug_disabled)
                err = -EBUSY;
        else
                err = _cpu_up(cpu, 0);
 
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
        return err;
 }
 
@@ -292,7 +358,7 @@ int disable_nonboot_cpus(void)
 {
        int cpu, first_cpu, error = 0;
 
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        first_cpu = first_cpu(cpu_online_map);
        /* We take down all of the non-boot CPUs in one shot to avoid races
         * with the userspace trying to use the CPU hotplug at the same time
@@ -319,7 +385,7 @@ int disable_nonboot_cpus(void)
        } else {
                printk(KERN_ERR "Non-boot CPUs are not disabled\n");
        }
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
        return error;
 }
 
@@ -328,7 +394,7 @@ void enable_nonboot_cpus(void)
        int cpu, error;
 
        /* Allow everyone to use the CPU hotplug again */
-       mutex_lock(&cpu_add_remove_lock);
+       cpu_maps_update_begin();
        cpu_hotplug_disabled = 0;
        if (cpus_empty(frozen_cpus))
                goto out;
@@ -344,6 +410,6 @@ void enable_nonboot_cpus(void)
        }
        cpus_clear(frozen_cpus);
 out:
-       mutex_unlock(&cpu_add_remove_lock);
+       cpu_maps_update_done();
 }
 #endif /* CONFIG_PM_SLEEP_SMP */
index 50f5dc46368841de3497fe96534df12b871e530b..cfaf6419d817e0a387f1c39d878f342e279818b6 100644 (file)
@@ -537,10 +537,10 @@ static int cpusets_overlap(struct cpuset *a, struct cpuset *b)
  *
  * Call with cgroup_mutex held.  May take callback_mutex during
  * call due to the kfifo_alloc() and kmalloc() calls.  May nest
- * a call to the lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
+ * a call to the get_online_cpus()/put_online_cpus() pair.
  * Must not be called holding callback_mutex, because we must not
- * call lock_cpu_hotplug() while holding callback_mutex.  Elsewhere
- * the kernel nests callback_mutex inside lock_cpu_hotplug() calls.
+ * call get_online_cpus() while holding callback_mutex.  Elsewhere
+ * the kernel nests callback_mutex inside get_online_cpus() calls.
  * So the reverse nesting would risk an ABBA deadlock.
  *
  * The three key local variables below are:
@@ -691,9 +691,9 @@ restart:
 
 rebuild:
        /* Have scheduler rebuild sched domains */
-       lock_cpu_hotplug();
+       get_online_cpus();
        partition_sched_domains(ndoms, doms);
-       unlock_cpu_hotplug();
+       put_online_cpus();
 
 done:
        if (q && !IS_ERR(q))
@@ -1617,10 +1617,10 @@ static struct cgroup_subsys_state *cpuset_create(
  *
  * If the cpuset being removed has its flag 'sched_load_balance'
  * enabled, then simulate turning sched_load_balance off, which
- * will call rebuild_sched_domains().  The lock_cpu_hotplug()
+ * will call rebuild_sched_domains().  The get_online_cpus()
  * call in rebuild_sched_domains() must not be made while holding
  * callback_mutex.  Elsewhere the kernel nests callback_mutex inside
- * lock_cpu_hotplug() calls.  So the reverse nesting would risk an
+ * get_online_cpus() calls.  So the reverse nesting would risk an
  * ABBA deadlock.
  */
 
index 8dd8ff2810095d9bab2e511e60dbfe2500ef8b90..39d22b3357dea001d75e37bc70e0ae8190321d2c 100644 (file)
@@ -1045,6 +1045,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        copy_flags(clone_flags, p);
        INIT_LIST_HEAD(&p->children);
        INIT_LIST_HEAD(&p->sibling);
+#ifdef CONFIG_PREEMPT_RCU
+       p->rcu_read_lock_nesting = 0;
+       p->rcu_flipctr_idx = 0;
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
        p->vfork_done = NULL;
        spin_lock_init(&p->alloc_lock);
 
@@ -1059,6 +1063,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->prev_utime = cputime_zero;
        p->prev_stime = cputime_zero;
 
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+       p->last_switch_count = 0;
+       p->last_switch_timestamp = 0;
+#endif
+
 #ifdef CONFIG_TASK_XACCT
        p->rchar = 0;           /* I/O counter: bytes read */
        p->wchar = 0;           /* I/O counter: bytes written */
@@ -1196,6 +1205,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 #ifdef TIF_SYSCALL_EMU
        clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
 #endif
+       clear_all_latency_tracing(p);
 
        /* Our parent execution domain becomes current domain
           These must match for thread signalling to apply */
@@ -1237,6 +1247,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
         * parent's CPU). This avoids alot of nasty races.
         */
        p->cpus_allowed = current->cpus_allowed;
+       p->rt.nr_cpus_allowed = current->rt.nr_cpus_allowed;
        if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed) ||
                        !cpu_online(task_cpu(p))))
                set_task_cpu(p, smp_processor_id());
index 172a1aeeafdb5a148f6a0063bc3bc719b1974096..db9824de8bf061323b734d88377a6fa606fb9a86 100644 (file)
@@ -1097,15 +1097,15 @@ static void unqueue_me_pi(struct futex_q *q)
 }
 
 /*
- * Fixup the pi_state owner with current.
+ * Fixup the pi_state owner with the new owner.
  *
  * Must be called with hash bucket lock held and mm->sem held for non
  * private futexes.
  */
 static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-                               struct task_struct *curr)
+                               struct task_struct *newowner)
 {
-       u32 newtid = task_pid_vnr(curr) | FUTEX_WAITERS;
+       u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
        struct futex_pi_state *pi_state = q->pi_state;
        u32 uval, curval, newval;
        int ret;
@@ -1119,12 +1119,12 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
        } else
                newtid |= FUTEX_OWNER_DIED;
 
-       pi_state->owner = curr;
+       pi_state->owner = newowner;
 
-       spin_lock_irq(&curr->pi_lock);
+       spin_lock_irq(&newowner->pi_lock);
        WARN_ON(!list_empty(&pi_state->list));
-       list_add(&pi_state->list, &curr->pi_state_list);
-       spin_unlock_irq(&curr->pi_lock);
+       list_add(&pi_state->list, &newowner->pi_state_list);
+       spin_unlock_irq(&newowner->pi_lock);
 
        /*
         * We own it, so we have to replace the pending owner
@@ -1508,9 +1508,40 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
                 * when we were on the way back before we locked the
                 * hash bucket.
                 */
-               if (q.pi_state->owner == curr &&
-                   rt_mutex_trylock(&q.pi_state->pi_mutex)) {
-                       ret = 0;
+               if (q.pi_state->owner == curr) {
+                       /*
+                        * Try to get the rt_mutex now. This might
+                        * fail as some other task acquired the
+                        * rt_mutex after we removed ourself from the
+                        * rt_mutex waiters list.
+                        */
+                       if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+                               ret = 0;
+                       else {
+                               /*
+                                * pi_state is incorrect, some other
+                                * task did a lock steal and we
+                                * returned due to timeout or signal
+                                * without taking the rt_mutex. Too
+                                * late. We can access the
+                                * rt_mutex_owner without locking, as
+                                * the other task is now blocked on
+                                * the hash bucket lock. Fix the state
+                                * up.
+                                */
+                               struct task_struct *owner;
+                               int res;
+
+                               owner = rt_mutex_owner(&q.pi_state->pi_mutex);
+                               res = fixup_pi_state_owner(uaddr, &q, owner);
+
+                               WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
+                                       owner);
+
+                               /* propagate -EFAULT, if the fixup failed */
+                               if (res)
+                                       ret = res;
+                       }
                } else {
                        /*
                         * Paranoia check. If we did not take the lock
index e65dd0b47cdc13a31abc762315152cb49edea8d8..bd5d6b5060bcd5704c278ea38954862fb463889f 100644 (file)
@@ -325,6 +325,22 @@ unsigned long ktime_divns(const ktime_t kt, s64 div)
 }
 #endif /* BITS_PER_LONG >= 64 */
 
+/*
+ * Check, whether the timer is on the callback pending list
+ */
+static inline int hrtimer_cb_pending(const struct hrtimer *timer)
+{
+       return timer->state & HRTIMER_STATE_PENDING;
+}
+
+/*
+ * Remove a timer from the callback pending list
+ */
+static inline void hrtimer_remove_cb_pending(struct hrtimer *timer)
+{
+       list_del_init(&timer->cb_entry);
+}
+
 /* High resolution timer related functions */
 #ifdef CONFIG_HIGH_RES_TIMERS
 
@@ -493,22 +509,6 @@ void hres_timers_resume(void)
        retrigger_next_event(NULL);
 }
 
-/*
- * Check, whether the timer is on the callback pending list
- */
-static inline int hrtimer_cb_pending(const struct hrtimer *timer)
-{
-       return timer->state & HRTIMER_STATE_PENDING;
-}
-
-/*
- * Remove a timer from the callback pending list
- */
-static inline void hrtimer_remove_cb_pending(struct hrtimer *timer)
-{
-       list_del_init(&timer->cb_entry);
-}
-
 /*
  * Initialize the high resolution related parts of cpu_base
  */
@@ -516,7 +516,6 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
 {
        base->expires_next.tv64 = KTIME_MAX;
        base->hres_active = 0;
-       INIT_LIST_HEAD(&base->cb_pending);
 }
 
 /*
@@ -524,7 +523,6 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
  */
 static inline void hrtimer_init_timer_hres(struct hrtimer *timer)
 {
-       INIT_LIST_HEAD(&timer->cb_entry);
 }
 
 /*
@@ -618,10 +616,13 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
 {
        return 0;
 }
-static inline int hrtimer_cb_pending(struct hrtimer *timer) { return 0; }
-static inline void hrtimer_remove_cb_pending(struct hrtimer *timer) { }
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { }
 static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { }
+static inline int hrtimer_reprogram(struct hrtimer *timer,
+                                   struct hrtimer_clock_base *base)
+{
+       return 0;
+}
 
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
@@ -1001,6 +1002,7 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
                clock_id = CLOCK_MONOTONIC;
 
        timer->base = &cpu_base->clock_base[clock_id];
+       INIT_LIST_HEAD(&timer->cb_entry);
        hrtimer_init_timer_hres(timer);
 
 #ifdef CONFIG_TIMER_STATS
@@ -1030,6 +1032,85 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
 }
 EXPORT_SYMBOL_GPL(hrtimer_get_res);
 
+static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
+{
+       spin_lock_irq(&cpu_base->lock);
+
+       while (!list_empty(&cpu_base->cb_pending)) {
+               enum hrtimer_restart (*fn)(struct hrtimer *);
+               struct hrtimer *timer;
+               int restart;
+
+               timer = list_entry(cpu_base->cb_pending.next,
+                                  struct hrtimer, cb_entry);
+
+               timer_stats_account_hrtimer(timer);
+
+               fn = timer->function;
+               __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0);
+               spin_unlock_irq(&cpu_base->lock);
+
+               restart = fn(timer);
+
+               spin_lock_irq(&cpu_base->lock);
+
+               timer->state &= ~HRTIMER_STATE_CALLBACK;
+               if (restart == HRTIMER_RESTART) {
+                       BUG_ON(hrtimer_active(timer));
+                       /*
+                        * Enqueue the timer, allow reprogramming of the event
+                        * device
+                        */
+                       enqueue_hrtimer(timer, timer->base, 1);
+               } else if (hrtimer_active(timer)) {
+                       /*
+                        * If the timer was rearmed on another CPU, reprogram
+                        * the event device.
+                        */
+                       if (timer->base->first == &timer->node)
+                               hrtimer_reprogram(timer, timer->base);
+               }
+       }
+       spin_unlock_irq(&cpu_base->lock);
+}
+
+static void __run_hrtimer(struct hrtimer *timer)
+{
+       struct hrtimer_clock_base *base = timer->base;
+       struct hrtimer_cpu_base *cpu_base = base->cpu_base;
+       enum hrtimer_restart (*fn)(struct hrtimer *);
+       int restart;
+
+       __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
+       timer_stats_account_hrtimer(timer);
+
+       fn = timer->function;
+       if (timer->cb_mode == HRTIMER_CB_IRQSAFE_NO_SOFTIRQ) {
+               /*
+                * Used for scheduler timers, avoid lock inversion with
+                * rq->lock and tasklist_lock.
+                *
+                * These timers are required to deal with enqueue expiry
+                * themselves and are not allowed to migrate.
+                */
+               spin_unlock(&cpu_base->lock);
+               restart = fn(timer);
+               spin_lock(&cpu_base->lock);
+       } else
+               restart = fn(timer);
+
+       /*
+        * Note: We clear the CALLBACK bit after enqueue_hrtimer to avoid
+        * reprogramming of the event hardware. This happens at the end of this
+        * function anyway.
+        */
+       if (restart != HRTIMER_NORESTART) {
+               BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
+               enqueue_hrtimer(timer, base, 0);
+       }
+       timer->state &= ~HRTIMER_STATE_CALLBACK;
+}
+
 #ifdef CONFIG_HIGH_RES_TIMERS
 
 /*
@@ -1087,21 +1168,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
                                continue;
                        }
 
-                       __remove_hrtimer(timer, base,
-                                        HRTIMER_STATE_CALLBACK, 0);
-                       timer_stats_account_hrtimer(timer);
-
-                       /*
-                        * Note: We clear the CALLBACK bit after
-                        * enqueue_hrtimer to avoid reprogramming of
-                        * the event hardware. This happens at the end
-                        * of this function anyway.
-                        */
-                       if (timer->function(timer) != HRTIMER_NORESTART) {
-                               BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
-                               enqueue_hrtimer(timer, base, 0);
-                       }
-                       timer->state &= ~HRTIMER_STATE_CALLBACK;
+                       __run_hrtimer(timer);
                }
                spin_unlock(&cpu_base->lock);
                base++;
@@ -1122,52 +1189,41 @@ void hrtimer_interrupt(struct clock_event_device *dev)
 
 static void run_hrtimer_softirq(struct softirq_action *h)
 {
-       struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
-
-       spin_lock_irq(&cpu_base->lock);
-
-       while (!list_empty(&cpu_base->cb_pending)) {
-               enum hrtimer_restart (*fn)(struct hrtimer *);
-               struct hrtimer *timer;
-               int restart;
-
-               timer = list_entry(cpu_base->cb_pending.next,
-                                  struct hrtimer, cb_entry);
+       run_hrtimer_pending(&__get_cpu_var(hrtimer_bases));
+}
 
-               timer_stats_account_hrtimer(timer);
+#endif /* CONFIG_HIGH_RES_TIMERS */
 
-               fn = timer->function;
-               __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0);
-               spin_unlock_irq(&cpu_base->lock);
+/*
+ * Called from timer softirq every jiffy, expire hrtimers:
+ *
+ * For HRT its the fall back code to run the softirq in the timer
+ * softirq context in case the hrtimer initialization failed or has
+ * not been done yet.
+ */
+void hrtimer_run_pending(void)
+{
+       struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
 
-               restart = fn(timer);
+       if (hrtimer_hres_active())
+               return;
 
-               spin_lock_irq(&cpu_base->lock);
+       /*
+        * This _is_ ugly: We have to check in the softirq context,
+        * whether we can switch to highres and / or nohz mode. The
+        * clocksource switch happens in the timer interrupt with
+        * xtime_lock held. Notification from there only sets the
+        * check bit in the tick_oneshot code, otherwise we might
+        * deadlock vs. xtime_lock.
+        */
+       if (tick_check_oneshot_change(!hrtimer_is_hres_enabled()))
+               hrtimer_switch_to_hres();
 
-               timer->state &= ~HRTIMER_STATE_CALLBACK;
-               if (restart == HRTIMER_RESTART) {
-                       BUG_ON(hrtimer_active(timer));
-                       /*
-                        * Enqueue the timer, allow reprogramming of the event
-                        * device
-                        */
-                       enqueue_hrtimer(timer, timer->base, 1);
-               } else if (hrtimer_active(timer)) {
-                       /*
-                        * If the timer was rearmed on another CPU, reprogram
-                        * the event device.
-                        */
-                       if (timer->base->first == &timer->node)
-                               hrtimer_reprogram(timer, timer->base);
-               }
-       }
-       spin_unlock_irq(&cpu_base->lock);
+       run_hrtimer_pending(cpu_base);
 }
 
-#endif /* CONFIG_HIGH_RES_TIMERS */
-
 /*
- * Expire the per base hrtimer-queue:
+ * Called from hardirq context every jiffy
  */
 static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base,
                                     int index)
@@ -1181,46 +1237,27 @@ static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base,
        if (base->get_softirq_time)
                base->softirq_time = base->get_softirq_time();
 
-       spin_lock_irq(&cpu_base->lock);
+       spin_lock(&cpu_base->lock);
 
        while ((node = base->first)) {
                struct hrtimer *timer;
-               enum hrtimer_restart (*fn)(struct hrtimer *);
-               int restart;
 
                timer = rb_entry(node, struct hrtimer, node);
                if (base->softirq_time.tv64 <= timer->expires.tv64)
                        break;
 
-#ifdef CONFIG_HIGH_RES_TIMERS
-               WARN_ON_ONCE(timer->cb_mode == HRTIMER_CB_IRQSAFE_NO_SOFTIRQ);
-#endif
-               timer_stats_account_hrtimer(timer);
-
-               fn = timer->function;
-               __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
-               spin_unlock_irq(&cpu_base->lock);
-
-               restart = fn(timer);
-
-               spin_lock_irq(&cpu_base->lock);
-
-               timer->state &= ~HRTIMER_STATE_CALLBACK;
-               if (restart != HRTIMER_NORESTART) {
-                       BUG_ON(hrtimer_active(timer));
-                       enqueue_hrtimer(timer, base, 0);
+               if (timer->cb_mode == HRTIMER_CB_SOFTIRQ) {
+                       __remove_hrtimer(timer, base, HRTIMER_STATE_PENDING, 0);
+                       list_add_tail(&timer->cb_entry,
+                                       &base->cpu_base->cb_pending);
+                       continue;
                }
+
+               __run_hrtimer(timer);
        }
-       spin_unlock_irq(&cpu_base->lock);
+       spin_unlock(&cpu_base->lock);
 }
 
-/*
- * Called from timer softirq every jiffy, expire hrtimers:
- *
- * For HRT its the fall back code to run the softirq in the timer
- * softirq context in case the hrtimer initialization failed or has
- * not been done yet.
- */
 void hrtimer_run_queues(void)
 {
        struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
@@ -1229,18 +1266,6 @@ void hrtimer_run_queues(void)
        if (hrtimer_hres_active())
                return;
 
-       /*
-        * This _is_ ugly: We have to check in the softirq context,
-        * whether we can switch to highres and / or nohz mode. The
-        * clocksource switch happens in the timer interrupt with
-        * xtime_lock held. Notification from there only sets the
-        * check bit in the tick_oneshot code, otherwise we might
-        * deadlock vs. xtime_lock.
-        */
-       if (tick_check_oneshot_change(!hrtimer_is_hres_enabled()))
-               if (hrtimer_switch_to_hres())
-                       return;
-
        hrtimer_get_softirq_time(cpu_base);
 
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++)
@@ -1268,7 +1293,7 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
        sl->timer.function = hrtimer_wakeup;
        sl->task = task;
 #ifdef CONFIG_HIGH_RES_TIMERS
-       sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART;
+       sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
 #endif
 }
 
@@ -1279,6 +1304,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
        do {
                set_current_state(TASK_INTERRUPTIBLE);
                hrtimer_start(&t->timer, t->timer.expires, mode);
+               if (!hrtimer_active(&t->timer))
+                       t->task = NULL;
 
                if (likely(t->task))
                        schedule();
@@ -1378,7 +1405,7 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
 /*
  * Functions related to boot-time initialization:
  */
-static void __devinit init_hrtimers_cpu(int cpu)
+static void __cpuinit init_hrtimers_cpu(int cpu)
 {
        struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
        int i;
@@ -1389,6 +1416,7 @@ static void __devinit init_hrtimers_cpu(int cpu)
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++)
                cpu_base->clock_base[i].cpu_base = cpu_base;
 
+       INIT_LIST_HEAD(&cpu_base->cb_pending);
        hrtimer_init_hres(cpu_base);
 }
 
index aa74a1ef2da8003768519e4283d2b392be0a4171..9a26eec9eb04b858cfb7d3244071b94f4d4872c9 100644 (file)
@@ -1404,6 +1404,7 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_OFFSET(list_head, next);
        VMCOREINFO_OFFSET(list_head, prev);
        VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
+       VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
        VMCOREINFO_NUMBER(NR_FREE_PAGES);
 
        arch_crash_save_vmcoreinfo();
index c6a4f8aebeba5c8a74a6bfc063e4ad08c3f14792..bb7df2a28bd719d07978593cb10f7264b6f43f3b 100644 (file)
@@ -451,13 +451,11 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
                             enum umh_wait wait)
 {
        DECLARE_COMPLETION_ONSTACK(done);
-       int retval;
+       int retval = 0;
 
        helper_lock();
-       if (sub_info->path[0] == '\0') {
-               retval = 0;
+       if (sub_info->path[0] == '\0')
                goto out;
-       }
 
        if (!khelper_wq || usermodehelper_disabled) {
                retval = -EBUSY;
@@ -468,13 +466,14 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
        sub_info->wait = wait;
 
        queue_work(khelper_wq, &sub_info->work);
-       if (wait == UMH_NO_WAIT) /* task has freed sub_info */
-               return 0;
+       if (wait == UMH_NO_WAIT)        /* task has freed sub_info */
+               goto unlock;
        wait_for_completion(&done);
        retval = sub_info->retval;
 
-  out:
+out:
        call_usermodehelper_freeinfo(sub_info);
+unlock:
        helper_unlock();
        return retval;
 }
index 65daa5373ca6354afc0c575c1938ed1e9a08c300..e53bc30e9ba5aa8b55311fd6700191b0f21a9597 100644 (file)
 #include <linux/sched.h>
 
 #define KERNEL_ATTR_RO(_name) \
-static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
+static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
 
 #define KERNEL_ATTR_RW(_name) \
-static struct subsys_attribute _name##_attr = \
+static struct kobj_attribute _name##_attr = \
        __ATTR(_name, 0644, _name##_show, _name##_store)
 
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
 /* current uevent sequence number */
-static ssize_t uevent_seqnum_show(struct kset *kset, char *page)
+static ssize_t uevent_seqnum_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(page, "%llu\n", (unsigned long long)uevent_seqnum);
+       return sprintf(buf, "%llu\n", (unsigned long long)uevent_seqnum);
 }
 KERNEL_ATTR_RO(uevent_seqnum);
 
 /* uevent helper program, used during early boo */
-static ssize_t uevent_helper_show(struct kset *kset, char *page)
+static ssize_t uevent_helper_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(page, "%s\n", uevent_helper);
+       return sprintf(buf, "%s\n", uevent_helper);
 }
-static ssize_t uevent_helper_store(struct kset *kset, const char *page, size_t count)
+static ssize_t uevent_helper_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t count)
 {
        if (count+1 > UEVENT_HELPER_PATH_LEN)
                return -ENOENT;
-       memcpy(uevent_helper, page, count);
+       memcpy(uevent_helper, buf, count);
        uevent_helper[count] = '\0';
        if (count && uevent_helper[count-1] == '\n')
                uevent_helper[count-1] = '\0';
@@ -50,21 +54,24 @@ KERNEL_ATTR_RW(uevent_helper);
 #endif
 
 #ifdef CONFIG_KEXEC
-static ssize_t kexec_loaded_show(struct kset *kset, char *page)
+static ssize_t kexec_loaded_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(page, "%d\n", !!kexec_image);
+       return sprintf(buf, "%d\n", !!kexec_image);
 }
 KERNEL_ATTR_RO(kexec_loaded);
 
-static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page)
+static ssize_t kexec_crash_loaded_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(page, "%d\n", !!kexec_crash_image);
+       return sprintf(buf, "%d\n", !!kexec_crash_image);
 }
 KERNEL_ATTR_RO(kexec_crash_loaded);
 
-static ssize_t vmcoreinfo_show(struct kset *kset, char *page)
+static ssize_t vmcoreinfo_show(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(page, "%lx %x\n",
+       return sprintf(buf, "%lx %x\n",
                       paddr_vmcoreinfo_note(),
                       (unsigned int)vmcoreinfo_max_size);
 }
@@ -94,8 +101,8 @@ static struct bin_attribute notes_attr = {
        .read = &notes_read,
 };
 
-decl_subsys(kernel, NULL, NULL);
-EXPORT_SYMBOL_GPL(kernel_subsys);
+struct kobject *kernel_kobj;
+EXPORT_SYMBOL_GPL(kernel_kobj);
 
 static struct attribute * kernel_attrs[] = {
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
@@ -116,24 +123,39 @@ static struct attribute_group kernel_attr_group = {
 
 static int __init ksysfs_init(void)
 {
-       int error = subsystem_register(&kernel_subsys);
-       if (!error)
-               error = sysfs_create_group(&kernel_subsys.kobj,
-                                          &kernel_attr_group);
+       int error;
 
-       if (!error && notes_size > 0) {
-               notes_attr.size = notes_size;
-               error = sysfs_create_bin_file(&kernel_subsys.kobj,
-                                             &notes_attr);
+       kernel_kobj = kobject_create_and_add("kernel", NULL);
+       if (!kernel_kobj) {
+               error = -ENOMEM;
+               goto exit;
        }
+       error = sysfs_create_group(kernel_kobj, &kernel_attr_group);
+       if (error)
+               goto kset_exit;
 
-       /*
-        * Create "/sys/kernel/uids" directory and corresponding root user's
-        * directory under it.
-        */
-       if (!error)
-               error = uids_kobject_init();
+       if (notes_size > 0) {
+               notes_attr.size = notes_size;
+               error = sysfs_create_bin_file(kernel_kobj, &notes_attr);
+               if (error)
+                       goto group_exit;
+       }
 
+       /* create the /sys/kernel/uids/ directory */
+       error = uids_sysfs_init();
+       if (error)
+               goto notes_exit;
+
+       return 0;
+
+notes_exit:
+       if (notes_size > 0)
+               sysfs_remove_bin_file(kernel_kobj, &notes_attr);
+group_exit:
+       sysfs_remove_group(kernel_kobj, &kernel_attr_group);
+kset_exit:
+       kobject_put(kernel_kobj);
+exit:
        return error;
 }
 
index dcfe724300eb3cd32c46c2d06de4fc92c7de070b..0ac887882f908502425deeebcda4c678812443cb 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/mutex.h>
 #include <asm/semaphore.h>
 
+#define KTHREAD_NICE_LEVEL (-5)
+
 static DEFINE_SPINLOCK(kthread_create_lock);
 static LIST_HEAD(kthread_create_list);
 struct task_struct *kthreadd_task;
@@ -94,10 +96,18 @@ static void create_kthread(struct kthread_create_info *create)
        if (pid < 0) {
                create->result = ERR_PTR(pid);
        } else {
+               struct sched_param param = { .sched_priority = 0 };
                wait_for_completion(&create->started);
                read_lock(&tasklist_lock);
                create->result = find_task_by_pid(pid);
                read_unlock(&tasklist_lock);
+               /*
+                * root may have changed our (kthreadd's) priority or CPU mask.
+                * The kernel thread should not inherit these properties.
+                */
+               sched_setscheduler(create->result, SCHED_NORMAL, &param);
+               set_user_nice(create->result, KTHREAD_NICE_LEVEL);
+               set_cpus_allowed(create->result, CPU_MASK_ALL);
        }
        complete(&create->done);
 }
@@ -221,7 +231,7 @@ int kthreadd(void *unused)
        /* Setup a clean context for our children to inherit. */
        set_task_comm(tsk, "kthreadd");
        ignore_signals(tsk);
-       set_user_nice(tsk, -5);
+       set_user_nice(tsk, KTHREAD_NICE_LEVEL);
        set_cpus_allowed(tsk, CPU_MASK_ALL);
 
        current->flags |= PF_NOFREEZE;
diff --git a/kernel/latencytop.c b/kernel/latencytop.c
new file mode 100644 (file)
index 0000000..b4e3c85
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * latencytop.c: Latency display infrastructure
+ *
+ * (C) Copyright 2008 Intel Corporation
+ * Author: Arjan van de Ven <arjan@linux.intel.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; version 2
+ * of the License.
+ */
+#include <linux/latencytop.h>
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+
+static DEFINE_SPINLOCK(latency_lock);
+
+#define MAXLR 128
+static struct latency_record latency_record[MAXLR];
+
+int latencytop_enabled;
+
+void clear_all_latency_tracing(struct task_struct *p)
+{
+       unsigned long flags;
+
+       if (!latencytop_enabled)
+               return;
+
+       spin_lock_irqsave(&latency_lock, flags);
+       memset(&p->latency_record, 0, sizeof(p->latency_record));
+       p->latency_record_count = 0;
+       spin_unlock_irqrestore(&latency_lock, flags);
+}
+
+static void clear_global_latency_tracing(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&latency_lock, flags);
+       memset(&latency_record, 0, sizeof(latency_record));
+       spin_unlock_irqrestore(&latency_lock, flags);
+}
+
+static void __sched
+account_global_scheduler_latency(struct task_struct *tsk, struct latency_record *lat)
+{
+       int firstnonnull = MAXLR + 1;
+       int i;
+
+       if (!latencytop_enabled)
+               return;
+
+       /* skip kernel threads for now */
+       if (!tsk->mm)
+               return;
+
+       for (i = 0; i < MAXLR; i++) {
+               int q;
+               int same = 1;
+               /* Nothing stored: */
+               if (!latency_record[i].backtrace[0]) {
+                       if (firstnonnull > i)
+                               firstnonnull = i;
+                       continue;
+               }
+               for (q = 0 ; q < LT_BACKTRACEDEPTH ; q++) {
+                       if (latency_record[i].backtrace[q] !=
+                               lat->backtrace[q])
+                               same = 0;
+                       if (same && lat->backtrace[q] == 0)
+                               break;
+                       if (same && lat->backtrace[q] == ULONG_MAX)
+                               break;
+               }
+               if (same) {
+                       latency_record[i].count++;
+                       latency_record[i].time += lat->time;
+                       if (lat->time > latency_record[i].max)
+                               latency_record[i].max = lat->time;
+                       return;
+               }
+       }
+
+       i = firstnonnull;
+       if (i >= MAXLR - 1)
+               return;
+
+       /* Allocted a new one: */
+       memcpy(&latency_record[i], lat, sizeof(struct latency_record));
+}
+
+static inline void store_stacktrace(struct task_struct *tsk, struct latency_record *lat)
+{
+       struct stack_trace trace;
+
+       memset(&trace, 0, sizeof(trace));
+       trace.max_entries = LT_BACKTRACEDEPTH;
+       trace.entries = &lat->backtrace[0];
+       trace.skip = 0;
+       save_stack_trace_tsk(tsk, &trace);
+}
+
+void __sched
+account_scheduler_latency(struct task_struct *tsk, int usecs, int inter)
+{
+       unsigned long flags;
+       int i, q;
+       struct latency_record lat;
+
+       if (!latencytop_enabled)
+               return;
+
+       /* Long interruptible waits are generally user requested... */
+       if (inter && usecs > 5000)
+               return;
+
+       memset(&lat, 0, sizeof(lat));
+       lat.count = 1;
+       lat.time = usecs;
+       lat.max = usecs;
+       store_stacktrace(tsk, &lat);
+
+       spin_lock_irqsave(&latency_lock, flags);
+
+       account_global_scheduler_latency(tsk, &lat);
+
+       /*
+        * short term hack; if we're > 32 we stop; future we recycle:
+        */
+       tsk->latency_record_count++;
+       if (tsk->latency_record_count >= LT_SAVECOUNT)
+               goto out_unlock;
+
+       for (i = 0; i < LT_SAVECOUNT ; i++) {
+               struct latency_record *mylat;
+               int same = 1;
+               mylat = &tsk->latency_record[i];
+               for (q = 0 ; q < LT_BACKTRACEDEPTH ; q++) {
+                       if (mylat->backtrace[q] !=
+                               lat.backtrace[q])
+                               same = 0;
+                       if (same && lat.backtrace[q] == 0)
+                               break;
+                       if (same && lat.backtrace[q] == ULONG_MAX)
+                               break;
+               }
+               if (same) {
+                       mylat->count++;
+                       mylat->time += lat.time;
+                       if (lat.time > mylat->max)
+                               mylat->max = lat.time;
+                       goto out_unlock;
+               }
+       }
+
+       /* Allocated a new one: */
+       i = tsk->latency_record_count;
+       memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record));
+
+out_unlock:
+       spin_unlock_irqrestore(&latency_lock, flags);
+}
+
+static int lstats_show(struct seq_file *m, void *v)
+{
+       int i;
+
+       seq_puts(m, "Latency Top version : v0.1\n");
+
+       for (i = 0; i < MAXLR; i++) {
+               if (latency_record[i].backtrace[0]) {
+                       int q;
+                       seq_printf(m, "%i %li %li ",
+                               latency_record[i].count,
+                               latency_record[i].time,
+                               latency_record[i].max);
+                       for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
+                               char sym[KSYM_NAME_LEN];
+                               char *c;
+                               if (!latency_record[i].backtrace[q])
+                                       break;
+                               if (latency_record[i].backtrace[q] == ULONG_MAX)
+                                       break;
+                               sprint_symbol(sym, latency_record[i].backtrace[q]);
+                               c = strchr(sym, '+');
+                               if (c)
+                                       *c = 0;
+                               seq_printf(m, "%s ", sym);
+                       }
+                       seq_printf(m, "\n");
+               }
+       }
+       return 0;
+}
+
+static ssize_t
+lstats_write(struct file *file, const char __user *buf, size_t count,
+            loff_t *offs)
+{
+       clear_global_latency_tracing();
+
+       return count;
+}
+
+static int lstats_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, lstats_show, NULL);
+}
+
+static struct file_operations lstats_fops = {
+       .open           = lstats_open,
+       .read           = seq_read,
+       .write          = lstats_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init init_lstats_procfs(void)
+{
+       struct proc_dir_entry *pe;
+
+       pe = create_proc_entry("latency_stats", 0644, NULL);
+       if (!pe)
+               return -ENOMEM;
+
+       pe->proc_fops = &lstats_fops;
+
+       return 0;
+}
+__initcall(init_lstats_procfs);
index 723bd9f9255687f7820b0e151ae23a3d5ca81e7b..3574379f4d62d2d04c9431c0c2172dc044d0ca66 100644 (file)
@@ -2932,7 +2932,7 @@ static void zap_class(struct lock_class *class)
 
 }
 
-static inline int within(void *addr, void *start, unsigned long size)
+static inline int within(const void *addr, void *start, unsigned long size)
 {
        return addr >= start && addr < start + size;
 }
@@ -2943,9 +2943,10 @@ void lockdep_free_key_range(void *start, unsigned long size)
        struct list_head *head;
        unsigned long flags;
        int i;
+       int locked;
 
        raw_local_irq_save(flags);
-       graph_lock();
+       locked = graph_lock();
 
        /*
         * Unhash all classes that were created by this module:
@@ -2954,12 +2955,16 @@ void lockdep_free_key_range(void *start, unsigned long size)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry)
+               list_for_each_entry_safe(class, next, head, hash_entry) {
                        if (within(class->key, start, size))
                                zap_class(class);
+                       else if (within(class->name, start, size))
+                               zap_class(class);
+               }
        }
 
-       graph_unlock();
+       if (locked)
+               graph_unlock();
        raw_local_irq_restore(flags);
 }
 
@@ -2969,6 +2974,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
        struct list_head *head;
        unsigned long flags;
        int i, j;
+       int locked;
 
        raw_local_irq_save(flags);
 
@@ -2987,7 +2993,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
         * Debug check: in the end all mapped classes should
         * be gone.
         */
-       graph_lock();
+       locked = graph_lock();
        for (i = 0; i < CLASSHASH_SIZE; i++) {
                head = classhash_table + i;
                if (list_empty(head))
@@ -3000,7 +3006,8 @@ void lockdep_reset_lock(struct lockdep_map *lock)
                        }
                }
        }
-       graph_unlock();
+       if (locked)
+               graph_unlock();
 
 out_restore:
        raw_local_irq_restore(flags);
@@ -3199,7 +3206,11 @@ retry:
 
 EXPORT_SYMBOL_GPL(debug_show_all_locks);
 
-void debug_show_held_locks(struct task_struct *task)
+/*
+ * Careful: only use this function if you are sure that
+ * the task cannot run in parallel!
+ */
+void __debug_show_held_locks(struct task_struct *task)
 {
        if (unlikely(!debug_locks)) {
                printk("INFO: lockdep is turned off.\n");
@@ -3207,6 +3218,12 @@ void debug_show_held_locks(struct task_struct *task)
        }
        lockdep_print_held_locks(task);
 }
+EXPORT_SYMBOL_GPL(__debug_show_held_locks);
+
+void debug_show_held_locks(struct task_struct *task)
+{
+               __debug_show_held_locks(task);
+}
 
 EXPORT_SYMBOL_GPL(debug_show_held_locks);
 
index 91fe6958b6e1b253f98c2ab08518693df00a1497..1bb4c5e0d56e330b1de92b5e20fddbd446e9d314 100644 (file)
@@ -47,8 +47,6 @@
 #include <asm/cacheflush.h>
 #include <linux/license.h>
 
-extern int module_sysfs_initialized;
-
 #if 0
 #define DEBUGP printk
 #else
@@ -498,6 +496,8 @@ static struct module_attribute modinfo_##field = {                    \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
+static char last_unloaded_module[MODULE_NAME_LEN+1];
+
 #ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
@@ -721,6 +721,8 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
                mod->exit();
                mutex_lock(&module_mutex);
        }
+       /* Store the name of the last unloaded module for diagnostic purposes */
+       sprintf(last_unloaded_module, mod->name);
        free_module(mod);
 
  out:
@@ -1122,7 +1124,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
                ++loaded;
        }
 
-       notes_attrs->dir = kobject_add_dir(&mod->mkobj.kobj, "notes");
+       notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
        if (!notes_attrs->dir)
                goto out;
 
@@ -1219,15 +1221,16 @@ int mod_sysfs_init(struct module *mod)
                err = -EINVAL;
                goto out;
        }
-       memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
-       err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name);
-       if (err)
-               goto out;
-       kobj_set_kset_s(&mod->mkobj, module_subsys);
        mod->mkobj.mod = mod;
 
-       kobject_init(&mod->mkobj.kobj);
+       memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
+       mod->mkobj.kobj.kset = module_kset;
+       err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
+                                  "%s", mod->name);
+       if (err)
+               kobject_put(&mod->mkobj.kobj);
 
+       /* delay uevent until full sysfs population */
 out:
        return err;
 }
@@ -1238,12 +1241,7 @@ int mod_sysfs_setup(struct module *mod,
 {
        int err;
 
-       /* delay uevent until full sysfs population */
-       err = kobject_add(&mod->mkobj.kobj);
-       if (err)
-               goto out;
-
-       mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
+       mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
        if (!mod->holders_dir) {
                err = -ENOMEM;
                goto out_unreg;
@@ -1263,11 +1261,9 @@ int mod_sysfs_setup(struct module *mod,
 out_unreg_param:
        module_param_sysfs_remove(mod);
 out_unreg_holders:
-       kobject_unregister(mod->holders_dir);
+       kobject_put(mod->holders_dir);
 out_unreg:
-       kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
-out:
        return err;
 }
 #endif
@@ -1276,9 +1272,9 @@ static void mod_kobject_remove(struct module *mod)
 {
        module_remove_modinfo_attrs(mod);
        module_param_sysfs_remove(mod);
-       kobject_unregister(mod->mkobj.drivers_dir);
-       kobject_unregister(mod->holders_dir);
-       kobject_unregister(&mod->mkobj.kobj);
+       kobject_put(mod->mkobj.drivers_dir);
+       kobject_put(mod->holders_dir);
+       kobject_put(&mod->mkobj.kobj);
 }
 
 /*
@@ -1884,10 +1880,10 @@ static struct module *load_module(void __user *umod,
        /* Now we've moved module, initialize linked lists, etc. */
        module_unload_init(mod);
 
-       /* Initialize kobject, so we can reference it. */
+       /* add kobject, so we can reference it. */
        err = mod_sysfs_init(mod);
        if (err)
-               goto cleanup;
+               goto free_unload;
 
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
@@ -2057,6 +2053,9 @@ static struct module *load_module(void __user *umod,
  arch_cleanup:
        module_arch_cleanup(mod);
  cleanup:
+       kobject_del(&mod->mkobj.kobj);
+       kobject_put(&mod->mkobj.kobj);
+ free_unload:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
  free_core:
@@ -2214,29 +2213,34 @@ static const char *get_ksymbol(struct module *mod,
 /* For kallsyms to ask for address resolution.  NULL means not found.
    We don't lock, as this is used for oops resolution and races are a
    lesser concern. */
+/* FIXME: Risky: returns a pointer into a module w/o lock */
 const char *module_address_lookup(unsigned long addr,
                                  unsigned long *size,
                                  unsigned long *offset,
                                  char **modname)
 {
        struct module *mod;
+       const char *ret = NULL;
 
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size)
                    || within(addr, mod->module_core, mod->core_size)) {
                        if (modname)
                                *modname = mod->name;
-                       return get_ksymbol(mod, addr, size, offset);
+                       ret = get_ksymbol(mod, addr, size, offset);
+                       break;
                }
        }
-       return NULL;
+       preempt_enable();
+       return ret;
 }
 
 int lookup_module_symbol_name(unsigned long addr, char *symname)
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size) ||
                    within(addr, mod->module_core, mod->core_size)) {
@@ -2246,12 +2250,12 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
                        if (!sym)
                                goto out;
                        strlcpy(symname, sym, KSYM_NAME_LEN);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
        }
 out:
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2260,7 +2264,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size) ||
                    within(addr, mod->module_core, mod->core_size)) {
@@ -2273,12 +2277,12 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
                                strlcpy(modname, mod->name, MODULE_NAME_LEN);
                        if (name)
                                strlcpy(name, sym, KSYM_NAME_LEN);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
        }
 out:
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2287,7 +2291,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
@@ -2296,12 +2300,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                                KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, mod);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
                symnum -= mod->num_symtab;
        }
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2324,6 +2328,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        unsigned long ret = 0;
 
        /* Don't lock: we're in enough trouble already. */
+       preempt_disable();
        if ((colon = strchr(name, ':')) != NULL) {
                *colon = '\0';
                if ((mod = find_module(name)) != NULL)
@@ -2334,6 +2339,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
                        if ((ret = mod_find_symname(mod, name)) != 0)
                                break;
        }
+       preempt_enable();
        return ret;
 }
 #endif /* CONFIG_KALLSYMS */
@@ -2355,21 +2361,30 @@ static void m_stop(struct seq_file *m, void *p)
        mutex_unlock(&module_mutex);
 }
 
-static char *taint_flags(unsigned int taints, char *buf)
+static char *module_flags(struct module *mod, char *buf)
 {
        int bx = 0;
 
-       if (taints) {
+       if (mod->taints ||
+           mod->state == MODULE_STATE_GOING ||
+           mod->state == MODULE_STATE_COMING) {
                buf[bx++] = '(';
-               if (taints & TAINT_PROPRIETARY_MODULE)
+               if (mod->taints & TAINT_PROPRIETARY_MODULE)
                        buf[bx++] = 'P';
-               if (taints & TAINT_FORCED_MODULE)
+               if (mod->taints & TAINT_FORCED_MODULE)
                        buf[bx++] = 'F';
                /*
                 * TAINT_FORCED_RMMOD: could be added.
                 * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
                 * apply to modules.
                 */
+
+               /* Show a - for module-is-being-unloaded */
+               if (mod->state == MODULE_STATE_GOING)
+                       buf[bx++] = '-';
+               /* Show a + for module-is-being-loaded */
+               if (mod->state == MODULE_STATE_COMING)
+                       buf[bx++] = '+';
                buf[bx++] = ')';
        }
        buf[bx] = '\0';
@@ -2396,7 +2411,7 @@ static int m_show(struct seq_file *m, void *p)
 
        /* Taints info */
        if (mod->taints)
-               seq_printf(m, " %s", taint_flags(mod->taints, buf));
+               seq_printf(m, " %s", module_flags(mod, buf));
 
        seq_printf(m, "\n");
        return 0;
@@ -2491,97 +2506,12 @@ void print_modules(void)
 
        printk("Modules linked in:");
        list_for_each_entry(mod, &modules, list)
-               printk(" %s%s", mod->name, taint_flags(mod->taints, buf));
+               printk(" %s%s", mod->name, module_flags(mod, buf));
+       if (last_unloaded_module[0])
+               printk(" [last unloaded: %s]", last_unloaded_module);
        printk("\n");
 }
 
-#ifdef CONFIG_SYSFS
-static char *make_driver_name(struct device_driver *drv)
-{
-       char *driver_name;
-
-       driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
-                             GFP_KERNEL);
-       if (!driver_name)
-               return NULL;
-
-       sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
-       return driver_name;
-}
-
-static void module_create_drivers_dir(struct module_kobject *mk)
-{
-       if (!mk || mk->drivers_dir)
-               return;
-
-       mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers");
-}
-
-void module_add_driver(struct module *mod, struct device_driver *drv)
-{
-       char *driver_name;
-       int no_warn;
-       struct module_kobject *mk = NULL;
-
-       if (!drv)
-               return;
-
-       if (mod)
-               mk = &mod->mkobj;
-       else if (drv->mod_name) {
-               struct kobject *mkobj;
-
-               /* Lookup built-in module entry in /sys/modules */
-               mkobj = kset_find_obj(&module_subsys, drv->mod_name);
-               if (mkobj) {
-                       mk = container_of(mkobj, struct module_kobject, kobj);
-                       /* remember our module structure */
-                       drv->mkobj = mk;
-                       /* kset_find_obj took a reference */
-                       kobject_put(mkobj);
-               }
-       }
-
-       if (!mk)
-               return;
-
-       /* Don't check return codes; these calls are idempotent */
-       no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");
-       driver_name = make_driver_name(drv);
-       if (driver_name) {
-               module_create_drivers_dir(mk);
-               no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,
-                                           driver_name);
-               kfree(driver_name);
-       }
-}
-EXPORT_SYMBOL(module_add_driver);
-
-void module_remove_driver(struct device_driver *drv)
-{
-       struct module_kobject *mk = NULL;
-       char *driver_name;
-
-       if (!drv)
-               return;
-
-       sysfs_remove_link(&drv->kobj, "module");
-
-       if (drv->owner)
-               mk = &drv->owner->mkobj;
-       else if (drv->mkobj)
-               mk = drv->mkobj;
-       if (mk && mk->drivers_dir) {
-               driver_name = make_driver_name(drv);
-               if (driver_name) {
-                       sysfs_remove_link(mk->drivers_dir, driver_name);
-                       kfree(driver_name);
-               }
-       }
-}
-EXPORT_SYMBOL(module_remove_driver);
-#endif
-
 #ifdef CONFIG_MODVERSIONS
 /* Generate the signature for struct module here, too, for modversions. */
 void struct_module(struct module *mod) { return; }
index 7686417ee00eba070b7d9b5c9dd293f9991199f1..67f65ee7211de8fa79311ca4141fdd96b9426765 100644 (file)
@@ -472,7 +472,7 @@ param_sysfs_setup(struct module_kobject *mk,
                        sizeof(mp->grp.attrs[0]));
        size[1] = (valid_attrs + 1) * sizeof(mp->grp.attrs[0]);
 
-       mp = kmalloc(size[0] + size[1], GFP_KERNEL);
+       mp = kzalloc(size[0] + size[1], GFP_KERNEL);
        if (!mp)
                return ERR_PTR(-ENOMEM);
 
@@ -560,11 +560,10 @@ static void __init kernel_param_sysfs_setup(const char *name,
        BUG_ON(!mk);
 
        mk->mod = THIS_MODULE;
-       kobj_set_kset_s(mk, module_subsys);
-       kobject_set_name(&mk->kobj, name);
-       kobject_init(&mk->kobj);
-       ret = kobject_add(&mk->kobj);
+       mk->kobj.kset = module_kset;
+       ret = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name);
        if (ret) {
+               kobject_put(&mk->kobj);
                printk(KERN_ERR "Module '%s' failed to be added to sysfs, "
                      "error number %d\n", name, ret);
                printk(KERN_ERR "The system will be unstable now.\n");
@@ -679,8 +678,6 @@ static struct sysfs_ops module_sysfs_ops = {
        .store = module_attr_store,
 };
 
-static struct kobj_type module_ktype;
-
 static int uevent_filter(struct kset *kset, struct kobject *kobj)
 {
        struct kobj_type *ktype = get_ktype(kobj);
@@ -694,21 +691,11 @@ static struct kset_uevent_ops module_uevent_ops = {
        .filter = uevent_filter,
 };
 
-decl_subsys(module, &module_ktype, &module_uevent_ops);
+struct kset *module_kset;
 int module_sysfs_initialized;
 
-static void module_release(struct kobject *kobj)
-{
-       /*
-        * Stupid empty release function to allow the memory for the kobject to
-        * be properly cleaned up.  This will not need to be present for 2.6.25
-        * with the upcoming kobject core rework.
-        */
-}
-
-static struct kobj_type module_ktype = {
+struct kobj_type module_ktype = {
        .sysfs_ops =    &module_sysfs_ops,
-       .release =      module_release,
 };
 
 /*
@@ -716,13 +703,11 @@ static struct kobj_type module_ktype = {
  */
 static int __init param_sysfs_init(void)
 {
-       int ret;
-
-       ret = subsystem_register(&module_subsys);
-       if (ret < 0) {
-               printk(KERN_WARNING "%s (%d): subsystem_register error: %d\n",
-                       __FILE__, __LINE__, ret);
-               return ret;
+       module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);
+       if (!module_kset) {
+               printk(KERN_WARNING "%s (%d): error creating kset\n",
+                       __FILE__, __LINE__);
+               return -ENOMEM;
        }
        module_sysfs_initialized = 1;
 
@@ -732,14 +717,7 @@ static int __init param_sysfs_init(void)
 }
 subsys_initcall(param_sysfs_init);
 
-#else
-#if 0
-static struct sysfs_ops module_sysfs_ops = {
-       .show = NULL,
-       .store = NULL,
-};
-#endif
-#endif
+#endif /* CONFIG_SYSFS */
 
 EXPORT_SYMBOL(param_set_byte);
 EXPORT_SYMBOL(param_get_byte);
index 68c96376e84a6078da9c07d6ebfc2b1c64a3e2a7..0b7c82ac467eb1db24e0614fe7cc1d2704d27a48 100644 (file)
@@ -967,6 +967,7 @@ static void check_thread_timers(struct task_struct *tsk,
 {
        int maxfire;
        struct list_head *timers = tsk->cpu_timers;
+       struct signal_struct *const sig = tsk->signal;
 
        maxfire = 20;
        tsk->it_prof_expires = cputime_zero;
@@ -1011,6 +1012,35 @@ static void check_thread_timers(struct task_struct *tsk,
                t->firing = 1;
                list_move_tail(&t->entry, firing);
        }
+
+       /*
+        * Check for the special case thread timers.
+        */
+       if (sig->rlim[RLIMIT_RTTIME].rlim_cur != RLIM_INFINITY) {
+               unsigned long hard = sig->rlim[RLIMIT_RTTIME].rlim_max;
+               unsigned long *soft = &sig->rlim[RLIMIT_RTTIME].rlim_cur;
+
+               if (hard != RLIM_INFINITY &&
+                   tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) {
+                       /*
+                        * At the hard limit, we just die.
+                        * No need to calculate anything else now.
+                        */
+                       __group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk);
+                       return;
+               }
+               if (tsk->rt.timeout > DIV_ROUND_UP(*soft, USEC_PER_SEC/HZ)) {
+                       /*
+                        * At the soft limit, send a SIGXCPU every second.
+                        */
+                       if (sig->rlim[RLIMIT_RTTIME].rlim_cur
+                           < sig->rlim[RLIMIT_RTTIME].rlim_max) {
+                               sig->rlim[RLIMIT_RTTIME].rlim_cur +=
+                                                               USEC_PER_SEC;
+                       }
+                       __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
+               }
+       }
 }
 
 /*
index 05b64790fe8391ed5189eee02144e5cf63f3fa2b..b138b431e27135aa7b2716335288069ea00beeee 100644 (file)
@@ -567,7 +567,8 @@ static const char * const hibernation_modes[] = {
  *     supports it (as determined by having hibernation_ops).
  */
 
-static ssize_t disk_show(struct kset *kset, char *buf)
+static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+                        char *buf)
 {
        int i;
        char *start = buf;
@@ -597,7 +598,8 @@ static ssize_t disk_show(struct kset *kset, char *buf)
 }
 
 
-static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
+static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+                         const char *buf, size_t n)
 {
        int error = 0;
        int i;
@@ -642,13 +644,15 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
 
 power_attr(disk);
 
-static ssize_t resume_show(struct kset *kset, char *buf)
+static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
+                          char *buf)
 {
        return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
                       MINOR(swsusp_resume_device));
 }
 
-static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
+static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
+                           const char *buf, size_t n)
 {
        unsigned int maj, min;
        dev_t res;
@@ -674,12 +678,14 @@ static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
 
 power_attr(resume);
 
-static ssize_t image_size_show(struct kset *kset, char *buf)
+static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
+                              char *buf)
 {
        return sprintf(buf, "%lu\n", image_size);
 }
 
-static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n)
+static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
+                               const char *buf, size_t n)
 {
        unsigned long size;
 
@@ -708,7 +714,7 @@ static struct attribute_group attr_group = {
 
 static int __init pm_disk_init(void)
 {
-       return sysfs_create_group(&power_subsys.kobj, &attr_group);
+       return sysfs_create_group(power_kobj, &attr_group);
 }
 
 core_initcall(pm_disk_init);
index 3cdf95b1dc92af97e13e8a6c68c4e0a6f8d42153..efc08360e627199374837ed95ea31ebcd0f94a80 100644 (file)
@@ -28,6 +28,9 @@ BLOCKING_NOTIFIER_HEAD(pm_chain_head);
 
 DEFINE_MUTEX(pm_mutex);
 
+unsigned int pm_flags;
+EXPORT_SYMBOL(pm_flags);
+
 #ifdef CONFIG_SUSPEND
 
 /* This is just an arbitrary number */
@@ -273,8 +276,7 @@ EXPORT_SYMBOL(pm_suspend);
 
 #endif /* CONFIG_SUSPEND */
 
-decl_subsys(power,NULL,NULL);
-
+struct kobject *power_kobj;
 
 /**
  *     state - control system power state.
@@ -287,7 +289,8 @@ decl_subsys(power,NULL,NULL);
  *     proper enumerated value, and initiates a suspend transition.
  */
 
-static ssize_t state_show(struct kset *kset, char *buf)
+static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buf)
 {
        char *s = buf;
 #ifdef CONFIG_SUSPEND
@@ -308,7 +311,8 @@ static ssize_t state_show(struct kset *kset, char *buf)
        return (s - buf);
 }
 
-static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t n)
 {
 #ifdef CONFIG_SUSPEND
        suspend_state_t state = PM_SUSPEND_STANDBY;
@@ -345,13 +349,15 @@ power_attr(state);
 #ifdef CONFIG_PM_TRACE
 int pm_trace_enabled;
 
-static ssize_t pm_trace_show(struct kset *kset, char *buf)
+static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
+                            char *buf)
 {
        return sprintf(buf, "%d\n", pm_trace_enabled);
 }
 
 static ssize_t
-pm_trace_store(struct kset *kset, const char *buf, size_t n)
+pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
+              const char *buf, size_t n)
 {
        int val;
 
@@ -383,10 +389,10 @@ static struct attribute_group attr_group = {
 
 static int __init pm_init(void)
 {
-       int error = subsystem_register(&power_subsys);
-       if (!error)
-               error = sysfs_create_group(&power_subsys.kobj,&attr_group);
-       return error;
+       power_kobj = kobject_create_and_add("power", NULL);
+       if (!power_kobj)
+               return -ENOMEM;
+       return sysfs_create_group(power_kobj, &attr_group);
 }
 
 core_initcall(pm_init);
index c50d15266c1096d42d61e296ea4da13d34cb57ec..60c73fa670d5a65b38f454c941201a22b7d4bf35 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
-int pm_active;
-
 /*
  *     Locking notes:
  *             pm_devs_lock can be a semaphore providing pm ops are not called
@@ -204,6 +202,4 @@ int pm_send_all(pm_request_t rqst, void *data)
 
 EXPORT_SYMBOL(pm_register);
 EXPORT_SYMBOL(pm_send_all);
-EXPORT_SYMBOL(pm_active);
-
 
index 195dc4611764b08a65780976a6231aaf004889fe..2093c3a9a994d8a7a3bd82487200b925ee16ac61 100644 (file)
@@ -54,7 +54,7 @@ extern int pfn_is_nosave(unsigned long);
 extern struct mutex pm_mutex;
 
 #define power_attr(_name) \
-static struct subsys_attribute _name##_attr = {        \
+static struct kobj_attribute _name##_attr = {  \
        .attr   = {                             \
                .name = __stringify(_name),     \
                .mode = 0644,                   \
@@ -63,8 +63,6 @@ static struct subsys_attribute _name##_attr = {       \
        .store  = _name##_store,                \
 }
 
-extern struct kset power_subsys;
-
 /* Preferred image size in bytes (default 500 MB) */
 extern unsigned long image_size;
 extern int in_suspend;
index 89011bf8c106615cf3569a3f1f80777afe3e55ef..423a8c765a5788fc1b422d87add42d8649ec9d31 100644 (file)
@@ -573,11 +573,6 @@ static int __init printk_time_setup(char *str)
 
 __setup("time", printk_time_setup);
 
-__attribute__((weak)) unsigned long long printk_clock(void)
-{
-       return sched_clock();
-}
-
 /* Check if we have any console registered that can be called early in boot. */
 static int have_callable_console(void)
 {
@@ -628,30 +623,57 @@ asmlinkage int printk(const char *fmt, ...)
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int printk_cpu = UINT_MAX;
 
+const char printk_recursion_bug_msg [] =
+                       KERN_CRIT "BUG: recent printk recursion!\n";
+static int printk_recursion_bug;
+
 asmlinkage int vprintk(const char *fmt, va_list args)
 {
+       static int log_level_unknown = 1;
+       static char printk_buf[1024];
+
        unsigned long flags;
-       int printed_len;
+       int printed_len = 0;
+       int this_cpu;
        char *p;
-       static char printk_buf[1024];
-       static int log_level_unknown = 1;
 
        boot_delay_msec();
 
        preempt_disable();
-       if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
-               /* If a crash is occurring during printk() on this CPU,
-                * make sure we can't deadlock */
-               zap_locks();
-
        /* This stops the holder of console_sem just where we want him */
        raw_local_irq_save(flags);
+       this_cpu = smp_processor_id();
+
+       /*
+        * Ouch, printk recursed into itself!
+        */
+       if (unlikely(printk_cpu == this_cpu)) {
+               /*
+                * If a crash is occurring during printk() on this CPU,
+                * then try to get the crash message out but make sure
+                * we can't deadlock. Otherwise just return to avoid the
+                * recursion and return - but flag the recursion so that
+                * it can be printed at the next appropriate moment:
+                */
+               if (!oops_in_progress) {
+                       printk_recursion_bug = 1;
+                       goto out_restore_irqs;
+               }
+               zap_locks();
+       }
+
        lockdep_off();
        spin_lock(&logbuf_lock);
-       printk_cpu = smp_processor_id();
+       printk_cpu = this_cpu;
 
+       if (printk_recursion_bug) {
+               printk_recursion_bug = 0;
+               strcpy(printk_buf, printk_recursion_bug_msg);
+               printed_len = sizeof(printk_recursion_bug_msg);
+       }
        /* Emit the output into the temporary buffer */
-       printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+       printed_len += vscnprintf(printk_buf + printed_len,
+                                 sizeof(printk_buf), fmt, args);
 
        /*
         * Copy the output into log_buf.  If the caller didn't provide
@@ -680,7 +702,9 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                                        loglev_char = default_message_loglevel
                                                + '0';
                                }
-                               t = printk_clock();
+                               t = 0;
+                               if (system_state != SYSTEM_BOOTING)
+                                       t = ktime_to_ns(ktime_get());
                                nanosec_rem = do_div(t, 1000000000);
                                tlen = sprintf(tbuf,
                                                "<%c>[%5lu.%06lu] ",
@@ -744,6 +768,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                printk_cpu = UINT_MAX;
                spin_unlock(&logbuf_lock);
                lockdep_on();
+out_restore_irqs:
                raw_local_irq_restore(flags);
        }
 
index 5e95330e51207c48a043b2675b1d015d48d0f488..e64c2da11c0f89018c31aca62dd69688d22d59eb 100644 (file)
@@ -52,7 +52,7 @@ static DEFINE_PER_CPU(int, cpu_profile_flip);
 static DEFINE_MUTEX(profile_flip_mutex);
 #endif /* CONFIG_SMP */
 
-static int __init profile_setup(char * str)
+static int __init profile_setup(char *str)
 {
        static char __initdata schedstr[] = "schedule";
        static char __initdata sleepstr[] = "sleep";
@@ -104,28 +104,28 @@ __setup("profile=", profile_setup);
 
 void __init profile_init(void)
 {
-       if (!prof_on) 
+       if (!prof_on)
                return;
+
        /* only text is profiled */
        prof_len = (_etext - _stext) >> prof_shift;
        prof_buffer = alloc_bootmem(prof_len*sizeof(atomic_t));
 }
 
 /* Profile event notifications */
+
 #ifdef CONFIG_PROFILING
+
 static BLOCKING_NOTIFIER_HEAD(task_exit_notifier);
 static ATOMIC_NOTIFIER_HEAD(task_free_notifier);
 static BLOCKING_NOTIFIER_HEAD(munmap_notifier);
-void profile_task_exit(struct task_struct * task)
+
+void profile_task_exit(struct task_struct *task)
 {
        blocking_notifier_call_chain(&task_exit_notifier, 0, task);
 }
-int profile_handoff_task(struct task_struct * task)
+
+int profile_handoff_task(struct task_struct *task)
 {
        int ret;
        ret = atomic_notifier_call_chain(&task_free_notifier, 0, task);
@@ -137,52 +137,55 @@ void profile_munmap(unsigned long addr)
        blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr);
 }
 
-int task_handoff_register(struct notifier_block * n)
+int task_handoff_register(struct notifier_block *n)
 {
        return atomic_notifier_chain_register(&task_free_notifier, n);
 }
+EXPORT_SYMBOL_GPL(task_handoff_register);
 
-int task_handoff_unregister(struct notifier_block * n)
+int task_handoff_unregister(struct notifier_block *n)
 {
        return atomic_notifier_chain_unregister(&task_free_notifier, n);
 }
+EXPORT_SYMBOL_GPL(task_handoff_unregister);
 
-int profile_event_register(enum profile_type type, struct notifier_block * n)
+int profile_event_register(enum profile_type type, struct notifier_block *n)
 {
        int err = -EINVAL;
+
        switch (type) {
-               case PROFILE_TASK_EXIT:
-                       err = blocking_notifier_chain_register(
-                                       &task_exit_notifier, n);
-                       break;
-               case PROFILE_MUNMAP:
-                       err = blocking_notifier_chain_register(
-                                       &munmap_notifier, n);
-                       break;
+       case PROFILE_TASK_EXIT:
+               err = blocking_notifier_chain_register(
+                               &task_exit_notifier, n);
+               break;
+       case PROFILE_MUNMAP:
+               err = blocking_notifier_chain_register(
+                               &munmap_notifier, n);
+               break;
        }
+
        return err;
 }
+EXPORT_SYMBOL_GPL(profile_event_register);
 
-int profile_event_unregister(enum profile_type type, struct notifier_block * n)
+int profile_event_unregister(enum profile_type type, struct notifier_block *n)
 {
        int err = -EINVAL;
+
        switch (type) {
-               case PROFILE_TASK_EXIT:
-                       err = blocking_notifier_chain_unregister(
-                                       &task_exit_notifier, n);
-                       break;
-               case PROFILE_MUNMAP:
-                       err = blocking_notifier_chain_unregister(
-                                       &munmap_notifier, n);
-                       break;
+       case PROFILE_TASK_EXIT:
+               err = blocking_notifier_chain_unregister(
+                               &task_exit_notifier, n);
+               break;
+       case PROFILE_MUNMAP:
+               err = blocking_notifier_chain_unregister(
+                               &munmap_notifier, n);
+               break;
        }
 
        return err;
 }
+EXPORT_SYMBOL_GPL(profile_event_unregister);
 
 int register_timer_hook(int (*hook)(struct pt_regs *))
 {
@@ -191,6 +194,7 @@ int register_timer_hook(int (*hook)(struct pt_regs *))
        timer_hook = hook;
        return 0;
 }
+EXPORT_SYMBOL_GPL(register_timer_hook);
 
 void unregister_timer_hook(int (*hook)(struct pt_regs *))
 {
@@ -199,13 +203,7 @@ void unregister_timer_hook(int (*hook)(struct pt_regs *))
        /* make sure all CPUs see the NULL hook */
        synchronize_sched();  /* Allow ongoing interrupts to complete. */
 }
-
-EXPORT_SYMBOL_GPL(register_timer_hook);
 EXPORT_SYMBOL_GPL(unregister_timer_hook);
-EXPORT_SYMBOL_GPL(task_handoff_register);
-EXPORT_SYMBOL_GPL(task_handoff_unregister);
-EXPORT_SYMBOL_GPL(profile_event_register);
-EXPORT_SYMBOL_GPL(profile_event_unregister);
 
 #endif /* CONFIG_PROFILING */
 
@@ -366,7 +364,7 @@ static int __devinit profile_cpu_callback(struct notifier_block *info,
                        per_cpu(cpu_profile_hits, cpu)[0] = page_address(page);
                }
                break;
-       out_free:
+out_free:
                page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
                per_cpu(cpu_profile_hits, cpu)[1] = NULL;
                __free_page(page);
@@ -409,7 +407,6 @@ void profile_hits(int type, void *__pc, unsigned int nr_hits)
        atomic_add(nr_hits, &prof_buffer[min(pc, prof_len - 1)]);
 }
 #endif /* !CONFIG_SMP */
-
 EXPORT_SYMBOL_GPL(profile_hits);
 
 void profile_tick(int type)
@@ -427,7 +424,7 @@ void profile_tick(int type)
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
 
-static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+static int prof_cpu_mask_read_proc(char *page, char **start, off_t off,
                        int count, int *eof, void *data)
 {
        int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
@@ -437,8 +434,8 @@ static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
        return len;
 }
 
-static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
-                                       unsigned long count, void *data)
+static int prof_cpu_mask_write_proc(struct file *file,
+       const char __user *buffer,  unsigned long count, void *data)
 {
        cpumask_t *mask = (cpumask_t *)data;
        unsigned long full_count = count, err;
@@ -457,7 +454,8 @@ void create_prof_cpu_mask(struct proc_dir_entry *root_irq_dir)
        struct proc_dir_entry *entry;
 
        /* create /proc/irq/prof_cpu_mask */
-       if (!(entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir)))
+       entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+       if (!entry)
                return;
        entry->data = (void *)&prof_cpu_mask;
        entry->read_proc = prof_cpu_mask_read_proc;
@@ -475,7 +473,7 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
        ssize_t read;
-       char * pnt;
+       char *pnt;
        unsigned int sample_step = 1 << prof_shift;
 
        profile_flip_buffers();
@@ -486,12 +484,12 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        read = 0;
 
        while (p < sizeof(unsigned int) && count > 0) {
-               if (put_user(*((char *)(&sample_step)+p),buf))
+               if (put_user(*((char *)(&sample_step)+p), buf))
                        return -EFAULT;
                buf++; p++; count--; read++;
        }
        pnt = (char *)prof_buffer + p - sizeof(atomic_t);
-       if (copy_to_user(buf,(void *)pnt,count))
+       if (copy_to_user(buf, (void *)pnt, count))
                return -EFAULT;
        read += count;
        *ppos += read;
@@ -508,7 +506,7 @@ static ssize_t write_profile(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
 #ifdef CONFIG_SMP
-       extern int setup_profiling_timer (unsigned int multiplier);
+       extern int setup_profiling_timer(unsigned int multiplier);
 
        if (count == sizeof(int)) {
                unsigned int multiplier;
@@ -591,7 +589,8 @@ static int __init create_proc_profile(void)
                return 0;
        if (create_hash_tables())
                return -1;
-       if (!(entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL)))
+       entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL);
+       if (!entry)
                return 0;
        entry->proc_fops = &proc_profile_operations;
        entry->size = (1+prof_len) * sizeof(atomic_t);
index 7c76f2ffaeaad78060cfb3223857a89c7a4ccb8f..c719bb9d79ab0dddd7a651d37b107b4368dfdd4b 100644 (file)
@@ -120,7 +120,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
        return ret;
 }
 
-static int may_attach(struct task_struct *task)
+int __ptrace_may_attach(struct task_struct *task)
 {
        /* May we inspect the given task?
         * This check is used both for attaching with ptrace
@@ -154,7 +154,7 @@ int ptrace_may_attach(struct task_struct *task)
 {
        int err;
        task_lock(task);
-       err = may_attach(task);
+       err = __ptrace_may_attach(task);
        task_unlock(task);
        return !err;
 }
@@ -196,7 +196,7 @@ repeat:
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;
-       retval = may_attach(task);
+       retval = __ptrace_may_attach(task);
        if (retval)
                goto bad;
 
@@ -470,6 +470,8 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
        lock_kernel();
        if (request == PTRACE_TRACEME) {
                ret = ptrace_traceme();
+               if (!ret)
+                       arch_ptrace_attach(current);
                goto out;
        }
 
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c
new file mode 100644 (file)
index 0000000..f4ffbd0
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion
+ *
+ * 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.
+ *
+ * Copyright IBM Corporation, 2001
+ *
+ * Authors: Dipankar Sarma <dipankar@in.ibm.com>
+ *         Manfred Spraul <manfred@colorfullife.com>
+ *
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *             Documentation/RCU
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key rcu_lock_key;
+struct lockdep_map rcu_lock_map =
+       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
+EXPORT_SYMBOL_GPL(rcu_lock_map);
+#endif
+
+
+/* Definition for rcupdate control block. */
+static struct rcu_ctrlblk rcu_ctrlblk = {
+       .cur = -300,
+       .completed = -300,
+       .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
+       .cpumask = CPU_MASK_NONE,
+};
+static struct rcu_ctrlblk rcu_bh_ctrlblk = {
+       .cur = -300,
+       .completed = -300,
+       .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
+       .cpumask = CPU_MASK_NONE,
+};
+
+DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
+DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L };
+
+static int blimit = 10;
+static int qhimark = 10000;
+static int qlowmark = 100;
+
+#ifdef CONFIG_SMP
+static void force_quiescent_state(struct rcu_data *rdp,
+                       struct rcu_ctrlblk *rcp)
+{
+       int cpu;
+       cpumask_t cpumask;
+       set_need_resched();
+       if (unlikely(!rcp->signaled)) {
+               rcp->signaled = 1;
+               /*
+                * Don't send IPI to itself. With irqs disabled,
+                * rdp->cpu is the current cpu.
+                */
+               cpumask = rcp->cpumask;
+               cpu_clear(rdp->cpu, cpumask);
+               for_each_cpu_mask(cpu, cpumask)
+                       smp_send_reschedule(cpu);
+       }
+}
+#else
+static inline void force_quiescent_state(struct rcu_data *rdp,
+                       struct rcu_ctrlblk *rcp)
+{
+       set_need_resched();
+}
+#endif
+
+/**
+ * call_rcu - Queue an RCU callback for invocation after a grace period.
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual update function to be invoked after the grace period
+ *
+ * The update function will be invoked some time after a full grace
+ * period elapses, in other words after all currently executing RCU
+ * read-side critical sections have completed.  RCU read-side critical
+ * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
+ * and may be nested.
+ */
+void call_rcu(struct rcu_head *head,
+                               void (*func)(struct rcu_head *rcu))
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+
+       head->func = func;
+       head->next = NULL;
+       local_irq_save(flags);
+       rdp = &__get_cpu_var(rcu_data);
+       *rdp->nxttail = head;
+       rdp->nxttail = &head->next;
+       if (unlikely(++rdp->qlen > qhimark)) {
+               rdp->blimit = INT_MAX;
+               force_quiescent_state(rdp, &rcu_ctrlblk);
+       }
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(call_rcu);
+
+/**
+ * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual update function to be invoked after the grace period
+ *
+ * The update function will be invoked some time after a full grace
+ * period elapses, in other words after all currently executing RCU
+ * read-side critical sections have completed. call_rcu_bh() assumes
+ * that the read-side critical sections end on completion of a softirq
+ * handler. This means that read-side critical sections in process
+ * context must not be interrupted by softirqs. This interface is to be
+ * used when most of the read-side critical sections are in softirq context.
+ * RCU read-side critical sections are delimited by rcu_read_lock() and
+ * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh()
+ * and rcu_read_unlock_bh(), if in process context. These may be nested.
+ */
+void call_rcu_bh(struct rcu_head *head,
+                               void (*func)(struct rcu_head *rcu))
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+
+       head->func = func;
+       head->next = NULL;
+       local_irq_save(flags);
+       rdp = &__get_cpu_var(rcu_bh_data);
+       *rdp->nxttail = head;
+       rdp->nxttail = &head->next;
+
+       if (unlikely(++rdp->qlen > qhimark)) {
+               rdp->blimit = INT_MAX;
+               force_quiescent_state(rdp, &rcu_bh_ctrlblk);
+       }
+
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(call_rcu_bh);
+
+/*
+ * Return the number of RCU batches processed thus far.  Useful
+ * for debug and statistics.
+ */
+long rcu_batches_completed(void)
+{
+       return rcu_ctrlblk.completed;
+}
+EXPORT_SYMBOL_GPL(rcu_batches_completed);
+
+/*
+ * Return the number of RCU batches processed thus far.  Useful
+ * for debug and statistics.
+ */
+long rcu_batches_completed_bh(void)
+{
+       return rcu_bh_ctrlblk.completed;
+}
+EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
+
+/* Raises the softirq for processing rcu_callbacks. */
+static inline void raise_rcu_softirq(void)
+{
+       raise_softirq(RCU_SOFTIRQ);
+       /*
+        * The smp_mb() here is required to ensure that this cpu's
+        * __rcu_process_callbacks() reads the most recently updated
+        * value of rcu->cur.
+        */
+       smp_mb();
+}
+
+/*
+ * Invoke the completed RCU callbacks. They are expected to be in
+ * a per-cpu list.
+ */
+static void rcu_do_batch(struct rcu_data *rdp)
+{
+       struct rcu_head *next, *list;
+       int count = 0;
+
+       list = rdp->donelist;
+       while (list) {
+               next = list->next;
+               prefetch(next);
+               list->func(list);
+               list = next;
+               if (++count >= rdp->blimit)
+                       break;
+       }
+       rdp->donelist = list;
+
+       local_irq_disable();
+       rdp->qlen -= count;
+       local_irq_enable();
+       if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark)
+               rdp->blimit = blimit;
+
+       if (!rdp->donelist)
+               rdp->donetail = &rdp->donelist;
+       else
+               raise_rcu_softirq();
+}
+
+/*
+ * Grace period handling:
+ * The grace period handling consists out of two steps:
+ * - A new grace period is started.
+ *   This is done by rcu_start_batch. The start is not broadcasted to
+ *   all cpus, they must pick this up by comparing rcp->cur with
+ *   rdp->quiescbatch. All cpus are recorded  in the
+ *   rcu_ctrlblk.cpumask bitmap.
+ * - All cpus must go through a quiescent state.
+ *   Since the start of the grace period is not broadcasted, at least two
+ *   calls to rcu_check_quiescent_state are required:
+ *   The first call just notices that a new grace period is running. The
+ *   following calls check if there was a quiescent state since the beginning
+ *   of the grace period. If so, it updates rcu_ctrlblk.cpumask. If
+ *   the bitmap is empty, then the grace period is completed.
+ *   rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
+ *   period (if necessary).
+ */
+/*
+ * Register a new batch of callbacks, and start it up if there is currently no
+ * active batch and the batch to be registered has not already occurred.
+ * Caller must hold rcu_ctrlblk.lock.
+ */
+static void rcu_start_batch(struct rcu_ctrlblk *rcp)
+{
+       if (rcp->next_pending &&
+                       rcp->completed == rcp->cur) {
+               rcp->next_pending = 0;
+               /*
+                * next_pending == 0 must be visible in
+                * __rcu_process_callbacks() before it can see new value of cur.
+                */
+               smp_wmb();
+               rcp->cur++;
+
+               /*
+                * Accessing nohz_cpu_mask before incrementing rcp->cur needs a
+                * Barrier  Otherwise it can cause tickless idle CPUs to be
+                * included in rcp->cpumask, which will extend graceperiods
+                * unnecessarily.
+                */
+               smp_mb();
+               cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
+
+               rcp->signaled = 0;
+       }
+}
+
+/*
+ * cpu went through a quiescent state since the beginning of the grace period.
+ * Clear it from the cpu mask and complete the grace period if it was the last
+ * cpu. Start another grace period if someone has further entries pending
+ */
+static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp)
+{
+       cpu_clear(cpu, rcp->cpumask);
+       if (cpus_empty(rcp->cpumask)) {
+               /* batch completed ! */
+               rcp->completed = rcp->cur;
+               rcu_start_batch(rcp);
+       }
+}
+
+/*
+ * Check if the cpu has gone through a quiescent state (say context
+ * switch). If so and if it already hasn't done so in this RCU
+ * quiescent cycle, then indicate that it has done so.
+ */
+static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
+                                       struct rcu_data *rdp)
+{
+       if (rdp->quiescbatch != rcp->cur) {
+               /* start new grace period: */
+               rdp->qs_pending = 1;
+               rdp->passed_quiesc = 0;
+               rdp->quiescbatch = rcp->cur;
+               return;
+       }
+
+       /* Grace period already completed for this cpu?
+        * qs_pending is checked instead of the actual bitmap to avoid
+        * cacheline trashing.
+        */
+       if (!rdp->qs_pending)
+               return;
+
+       /*
+        * Was there a quiescent state since the beginning of the grace
+        * period? If no, then exit and wait for the next call.
+        */
+       if (!rdp->passed_quiesc)
+               return;
+       rdp->qs_pending = 0;
+
+       spin_lock(&rcp->lock);
+       /*
+        * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync
+        * during cpu startup. Ignore the quiescent state.
+        */
+       if (likely(rdp->quiescbatch == rcp->cur))
+               cpu_quiet(rdp->cpu, rcp);
+
+       spin_unlock(&rcp->lock);
+}
+
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
+ * locking requirements, the list it's pulling from has to belong to a cpu
+ * which is dead and hence not processing interrupts.
+ */
+static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
+                               struct rcu_head **tail)
+{
+       local_irq_disable();
+       *this_rdp->nxttail = list;
+       if (list)
+               this_rdp->nxttail = tail;
+       local_irq_enable();
+}
+
+static void __rcu_offline_cpu(struct rcu_data *this_rdp,
+                               struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
+{
+       /* if the cpu going offline owns the grace period
+        * we can block indefinitely waiting for it, so flush
+        * it here
+        */
+       spin_lock_bh(&rcp->lock);
+       if (rcp->cur != rcp->completed)
+               cpu_quiet(rdp->cpu, rcp);
+       spin_unlock_bh(&rcp->lock);
+       rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail);
+       rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail);
+       rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail);
+}
+
+static void rcu_offline_cpu(int cpu)
+{
+       struct rcu_data *this_rdp = &get_cpu_var(rcu_data);
+       struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data);
+
+       __rcu_offline_cpu(this_rdp, &rcu_ctrlblk,
+                                       &per_cpu(rcu_data, cpu));
+       __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk,
+                                       &per_cpu(rcu_bh_data, cpu));
+       put_cpu_var(rcu_data);
+       put_cpu_var(rcu_bh_data);
+}
+
+#else
+
+static void rcu_offline_cpu(int cpu)
+{
+}
+
+#endif
+
+/*
+ * This does the RCU processing work from softirq context.
+ */
+static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
+                                       struct rcu_data *rdp)
+{
+       if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) {
+               *rdp->donetail = rdp->curlist;
+               rdp->donetail = rdp->curtail;
+               rdp->curlist = NULL;
+               rdp->curtail = &rdp->curlist;
+       }
+
+       if (rdp->nxtlist && !rdp->curlist) {
+               local_irq_disable();
+               rdp->curlist = rdp->nxtlist;
+               rdp->curtail = rdp->nxttail;
+               rdp->nxtlist = NULL;
+               rdp->nxttail = &rdp->nxtlist;
+               local_irq_enable();
+
+               /*
+                * start the next batch of callbacks
+                */
+
+               /* determine batch number */
+               rdp->batch = rcp->cur + 1;
+               /* see the comment and corresponding wmb() in
+                * the rcu_start_batch()
+                */
+               smp_rmb();
+
+               if (!rcp->next_pending) {
+                       /* and start it/schedule start if it's a new batch */
+                       spin_lock(&rcp->lock);
+                       rcp->next_pending = 1;
+                       rcu_start_batch(rcp);
+                       spin_unlock(&rcp->lock);
+               }
+       }
+
+       rcu_check_quiescent_state(rcp, rdp);
+       if (rdp->donelist)
+               rcu_do_batch(rdp);
+}
+
+static void rcu_process_callbacks(struct softirq_action *unused)
+{
+       __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data));
+       __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
+}
+
+static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
+{
+       /* This cpu has pending rcu entries and the grace period
+        * for them has completed.
+        */
+       if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
+               return 1;
+
+       /* This cpu has no pending entries, but there are new entries */
+       if (!rdp->curlist && rdp->nxtlist)
+               return 1;
+
+       /* This cpu has finished callbacks to invoke */
+       if (rdp->donelist)
+               return 1;
+
+       /* The rcu core waits for a quiescent state from the cpu */
+       if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
+               return 1;
+
+       /* nothing to do */
+       return 0;
+}
+
+/*
+ * Check to see if there is any immediate RCU-related work to be done
+ * by the current CPU, returning 1 if so.  This function is part of the
+ * RCU implementation; it is -not- an exported member of the RCU API.
+ */
+int rcu_pending(int cpu)
+{
+       return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
+               __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
+}
+
+/*
+ * Check to see if any future RCU-related work will need to be done
+ * by the current CPU, even if none need be done immediately, returning
+ * 1 if so.  This function is part of the RCU implementation; it is -not-
+ * an exported member of the RCU API.
+ */
+int rcu_needs_cpu(int cpu)
+{
+       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
+       struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
+
+       return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu));
+}
+
+void rcu_check_callbacks(int cpu, int user)
+{
+       if (user ||
+           (idle_cpu(cpu) && !in_softirq() &&
+                               hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
+               rcu_qsctr_inc(cpu);
+               rcu_bh_qsctr_inc(cpu);
+       } else if (!in_softirq())
+               rcu_bh_qsctr_inc(cpu);
+       raise_rcu_softirq();
+}
+
+static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
+                                               struct rcu_data *rdp)
+{
+       memset(rdp, 0, sizeof(*rdp));
+       rdp->curtail = &rdp->curlist;
+       rdp->nxttail = &rdp->nxtlist;
+       rdp->donetail = &rdp->donelist;
+       rdp->quiescbatch = rcp->completed;
+       rdp->qs_pending = 0;
+       rdp->cpu = cpu;
+       rdp->blimit = blimit;
+}
+
+static void __cpuinit rcu_online_cpu(int cpu)
+{
+       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
+       struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu);
+
+       rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp);
+       rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp);
+       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL);
+}
+
+static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
+                               unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               rcu_online_cpu(cpu);
+               break;
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               rcu_offline_cpu(cpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata rcu_nb = {
+       .notifier_call  = rcu_cpu_notify,
+};
+
+/*
+ * Initializes rcu mechanism.  Assumed to be called early.
+ * That is before local timer(SMP) or jiffie timer (uniproc) is setup.
+ * Note that rcu_qsctr and friends are implicitly
+ * initialized due to the choice of ``0'' for RCU_CTR_INVALID.
+ */
+void __init __rcu_init(void)
+{
+       rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
+                       (void *)(long)smp_processor_id());
+       /* Register notifier for non-boot CPUs */
+       register_cpu_notifier(&rcu_nb);
+}
+
+module_param(blimit, int, 0);
+module_param(qhimark, int, 0);
+module_param(qlowmark, int, 0);
index a66d4d1615f7ff978616c86a350d582cc11ff20f..760dfc233a00ae103fdce2bfe335ad9b14ca39cc 100644 (file)
@@ -15,7 +15,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Copyright (C) IBM Corporation, 2001
+ * Copyright IBM Corporation, 2001
  *
  * Authors: Dipankar Sarma <dipankar@in.ibm.com>
  *         Manfred Spraul <manfred@colorfullife.com>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/smp.h>
-#include <linux/rcupdate.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <asm/atomic.h>
 #include <linux/bitops.h>
-#include <linux/module.h>
 #include <linux/completion.h>
-#include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/mutex.h>
+#include <linux/module.h>
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-static struct lock_class_key rcu_lock_key;
-struct lockdep_map rcu_lock_map =
-       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
-
-EXPORT_SYMBOL_GPL(rcu_lock_map);
-#endif
-
-/* Definition for rcupdate control block. */
-static struct rcu_ctrlblk rcu_ctrlblk = {
-       .cur = -300,
-       .completed = -300,
-       .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
-       .cpumask = CPU_MASK_NONE,
-};
-static struct rcu_ctrlblk rcu_bh_ctrlblk = {
-       .cur = -300,
-       .completed = -300,
-       .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
-       .cpumask = CPU_MASK_NONE,
+struct rcu_synchronize {
+       struct rcu_head head;
+       struct completion completion;
 };
 
-DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
-DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L };
-
-/* Fake initialization required by compiler */
-static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL};
-static int blimit = 10;
-static int qhimark = 10000;
-static int qlowmark = 100;
-
+static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
 static atomic_t rcu_barrier_cpu_count;
 static DEFINE_MUTEX(rcu_barrier_mutex);
 static struct completion rcu_barrier_completion;
 
-#ifdef CONFIG_SMP
-static void force_quiescent_state(struct rcu_data *rdp,
-                       struct rcu_ctrlblk *rcp)
-{
-       int cpu;
-       cpumask_t cpumask;
-       set_need_resched();
-       if (unlikely(!rcp->signaled)) {
-               rcp->signaled = 1;
-               /*
-                * Don't send IPI to itself. With irqs disabled,
-                * rdp->cpu is the current cpu.
-                */
-               cpumask = rcp->cpumask;
-               cpu_clear(rdp->cpu, cpumask);
-               for_each_cpu_mask(cpu, cpumask)
-                       smp_send_reschedule(cpu);
-       }
-}
-#else
-static inline void force_quiescent_state(struct rcu_data *rdp,
-                       struct rcu_ctrlblk *rcp)
+/* Because of FASTCALL declaration of complete, we use this wrapper */
+static void wakeme_after_rcu(struct rcu_head  *head)
 {
-       set_need_resched();
+       struct rcu_synchronize *rcu;
+
+       rcu = container_of(head, struct rcu_synchronize, head);
+       complete(&rcu->completion);
 }
-#endif
 
 /**
- * call_rcu - Queue an RCU callback for invocation after a grace period.
- * @head: structure to be used for queueing the RCU updates.
- * @func: actual update function to be invoked after the grace period
+ * synchronize_rcu - wait until a grace period has elapsed.
  *
- * The update function will be invoked some time after a full grace
- * period elapses, in other words after all currently executing RCU
+ * Control will return to the caller some time after a full grace
+ * period has elapsed, in other words after all currently executing RCU
  * read-side critical sections have completed.  RCU read-side critical
  * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
  * and may be nested.
  */
-void fastcall call_rcu(struct rcu_head *head,
-                               void (*func)(struct rcu_head *rcu))
-{
-       unsigned long flags;
-       struct rcu_data *rdp;
-
-       head->func = func;
-       head->next = NULL;
-       local_irq_save(flags);
-       rdp = &__get_cpu_var(rcu_data);
-       *rdp->nxttail = head;
-       rdp->nxttail = &head->next;
-       if (unlikely(++rdp->qlen > qhimark)) {
-               rdp->blimit = INT_MAX;
-               force_quiescent_state(rdp, &rcu_ctrlblk);
-       }
-       local_irq_restore(flags);
-}
-
-/**
- * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
- * @head: structure to be used for queueing the RCU updates.
- * @func: actual update function to be invoked after the grace period
- *
- * The update function will be invoked some time after a full grace
- * period elapses, in other words after all currently executing RCU
- * read-side critical sections have completed. call_rcu_bh() assumes
- * that the read-side critical sections end on completion of a softirq
- * handler. This means that read-side critical sections in process
- * context must not be interrupted by softirqs. This interface is to be
- * used when most of the read-side critical sections are in softirq context.
- * RCU read-side critical sections are delimited by rcu_read_lock() and
- * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh()
- * and rcu_read_unlock_bh(), if in process context. These may be nested.
- */
-void fastcall call_rcu_bh(struct rcu_head *head,
-                               void (*func)(struct rcu_head *rcu))
+void synchronize_rcu(void)
 {
-       unsigned long flags;
-       struct rcu_data *rdp;
-
-       head->func = func;
-       head->next = NULL;
-       local_irq_save(flags);
-       rdp = &__get_cpu_var(rcu_bh_data);
-       *rdp->nxttail = head;
-       rdp->nxttail = &head->next;
-
-       if (unlikely(++rdp->qlen > qhimark)) {
-               rdp->blimit = INT_MAX;
-               force_quiescent_state(rdp, &rcu_bh_ctrlblk);
-       }
-
-       local_irq_restore(flags);
-}
+       struct rcu_synchronize rcu;
 
-/*
- * Return the number of RCU batches processed thus far.  Useful
- * for debug and statistics.
- */
-long rcu_batches_completed(void)
-{
-       return rcu_ctrlblk.completed;
-}
+       init_completion(&rcu.completion);
+       /* Will wake me after RCU finished */
+       call_rcu(&rcu.head, wakeme_after_rcu);
 
-/*
- * Return the number of RCU batches processed thus far.  Useful
- * for debug and statistics.
- */
-long rcu_batches_completed_bh(void)
-{
-       return rcu_bh_ctrlblk.completed;
+       /* Wait for it */
+       wait_for_completion(&rcu.completion);
 }
+EXPORT_SYMBOL_GPL(synchronize_rcu);
 
 static void rcu_barrier_callback(struct rcu_head *notused)
 {
@@ -207,10 +99,8 @@ static void rcu_barrier_callback(struct rcu_head *notused)
 static void rcu_barrier_func(void *notused)
 {
        int cpu = smp_processor_id();
-       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
-       struct rcu_head *head;
+       struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
 
-       head = &rdp->barrier;
        atomic_inc(&rcu_barrier_cpu_count);
        call_rcu(head, rcu_barrier_callback);
 }
@@ -225,420 +115,24 @@ void rcu_barrier(void)
        mutex_lock(&rcu_barrier_mutex);
        init_completion(&rcu_barrier_completion);
        atomic_set(&rcu_barrier_cpu_count, 0);
+       /*
+        * The queueing of callbacks in all CPUs must be atomic with
+        * respect to RCU, otherwise one CPU may queue a callback,
+        * wait for a grace period, decrement barrier count and call
+        * complete(), while other CPUs have not yet queued anything.
+        * So, we need to make sure that grace periods cannot complete
+        * until all the callbacks are queued.
+        */
+       rcu_read_lock();
        on_each_cpu(rcu_barrier_func, NULL, 0, 1);
+       rcu_read_unlock();
        wait_for_completion(&rcu_barrier_completion);
        mutex_unlock(&rcu_barrier_mutex);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
-/*
- * Invoke the completed RCU callbacks. They are expected to be in
- * a per-cpu list.
- */
-static void rcu_do_batch(struct rcu_data *rdp)
-{
-       struct rcu_head *next, *list;
-       int count = 0;
-
-       list = rdp->donelist;
-       while (list) {
-               next = list->next;
-               prefetch(next);
-               list->func(list);
-               list = next;
-               if (++count >= rdp->blimit)
-                       break;
-       }
-       rdp->donelist = list;
-
-       local_irq_disable();
-       rdp->qlen -= count;
-       local_irq_enable();
-       if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark)
-               rdp->blimit = blimit;
-
-       if (!rdp->donelist)
-               rdp->donetail = &rdp->donelist;
-       else
-               tasklet_schedule(&per_cpu(rcu_tasklet, rdp->cpu));
-}
-
-/*
- * Grace period handling:
- * The grace period handling consists out of two steps:
- * - A new grace period is started.
- *   This is done by rcu_start_batch. The start is not broadcasted to
- *   all cpus, they must pick this up by comparing rcp->cur with
- *   rdp->quiescbatch. All cpus are recorded  in the
- *   rcu_ctrlblk.cpumask bitmap.
- * - All cpus must go through a quiescent state.
- *   Since the start of the grace period is not broadcasted, at least two
- *   calls to rcu_check_quiescent_state are required:
- *   The first call just notices that a new grace period is running. The
- *   following calls check if there was a quiescent state since the beginning
- *   of the grace period. If so, it updates rcu_ctrlblk.cpumask. If
- *   the bitmap is empty, then the grace period is completed.
- *   rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
- *   period (if necessary).
- */
-/*
- * Register a new batch of callbacks, and start it up if there is currently no
- * active batch and the batch to be registered has not already occurred.
- * Caller must hold rcu_ctrlblk.lock.
- */
-static void rcu_start_batch(struct rcu_ctrlblk *rcp)
-{
-       if (rcp->next_pending &&
-                       rcp->completed == rcp->cur) {
-               rcp->next_pending = 0;
-               /*
-                * next_pending == 0 must be visible in
-                * __rcu_process_callbacks() before it can see new value of cur.
-                */
-               smp_wmb();
-               rcp->cur++;
-
-               /*
-                * Accessing nohz_cpu_mask before incrementing rcp->cur needs a
-                * Barrier  Otherwise it can cause tickless idle CPUs to be
-                * included in rcp->cpumask, which will extend graceperiods
-                * unnecessarily.
-                */
-               smp_mb();
-               cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
-
-               rcp->signaled = 0;
-       }
-}
-
-/*
- * cpu went through a quiescent state since the beginning of the grace period.
- * Clear it from the cpu mask and complete the grace period if it was the last
- * cpu. Start another grace period if someone has further entries pending
- */
-static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp)
-{
-       cpu_clear(cpu, rcp->cpumask);
-       if (cpus_empty(rcp->cpumask)) {
-               /* batch completed ! */
-               rcp->completed = rcp->cur;
-               rcu_start_batch(rcp);
-       }
-}
-
-/*
- * Check if the cpu has gone through a quiescent state (say context
- * switch). If so and if it already hasn't done so in this RCU
- * quiescent cycle, then indicate that it has done so.
- */
-static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
-                                       struct rcu_data *rdp)
-{
-       if (rdp->quiescbatch != rcp->cur) {
-               /* start new grace period: */
-               rdp->qs_pending = 1;
-               rdp->passed_quiesc = 0;
-               rdp->quiescbatch = rcp->cur;
-               return;
-       }
-
-       /* Grace period already completed for this cpu?
-        * qs_pending is checked instead of the actual bitmap to avoid
-        * cacheline trashing.
-        */
-       if (!rdp->qs_pending)
-               return;
-
-       /* 
-        * Was there a quiescent state since the beginning of the grace
-        * period? If no, then exit and wait for the next call.
-        */
-       if (!rdp->passed_quiesc)
-               return;
-       rdp->qs_pending = 0;
-
-       spin_lock(&rcp->lock);
-       /*
-        * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync
-        * during cpu startup. Ignore the quiescent state.
-        */
-       if (likely(rdp->quiescbatch == rcp->cur))
-               cpu_quiet(rdp->cpu, rcp);
-
-       spin_unlock(&rcp->lock);
-}
-
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
- * locking requirements, the list it's pulling from has to belong to a cpu
- * which is dead and hence not processing interrupts.
- */
-static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
-                               struct rcu_head **tail)
-{
-       local_irq_disable();
-       *this_rdp->nxttail = list;
-       if (list)
-               this_rdp->nxttail = tail;
-       local_irq_enable();
-}
-
-static void __rcu_offline_cpu(struct rcu_data *this_rdp,
-                               struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
-{
-       /* if the cpu going offline owns the grace period
-        * we can block indefinitely waiting for it, so flush
-        * it here
-        */
-       spin_lock_bh(&rcp->lock);
-       if (rcp->cur != rcp->completed)
-               cpu_quiet(rdp->cpu, rcp);
-       spin_unlock_bh(&rcp->lock);
-       rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail);
-       rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail);
-       rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail);
-}
-
-static void rcu_offline_cpu(int cpu)
-{
-       struct rcu_data *this_rdp = &get_cpu_var(rcu_data);
-       struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data);
-
-       __rcu_offline_cpu(this_rdp, &rcu_ctrlblk,
-                                       &per_cpu(rcu_data, cpu));
-       __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk,
-                                       &per_cpu(rcu_bh_data, cpu));
-       put_cpu_var(rcu_data);
-       put_cpu_var(rcu_bh_data);
-       tasklet_kill_immediate(&per_cpu(rcu_tasklet, cpu), cpu);
-}
-
-#else
-
-static void rcu_offline_cpu(int cpu)
-{
-}
-
-#endif
-
-/*
- * This does the RCU processing work from tasklet context. 
- */
-static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
-                                       struct rcu_data *rdp)
-{
-       if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) {
-               *rdp->donetail = rdp->curlist;
-               rdp->donetail = rdp->curtail;
-               rdp->curlist = NULL;
-               rdp->curtail = &rdp->curlist;
-       }
-
-       if (rdp->nxtlist && !rdp->curlist) {
-               local_irq_disable();
-               rdp->curlist = rdp->nxtlist;
-               rdp->curtail = rdp->nxttail;
-               rdp->nxtlist = NULL;
-               rdp->nxttail = &rdp->nxtlist;
-               local_irq_enable();
-
-               /*
-                * start the next batch of callbacks
-                */
-
-               /* determine batch number */
-               rdp->batch = rcp->cur + 1;
-               /* see the comment and corresponding wmb() in
-                * the rcu_start_batch()
-                */
-               smp_rmb();
-
-               if (!rcp->next_pending) {
-                       /* and start it/schedule start if it's a new batch */
-                       spin_lock(&rcp->lock);
-                       rcp->next_pending = 1;
-                       rcu_start_batch(rcp);
-                       spin_unlock(&rcp->lock);
-               }
-       }
-
-       rcu_check_quiescent_state(rcp, rdp);
-       if (rdp->donelist)
-               rcu_do_batch(rdp);
-}
-
-static void rcu_process_callbacks(unsigned long unused)
-{
-       __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data));
-       __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
-}
-
-static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
-{
-       /* This cpu has pending rcu entries and the grace period
-        * for them has completed.
-        */
-       if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
-               return 1;
-
-       /* This cpu has no pending entries, but there are new entries */
-       if (!rdp->curlist && rdp->nxtlist)
-               return 1;
-
-       /* This cpu has finished callbacks to invoke */
-       if (rdp->donelist)
-               return 1;
-
-       /* The rcu core waits for a quiescent state from the cpu */
-       if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
-               return 1;
-
-       /* nothing to do */
-       return 0;
-}
-
-/*
- * Check to see if there is any immediate RCU-related work to be done
- * by the current CPU, returning 1 if so.  This function is part of the
- * RCU implementation; it is -not- an exported member of the RCU API.
- */
-int rcu_pending(int cpu)
-{
-       return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
-               __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
-}
-
-/*
- * Check to see if any future RCU-related work will need to be done
- * by the current CPU, even if none need be done immediately, returning
- * 1 if so.  This function is part of the RCU implementation; it is -not-
- * an exported member of the RCU API.
- */
-int rcu_needs_cpu(int cpu)
-{
-       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
-       struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
-
-       return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu));
-}
-
-void rcu_check_callbacks(int cpu, int user)
-{
-       if (user || 
-           (idle_cpu(cpu) && !in_softirq() && 
-                               hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
-               rcu_qsctr_inc(cpu);
-               rcu_bh_qsctr_inc(cpu);
-       } else if (!in_softirq())
-               rcu_bh_qsctr_inc(cpu);
-       tasklet_schedule(&per_cpu(rcu_tasklet, cpu));
-}
-
-static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
-                                               struct rcu_data *rdp)
-{
-       memset(rdp, 0, sizeof(*rdp));
-       rdp->curtail = &rdp->curlist;
-       rdp->nxttail = &rdp->nxtlist;
-       rdp->donetail = &rdp->donelist;
-       rdp->quiescbatch = rcp->completed;
-       rdp->qs_pending = 0;
-       rdp->cpu = cpu;
-       rdp->blimit = blimit;
-}
-
-static void __devinit rcu_online_cpu(int cpu)
-{
-       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
-       struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu);
-
-       rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp);
-       rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp);
-       tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL);
-}
-
-static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
-                               unsigned long action, void *hcpu)
-{
-       long cpu = (long)hcpu;
-       switch (action) {
-       case CPU_UP_PREPARE:
-       case CPU_UP_PREPARE_FROZEN:
-               rcu_online_cpu(cpu);
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               rcu_offline_cpu(cpu);
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata rcu_nb = {
-       .notifier_call  = rcu_cpu_notify,
-};
-
-/*
- * Initializes rcu mechanism.  Assumed to be called early.
- * That is before local timer(SMP) or jiffie timer (uniproc) is setup.
- * Note that rcu_qsctr and friends are implicitly
- * initialized due to the choice of ``0'' for RCU_CTR_INVALID.
- */
 void __init rcu_init(void)
 {
-       rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
-                       (void *)(long)smp_processor_id());
-       /* Register notifier for non-boot CPUs */
-       register_cpu_notifier(&rcu_nb);
-}
-
-struct rcu_synchronize {
-       struct rcu_head head;
-       struct completion completion;
-};
-
-/* Because of FASTCALL declaration of complete, we use this wrapper */
-static void wakeme_after_rcu(struct rcu_head  *head)
-{
-       struct rcu_synchronize *rcu;
-
-       rcu = container_of(head, struct rcu_synchronize, head);
-       complete(&rcu->completion);
+       __rcu_init();
 }
 
-/**
- * synchronize_rcu - wait until a grace period has elapsed.
- *
- * Control will return to the caller some time after a full grace
- * period has elapsed, in other words after all currently executing RCU
- * read-side critical sections have completed.  RCU read-side critical
- * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
- * and may be nested.
- *
- * If your read-side code is not protected by rcu_read_lock(), do -not-
- * use synchronize_rcu().
- */
-void synchronize_rcu(void)
-{
-       struct rcu_synchronize rcu;
-
-       init_completion(&rcu.completion);
-       /* Will wake me after RCU finished */
-       call_rcu(&rcu.head, wakeme_after_rcu);
-
-       /* Wait for it */
-       wait_for_completion(&rcu.completion);
-}
-
-module_param(blimit, int, 0);
-module_param(qhimark, int, 0);
-module_param(qlowmark, int, 0);
-EXPORT_SYMBOL_GPL(rcu_batches_completed);
-EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
-EXPORT_SYMBOL_GPL(call_rcu);
-EXPORT_SYMBOL_GPL(call_rcu_bh);
-EXPORT_SYMBOL_GPL(synchronize_rcu);
diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c
new file mode 100644 (file)
index 0000000..987cfb7
--- /dev/null
@@ -0,0 +1,953 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion, realtime implementation
+ *
+ * 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.
+ *
+ * Copyright IBM Corporation, 2006
+ *
+ * Authors: Paul E. McKenney <paulmck@us.ibm.com>
+ *             With thanks to Esben Nielsen, Bill Huey, and Ingo Molnar
+ *             for pushing me away from locks and towards counters, and
+ *             to Suparna Bhattacharya for pushing me completely away
+ *             from atomic instructions on the read side.
+ *
+ * Papers:  http://www.rdrop.com/users/paulmck/RCU
+ *
+ * Design Document: http://lwn.net/Articles/253651/
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *             Documentation/RCU/ *.txt
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/rcupdate.h>
+#include <linux/cpu.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/byteorder/swabb.h>
+#include <linux/cpumask.h>
+#include <linux/rcupreempt_trace.h>
+
+/*
+ * Macro that prevents the compiler from reordering accesses, but does
+ * absolutely -nothing- to prevent CPUs from reordering.  This is used
+ * only to mediate communication between mainline code and hardware
+ * interrupt and NMI handlers.
+ */
+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+
+/*
+ * PREEMPT_RCU data structures.
+ */
+
+/*
+ * GP_STAGES specifies the number of times the state machine has
+ * to go through the all the rcu_try_flip_states (see below)
+ * in a single Grace Period.
+ *
+ * GP in GP_STAGES stands for Grace Period ;)
+ */
+#define GP_STAGES    2
+struct rcu_data {
+       spinlock_t      lock;           /* Protect rcu_data fields. */
+       long            completed;      /* Number of last completed batch. */
+       int             waitlistcount;
+       struct tasklet_struct rcu_tasklet;
+       struct rcu_head *nextlist;
+       struct rcu_head **nexttail;
+       struct rcu_head *waitlist[GP_STAGES];
+       struct rcu_head **waittail[GP_STAGES];
+       struct rcu_head *donelist;
+       struct rcu_head **donetail;
+       long rcu_flipctr[2];
+#ifdef CONFIG_RCU_TRACE
+       struct rcupreempt_trace trace;
+#endif /* #ifdef CONFIG_RCU_TRACE */
+};
+
+/*
+ * States for rcu_try_flip() and friends.
+ */
+
+enum rcu_try_flip_states {
+
+       /*
+        * Stay here if nothing is happening. Flip the counter if somthing
+        * starts happening. Denoted by "I"
+        */
+       rcu_try_flip_idle_state,
+
+       /*
+        * Wait here for all CPUs to notice that the counter has flipped. This
+        * prevents the old set of counters from ever being incremented once
+        * we leave this state, which in turn is necessary because we cannot
+        * test any individual counter for zero -- we can only check the sum.
+        * Denoted by "A".
+        */
+       rcu_try_flip_waitack_state,
+
+       /*
+        * Wait here for the sum of the old per-CPU counters to reach zero.
+        * Denoted by "Z".
+        */
+       rcu_try_flip_waitzero_state,
+
+       /*
+        * Wait here for each of the other CPUs to execute a memory barrier.
+        * This is necessary to ensure that these other CPUs really have
+        * completed executing their RCU read-side critical sections, despite
+        * their CPUs wildly reordering memory. Denoted by "M".
+        */
+       rcu_try_flip_waitmb_state,
+};
+
+struct rcu_ctrlblk {
+       spinlock_t      fliplock;       /* Protect state-machine transitions. */
+       long            completed;      /* Number of last completed batch. */
+       enum rcu_try_flip_states rcu_try_flip_state; /* The current state of
+                                                       the rcu state machine */
+};
+
+static DEFINE_PER_CPU(struct rcu_data, rcu_data);
+static struct rcu_ctrlblk rcu_ctrlblk = {
+       .fliplock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.fliplock),
+       .completed = 0,
+       .rcu_try_flip_state = rcu_try_flip_idle_state,
+};
+
+
+#ifdef CONFIG_RCU_TRACE
+static char *rcu_try_flip_state_names[] =
+       { "idle", "waitack", "waitzero", "waitmb" };
+#endif /* #ifdef CONFIG_RCU_TRACE */
+
+static cpumask_t rcu_cpu_online_map __read_mostly = CPU_MASK_NONE;
+
+/*
+ * Enum and per-CPU flag to determine when each CPU has seen
+ * the most recent counter flip.
+ */
+
+enum rcu_flip_flag_values {
+       rcu_flip_seen,          /* Steady/initial state, last flip seen. */
+                               /* Only GP detector can update. */
+       rcu_flipped             /* Flip just completed, need confirmation. */
+                               /* Only corresponding CPU can update. */
+};
+static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_flip_flag_values, rcu_flip_flag)
+                                                               = rcu_flip_seen;
+
+/*
+ * Enum and per-CPU flag to determine when each CPU has executed the
+ * needed memory barrier to fence in memory references from its last RCU
+ * read-side critical section in the just-completed grace period.
+ */
+
+enum rcu_mb_flag_values {
+       rcu_mb_done,            /* Steady/initial state, no mb()s required. */
+                               /* Only GP detector can update. */
+       rcu_mb_needed           /* Flip just completed, need an mb(). */
+                               /* Only corresponding CPU can update. */
+};
+static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_mb_flag_values, rcu_mb_flag)
+                                                               = rcu_mb_done;
+
+/*
+ * RCU_DATA_ME: find the current CPU's rcu_data structure.
+ * RCU_DATA_CPU: find the specified CPU's rcu_data structure.
+ */
+#define RCU_DATA_ME()          (&__get_cpu_var(rcu_data))
+#define RCU_DATA_CPU(cpu)      (&per_cpu(rcu_data, cpu))
+
+/*
+ * Helper macro for tracing when the appropriate rcu_data is not
+ * cached in a local variable, but where the CPU number is so cached.
+ */
+#define RCU_TRACE_CPU(f, cpu) RCU_TRACE(f, &(RCU_DATA_CPU(cpu)->trace));
+
+/*
+ * Helper macro for tracing when the appropriate rcu_data is not
+ * cached in a local variable.
+ */
+#define RCU_TRACE_ME(f) RCU_TRACE(f, &(RCU_DATA_ME()->trace));
+
+/*
+ * Helper macro for tracing when the appropriate rcu_data is pointed
+ * to by a local variable.
+ */
+#define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace));
+
+/*
+ * Return the number of RCU batches processed thus far.  Useful
+ * for debug and statistics.
+ */
+long rcu_batches_completed(void)
+{
+       return rcu_ctrlblk.completed;
+}
+EXPORT_SYMBOL_GPL(rcu_batches_completed);
+
+EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
+
+void __rcu_read_lock(void)
+{
+       int idx;
+       struct task_struct *t = current;
+       int nesting;
+
+       nesting = ACCESS_ONCE(t->rcu_read_lock_nesting);
+       if (nesting != 0) {
+
+               /* An earlier rcu_read_lock() covers us, just count it. */
+
+               t->rcu_read_lock_nesting = nesting + 1;
+
+       } else {
+               unsigned long flags;
+
+               /*
+                * We disable interrupts for the following reasons:
+                * - If we get scheduling clock interrupt here, and we
+                *   end up acking the counter flip, it's like a promise
+                *   that we will never increment the old counter again.
+                *   Thus we will break that promise if that
+                *   scheduling clock interrupt happens between the time
+                *   we pick the .completed field and the time that we
+                *   increment our counter.
+                *
+                * - We don't want to be preempted out here.
+                *
+                * NMIs can still occur, of course, and might themselves
+                * contain rcu_read_lock().
+                */
+
+               local_irq_save(flags);
+
+               /*
+                * Outermost nesting of rcu_read_lock(), so increment
+                * the current counter for the current CPU.  Use volatile
+                * casts to prevent the compiler from reordering.
+                */
+
+               idx = ACCESS_ONCE(rcu_ctrlblk.completed) & 0x1;
+               ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])++;
+
+               /*
+                * Now that the per-CPU counter has been incremented, we
+                * are protected from races with rcu_read_lock() invoked
+                * from NMI handlers on this CPU.  We can therefore safely
+                * increment the nesting counter, relieving further NMIs
+                * of the need to increment the per-CPU counter.
+                */
+
+               ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting + 1;
+
+               /*
+                * Now that we have preventing any NMIs from storing
+                * to the ->rcu_flipctr_idx, we can safely use it to
+                * remember which counter to decrement in the matching
+                * rcu_read_unlock().
+                */
+
+               ACCESS_ONCE(t->rcu_flipctr_idx) = idx;
+               local_irq_restore(flags);
+       }
+}
+EXPORT_SYMBOL_GPL(__rcu_read_lock);
+
+void __rcu_read_unlock(void)
+{
+       int idx;
+       struct task_struct *t = current;
+       int nesting;
+
+       nesting = ACCESS_ONCE(t->rcu_read_lock_nesting);
+       if (nesting > 1) {
+
+               /*
+                * We are still protected by the enclosing rcu_read_lock(),
+                * so simply decrement the counter.
+                */
+
+               t->rcu_read_lock_nesting = nesting - 1;
+
+       } else {
+               unsigned long flags;
+
+               /*
+                * Disable local interrupts to prevent the grace-period
+                * detection state machine from seeing us half-done.
+                * NMIs can still occur, of course, and might themselves
+                * contain rcu_read_lock() and rcu_read_unlock().
+                */
+
+               local_irq_save(flags);
+
+               /*
+                * Outermost nesting of rcu_read_unlock(), so we must
+                * decrement the current counter for the current CPU.
+                * This must be done carefully, because NMIs can
+                * occur at any point in this code, and any rcu_read_lock()
+                * and rcu_read_unlock() pairs in the NMI handlers
+                * must interact non-destructively with this code.
+                * Lots of volatile casts, and -very- careful ordering.
+                *
+                * Changes to this code, including this one, must be
+                * inspected, validated, and tested extremely carefully!!!
+                */
+
+               /*
+                * First, pick up the index.
+                */
+
+               idx = ACCESS_ONCE(t->rcu_flipctr_idx);
+
+               /*
+                * Now that we have fetched the counter index, it is
+                * safe to decrement the per-task RCU nesting counter.
+                * After this, any interrupts or NMIs will increment and
+                * decrement the per-CPU counters.
+                */
+               ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting - 1;
+
+               /*
+                * It is now safe to decrement this task's nesting count.
+                * NMIs that occur after this statement will route their
+                * rcu_read_lock() calls through this "else" clause, and
+                * will thus start incrementing the per-CPU counter on
+                * their own.  They will also clobber ->rcu_flipctr_idx,
+                * but that is OK, since we have already fetched it.
+                */
+
+               ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])--;
+               local_irq_restore(flags);
+       }
+}
+EXPORT_SYMBOL_GPL(__rcu_read_unlock);
+
+/*
+ * If a global counter flip has occurred since the last time that we
+ * advanced callbacks, advance them.  Hardware interrupts must be
+ * disabled when calling this function.
+ */
+static void __rcu_advance_callbacks(struct rcu_data *rdp)
+{
+       int cpu;
+       int i;
+       int wlc = 0;
+
+       if (rdp->completed != rcu_ctrlblk.completed) {
+               if (rdp->waitlist[GP_STAGES - 1] != NULL) {
+                       *rdp->donetail = rdp->waitlist[GP_STAGES - 1];
+                       rdp->donetail = rdp->waittail[GP_STAGES - 1];
+                       RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp);
+               }
+               for (i = GP_STAGES - 2; i >= 0; i--) {
+                       if (rdp->waitlist[i] != NULL) {
+                               rdp->waitlist[i + 1] = rdp->waitlist[i];
+                               rdp->waittail[i + 1] = rdp->waittail[i];
+                               wlc++;
+                       } else {
+                               rdp->waitlist[i + 1] = NULL;
+                               rdp->waittail[i + 1] =
+                                       &rdp->waitlist[i + 1];
+                       }
+               }
+               if (rdp->nextlist != NULL) {
+                       rdp->waitlist[0] = rdp->nextlist;
+                       rdp->waittail[0] = rdp->nexttail;
+                       wlc++;
+                       rdp->nextlist = NULL;
+                       rdp->nexttail = &rdp->nextlist;
+                       RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp);
+               } else {
+                       rdp->waitlist[0] = NULL;
+                       rdp->waittail[0] = &rdp->waitlist[0];
+               }
+               rdp->waitlistcount = wlc;
+               rdp->completed = rcu_ctrlblk.completed;
+       }
+
+       /*
+        * Check to see if this CPU needs to report that it has seen
+        * the most recent counter flip, thereby declaring that all
+        * subsequent rcu_read_lock() invocations will respect this flip.
+        */
+
+       cpu = raw_smp_processor_id();
+       if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) {
+               smp_mb();  /* Subsequent counter accesses must see new value */
+               per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen;
+               smp_mb();  /* Subsequent RCU read-side critical sections */
+                          /*  seen -after- acknowledgement. */
+       }
+}
+
+/*
+ * Get here when RCU is idle.  Decide whether we need to
+ * move out of idle state, and return non-zero if so.
+ * "Straightforward" approach for the moment, might later
+ * use callback-list lengths, grace-period duration, or
+ * some such to determine when to exit idle state.
+ * Might also need a pre-idle test that does not acquire
+ * the lock, but let's get the simple case working first...
+ */
+
+static int
+rcu_try_flip_idle(void)
+{
+       int cpu;
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_i1);
+       if (!rcu_pending(smp_processor_id())) {
+               RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1);
+               return 0;
+       }
+
+       /*
+        * Do the flip.
+        */
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_g1);
+       rcu_ctrlblk.completed++;  /* stands in for rcu_try_flip_g2 */
+
+       /*
+        * Need a memory barrier so that other CPUs see the new
+        * counter value before they see the subsequent change of all
+        * the rcu_flip_flag instances to rcu_flipped.
+        */
+
+       smp_mb();       /* see above block comment. */
+
+       /* Now ask each CPU for acknowledgement of the flip. */
+
+       for_each_cpu_mask(cpu, rcu_cpu_online_map)
+               per_cpu(rcu_flip_flag, cpu) = rcu_flipped;
+
+       return 1;
+}
+
+/*
+ * Wait for CPUs to acknowledge the flip.
+ */
+
+static int
+rcu_try_flip_waitack(void)
+{
+       int cpu;
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_a1);
+       for_each_cpu_mask(cpu, rcu_cpu_online_map)
+               if (per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) {
+                       RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1);
+                       return 0;
+               }
+
+       /*
+        * Make sure our checks above don't bleed into subsequent
+        * waiting for the sum of the counters to reach zero.
+        */
+
+       smp_mb();       /* see above block comment. */
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_a2);
+       return 1;
+}
+
+/*
+ * Wait for collective ``last'' counter to reach zero,
+ * then tell all CPUs to do an end-of-grace-period memory barrier.
+ */
+
+static int
+rcu_try_flip_waitzero(void)
+{
+       int cpu;
+       int lastidx = !(rcu_ctrlblk.completed & 0x1);
+       int sum = 0;
+
+       /* Check to see if the sum of the "last" counters is zero. */
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_z1);
+       for_each_cpu_mask(cpu, rcu_cpu_online_map)
+               sum += RCU_DATA_CPU(cpu)->rcu_flipctr[lastidx];
+       if (sum != 0) {
+               RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1);
+               return 0;
+       }
+
+       /*
+        * This ensures that the other CPUs see the call for
+        * memory barriers -after- the sum to zero has been
+        * detected here
+        */
+       smp_mb();  /*  ^^^^^^^^^^^^ */
+
+       /* Call for a memory barrier from each CPU. */
+       for_each_cpu_mask(cpu, rcu_cpu_online_map)
+               per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed;
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_z2);
+       return 1;
+}
+
+/*
+ * Wait for all CPUs to do their end-of-grace-period memory barrier.
+ * Return 0 once all CPUs have done so.
+ */
+
+static int
+rcu_try_flip_waitmb(void)
+{
+       int cpu;
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_m1);
+       for_each_cpu_mask(cpu, rcu_cpu_online_map)
+               if (per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) {
+                       RCU_TRACE_ME(rcupreempt_trace_try_flip_me1);
+                       return 0;
+               }
+
+       smp_mb(); /* Ensure that the above checks precede any following flip. */
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_m2);
+       return 1;
+}
+
+/*
+ * Attempt a single flip of the counters.  Remember, a single flip does
+ * -not- constitute a grace period.  Instead, the interval between
+ * at least GP_STAGES consecutive flips is a grace period.
+ *
+ * If anyone is nuts enough to run this CONFIG_PREEMPT_RCU implementation
+ * on a large SMP, they might want to use a hierarchical organization of
+ * the per-CPU-counter pairs.
+ */
+static void rcu_try_flip(void)
+{
+       unsigned long flags;
+
+       RCU_TRACE_ME(rcupreempt_trace_try_flip_1);
+       if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, flags))) {
+               RCU_TRACE_ME(rcupreempt_trace_try_flip_e1);
+               return;
+       }
+
+       /*
+        * Take the next transition(s) through the RCU grace-period
+        * flip-counter state machine.
+        */
+
+       switch (rcu_ctrlblk.rcu_try_flip_state) {
+       case rcu_try_flip_idle_state:
+               if (rcu_try_flip_idle())
+                       rcu_ctrlblk.rcu_try_flip_state =
+                               rcu_try_flip_waitack_state;
+               break;
+       case rcu_try_flip_waitack_state:
+               if (rcu_try_flip_waitack())
+                       rcu_ctrlblk.rcu_try_flip_state =
+                               rcu_try_flip_waitzero_state;
+               break;
+       case rcu_try_flip_waitzero_state:
+               if (rcu_try_flip_waitzero())
+                       rcu_ctrlblk.rcu_try_flip_state =
+                               rcu_try_flip_waitmb_state;
+               break;
+       case rcu_try_flip_waitmb_state:
+               if (rcu_try_flip_waitmb())
+                       rcu_ctrlblk.rcu_try_flip_state =
+                               rcu_try_flip_idle_state;
+       }
+       spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
+}
+
+/*
+ * Check to see if this CPU needs to do a memory barrier in order to
+ * ensure that any prior RCU read-side critical sections have committed
+ * their counter manipulations and critical-section memory references
+ * before declaring the grace period to be completed.
+ */
+static void rcu_check_mb(int cpu)
+{
+       if (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed) {
+               smp_mb();  /* Ensure RCU read-side accesses are visible. */
+               per_cpu(rcu_mb_flag, cpu) = rcu_mb_done;
+       }
+}
+
+void rcu_check_callbacks(int cpu, int user)
+{
+       unsigned long flags;
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+
+       rcu_check_mb(cpu);
+       if (rcu_ctrlblk.completed == rdp->completed)
+               rcu_try_flip();
+       spin_lock_irqsave(&rdp->lock, flags);
+       RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp);
+       __rcu_advance_callbacks(rdp);
+       if (rdp->donelist == NULL) {
+               spin_unlock_irqrestore(&rdp->lock, flags);
+       } else {
+               spin_unlock_irqrestore(&rdp->lock, flags);
+               raise_softirq(RCU_SOFTIRQ);
+       }
+}
+
+/*
+ * Needed by dynticks, to make sure all RCU processing has finished
+ * when we go idle:
+ */
+void rcu_advance_callbacks(int cpu, int user)
+{
+       unsigned long flags;
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+
+       if (rcu_ctrlblk.completed == rdp->completed) {
+               rcu_try_flip();
+               if (rcu_ctrlblk.completed == rdp->completed)
+                       return;
+       }
+       spin_lock_irqsave(&rdp->lock, flags);
+       RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp);
+       __rcu_advance_callbacks(rdp);
+       spin_unlock_irqrestore(&rdp->lock, flags);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+#define rcu_offline_cpu_enqueue(srclist, srctail, dstlist, dsttail) do { \
+               *dsttail = srclist; \
+               if (srclist != NULL) { \
+                       dsttail = srctail; \
+                       srclist = NULL; \
+                       srctail = &srclist;\
+               } \
+       } while (0)
+
+void rcu_offline_cpu(int cpu)
+{
+       int i;
+       struct rcu_head *list = NULL;
+       unsigned long flags;
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+       struct rcu_head **tail = &list;
+
+       /*
+        * Remove all callbacks from the newly dead CPU, retaining order.
+        * Otherwise rcu_barrier() will fail
+        */
+
+       spin_lock_irqsave(&rdp->lock, flags);
+       rcu_offline_cpu_enqueue(rdp->donelist, rdp->donetail, list, tail);
+       for (i = GP_STAGES - 1; i >= 0; i--)
+               rcu_offline_cpu_enqueue(rdp->waitlist[i], rdp->waittail[i],
+                                               list, tail);
+       rcu_offline_cpu_enqueue(rdp->nextlist, rdp->nexttail, list, tail);
+       spin_unlock_irqrestore(&rdp->lock, flags);
+       rdp->waitlistcount = 0;
+
+       /* Disengage the newly dead CPU from the grace-period computation. */
+
+       spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags);
+       rcu_check_mb(cpu);
+       if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) {
+               smp_mb();  /* Subsequent counter accesses must see new value */
+               per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen;
+               smp_mb();  /* Subsequent RCU read-side critical sections */
+                          /*  seen -after- acknowledgement. */
+       }
+
+       RCU_DATA_ME()->rcu_flipctr[0] += RCU_DATA_CPU(cpu)->rcu_flipctr[0];
+       RCU_DATA_ME()->rcu_flipctr[1] += RCU_DATA_CPU(cpu)->rcu_flipctr[1];
+
+       RCU_DATA_CPU(cpu)->rcu_flipctr[0] = 0;
+       RCU_DATA_CPU(cpu)->rcu_flipctr[1] = 0;
+
+       cpu_clear(cpu, rcu_cpu_online_map);
+
+       spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
+
+       /*
+        * Place the removed callbacks on the current CPU's queue.
+        * Make them all start a new grace period: simple approach,
+        * in theory could starve a given set of callbacks, but
+        * you would need to be doing some serious CPU hotplugging
+        * to make this happen.  If this becomes a problem, adding
+        * a synchronize_rcu() to the hotplug path would be a simple
+        * fix.
+        */
+
+       rdp = RCU_DATA_ME();
+       spin_lock_irqsave(&rdp->lock, flags);
+       *rdp->nexttail = list;
+       if (list)
+               rdp->nexttail = tail;
+       spin_unlock_irqrestore(&rdp->lock, flags);
+}
+
+void __devinit rcu_online_cpu(int cpu)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags);
+       cpu_set(cpu, rcu_cpu_online_map);
+       spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
+}
+
+#else /* #ifdef CONFIG_HOTPLUG_CPU */
+
+void rcu_offline_cpu(int cpu)
+{
+}
+
+void __devinit rcu_online_cpu(int cpu)
+{
+}
+
+#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
+
+static void rcu_process_callbacks(struct softirq_action *unused)
+{
+       unsigned long flags;
+       struct rcu_head *next, *list;
+       struct rcu_data *rdp = RCU_DATA_ME();
+
+       spin_lock_irqsave(&rdp->lock, flags);
+       list = rdp->donelist;
+       if (list == NULL) {
+               spin_unlock_irqrestore(&rdp->lock, flags);
+               return;
+       }
+       rdp->donelist = NULL;
+       rdp->donetail = &rdp->donelist;
+       RCU_TRACE_RDP(rcupreempt_trace_done_remove, rdp);
+       spin_unlock_irqrestore(&rdp->lock, flags);
+       while (list) {
+               next = list->next;
+               list->func(list);
+               list = next;
+               RCU_TRACE_ME(rcupreempt_trace_invoke);
+       }
+}
+
+void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+
+       head->func = func;
+       head->next = NULL;
+       local_irq_save(flags);
+       rdp = RCU_DATA_ME();
+       spin_lock(&rdp->lock);
+       __rcu_advance_callbacks(rdp);
+       *rdp->nexttail = head;
+       rdp->nexttail = &head->next;
+       RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp);
+       spin_unlock(&rdp->lock);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(call_rcu);
+
+/*
+ * Wait until all currently running preempt_disable() code segments
+ * (including hardware-irq-disable segments) complete.  Note that
+ * in -rt this does -not- necessarily result in all currently executing
+ * interrupt -handlers- having completed.
+ */
+void __synchronize_sched(void)
+{
+       cpumask_t oldmask;
+       int cpu;
+
+       if (sched_getaffinity(0, &oldmask) < 0)
+               oldmask = cpu_possible_map;
+       for_each_online_cpu(cpu) {
+               sched_setaffinity(0, cpumask_of_cpu(cpu));
+               schedule();
+       }
+       sched_setaffinity(0, oldmask);
+}
+EXPORT_SYMBOL_GPL(__synchronize_sched);
+
+/*
+ * Check to see if any future RCU-related work will need to be done
+ * by the current CPU, even if none need be done immediately, returning
+ * 1 if so.  Assumes that notifiers would take care of handling any
+ * outstanding requests from the RCU core.
+ *
+ * This function is part of the RCU implementation; it is -not-
+ * an exported member of the RCU API.
+ */
+int rcu_needs_cpu(int cpu)
+{
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+
+       return (rdp->donelist != NULL ||
+               !!rdp->waitlistcount ||
+               rdp->nextlist != NULL);
+}
+
+int rcu_pending(int cpu)
+{
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+
+       /* The CPU has at least one callback queued somewhere. */
+
+       if (rdp->donelist != NULL ||
+           !!rdp->waitlistcount ||
+           rdp->nextlist != NULL)
+               return 1;
+
+       /* The RCU core needs an acknowledgement from this CPU. */
+
+       if ((per_cpu(rcu_flip_flag, cpu) == rcu_flipped) ||
+           (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed))
+               return 1;
+
+       /* This CPU has fallen behind the global grace-period number. */
+
+       if (rdp->completed != rcu_ctrlblk.completed)
+               return 1;
+
+       /* Nothing needed from this CPU. */
+
+       return 0;
+}
+
+static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
+                               unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               rcu_online_cpu(cpu);
+               break;
+       case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               rcu_offline_cpu(cpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata rcu_nb = {
+       .notifier_call = rcu_cpu_notify,
+};
+
+void __init __rcu_init(void)
+{
+       int cpu;
+       int i;
+       struct rcu_data *rdp;
+
+       printk(KERN_NOTICE "Preemptible RCU implementation.\n");
+       for_each_possible_cpu(cpu) {
+               rdp = RCU_DATA_CPU(cpu);
+               spin_lock_init(&rdp->lock);
+               rdp->completed = 0;
+               rdp->waitlistcount = 0;
+               rdp->nextlist = NULL;
+               rdp->nexttail = &rdp->nextlist;
+               for (i = 0; i < GP_STAGES; i++) {
+                       rdp->waitlist[i] = NULL;
+                       rdp->waittail[i] = &rdp->waitlist[i];
+               }
+               rdp->donelist = NULL;
+               rdp->donetail = &rdp->donelist;
+               rdp->rcu_flipctr[0] = 0;
+               rdp->rcu_flipctr[1] = 0;
+       }
+       register_cpu_notifier(&rcu_nb);
+
+       /*
+        * We don't need protection against CPU-Hotplug here
+        * since
+        * a) If a CPU comes online while we are iterating over the
+        *    cpu_online_map below, we would only end up making a
+        *    duplicate call to rcu_online_cpu() which sets the corresponding
+        *    CPU's mask in the rcu_cpu_online_map.
+        *
+        * b) A CPU cannot go offline at this point in time since the user
+        *    does not have access to the sysfs interface, nor do we
+        *    suspend the system.
+        */
+       for_each_online_cpu(cpu)
+               rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long) cpu);
+
+       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL);
+}
+
+/*
+ * Deprecated, use synchronize_rcu() or synchronize_sched() instead.
+ */
+void synchronize_kernel(void)
+{
+       synchronize_rcu();
+}
+
+#ifdef CONFIG_RCU_TRACE
+long *rcupreempt_flipctr(int cpu)
+{
+       return &RCU_DATA_CPU(cpu)->rcu_flipctr[0];
+}
+EXPORT_SYMBOL_GPL(rcupreempt_flipctr);
+
+int rcupreempt_flip_flag(int cpu)
+{
+       return per_cpu(rcu_flip_flag, cpu);
+}
+EXPORT_SYMBOL_GPL(rcupreempt_flip_flag);
+
+int rcupreempt_mb_flag(int cpu)
+{
+       return per_cpu(rcu_mb_flag, cpu);
+}
+EXPORT_SYMBOL_GPL(rcupreempt_mb_flag);
+
+char *rcupreempt_try_flip_state_name(void)
+{
+       return rcu_try_flip_state_names[rcu_ctrlblk.rcu_try_flip_state];
+}
+EXPORT_SYMBOL_GPL(rcupreempt_try_flip_state_name);
+
+struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu)
+{
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+
+       return &rdp->trace;
+}
+EXPORT_SYMBOL_GPL(rcupreempt_trace_cpu);
+
+#endif /* #ifdef RCU_TRACE */
diff --git a/kernel/rcupreempt_trace.c b/kernel/rcupreempt_trace.c
new file mode 100644 (file)
index 0000000..49ac494
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Read-Copy Update tracing for realtime implementation
+ *
+ * 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.
+ *
+ * Copyright IBM Corporation, 2006
+ *
+ * Papers:  http://www.rdrop.com/users/paulmck/RCU
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *             Documentation/RCU/ *.txt
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/rcupdate.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/rcupreempt_trace.h>
+#include <linux/debugfs.h>
+
+static struct mutex rcupreempt_trace_mutex;
+static char *rcupreempt_trace_buf;
+#define RCUPREEMPT_TRACE_BUF_SIZE 4096
+
+void rcupreempt_trace_move2done(struct rcupreempt_trace *trace)
+{
+       trace->done_length += trace->wait_length;
+       trace->done_add += trace->wait_length;
+       trace->wait_length = 0;
+}
+void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace)
+{
+       trace->wait_length += trace->next_length;
+       trace->wait_add += trace->next_length;
+       trace->next_length = 0;
+}
+void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace)
+{
+       atomic_inc(&trace->rcu_try_flip_1);
+}
+void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace)
+{
+       atomic_inc(&trace->rcu_try_flip_e1);
+}
+void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_i1++;
+}
+void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_ie1++;
+}
+void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_g1++;
+}
+void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_a1++;
+}
+void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_ae1++;
+}
+void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_a2++;
+}
+void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_z1++;
+}
+void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_ze1++;
+}
+void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_z2++;
+}
+void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_m1++;
+}
+void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_me1++;
+}
+void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace)
+{
+       trace->rcu_try_flip_m2++;
+}
+void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace)
+{
+       trace->rcu_check_callbacks++;
+}
+void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace)
+{
+       trace->done_remove += trace->done_length;
+       trace->done_length = 0;
+}
+void rcupreempt_trace_invoke(struct rcupreempt_trace *trace)
+{
+       atomic_inc(&trace->done_invoked);
+}
+void rcupreempt_trace_next_add(struct rcupreempt_trace *trace)
+{
+       trace->next_add++;
+       trace->next_length++;
+}
+
+static void rcupreempt_trace_sum(struct rcupreempt_trace *sp)
+{
+       struct rcupreempt_trace *cp;
+       int cpu;
+
+       memset(sp, 0, sizeof(*sp));
+       for_each_possible_cpu(cpu) {
+               cp = rcupreempt_trace_cpu(cpu);
+               sp->next_length += cp->next_length;
+               sp->next_add += cp->next_add;
+               sp->wait_length += cp->wait_length;
+               sp->wait_add += cp->wait_add;
+               sp->done_length += cp->done_length;
+               sp->done_add += cp->done_add;
+               sp->done_remove += cp->done_remove;
+               atomic_set(&sp->done_invoked, atomic_read(&cp->done_invoked));
+               sp->rcu_check_callbacks += cp->rcu_check_callbacks;
+               atomic_set(&sp->rcu_try_flip_1,
+                          atomic_read(&cp->rcu_try_flip_1));
+               atomic_set(&sp->rcu_try_flip_e1,
+                          atomic_read(&cp->rcu_try_flip_e1));
+               sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1;
+               sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1;
+               sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1;
+               sp->rcu_try_flip_a1 += cp->rcu_try_flip_a1;
+               sp->rcu_try_flip_ae1 += cp->rcu_try_flip_ae1;
+               sp->rcu_try_flip_a2 += cp->rcu_try_flip_a2;
+               sp->rcu_try_flip_z1 += cp->rcu_try_flip_z1;
+               sp->rcu_try_flip_ze1 += cp->rcu_try_flip_ze1;
+               sp->rcu_try_flip_z2 += cp->rcu_try_flip_z2;
+               sp->rcu_try_flip_m1 += cp->rcu_try_flip_m1;
+               sp->rcu_try_flip_me1 += cp->rcu_try_flip_me1;
+               sp->rcu_try_flip_m2 += cp->rcu_try_flip_m2;
+       }
+}
+
+static ssize_t rcustats_read(struct file *filp, char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       struct rcupreempt_trace trace;
+       ssize_t bcount;
+       int cnt = 0;
+
+       rcupreempt_trace_sum(&trace);
+       mutex_lock(&rcupreempt_trace_mutex);
+       snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt,
+                "ggp=%ld rcc=%ld\n",
+                rcu_batches_completed(),
+                trace.rcu_check_callbacks);
+       snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt,
+                "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n"
+                "1=%d e1=%d i1=%ld ie1=%ld g1=%ld a1=%ld ae1=%ld a2=%ld\n"
+                "z1=%ld ze1=%ld z2=%ld m1=%ld me1=%ld m2=%ld\n",
+
+                trace.next_add, trace.next_length,
+                trace.wait_add, trace.wait_length,
+                trace.done_add, trace.done_length,
+                trace.done_remove, atomic_read(&trace.done_invoked),
+                atomic_read(&trace.rcu_try_flip_1),
+                atomic_read(&trace.rcu_try_flip_e1),
+                trace.rcu_try_flip_i1, trace.rcu_try_flip_ie1,
+                trace.rcu_try_flip_g1,
+                trace.rcu_try_flip_a1, trace.rcu_try_flip_ae1,
+                        trace.rcu_try_flip_a2,
+                trace.rcu_try_flip_z1, trace.rcu_try_flip_ze1,
+                        trace.rcu_try_flip_z2,
+                trace.rcu_try_flip_m1, trace.rcu_try_flip_me1,
+                       trace.rcu_try_flip_m2);
+       bcount = simple_read_from_buffer(buffer, count, ppos,
+                       rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
+       mutex_unlock(&rcupreempt_trace_mutex);
+       return bcount;
+}
+
+static ssize_t rcugp_read(struct file *filp, char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       long oldgp = rcu_batches_completed();
+       ssize_t bcount;
+
+       mutex_lock(&rcupreempt_trace_mutex);
+       synchronize_rcu();
+       snprintf(rcupreempt_trace_buf, RCUPREEMPT_TRACE_BUF_SIZE,
+               "oldggp=%ld  newggp=%ld\n", oldgp, rcu_batches_completed());
+       bcount = simple_read_from_buffer(buffer, count, ppos,
+                       rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
+       mutex_unlock(&rcupreempt_trace_mutex);
+       return bcount;
+}
+
+static ssize_t rcuctrs_read(struct file *filp, char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       int cnt = 0;
+       int cpu;
+       int f = rcu_batches_completed() & 0x1;
+       ssize_t bcount;
+
+       mutex_lock(&rcupreempt_trace_mutex);
+
+       cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE,
+                               "CPU last cur F M\n");
+       for_each_online_cpu(cpu) {
+               long *flipctr = rcupreempt_flipctr(cpu);
+               cnt += snprintf(&rcupreempt_trace_buf[cnt],
+                               RCUPREEMPT_TRACE_BUF_SIZE - cnt,
+                                       "%3d %4ld %3ld %d %d\n",
+                              cpu,
+                              flipctr[!f],
+                              flipctr[f],
+                              rcupreempt_flip_flag(cpu),
+                              rcupreempt_mb_flag(cpu));
+       }
+       cnt += snprintf(&rcupreempt_trace_buf[cnt],
+                       RCUPREEMPT_TRACE_BUF_SIZE - cnt,
+                       "ggp = %ld, state = %s\n",
+                       rcu_batches_completed(),
+                       rcupreempt_try_flip_state_name());
+       cnt += snprintf(&rcupreempt_trace_buf[cnt],
+                       RCUPREEMPT_TRACE_BUF_SIZE - cnt,
+                       "\n");
+       bcount = simple_read_from_buffer(buffer, count, ppos,
+                       rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
+       mutex_unlock(&rcupreempt_trace_mutex);
+       return bcount;
+}
+
+static struct file_operations rcustats_fops = {
+       .owner = THIS_MODULE,
+       .read = rcustats_read,
+};
+
+static struct file_operations rcugp_fops = {
+       .owner = THIS_MODULE,
+       .read = rcugp_read,
+};
+
+static struct file_operations rcuctrs_fops = {
+       .owner = THIS_MODULE,
+       .read = rcuctrs_read,
+};
+
+static struct dentry *rcudir, *statdir, *ctrsdir, *gpdir;
+static int rcupreempt_debugfs_init(void)
+{
+       rcudir = debugfs_create_dir("rcu", NULL);
+       if (!rcudir)
+               goto out;
+       statdir = debugfs_create_file("rcustats", 0444, rcudir,
+                                               NULL, &rcustats_fops);
+       if (!statdir)
+               goto free_out;
+
+       gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
+       if (!gpdir)
+               goto free_out;
+
+       ctrsdir = debugfs_create_file("rcuctrs", 0444, rcudir,
+                                               NULL, &rcuctrs_fops);
+       if (!ctrsdir)
+               goto free_out;
+       return 0;
+free_out:
+       if (statdir)
+               debugfs_remove(statdir);
+       if (gpdir)
+               debugfs_remove(gpdir);
+       debugfs_remove(rcudir);
+out:
+       return 1;
+}
+
+static int __init rcupreempt_trace_init(void)
+{
+       mutex_init(&rcupreempt_trace_mutex);
+       rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL);
+       if (!rcupreempt_trace_buf)
+               return 1;
+       return rcupreempt_debugfs_init();
+}
+
+static void __exit rcupreempt_trace_cleanup(void)
+{
+       debugfs_remove(statdir);
+       debugfs_remove(gpdir);
+       debugfs_remove(ctrsdir);
+       debugfs_remove(rcudir);
+       kfree(rcupreempt_trace_buf);
+}
+
+
+module_init(rcupreempt_trace_init);
+module_exit(rcupreempt_trace_cleanup);
index c3e165c2318f16657023d7693dd6a77762945861..fd599829e72a5d49a5852272ba234be8c38accaf 100644 (file)
@@ -726,11 +726,11 @@ static void rcu_torture_shuffle_tasks(void)
        cpumask_t tmp_mask = CPU_MASK_ALL;
        int i;
 
-       lock_cpu_hotplug();
+       get_online_cpus();
 
        /* No point in shuffling if there is only one online CPU (ex: UP) */
        if (num_online_cpus() == 1) {
-               unlock_cpu_hotplug();
+               put_online_cpus();
                return;
        }
 
@@ -762,7 +762,7 @@ static void rcu_torture_shuffle_tasks(void)
        else
                rcu_idle_cpu--;
 
-       unlock_cpu_hotplug();
+       put_online_cpus();
 }
 
 /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
index e3055ba6915978c4290492ef16cacb3f3a844c61..092e4c620af908410a30ef3ee9ece43df72dcb84 100644 (file)
@@ -394,7 +394,7 @@ static SYSDEV_ATTR(status, 0600, sysfs_test_status, NULL);
 static SYSDEV_ATTR(command, 0600, NULL, sysfs_test_command);
 
 static struct sysdev_class rttest_sysclass = {
-       set_kset_name("rttest"),
+       .name = "rttest",
 };
 
 static int init_test_thread(int id)
index 3df84ea6aba91972ab78af7846392051422264b4..524285e46fa788e7e0a04612a611965b7650a2d5 100644 (file)
@@ -22,6 +22,8 @@
  *              by Peter Williams
  *  2007-05-06  Interactivity improvements to CFS by Mike Galbraith
  *  2007-07-01  Group scheduling enhancements by Srivatsa Vaddagiri
+ *  2007-11-29  RT balancing improvements by Steven Rostedt, Gregory Haskins,
+ *              Thomas Gleixner, Mike Kravetz
  */
 
 #include <linux/mm.h>
@@ -63,6 +65,7 @@
 #include <linux/reciprocal_div.h>
 #include <linux/unistd.h>
 #include <linux/pagemap.h>
+#include <linux/hrtimer.h>
 
 #include <asm/tlb.h>
 #include <asm/irq_regs.h>
@@ -96,10 +99,9 @@ unsigned long long __attribute__((weak)) sched_clock(void)
 #define MAX_USER_PRIO          (USER_PRIO(MAX_PRIO))
 
 /*
- * Some helpers for converting nanosecond timing to jiffy resolution
+ * Helpers for converting nanosecond timing to jiffy resolution
  */
 #define NS_TO_JIFFIES(TIME)    ((unsigned long)(TIME) / (NSEC_PER_SEC / HZ))
-#define JIFFIES_TO_NS(TIME)    ((TIME) * (NSEC_PER_SEC / HZ))
 
 #define NICE_0_LOAD            SCHED_LOAD_SCALE
 #define NICE_0_SHIFT           SCHED_LOAD_SHIFT
@@ -159,6 +161,8 @@ struct rt_prio_array {
 
 struct cfs_rq;
 
+static LIST_HEAD(task_groups);
+
 /* task group related information */
 struct task_group {
 #ifdef CONFIG_FAIR_CGROUP_SCHED
@@ -168,10 +172,50 @@ struct task_group {
        struct sched_entity **se;
        /* runqueue "owned" by this group on each cpu */
        struct cfs_rq **cfs_rq;
+
+       struct sched_rt_entity **rt_se;
+       struct rt_rq **rt_rq;
+
+       unsigned int rt_ratio;
+
+       /*
+        * shares assigned to a task group governs how much of cpu bandwidth
+        * is allocated to the group. The more shares a group has, the more is
+        * the cpu bandwidth allocated to it.
+        *
+        * For ex, lets say that there are three task groups, A, B and C which
+        * have been assigned shares 1000, 2000 and 3000 respectively. Then,
+        * cpu bandwidth allocated by the scheduler to task groups A, B and C
+        * should be:
+        *
+        *      Bw(A) = 1000/(1000+2000+3000) * 100 = 16.66%
+        *      Bw(B) = 2000/(1000+2000+3000) * 100 = 33.33%
+        *      Bw(C) = 3000/(1000+2000+3000) * 100 = 50%
+        *
+        * The weight assigned to a task group's schedulable entities on every
+        * cpu (task_group.se[a_cpu]->load.weight) is derived from the task
+        * group's shares. For ex: lets say that task group A has been
+        * assigned shares of 1000 and there are two CPUs in a system. Then,
+        *
+        *  tg_A->se[0]->load.weight = tg_A->se[1]->load.weight = 1000;
+        *
+        * Note: It's not necessary that each of a task's group schedulable
+        *       entity have the same weight on all CPUs. If the group
+        *       has 2 of its tasks on CPU0 and 1 task on CPU1, then a
+        *       better distribution of weight could be:
+        *
+        *      tg_A->se[0]->load.weight = 2/3 * 2000 = 1333
+        *      tg_A->se[1]->load.weight = 1/2 * 2000 =  667
+        *
+        * rebalance_shares() is responsible for distributing the shares of a
+        * task groups like this among the group's schedulable entities across
+        * cpus.
+        *
+        */
        unsigned long shares;
-       /* spinlock to serialize modification to shares */
-       spinlock_t lock;
+
        struct rcu_head rcu;
+       struct list_head list;
 };
 
 /* Default task group's sched entity on each cpu */
@@ -179,24 +223,51 @@ static DEFINE_PER_CPU(struct sched_entity, init_sched_entity);
 /* Default task group's cfs_rq on each cpu */
 static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp;
 
+static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity);
+static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp;
+
 static struct sched_entity *init_sched_entity_p[NR_CPUS];
 static struct cfs_rq *init_cfs_rq_p[NR_CPUS];
 
+static struct sched_rt_entity *init_sched_rt_entity_p[NR_CPUS];
+static struct rt_rq *init_rt_rq_p[NR_CPUS];
+
+/* task_group_mutex serializes add/remove of task groups and also changes to
+ * a task group's cpu shares.
+ */
+static DEFINE_MUTEX(task_group_mutex);
+
+/* doms_cur_mutex serializes access to doms_cur[] array */
+static DEFINE_MUTEX(doms_cur_mutex);
+
+#ifdef CONFIG_SMP
+/* kernel thread that runs rebalance_shares() periodically */
+static struct task_struct *lb_monitor_task;
+static int load_balance_monitor(void *unused);
+#endif
+
+static void set_se_shares(struct sched_entity *se, unsigned long shares);
+
 /* Default task group.
  *     Every task in system belong to this group at bootup.
  */
 struct task_group init_task_group = {
-       .se     = init_sched_entity_p,
+       .se     = init_sched_entity_p,
        .cfs_rq = init_cfs_rq_p,
+
+       .rt_se  = init_sched_rt_entity_p,
+       .rt_rq  = init_rt_rq_p,
 };
 
 #ifdef CONFIG_FAIR_USER_SCHED
-# define INIT_TASK_GRP_LOAD    2*NICE_0_LOAD
+# define INIT_TASK_GROUP_LOAD  (2*NICE_0_LOAD)
 #else
-# define INIT_TASK_GRP_LOAD    NICE_0_LOAD
+# define INIT_TASK_GROUP_LOAD  NICE_0_LOAD
 #endif
 
-static int init_task_group_load = INIT_TASK_GRP_LOAD;
+#define MIN_GROUP_SHARES       2
+
+static int init_task_group_load = INIT_TASK_GROUP_LOAD;
 
 /* return group to which a task belongs */
 static inline struct task_group *task_group(struct task_struct *p)
@@ -215,15 +286,42 @@ static inline struct task_group *task_group(struct task_struct *p)
 }
 
 /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
-static inline void set_task_cfs_rq(struct task_struct *p, unsigned int cpu)
+static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
 {
        p->se.cfs_rq = task_group(p)->cfs_rq[cpu];
        p->se.parent = task_group(p)->se[cpu];
+
+       p->rt.rt_rq  = task_group(p)->rt_rq[cpu];
+       p->rt.parent = task_group(p)->rt_se[cpu];
+}
+
+static inline void lock_task_group_list(void)
+{
+       mutex_lock(&task_group_mutex);
+}
+
+static inline void unlock_task_group_list(void)
+{
+       mutex_unlock(&task_group_mutex);
+}
+
+static inline void lock_doms_cur(void)
+{
+       mutex_lock(&doms_cur_mutex);
+}
+
+static inline void unlock_doms_cur(void)
+{
+       mutex_unlock(&doms_cur_mutex);
 }
 
 #else
 
-static inline void set_task_cfs_rq(struct task_struct *p, unsigned int cpu) { }
+static inline void set_task_rq(struct task_struct *p, unsigned int cpu) { }
+static inline void lock_task_group_list(void) { }
+static inline void unlock_task_group_list(void) { }
+static inline void lock_doms_cur(void) { }
+static inline void unlock_doms_cur(void) { }
 
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
@@ -264,10 +362,56 @@ struct cfs_rq {
 /* Real-Time classes' related field in a runqueue: */
 struct rt_rq {
        struct rt_prio_array active;
-       int rt_load_balance_idx;
-       struct list_head *rt_load_balance_head, *rt_load_balance_curr;
+       unsigned long rt_nr_running;
+#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED
+       int highest_prio; /* highest queued rt task prio */
+#endif
+#ifdef CONFIG_SMP
+       unsigned long rt_nr_migratory;
+       int overloaded;
+#endif
+       int rt_throttled;
+       u64 rt_time;
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       struct rq *rq;
+       struct list_head leaf_rt_rq_list;
+       struct task_group *tg;
+       struct sched_rt_entity *rt_se;
+#endif
 };
 
+#ifdef CONFIG_SMP
+
+/*
+ * We add the notion of a root-domain which will be used to define per-domain
+ * variables. Each exclusive cpuset essentially defines an island domain by
+ * fully partitioning the member cpus from any other cpuset. Whenever a new
+ * exclusive cpuset is created, we also create and attach a new root-domain
+ * object.
+ *
+ */
+struct root_domain {
+       atomic_t refcount;
+       cpumask_t span;
+       cpumask_t online;
+
+       /*
+        * The "RT overload" flag: it gets set if a CPU has more than
+        * one runnable RT task.
+        */
+       cpumask_t rto_mask;
+       atomic_t rto_count;
+};
+
+/*
+ * By default the system creates a single root-domain with all cpus as
+ * members (mimicking the global state we have today).
+ */
+static struct root_domain def_root_domain;
+
+#endif
+
 /*
  * This is the main, per-CPU runqueue data structure.
  *
@@ -296,11 +440,15 @@ struct rq {
        u64 nr_switches;
 
        struct cfs_rq cfs;
+       struct rt_rq rt;
+       u64 rt_period_expire;
+       int rt_throttled;
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
        /* list of leaf cfs_rq on this cpu: */
        struct list_head leaf_cfs_rq_list;
+       struct list_head leaf_rt_rq_list;
 #endif
-       struct rt_rq rt;
 
        /*
         * This is part of a global counter where only the total sum
@@ -317,7 +465,7 @@ struct rq {
        u64 clock, prev_clock_raw;
        s64 clock_max_delta;
 
-       unsigned int clock_warps, clock_overflows;
+       unsigned int clock_warps, clock_overflows, clock_underflows;
        u64 idle_clock;
        unsigned int clock_deep_idle_events;
        u64 tick_timestamp;
@@ -325,6 +473,7 @@ struct rq {
        atomic_t nr_iowait;
 
 #ifdef CONFIG_SMP
+       struct root_domain *rd;
        struct sched_domain *sd;
 
        /* For active balancing */
@@ -337,6 +486,12 @@ struct rq {
        struct list_head migration_queue;
 #endif
 
+#ifdef CONFIG_SCHED_HRTICK
+       unsigned long hrtick_flags;
+       ktime_t hrtick_expire;
+       struct hrtimer hrtick_timer;
+#endif
+
 #ifdef CONFIG_SCHEDSTATS
        /* latency stats */
        struct sched_info rq_sched_info;
@@ -363,7 +518,6 @@ struct rq {
 };
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
-static DEFINE_MUTEX(sched_hotcpu_mutex);
 
 static inline void check_preempt_curr(struct rq *rq, struct task_struct *p)
 {
@@ -441,6 +595,23 @@ static void update_rq_clock(struct rq *rq)
 #define task_rq(p)             cpu_rq(task_cpu(p))
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 
+unsigned long rt_needs_cpu(int cpu)
+{
+       struct rq *rq = cpu_rq(cpu);
+       u64 delta;
+
+       if (!rq->rt_throttled)
+               return 0;
+
+       if (rq->clock > rq->rt_period_expire)
+               return 1;
+
+       delta = rq->rt_period_expire - rq->clock;
+       do_div(delta, NSEC_PER_SEC / HZ);
+
+       return (unsigned long)delta;
+}
+
 /*
  * Tunables that become constants when CONFIG_SCHED_DEBUG is off:
  */
@@ -459,6 +630,8 @@ enum {
        SCHED_FEAT_START_DEBIT          = 4,
        SCHED_FEAT_TREE_AVG             = 8,
        SCHED_FEAT_APPROX_AVG           = 16,
+       SCHED_FEAT_HRTICK               = 32,
+       SCHED_FEAT_DOUBLE_TICK          = 64,
 };
 
 const_debug unsigned int sysctl_sched_features =
@@ -466,7 +639,9 @@ const_debug unsigned int sysctl_sched_features =
                SCHED_FEAT_WAKEUP_PREEMPT       * 1 |
                SCHED_FEAT_START_DEBIT          * 1 |
                SCHED_FEAT_TREE_AVG             * 0 |
-               SCHED_FEAT_APPROX_AVG           * 0;
+               SCHED_FEAT_APPROX_AVG           * 0 |
+               SCHED_FEAT_HRTICK               * 1 |
+               SCHED_FEAT_DOUBLE_TICK          * 0;
 
 #define sched_feat(x) (sysctl_sched_features & SCHED_FEAT_##x)
 
@@ -476,6 +651,21 @@ const_debug unsigned int sysctl_sched_features =
  */
 const_debug unsigned int sysctl_sched_nr_migrate = 32;
 
+/*
+ * period over which we measure -rt task cpu usage in ms.
+ * default: 1s
+ */
+const_debug unsigned int sysctl_sched_rt_period = 1000;
+
+#define SCHED_RT_FRAC_SHIFT    16
+#define SCHED_RT_FRAC          (1UL << SCHED_RT_FRAC_SHIFT)
+
+/*
+ * ratio of time -rt tasks may consume.
+ * default: 95%
+ */
+const_debug unsigned int sysctl_sched_rt_ratio = 62259;
+
 /*
  * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
  * clock constructed from sched_clock():
@@ -668,7 +858,6 @@ void sched_clock_idle_wakeup_event(u64 delta_ns)
        struct rq *rq = cpu_rq(smp_processor_id());
        u64 now = sched_clock();
 
-       touch_softlockup_watchdog();
        rq->idle_clock += delta_ns;
        /*
         * Override the previous timestamp and ignore all
@@ -680,9 +869,177 @@ void sched_clock_idle_wakeup_event(u64 delta_ns)
        rq->prev_clock_raw = now;
        rq->clock += delta_ns;
        spin_unlock(&rq->lock);
+       touch_softlockup_watchdog();
 }
 EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
 
+static void __resched_task(struct task_struct *p, int tif_bit);
+
+static inline void resched_task(struct task_struct *p)
+{
+       __resched_task(p, TIF_NEED_RESCHED);
+}
+
+#ifdef CONFIG_SCHED_HRTICK
+/*
+ * Use HR-timers to deliver accurate preemption points.
+ *
+ * Its all a bit involved since we cannot program an hrt while holding the
+ * rq->lock. So what we do is store a state in in rq->hrtick_* and ask for a
+ * reschedule event.
+ *
+ * When we get rescheduled we reprogram the hrtick_timer outside of the
+ * rq->lock.
+ */
+static inline void resched_hrt(struct task_struct *p)
+{
+       __resched_task(p, TIF_HRTICK_RESCHED);
+}
+
+static inline void resched_rq(struct rq *rq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rq->lock, flags);
+       resched_task(rq->curr);
+       spin_unlock_irqrestore(&rq->lock, flags);
+}
+
+enum {
+       HRTICK_SET,             /* re-programm hrtick_timer */
+       HRTICK_RESET,           /* not a new slice */
+};
+
+/*
+ * Use hrtick when:
+ *  - enabled by features
+ *  - hrtimer is actually high res
+ */
+static inline int hrtick_enabled(struct rq *rq)
+{
+       if (!sched_feat(HRTICK))
+               return 0;
+       return hrtimer_is_hres_active(&rq->hrtick_timer);
+}
+
+/*
+ * Called to set the hrtick timer state.
+ *
+ * called with rq->lock held and irqs disabled
+ */
+static void hrtick_start(struct rq *rq, u64 delay, int reset)
+{
+       assert_spin_locked(&rq->lock);
+
+       /*
+        * preempt at: now + delay
+        */
+       rq->hrtick_expire =
+               ktime_add_ns(rq->hrtick_timer.base->get_time(), delay);
+       /*
+        * indicate we need to program the timer
+        */
+       __set_bit(HRTICK_SET, &rq->hrtick_flags);
+       if (reset)
+               __set_bit(HRTICK_RESET, &rq->hrtick_flags);
+
+       /*
+        * New slices are called from the schedule path and don't need a
+        * forced reschedule.
+        */
+       if (reset)
+               resched_hrt(rq->curr);
+}
+
+static void hrtick_clear(struct rq *rq)
+{
+       if (hrtimer_active(&rq->hrtick_timer))
+               hrtimer_cancel(&rq->hrtick_timer);
+}
+
+/*
+ * Update the timer from the possible pending state.
+ */
+static void hrtick_set(struct rq *rq)
+{
+       ktime_t time;
+       int set, reset;
+       unsigned long flags;
+
+       WARN_ON_ONCE(cpu_of(rq) != smp_processor_id());
+
+       spin_lock_irqsave(&rq->lock, flags);
+       set = __test_and_clear_bit(HRTICK_SET, &rq->hrtick_flags);
+       reset = __test_and_clear_bit(HRTICK_RESET, &rq->hrtick_flags);
+       time = rq->hrtick_expire;
+       clear_thread_flag(TIF_HRTICK_RESCHED);
+       spin_unlock_irqrestore(&rq->lock, flags);
+
+       if (set) {
+               hrtimer_start(&rq->hrtick_timer, time, HRTIMER_MODE_ABS);
+               if (reset && !hrtimer_active(&rq->hrtick_timer))
+                       resched_rq(rq);
+       } else
+               hrtick_clear(rq);
+}
+
+/*
+ * High-resolution timer tick.
+ * Runs from hardirq context with interrupts disabled.
+ */
+static enum hrtimer_restart hrtick(struct hrtimer *timer)
+{
+       struct rq *rq = container_of(timer, struct rq, hrtick_timer);
+
+       WARN_ON_ONCE(cpu_of(rq) != smp_processor_id());
+
+       spin_lock(&rq->lock);
+       __update_rq_clock(rq);
+       rq->curr->sched_class->task_tick(rq, rq->curr, 1);
+       spin_unlock(&rq->lock);
+
+       return HRTIMER_NORESTART;
+}
+
+static inline void init_rq_hrtick(struct rq *rq)
+{
+       rq->hrtick_flags = 0;
+       hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       rq->hrtick_timer.function = hrtick;
+       rq->hrtick_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+}
+
+void hrtick_resched(void)
+{
+       struct rq *rq;
+       unsigned long flags;
+
+       if (!test_thread_flag(TIF_HRTICK_RESCHED))
+               return;
+
+       local_irq_save(flags);
+       rq = cpu_rq(smp_processor_id());
+       hrtick_set(rq);
+       local_irq_restore(flags);
+}
+#else
+static inline void hrtick_clear(struct rq *rq)
+{
+}
+
+static inline void hrtick_set(struct rq *rq)
+{
+}
+
+static inline void init_rq_hrtick(struct rq *rq)
+{
+}
+
+void hrtick_resched(void)
+{
+}
+#endif
+
 /*
  * resched_task - mark a task 'to be rescheduled now'.
  *
@@ -696,16 +1053,16 @@ EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
 #define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
 #endif
 
-static void resched_task(struct task_struct *p)
+static void __resched_task(struct task_struct *p, int tif_bit)
 {
        int cpu;
 
        assert_spin_locked(&task_rq(p)->lock);
 
-       if (unlikely(test_tsk_thread_flag(p, TIF_NEED_RESCHED)))
+       if (unlikely(test_tsk_thread_flag(p, tif_bit)))
                return;
 
-       set_tsk_thread_flag(p, TIF_NEED_RESCHED);
+       set_tsk_thread_flag(p, tif_bit);
 
        cpu = task_cpu(p);
        if (cpu == smp_processor_id())
@@ -728,10 +1085,10 @@ static void resched_cpu(int cpu)
        spin_unlock_irqrestore(&rq->lock, flags);
 }
 #else
-static inline void resched_task(struct task_struct *p)
+static void __resched_task(struct task_struct *p, int tif_bit)
 {
        assert_spin_locked(&task_rq(p)->lock);
-       set_tsk_need_resched(p);
+       set_tsk_thread_flag(p, tif_bit);
 }
 #endif
 
@@ -871,6 +1228,23 @@ static void cpuacct_charge(struct task_struct *tsk, u64 cputime);
 static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {}
 #endif
 
+static inline void inc_cpu_load(struct rq *rq, unsigned long load)
+{
+       update_load_add(&rq->load, load);
+}
+
+static inline void dec_cpu_load(struct rq *rq, unsigned long load)
+{
+       update_load_sub(&rq->load, load);
+}
+
+#ifdef CONFIG_SMP
+static unsigned long source_load(int cpu, int type);
+static unsigned long target_load(int cpu, int type);
+static unsigned long cpu_avg_load_per_task(int cpu);
+static int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd);
+#endif /* CONFIG_SMP */
+
 #include "sched_stats.h"
 #include "sched_idletask.c"
 #include "sched_fair.c"
@@ -881,41 +1255,14 @@ static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {}
 
 #define sched_class_highest (&rt_sched_class)
 
-/*
- * Update delta_exec, delta_fair fields for rq.
- *
- * delta_fair clock advances at a rate inversely proportional to
- * total load (rq->load.weight) on the runqueue, while
- * delta_exec advances at the same rate as wall-clock (provided
- * cpu is not idle).
- *
- * delta_exec / delta_fair is a measure of the (smoothened) load on this
- * runqueue over any given interval. This (smoothened) load is used
- * during load balance.
- *
- * This function is called /before/ updating rq->load
- * and when switching tasks.
- */
-static inline void inc_load(struct rq *rq, const struct task_struct *p)
-{
-       update_load_add(&rq->load, p->se.load.weight);
-}
-
-static inline void dec_load(struct rq *rq, const struct task_struct *p)
-{
-       update_load_sub(&rq->load, p->se.load.weight);
-}
-
 static void inc_nr_running(struct task_struct *p, struct rq *rq)
 {
        rq->nr_running++;
-       inc_load(rq, p);
 }
 
 static void dec_nr_running(struct task_struct *p, struct rq *rq)
 {
        rq->nr_running--;
-       dec_load(rq, p);
 }
 
 static void set_load_weight(struct task_struct *p)
@@ -1039,7 +1386,7 @@ unsigned long weighted_cpuload(const int cpu)
 
 static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
 {
-       set_task_cfs_rq(p, cpu);
+       set_task_rq(p, cpu);
 #ifdef CONFIG_SMP
        /*
         * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be
@@ -1051,12 +1398,24 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
 #endif
 }
 
+static inline void check_class_changed(struct rq *rq, struct task_struct *p,
+                                      const struct sched_class *prev_class,
+                                      int oldprio, int running)
+{
+       if (prev_class != p->sched_class) {
+               if (prev_class->switched_from)
+                       prev_class->switched_from(rq, p, running);
+               p->sched_class->switched_to(rq, p, running);
+       } else
+               p->sched_class->prio_changed(rq, p, oldprio, running);
+}
+
 #ifdef CONFIG_SMP
 
 /*
  * Is this task likely cache-hot:
  */
-static inline int
+static int
 task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
 {
        s64 delta;
@@ -1281,7 +1640,7 @@ static unsigned long target_load(int cpu, int type)
 /*
  * Return the average load per task on the cpu's run queue
  */
-static inline unsigned long cpu_avg_load_per_task(int cpu)
+static unsigned long cpu_avg_load_per_task(int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
        unsigned long total = weighted_cpuload(cpu);
@@ -1438,58 +1797,6 @@ static int sched_balance_self(int cpu, int flag)
 
 #endif /* CONFIG_SMP */
 
-/*
- * wake_idle() will wake a task on an idle cpu if task->cpu is
- * not idle and an idle cpu is available.  The span of cpus to
- * search starts with cpus closest then further out as needed,
- * so we always favor a closer, idle cpu.
- *
- * Returns the CPU we should wake onto.
- */
-#if defined(ARCH_HAS_SCHED_WAKE_IDLE)
-static int wake_idle(int cpu, struct task_struct *p)
-{
-       cpumask_t tmp;
-       struct sched_domain *sd;
-       int i;
-
-       /*
-        * If it is idle, then it is the best cpu to run this task.
-        *
-        * This cpu is also the best, if it has more than one task already.
-        * Siblings must be also busy(in most cases) as they didn't already
-        * pickup the extra load from this cpu and hence we need not check
-        * sibling runqueue info. This will avoid the checks and cache miss
-        * penalities associated with that.
-        */
-       if (idle_cpu(cpu) || cpu_rq(cpu)->nr_running > 1)
-               return cpu;
-
-       for_each_domain(cpu, sd) {
-               if (sd->flags & SD_WAKE_IDLE) {
-                       cpus_and(tmp, sd->span, p->cpus_allowed);
-                       for_each_cpu_mask(i, tmp) {
-                               if (idle_cpu(i)) {
-                                       if (i != task_cpu(p)) {
-                                               schedstat_inc(p,
-                                                       se.nr_wakeups_idle);
-                                       }
-                                       return i;
-                               }
-                       }
-               } else {
-                       break;
-               }
-       }
-       return cpu;
-}
-#else
-static inline int wake_idle(int cpu, struct task_struct *p)
-{
-       return cpu;
-}
-#endif
-
 /***
  * try_to_wake_up - wake up a thread
  * @p: the to-be-woken-up thread
@@ -1510,11 +1817,6 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
        unsigned long flags;
        long old_state;
        struct rq *rq;
-#ifdef CONFIG_SMP
-       struct sched_domain *sd, *this_sd = NULL;
-       unsigned long load, this_load;
-       int new_cpu;
-#endif
 
        rq = task_rq_lock(p, &flags);
        old_state = p->state;
@@ -1532,92 +1834,9 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
        if (unlikely(task_running(rq, p)))
                goto out_activate;
 
-       new_cpu = cpu;
-
-       schedstat_inc(rq, ttwu_count);
-       if (cpu == this_cpu) {
-               schedstat_inc(rq, ttwu_local);
-               goto out_set_cpu;
-       }
-
-       for_each_domain(this_cpu, sd) {
-               if (cpu_isset(cpu, sd->span)) {
-                       schedstat_inc(sd, ttwu_wake_remote);
-                       this_sd = sd;
-                       break;
-               }
-       }
-
-       if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
-               goto out_set_cpu;
-
-       /*
-        * Check for affine wakeup and passive balancing possibilities.
-        */
-       if (this_sd) {
-               int idx = this_sd->wake_idx;
-               unsigned int imbalance;
-
-               imbalance = 100 + (this_sd->imbalance_pct - 100) / 2;
-
-               load = source_load(cpu, idx);
-               this_load = target_load(this_cpu, idx);
-
-               new_cpu = this_cpu; /* Wake to this CPU if we can */
-
-               if (this_sd->flags & SD_WAKE_AFFINE) {
-                       unsigned long tl = this_load;
-                       unsigned long tl_per_task;
-
-                       /*
-                        * Attract cache-cold tasks on sync wakeups:
-                        */
-                       if (sync && !task_hot(p, rq->clock, this_sd))
-                               goto out_set_cpu;
-
-                       schedstat_inc(p, se.nr_wakeups_affine_attempts);
-                       tl_per_task = cpu_avg_load_per_task(this_cpu);
-
-                       /*
-                        * If sync wakeup then subtract the (maximum possible)
-                        * effect of the currently running task from the load
-                        * of the current CPU:
-                        */
-                       if (sync)
-                               tl -= current->se.load.weight;
-
-                       if ((tl <= load &&
-                               tl + target_load(cpu, idx) <= tl_per_task) ||
-                              100*(tl + p->se.load.weight) <= imbalance*load) {
-                               /*
-                                * This domain has SD_WAKE_AFFINE and
-                                * p is cache cold in this domain, and
-                                * there is no bad imbalance.
-                                */
-                               schedstat_inc(this_sd, ttwu_move_affine);
-                               schedstat_inc(p, se.nr_wakeups_affine);
-                               goto out_set_cpu;
-                       }
-               }
-
-               /*
-                * Start passive balancing when half the imbalance_pct
-                * limit is reached.
-                */
-               if (this_sd->flags & SD_WAKE_BALANCE) {
-                       if (imbalance*this_load <= 100*load) {
-                               schedstat_inc(this_sd, ttwu_move_balance);
-                               schedstat_inc(p, se.nr_wakeups_passive);
-                               goto out_set_cpu;
-                       }
-               }
-       }
-
-       new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */
-out_set_cpu:
-       new_cpu = wake_idle(new_cpu, p);
-       if (new_cpu != cpu) {
-               set_task_cpu(p, new_cpu);
+       cpu = p->sched_class->select_task_rq(p, sync);
+       if (cpu != orig_cpu) {
+               set_task_cpu(p, cpu);
                task_rq_unlock(rq, &flags);
                /* might preempt at this point */
                rq = task_rq_lock(p, &flags);
@@ -1631,6 +1850,21 @@ out_set_cpu:
                cpu = task_cpu(p);
        }
 
+#ifdef CONFIG_SCHEDSTATS
+       schedstat_inc(rq, ttwu_count);
+       if (cpu == this_cpu)
+               schedstat_inc(rq, ttwu_local);
+       else {
+               struct sched_domain *sd;
+               for_each_domain(this_cpu, sd) {
+                       if (cpu_isset(cpu, sd->span)) {
+                               schedstat_inc(sd, ttwu_wake_remote);
+                               break;
+                       }
+               }
+       }
+#endif
+
 out_activate:
 #endif /* CONFIG_SMP */
        schedstat_inc(p, se.nr_wakeups);
@@ -1649,6 +1883,10 @@ out_activate:
 
 out_running:
        p->state = TASK_RUNNING;
+#ifdef CONFIG_SMP
+       if (p->sched_class->task_wake_up)
+               p->sched_class->task_wake_up(rq, p);
+#endif
 out:
        task_rq_unlock(rq, &flags);
 
@@ -1691,7 +1929,7 @@ static void __sched_fork(struct task_struct *p)
        p->se.wait_max                  = 0;
 #endif
 
-       INIT_LIST_HEAD(&p->run_list);
+       INIT_LIST_HEAD(&p->rt.run_list);
        p->se.on_rq = 0;
 
 #ifdef CONFIG_PREEMPT_NOTIFIERS
@@ -1771,6 +2009,10 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
                inc_nr_running(p, rq);
        }
        check_preempt_curr(rq, p);
+#ifdef CONFIG_SMP
+       if (p->sched_class->task_wake_up)
+               p->sched_class->task_wake_up(rq, p);
+#endif
        task_rq_unlock(rq, &flags);
 }
 
@@ -1891,6 +2133,11 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
        prev_state = prev->state;
        finish_arch_switch(prev);
        finish_lock_switch(rq, prev);
+#ifdef CONFIG_SMP
+       if (current->sched_class->post_schedule)
+               current->sched_class->post_schedule(rq);
+#endif
+
        fire_sched_in_preempt_notifiers(current);
        if (mm)
                mmdrop(mm);
@@ -2124,11 +2371,13 @@ static void double_rq_unlock(struct rq *rq1, struct rq *rq2)
 /*
  * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
  */
-static void double_lock_balance(struct rq *this_rq, struct rq *busiest)
+static int double_lock_balance(struct rq *this_rq, struct rq *busiest)
        __releases(this_rq->lock)
        __acquires(busiest->lock)
        __acquires(this_rq->lock)
 {
+       int ret = 0;
+
        if (unlikely(!irqs_disabled())) {
                /* printk() doesn't work good under rq->lock */
                spin_unlock(&this_rq->lock);
@@ -2139,9 +2388,11 @@ static void double_lock_balance(struct rq *this_rq, struct rq *busiest)
                        spin_unlock(&this_rq->lock);
                        spin_lock(&busiest->lock);
                        spin_lock(&this_rq->lock);
+                       ret = 1;
                } else
                        spin_lock(&busiest->lock);
        }
+       return ret;
 }
 
 /*
@@ -3485,12 +3736,14 @@ void scheduler_tick(void)
        /*
         * Let rq->clock advance by at least TICK_NSEC:
         */
-       if (unlikely(rq->clock < next_tick))
+       if (unlikely(rq->clock < next_tick)) {
                rq->clock = next_tick;
+               rq->clock_underflows++;
+       }
        rq->tick_timestamp = rq->clock;
        update_cpu_load(rq);
-       if (curr != rq->idle) /* FIXME: needed? */
-               curr->sched_class->task_tick(rq, curr);
+       curr->sched_class->task_tick(rq, curr, 0);
+       update_sched_rt_period(rq);
        spin_unlock(&rq->lock);
 
 #ifdef CONFIG_SMP
@@ -3636,6 +3889,8 @@ need_resched_nonpreemptible:
 
        schedule_debug(prev);
 
+       hrtick_clear(rq);
+
        /*
         * Do the rq-clock update outside the rq lock:
         */
@@ -3654,6 +3909,11 @@ need_resched_nonpreemptible:
                switch_count = &prev->nvcsw;
        }
 
+#ifdef CONFIG_SMP
+       if (prev->sched_class->pre_schedule)
+               prev->sched_class->pre_schedule(rq, prev);
+#endif
+
        if (unlikely(!rq->nr_running))
                idle_balance(cpu, rq);
 
@@ -3668,14 +3928,20 @@ need_resched_nonpreemptible:
                ++*switch_count;
 
                context_switch(rq, prev, next); /* unlocks the rq */
+               /*
+                * the context switch might have flipped the stack from under
+                * us, hence refresh the local variables.
+                */
+               cpu = smp_processor_id();
+               rq = cpu_rq(cpu);
        } else
                spin_unlock_irq(&rq->lock);
 
-       if (unlikely(reacquire_kernel_lock(current) < 0)) {
-               cpu = smp_processor_id();
-               rq = cpu_rq(cpu);
+       hrtick_set(rq);
+
+       if (unlikely(reacquire_kernel_lock(current) < 0))
                goto need_resched_nonpreemptible;
-       }
+
        preempt_enable_no_resched();
        if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
                goto need_resched;
@@ -3691,10 +3957,9 @@ EXPORT_SYMBOL(schedule);
 asmlinkage void __sched preempt_schedule(void)
 {
        struct thread_info *ti = current_thread_info();
-#ifdef CONFIG_PREEMPT_BKL
        struct task_struct *task = current;
        int saved_lock_depth;
-#endif
+
        /*
         * If there is a non-zero preempt_count or interrupts are disabled,
         * we do not want to preempt the current task. Just return..
@@ -3710,14 +3975,10 @@ asmlinkage void __sched preempt_schedule(void)
                 * clear ->lock_depth so that schedule() doesnt
                 * auto-release the semaphore:
                 */
-#ifdef CONFIG_PREEMPT_BKL
                saved_lock_depth = task->lock_depth;
                task->lock_depth = -1;
-#endif
                schedule();
-#ifdef CONFIG_PREEMPT_BKL
                task->lock_depth = saved_lock_depth;
-#endif
                sub_preempt_count(PREEMPT_ACTIVE);
 
                /*
@@ -3738,10 +3999,9 @@ EXPORT_SYMBOL(preempt_schedule);
 asmlinkage void __sched preempt_schedule_irq(void)
 {
        struct thread_info *ti = current_thread_info();
-#ifdef CONFIG_PREEMPT_BKL
        struct task_struct *task = current;
        int saved_lock_depth;
-#endif
+
        /* Catch callers which need to be fixed */
        BUG_ON(ti->preempt_count || !irqs_disabled());
 
@@ -3753,16 +4013,12 @@ asmlinkage void __sched preempt_schedule_irq(void)
                 * clear ->lock_depth so that schedule() doesnt
                 * auto-release the semaphore:
                 */
-#ifdef CONFIG_PREEMPT_BKL
                saved_lock_depth = task->lock_depth;
                task->lock_depth = -1;
-#endif
                local_irq_enable();
                schedule();
                local_irq_disable();
-#ifdef CONFIG_PREEMPT_BKL
                task->lock_depth = saved_lock_depth;
-#endif
                sub_preempt_count(PREEMPT_ACTIVE);
 
                /*
@@ -4019,6 +4275,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        unsigned long flags;
        int oldprio, on_rq, running;
        struct rq *rq;
+       const struct sched_class *prev_class = p->sched_class;
 
        BUG_ON(prio < 0 || prio > MAX_PRIO);
 
@@ -4044,18 +4301,10 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        if (on_rq) {
                if (running)
                        p->sched_class->set_curr_task(rq);
+
                enqueue_task(rq, p, 0);
-               /*
-                * Reschedule if we are currently running on this runqueue and
-                * our priority decreased, or if we are not currently running on
-                * this runqueue and our priority is higher than the current's
-                */
-               if (running) {
-                       if (p->prio > oldprio)
-                               resched_task(rq->curr);
-               } else {
-                       check_preempt_curr(rq, p);
-               }
+
+               check_class_changed(rq, p, prev_class, oldprio, running);
        }
        task_rq_unlock(rq, &flags);
 }
@@ -4087,10 +4336,8 @@ void set_user_nice(struct task_struct *p, long nice)
                goto out_unlock;
        }
        on_rq = p->se.on_rq;
-       if (on_rq) {
+       if (on_rq)
                dequeue_task(rq, p, 0);
-               dec_load(rq, p);
-       }
 
        p->static_prio = NICE_TO_PRIO(nice);
        set_load_weight(p);
@@ -4100,7 +4347,6 @@ void set_user_nice(struct task_struct *p, long nice)
 
        if (on_rq) {
                enqueue_task(rq, p, 0);
-               inc_load(rq, p);
                /*
                 * If the task increased its priority or is running and
                 * lowered its priority, then reschedule its CPU:
@@ -4258,6 +4504,7 @@ int sched_setscheduler(struct task_struct *p, int policy,
 {
        int retval, oldprio, oldpolicy = -1, on_rq, running;
        unsigned long flags;
+       const struct sched_class *prev_class = p->sched_class;
        struct rq *rq;
 
        /* may grab non-irq protected spin_locks */
@@ -4351,18 +4598,10 @@ recheck:
        if (on_rq) {
                if (running)
                        p->sched_class->set_curr_task(rq);
+
                activate_task(rq, p, 0);
-               /*
-                * Reschedule if we are currently running on this runqueue and
-                * our priority decreased, or if we are not currently running on
-                * this runqueue and our priority is higher than the current's
-                */
-               if (running) {
-                       if (p->prio > oldprio)
-                               resched_task(rq->curr);
-               } else {
-                       check_preempt_curr(rq, p);
-               }
+
+               check_class_changed(rq, p, prev_class, oldprio, running);
        }
        __task_rq_unlock(rq);
        spin_unlock_irqrestore(&p->pi_lock, flags);
@@ -4490,13 +4729,13 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
        struct task_struct *p;
        int retval;
 
-       mutex_lock(&sched_hotcpu_mutex);
+       get_online_cpus();
        read_lock(&tasklist_lock);
 
        p = find_process_by_pid(pid);
        if (!p) {
                read_unlock(&tasklist_lock);
-               mutex_unlock(&sched_hotcpu_mutex);
+               put_online_cpus();
                return -ESRCH;
        }
 
@@ -4536,7 +4775,7 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
        }
 out_unlock:
        put_task_struct(p);
-       mutex_unlock(&sched_hotcpu_mutex);
+       put_online_cpus();
        return retval;
 }
 
@@ -4593,7 +4832,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
        struct task_struct *p;
        int retval;
 
-       mutex_lock(&sched_hotcpu_mutex);
+       get_online_cpus();
        read_lock(&tasklist_lock);
 
        retval = -ESRCH;
@@ -4609,7 +4848,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
 
 out_unlock:
        read_unlock(&tasklist_lock);
-       mutex_unlock(&sched_hotcpu_mutex);
+       put_online_cpus();
 
        return retval;
 }
@@ -4683,7 +4922,8 @@ static void __cond_resched(void)
        } while (need_resched());
 }
 
-int __sched cond_resched(void)
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_VOLUNTARY)
+int __sched _cond_resched(void)
 {
        if (need_resched() && !(preempt_count() & PREEMPT_ACTIVE) &&
                                        system_state == SYSTEM_RUNNING) {
@@ -4692,7 +4932,8 @@ int __sched cond_resched(void)
        }
        return 0;
 }
-EXPORT_SYMBOL(cond_resched);
+EXPORT_SYMBOL(_cond_resched);
+#endif
 
 /*
  * cond_resched_lock() - if a reschedule is pending, drop the given lock,
@@ -4890,7 +5131,7 @@ out_unlock:
 
 static const char stat_nam[] = "RSDTtZX";
 
-static void show_task(struct task_struct *p)
+void sched_show_task(struct task_struct *p)
 {
        unsigned long free = 0;
        unsigned state;
@@ -4918,10 +5159,9 @@ static void show_task(struct task_struct *p)
        }
 #endif
        printk(KERN_CONT "%5lu %5d %6d\n", free,
-               task_pid_nr(p), task_pid_nr(p->parent));
+               task_pid_nr(p), task_pid_nr(p->real_parent));
 
-       if (state != TASK_RUNNING)
-               show_stack(p, NULL);
+       show_stack(p, NULL);
 }
 
 void show_state_filter(unsigned long state_filter)
@@ -4943,7 +5183,7 @@ void show_state_filter(unsigned long state_filter)
                 */
                touch_nmi_watchdog();
                if (!state_filter || (p->state & state_filter))
-                       show_task(p);
+                       sched_show_task(p);
        } while_each_thread(g, p);
 
        touch_all_softlockup_watchdogs();
@@ -4992,11 +5232,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        spin_unlock_irqrestore(&rq->lock, flags);
 
        /* Set the preempt count _outside_ the spinlocks! */
-#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL)
-       task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0);
-#else
        task_thread_info(idle)->preempt_count = 0;
-#endif
+
        /*
         * The idle tasks have their own, simple scheduling class:
         */
@@ -5077,7 +5314,13 @@ int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
                goto out;
        }
 
-       p->cpus_allowed = new_mask;
+       if (p->sched_class->set_cpus_allowed)
+               p->sched_class->set_cpus_allowed(p, &new_mask);
+       else {
+               p->cpus_allowed = new_mask;
+               p->rt.nr_cpus_allowed = cpus_weight(new_mask);
+       }
+
        /* Can the task run on the task's current CPU? If so, we're done */
        if (cpu_isset(task_cpu(p), new_mask))
                goto out;
@@ -5569,9 +5812,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
        struct rq *rq;
 
        switch (action) {
-       case CPU_LOCK_ACQUIRE:
-               mutex_lock(&sched_hotcpu_mutex);
-               break;
 
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
@@ -5590,6 +5830,15 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_ONLINE_FROZEN:
                /* Strictly unnecessary, as first user will wake it. */
                wake_up_process(cpu_rq(cpu)->migration_thread);
+
+               /* Update our root-domain */
+               rq = cpu_rq(cpu);
+               spin_lock_irqsave(&rq->lock, flags);
+               if (rq->rd) {
+                       BUG_ON(!cpu_isset(cpu, rq->rd->span));
+                       cpu_set(cpu, rq->rd->online);
+               }
+               spin_unlock_irqrestore(&rq->lock, flags);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -5640,10 +5889,18 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                }
                spin_unlock_irq(&rq->lock);
                break;
-#endif
-       case CPU_LOCK_RELEASE:
-               mutex_unlock(&sched_hotcpu_mutex);
+
+       case CPU_DOWN_PREPARE:
+               /* Update our root-domain */
+               rq = cpu_rq(cpu);
+               spin_lock_irqsave(&rq->lock, flags);
+               if (rq->rd) {
+                       BUG_ON(!cpu_isset(cpu, rq->rd->span));
+                       cpu_clear(cpu, rq->rd->online);
+               }
+               spin_unlock_irqrestore(&rq->lock, flags);
                break;
+#endif
        }
        return NOTIFY_OK;
 }
@@ -5831,11 +6088,76 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent)
        return 1;
 }
 
+static void rq_attach_root(struct rq *rq, struct root_domain *rd)
+{
+       unsigned long flags;
+       const struct sched_class *class;
+
+       spin_lock_irqsave(&rq->lock, flags);
+
+       if (rq->rd) {
+               struct root_domain *old_rd = rq->rd;
+
+               for (class = sched_class_highest; class; class = class->next) {
+                       if (class->leave_domain)
+                               class->leave_domain(rq);
+               }
+
+               cpu_clear(rq->cpu, old_rd->span);
+               cpu_clear(rq->cpu, old_rd->online);
+
+               if (atomic_dec_and_test(&old_rd->refcount))
+                       kfree(old_rd);
+       }
+
+       atomic_inc(&rd->refcount);
+       rq->rd = rd;
+
+       cpu_set(rq->cpu, rd->span);
+       if (cpu_isset(rq->cpu, cpu_online_map))
+               cpu_set(rq->cpu, rd->online);
+
+       for (class = sched_class_highest; class; class = class->next) {
+               if (class->join_domain)
+                       class->join_domain(rq);
+       }
+
+       spin_unlock_irqrestore(&rq->lock, flags);
+}
+
+static void init_rootdomain(struct root_domain *rd)
+{
+       memset(rd, 0, sizeof(*rd));
+
+       cpus_clear(rd->span);
+       cpus_clear(rd->online);
+}
+
+static void init_defrootdomain(void)
+{
+       init_rootdomain(&def_root_domain);
+       atomic_set(&def_root_domain.refcount, 1);
+}
+
+static struct root_domain *alloc_rootdomain(void)
+{
+       struct root_domain *rd;
+
+       rd = kmalloc(sizeof(*rd), GFP_KERNEL);
+       if (!rd)
+               return NULL;
+
+       init_rootdomain(rd);
+
+       return rd;
+}
+
 /*
- * Attach the domain 'sd' to 'cpu' as its base domain.  Callers must
+ * Attach the domain 'sd' to 'cpu' as its base domain. Callers must
  * hold the hotplug lock.
  */
-static void cpu_attach_domain(struct sched_domain *sd, int cpu)
+static void
+cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
        struct sched_domain *tmp;
@@ -5860,6 +6182,7 @@ static void cpu_attach_domain(struct sched_domain *sd, int cpu)
 
        sched_domain_debug(sd, cpu);
 
+       rq_attach_root(rq, rd);
        rcu_assign_pointer(rq->sd, sd);
 }
 
@@ -6228,6 +6551,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 static int build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
+       struct root_domain *rd;
 #ifdef CONFIG_NUMA
        struct sched_group **sched_group_nodes = NULL;
        int sd_allnodes = 0;
@@ -6244,6 +6568,12 @@ static int build_sched_domains(const cpumask_t *cpu_map)
        sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes;
 #endif
 
+       rd = alloc_rootdomain();
+       if (!rd) {
+               printk(KERN_WARNING "Cannot alloc root domain\n");
+               return -ENOMEM;
+       }
+
        /*
         * Set up domains for cpus specified by the cpu_map.
         */
@@ -6460,7 +6790,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
 #else
                sd = &per_cpu(phys_domains, i);
 #endif
-               cpu_attach_domain(sd, i);
+               cpu_attach_domain(sd, rd, i);
        }
 
        return 0;
@@ -6518,7 +6848,7 @@ static void detach_destroy_domains(const cpumask_t *cpu_map)
        unregister_sched_domain_sysctl();
 
        for_each_cpu_mask(i, *cpu_map)
-               cpu_attach_domain(NULL, i);
+               cpu_attach_domain(NULL, &def_root_domain, i);
        synchronize_sched();
        arch_destroy_sched_domains(cpu_map);
 }
@@ -6548,6 +6878,8 @@ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new)
 {
        int i, j;
 
+       lock_doms_cur();
+
        /* always unregister in case we don't destroy any domains */
        unregister_sched_domain_sysctl();
 
@@ -6588,6 +6920,8 @@ match2:
        ndoms_cur = ndoms_new;
 
        register_sched_domain_sysctl();
+
+       unlock_doms_cur();
 }
 
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
@@ -6595,10 +6929,10 @@ static int arch_reinit_sched_domains(void)
 {
        int err;
 
-       mutex_lock(&sched_hotcpu_mutex);
+       get_online_cpus();
        detach_destroy_domains(&cpu_online_map);
        err = arch_init_sched_domains(&cpu_online_map);
-       mutex_unlock(&sched_hotcpu_mutex);
+       put_online_cpus();
 
        return err;
 }
@@ -6709,12 +7043,12 @@ void __init sched_init_smp(void)
 {
        cpumask_t non_isolated_cpus;
 
-       mutex_lock(&sched_hotcpu_mutex);
+       get_online_cpus();
        arch_init_sched_domains(&cpu_online_map);
        cpus_andnot(non_isolated_cpus, cpu_possible_map, cpu_isolated_map);
        if (cpus_empty(non_isolated_cpus))
                cpu_set(smp_processor_id(), non_isolated_cpus);
-       mutex_unlock(&sched_hotcpu_mutex);
+       put_online_cpus();
        /* XXX: Theoretical race here - CPU may be hotplugged now */
        hotcpu_notifier(update_sched_domains, 0);
 
@@ -6722,6 +7056,21 @@ void __init sched_init_smp(void)
        if (set_cpus_allowed(current, non_isolated_cpus) < 0)
                BUG();
        sched_init_granularity();
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       if (nr_cpu_ids == 1)
+               return;
+
+       lb_monitor_task = kthread_create(load_balance_monitor, NULL,
+                                        "group_balance");
+       if (!IS_ERR(lb_monitor_task)) {
+               lb_monitor_task->flags |= PF_NOFREEZE;
+               wake_up_process(lb_monitor_task);
+       } else {
+               printk(KERN_ERR "Could not create load balance monitor thread"
+                       "(error = %ld) \n", PTR_ERR(lb_monitor_task));
+       }
+#endif
 }
 #else
 void __init sched_init_smp(void)
@@ -6746,13 +7095,87 @@ static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
        cfs_rq->min_vruntime = (u64)(-(1LL << 20));
 }
 
+static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq)
+{
+       struct rt_prio_array *array;
+       int i;
+
+       array = &rt_rq->active;
+       for (i = 0; i < MAX_RT_PRIO; i++) {
+               INIT_LIST_HEAD(array->queue + i);
+               __clear_bit(i, array->bitmap);
+       }
+       /* delimiter for bitsearch: */
+       __set_bit(MAX_RT_PRIO, array->bitmap);
+
+#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED
+       rt_rq->highest_prio = MAX_RT_PRIO;
+#endif
+#ifdef CONFIG_SMP
+       rt_rq->rt_nr_migratory = 0;
+       rt_rq->overloaded = 0;
+#endif
+
+       rt_rq->rt_time = 0;
+       rt_rq->rt_throttled = 0;
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       rt_rq->rq = rq;
+#endif
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+static void init_tg_cfs_entry(struct rq *rq, struct task_group *tg,
+               struct cfs_rq *cfs_rq, struct sched_entity *se,
+               int cpu, int add)
+{
+       tg->cfs_rq[cpu] = cfs_rq;
+       init_cfs_rq(cfs_rq, rq);
+       cfs_rq->tg = tg;
+       if (add)
+               list_add(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+
+       tg->se[cpu] = se;
+       se->cfs_rq = &rq->cfs;
+       se->my_q = cfs_rq;
+       se->load.weight = tg->shares;
+       se->load.inv_weight = div64_64(1ULL<<32, se->load.weight);
+       se->parent = NULL;
+}
+
+static void init_tg_rt_entry(struct rq *rq, struct task_group *tg,
+               struct rt_rq *rt_rq, struct sched_rt_entity *rt_se,
+               int cpu, int add)
+{
+       tg->rt_rq[cpu] = rt_rq;
+       init_rt_rq(rt_rq, rq);
+       rt_rq->tg = tg;
+       rt_rq->rt_se = rt_se;
+       if (add)
+               list_add(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list);
+
+       tg->rt_se[cpu] = rt_se;
+       rt_se->rt_rq = &rq->rt;
+       rt_se->my_q = rt_rq;
+       rt_se->parent = NULL;
+       INIT_LIST_HEAD(&rt_se->run_list);
+}
+#endif
+
 void __init sched_init(void)
 {
        int highest_cpu = 0;
        int i, j;
 
+#ifdef CONFIG_SMP
+       init_defrootdomain();
+#endif
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       list_add(&init_task_group.list, &task_groups);
+#endif
+
        for_each_possible_cpu(i) {
-               struct rt_prio_array *array;
                struct rq *rq;
 
                rq = cpu_rq(i);
@@ -6761,52 +7184,39 @@ void __init sched_init(void)
                rq->nr_running = 0;
                rq->clock = 1;
                init_cfs_rq(&rq->cfs, rq);
+               init_rt_rq(&rq->rt, rq);
 #ifdef CONFIG_FAIR_GROUP_SCHED
-               INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
-               {
-                       struct cfs_rq *cfs_rq = &per_cpu(init_cfs_rq, i);
-                       struct sched_entity *se =
-                                        &per_cpu(init_sched_entity, i);
-
-                       init_cfs_rq_p[i] = cfs_rq;
-                       init_cfs_rq(cfs_rq, rq);
-                       cfs_rq->tg = &init_task_group;
-                       list_add(&cfs_rq->leaf_cfs_rq_list,
-                                                        &rq->leaf_cfs_rq_list);
-
-                       init_sched_entity_p[i] = se;
-                       se->cfs_rq = &rq->cfs;
-                       se->my_q = cfs_rq;
-                       se->load.weight = init_task_group_load;
-                       se->load.inv_weight =
-                                div64_64(1ULL<<32, init_task_group_load);
-                       se->parent = NULL;
-               }
                init_task_group.shares = init_task_group_load;
-               spin_lock_init(&init_task_group.lock);
+               INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
+               init_tg_cfs_entry(rq, &init_task_group,
+                               &per_cpu(init_cfs_rq, i),
+                               &per_cpu(init_sched_entity, i), i, 1);
+
+               init_task_group.rt_ratio = sysctl_sched_rt_ratio; /* XXX */
+               INIT_LIST_HEAD(&rq->leaf_rt_rq_list);
+               init_tg_rt_entry(rq, &init_task_group,
+                               &per_cpu(init_rt_rq, i),
+                               &per_cpu(init_sched_rt_entity, i), i, 1);
 #endif
+               rq->rt_period_expire = 0;
+               rq->rt_throttled = 0;
 
                for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
                        rq->cpu_load[j] = 0;
 #ifdef CONFIG_SMP
                rq->sd = NULL;
+               rq->rd = NULL;
                rq->active_balance = 0;
                rq->next_balance = jiffies;
                rq->push_cpu = 0;
                rq->cpu = i;
                rq->migration_thread = NULL;
                INIT_LIST_HEAD(&rq->migration_queue);
+               rq_attach_root(rq, &def_root_domain);
 #endif
+               init_rq_hrtick(rq);
                atomic_set(&rq->nr_iowait, 0);
-
-               array = &rq->rt.active;
-               for (j = 0; j < MAX_RT_PRIO; j++) {
-                       INIT_LIST_HEAD(array->queue + j);
-                       __clear_bit(j, array->bitmap);
-               }
                highest_cpu = i;
-               /* delimiter for bitsearch: */
-               __set_bit(MAX_RT_PRIO, array->bitmap);
        }
 
        set_load_weight(&init_task);
@@ -6975,12 +7385,187 @@ void set_curr_task(int cpu, struct task_struct *p)
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 
+#ifdef CONFIG_SMP
+/*
+ * distribute shares of all task groups among their schedulable entities,
+ * to reflect load distribution across cpus.
+ */
+static int rebalance_shares(struct sched_domain *sd, int this_cpu)
+{
+       struct cfs_rq *cfs_rq;
+       struct rq *rq = cpu_rq(this_cpu);
+       cpumask_t sdspan = sd->span;
+       int balanced = 1;
+
+       /* Walk thr' all the task groups that we have */
+       for_each_leaf_cfs_rq(rq, cfs_rq) {
+               int i;
+               unsigned long total_load = 0, total_shares;
+               struct task_group *tg = cfs_rq->tg;
+
+               /* Gather total task load of this group across cpus */
+               for_each_cpu_mask(i, sdspan)
+                       total_load += tg->cfs_rq[i]->load.weight;
+
+               /* Nothing to do if this group has no load */
+               if (!total_load)
+                       continue;
+
+               /*
+                * tg->shares represents the number of cpu shares the task group
+                * is eligible to hold on a single cpu. On N cpus, it is
+                * eligible to hold (N * tg->shares) number of cpu shares.
+                */
+               total_shares = tg->shares * cpus_weight(sdspan);
+
+               /*
+                * redistribute total_shares across cpus as per the task load
+                * distribution.
+                */
+               for_each_cpu_mask(i, sdspan) {
+                       unsigned long local_load, local_shares;
+
+                       local_load = tg->cfs_rq[i]->load.weight;
+                       local_shares = (local_load * total_shares) / total_load;
+                       if (!local_shares)
+                               local_shares = MIN_GROUP_SHARES;
+                       if (local_shares == tg->se[i]->load.weight)
+                               continue;
+
+                       spin_lock_irq(&cpu_rq(i)->lock);
+                       set_se_shares(tg->se[i], local_shares);
+                       spin_unlock_irq(&cpu_rq(i)->lock);
+                       balanced = 0;
+               }
+       }
+
+       return balanced;
+}
+
+/*
+ * How frequently should we rebalance_shares() across cpus?
+ *
+ * The more frequently we rebalance shares, the more accurate is the fairness
+ * of cpu bandwidth distribution between task groups. However higher frequency
+ * also implies increased scheduling overhead.
+ *
+ * sysctl_sched_min_bal_int_shares represents the minimum interval between
+ * consecutive calls to rebalance_shares() in the same sched domain.
+ *
+ * sysctl_sched_max_bal_int_shares represents the maximum interval between
+ * consecutive calls to rebalance_shares() in the same sched domain.
+ *
+ * These settings allows for the appropriate trade-off between accuracy of
+ * fairness and the associated overhead.
+ *
+ */
+
+/* default: 8ms, units: milliseconds */
+const_debug unsigned int sysctl_sched_min_bal_int_shares = 8;
+
+/* default: 128ms, units: milliseconds */
+const_debug unsigned int sysctl_sched_max_bal_int_shares = 128;
+
+/* kernel thread that runs rebalance_shares() periodically */
+static int load_balance_monitor(void *unused)
+{
+       unsigned int timeout = sysctl_sched_min_bal_int_shares;
+       struct sched_param schedparm;
+       int ret;
+
+       /*
+        * We don't want this thread's execution to be limited by the shares
+        * assigned to default group (init_task_group). Hence make it run
+        * as a SCHED_RR RT task at the lowest priority.
+        */
+       schedparm.sched_priority = 1;
+       ret = sched_setscheduler(current, SCHED_RR, &schedparm);
+       if (ret)
+               printk(KERN_ERR "Couldn't set SCHED_RR policy for load balance"
+                               " monitor thread (error = %d) \n", ret);
+
+       while (!kthread_should_stop()) {
+               int i, cpu, balanced = 1;
+
+               /* Prevent cpus going down or coming up */
+               get_online_cpus();
+               /* lockout changes to doms_cur[] array */
+               lock_doms_cur();
+               /*
+                * Enter a rcu read-side critical section to safely walk rq->sd
+                * chain on various cpus and to walk task group list
+                * (rq->leaf_cfs_rq_list) in rebalance_shares().
+                */
+               rcu_read_lock();
+
+               for (i = 0; i < ndoms_cur; i++) {
+                       cpumask_t cpumap = doms_cur[i];
+                       struct sched_domain *sd = NULL, *sd_prev = NULL;
+
+                       cpu = first_cpu(cpumap);
+
+                       /* Find the highest domain at which to balance shares */
+                       for_each_domain(cpu, sd) {
+                               if (!(sd->flags & SD_LOAD_BALANCE))
+                                       continue;
+                               sd_prev = sd;
+                       }
+
+                       sd = sd_prev;
+                       /* sd == NULL? No load balance reqd in this domain */
+                       if (!sd)
+                               continue;
+
+                       balanced &= rebalance_shares(sd, cpu);
+               }
+
+               rcu_read_unlock();
+
+               unlock_doms_cur();
+               put_online_cpus();
+
+               if (!balanced)
+                       timeout = sysctl_sched_min_bal_int_shares;
+               else if (timeout < sysctl_sched_max_bal_int_shares)
+                       timeout *= 2;
+
+               msleep_interruptible(timeout);
+       }
+
+       return 0;
+}
+#endif /* CONFIG_SMP */
+
+static void free_sched_group(struct task_group *tg)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               if (tg->cfs_rq)
+                       kfree(tg->cfs_rq[i]);
+               if (tg->se)
+                       kfree(tg->se[i]);
+               if (tg->rt_rq)
+                       kfree(tg->rt_rq[i]);
+               if (tg->rt_se)
+                       kfree(tg->rt_se[i]);
+       }
+
+       kfree(tg->cfs_rq);
+       kfree(tg->se);
+       kfree(tg->rt_rq);
+       kfree(tg->rt_se);
+       kfree(tg);
+}
+
 /* allocate runqueue etc for a new task group */
 struct task_group *sched_create_group(void)
 {
        struct task_group *tg;
        struct cfs_rq *cfs_rq;
        struct sched_entity *se;
+       struct rt_rq *rt_rq;
+       struct sched_rt_entity *rt_se;
        struct rq *rq;
        int i;
 
@@ -6994,97 +7579,89 @@ struct task_group *sched_create_group(void)
        tg->se = kzalloc(sizeof(se) * NR_CPUS, GFP_KERNEL);
        if (!tg->se)
                goto err;
+       tg->rt_rq = kzalloc(sizeof(rt_rq) * NR_CPUS, GFP_KERNEL);
+       if (!tg->rt_rq)
+               goto err;
+       tg->rt_se = kzalloc(sizeof(rt_se) * NR_CPUS, GFP_KERNEL);
+       if (!tg->rt_se)
+               goto err;
+
+       tg->shares = NICE_0_LOAD;
+       tg->rt_ratio = 0; /* XXX */
 
        for_each_possible_cpu(i) {
                rq = cpu_rq(i);
 
-               cfs_rq = kmalloc_node(sizeof(struct cfs_rq), GFP_KERNEL,
-                                                        cpu_to_node(i));
+               cfs_rq = kmalloc_node(sizeof(struct cfs_rq),
+                               GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
                if (!cfs_rq)
                        goto err;
 
-               se = kmalloc_node(sizeof(struct sched_entity), GFP_KERNEL,
-                                                       cpu_to_node(i));
+               se = kmalloc_node(sizeof(struct sched_entity),
+                               GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
                if (!se)
                        goto err;
 
-               memset(cfs_rq, 0, sizeof(struct cfs_rq));
-               memset(se, 0, sizeof(struct sched_entity));
+               rt_rq = kmalloc_node(sizeof(struct rt_rq),
+                               GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
+               if (!rt_rq)
+                       goto err;
 
-               tg->cfs_rq[i] = cfs_rq;
-               init_cfs_rq(cfs_rq, rq);
-               cfs_rq->tg = tg;
+               rt_se = kmalloc_node(sizeof(struct sched_rt_entity),
+                               GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
+               if (!rt_se)
+                       goto err;
 
-               tg->se[i] = se;
-               se->cfs_rq = &rq->cfs;
-               se->my_q = cfs_rq;
-               se->load.weight = NICE_0_LOAD;
-               se->load.inv_weight = div64_64(1ULL<<32, NICE_0_LOAD);
-               se->parent = NULL;
+               init_tg_cfs_entry(rq, tg, cfs_rq, se, i, 0);
+               init_tg_rt_entry(rq, tg, rt_rq, rt_se, i, 0);
        }
 
+       lock_task_group_list();
        for_each_possible_cpu(i) {
                rq = cpu_rq(i);
                cfs_rq = tg->cfs_rq[i];
                list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+               rt_rq = tg->rt_rq[i];
+               list_add_rcu(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list);
        }
-
-       tg->shares = NICE_0_LOAD;
-       spin_lock_init(&tg->lock);
+       list_add_rcu(&tg->list, &task_groups);
+       unlock_task_group_list();
 
        return tg;
 
 err:
-       for_each_possible_cpu(i) {
-               if (tg->cfs_rq)
-                       kfree(tg->cfs_rq[i]);
-               if (tg->se)
-                       kfree(tg->se[i]);
-       }
-       kfree(tg->cfs_rq);
-       kfree(tg->se);
-       kfree(tg);
-
+       free_sched_group(tg);
        return ERR_PTR(-ENOMEM);
 }
 
 /* rcu callback to free various structures associated with a task group */
-static void free_sched_group(struct rcu_head *rhp)
+static void free_sched_group_rcu(struct rcu_head *rhp)
 {
-       struct task_group *tg = container_of(rhp, struct task_group, rcu);
-       struct cfs_rq *cfs_rq;
-       struct sched_entity *se;
-       int i;
-
        /* now it should be safe to free those cfs_rqs */
-       for_each_possible_cpu(i) {
-               cfs_rq = tg->cfs_rq[i];
-               kfree(cfs_rq);
-
-               se = tg->se[i];
-               kfree(se);
-       }
-
-       kfree(tg->cfs_rq);
-       kfree(tg->se);
-       kfree(tg);
+       free_sched_group(container_of(rhp, struct task_group, rcu));
 }
 
 /* Destroy runqueue etc associated with a task group */
 void sched_destroy_group(struct task_group *tg)
 {
        struct cfs_rq *cfs_rq = NULL;
+       struct rt_rq *rt_rq = NULL;
        int i;
 
+       lock_task_group_list();
        for_each_possible_cpu(i) {
                cfs_rq = tg->cfs_rq[i];
                list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
+               rt_rq = tg->rt_rq[i];
+               list_del_rcu(&rt_rq->leaf_rt_rq_list);
        }
+       list_del_rcu(&tg->list);
+       unlock_task_group_list();
 
        BUG_ON(!cfs_rq);
 
        /* wait for possible concurrent references to cfs_rqs complete */
-       call_rcu(&tg->rcu, free_sched_group);
+       call_rcu(&tg->rcu, free_sched_group_rcu);
 }
 
 /* change task's runqueue when it moves between groups.
@@ -7100,11 +7677,6 @@ void sched_move_task(struct task_struct *tsk)
 
        rq = task_rq_lock(tsk, &flags);
 
-       if (tsk->sched_class != &fair_sched_class) {
-               set_task_cfs_rq(tsk, task_cpu(tsk));
-               goto done;
-       }
-
        update_rq_clock(rq);
 
        running = task_current(rq, tsk);
@@ -7116,7 +7688,7 @@ void sched_move_task(struct task_struct *tsk)
                        tsk->sched_class->put_prev_task(rq, tsk);
        }
 
-       set_task_cfs_rq(tsk, task_cpu(tsk));
+       set_task_rq(tsk, task_cpu(tsk));
 
        if (on_rq) {
                if (unlikely(running))
@@ -7124,45 +7696,82 @@ void sched_move_task(struct task_struct *tsk)
                enqueue_task(rq, tsk, 0);
        }
 
-done:
        task_rq_unlock(rq, &flags);
 }
 
+/* rq->lock to be locked by caller */
 static void set_se_shares(struct sched_entity *se, unsigned long shares)
 {
        struct cfs_rq *cfs_rq = se->cfs_rq;
        struct rq *rq = cfs_rq->rq;
        int on_rq;
 
-       spin_lock_irq(&rq->lock);
+       if (!shares)
+               shares = MIN_GROUP_SHARES;
 
        on_rq = se->on_rq;
-       if (on_rq)
+       if (on_rq) {
                dequeue_entity(cfs_rq, se, 0);
+               dec_cpu_load(rq, se->load.weight);
+       }
 
        se->load.weight = shares;
        se->load.inv_weight = div64_64((1ULL<<32), shares);
 
-       if (on_rq)
+       if (on_rq) {
                enqueue_entity(cfs_rq, se, 0);
-
-       spin_unlock_irq(&rq->lock);
+               inc_cpu_load(rq, se->load.weight);
+       }
 }
 
 int sched_group_set_shares(struct task_group *tg, unsigned long shares)
 {
        int i;
+       struct cfs_rq *cfs_rq;
+       struct rq *rq;
 
-       spin_lock(&tg->lock);
+       lock_task_group_list();
        if (tg->shares == shares)
                goto done;
 
+       if (shares < MIN_GROUP_SHARES)
+               shares = MIN_GROUP_SHARES;
+
+       /*
+        * Prevent any load balance activity (rebalance_shares,
+        * load_balance_fair) from referring to this group first,
+        * by taking it off the rq->leaf_cfs_rq_list on each cpu.
+        */
+       for_each_possible_cpu(i) {
+               cfs_rq = tg->cfs_rq[i];
+               list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
+       }
+
+       /* wait for any ongoing reference to this group to finish */
+       synchronize_sched();
+
+       /*
+        * Now we are free to modify the group's share on each cpu
+        * w/o tripping rebalance_share or load_balance_fair.
+        */
        tg->shares = shares;
-       for_each_possible_cpu(i)
+       for_each_possible_cpu(i) {
+               spin_lock_irq(&cpu_rq(i)->lock);
                set_se_shares(tg->se[i], shares);
+               spin_unlock_irq(&cpu_rq(i)->lock);
+       }
 
+       /*
+        * Enable load balance activity on this group, by inserting it back on
+        * each cpu's rq->leaf_cfs_rq_list.
+        */
+       for_each_possible_cpu(i) {
+               rq = cpu_rq(i);
+               cfs_rq = tg->cfs_rq[i];
+               list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list);
+       }
 done:
-       spin_unlock(&tg->lock);
+       unlock_task_group_list();
        return 0;
 }
 
@@ -7171,6 +7780,31 @@ unsigned long sched_group_shares(struct task_group *tg)
        return tg->shares;
 }
 
+/*
+ * Ensure the total rt_ratio <= sysctl_sched_rt_ratio
+ */
+int sched_group_set_rt_ratio(struct task_group *tg, unsigned long rt_ratio)
+{
+       struct task_group *tgi;
+       unsigned long total = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(tgi, &task_groups, list)
+               total += tgi->rt_ratio;
+       rcu_read_unlock();
+
+       if (total + rt_ratio - tg->rt_ratio > sysctl_sched_rt_ratio)
+               return -EINVAL;
+
+       tg->rt_ratio = rt_ratio;
+       return 0;
+}
+
+unsigned long sched_group_rt_ratio(struct task_group *tg)
+{
+       return tg->rt_ratio;
+}
+
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 #ifdef CONFIG_FAIR_CGROUP_SCHED
@@ -7246,12 +7880,30 @@ static u64 cpu_shares_read_uint(struct cgroup *cgrp, struct cftype *cft)
        return (u64) tg->shares;
 }
 
+static int cpu_rt_ratio_write_uint(struct cgroup *cgrp, struct cftype *cftype,
+               u64 rt_ratio_val)
+{
+       return sched_group_set_rt_ratio(cgroup_tg(cgrp), rt_ratio_val);
+}
+
+static u64 cpu_rt_ratio_read_uint(struct cgroup *cgrp, struct cftype *cft)
+{
+       struct task_group *tg = cgroup_tg(cgrp);
+
+       return (u64) tg->rt_ratio;
+}
+
 static struct cftype cpu_files[] = {
        {
                .name = "shares",
                .read_uint = cpu_shares_read_uint,
                .write_uint = cpu_shares_write_uint,
        },
+       {
+               .name = "rt_ratio",
+               .read_uint = cpu_rt_ratio_read_uint,
+               .write_uint = cpu_rt_ratio_write_uint,
+       },
 };
 
 static int cpu_cgroup_populate(struct cgroup_subsys *ss, struct cgroup *cont)
index d30467b47ddd0cd681f6da0afbe9c96c8b52df93..4b5e24cf2f4a98387c849d8461b85a8a9c79aa55 100644 (file)
@@ -31,9 +31,9 @@
 /*
  * Ease the printing of nsec fields:
  */
-static long long nsec_high(long long nsec)
+static long long nsec_high(unsigned long long nsec)
 {
-       if (nsec < 0) {
+       if ((long long)nsec < 0) {
                nsec = -nsec;
                do_div(nsec, 1000000);
                return -nsec;
@@ -43,9 +43,9 @@ static long long nsec_high(long long nsec)
        return nsec;
 }
 
-static unsigned long nsec_low(long long nsec)
+static unsigned long nsec_low(unsigned long long nsec)
 {
-       if (nsec < 0)
+       if ((long long)nsec < 0)
                nsec = -nsec;
 
        return do_div(nsec, 1000000);
@@ -179,6 +179,7 @@ static void print_cpu(struct seq_file *m, int cpu)
        PN(prev_clock_raw);
        P(clock_warps);
        P(clock_overflows);
+       P(clock_underflows);
        P(clock_deep_idle_events);
        PN(clock_max_delta);
        P(cpu_load[0]);
@@ -299,6 +300,8 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        PN(se.exec_max);
        PN(se.slice_max);
        PN(se.wait_max);
+       PN(se.wait_sum);
+       P(se.wait_count);
        P(sched_info.bkl_count);
        P(se.nr_migrations);
        P(se.nr_migrations_cold);
@@ -366,6 +369,8 @@ void proc_sched_set_task(struct task_struct *p)
 {
 #ifdef CONFIG_SCHEDSTATS
        p->se.wait_max                          = 0;
+       p->se.wait_sum                          = 0;
+       p->se.wait_count                        = 0;
        p->se.sleep_max                         = 0;
        p->se.sum_sleep_runtime                 = 0;
        p->se.block_max                         = 0;
index da7c061e72062eacd6afee8a9870e9044ad0e2c5..72e25c7a3a186dc9830c206662dca4ad7d5892cb 100644 (file)
@@ -20,6 +20,8 @@
  *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
  */
 
+#include <linux/latencytop.h>
+
 /*
  * Targeted preemption latency for CPU-bound tasks:
  * (default: 20ms * (1 + ilog(ncpus)), units: nanoseconds)
@@ -248,8 +250,8 @@ static u64 __sched_period(unsigned long nr_running)
        unsigned long nr_latency = sched_nr_latency;
 
        if (unlikely(nr_running > nr_latency)) {
+               period = sysctl_sched_min_granularity;
                period *= nr_running;
-               do_div(period, nr_latency);
        }
 
        return period;
@@ -383,6 +385,9 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
        schedstat_set(se->wait_max, max(se->wait_max,
                        rq_of(cfs_rq)->clock - se->wait_start));
+       schedstat_set(se->wait_count, se->wait_count + 1);
+       schedstat_set(se->wait_sum, se->wait_sum +
+                       rq_of(cfs_rq)->clock - se->wait_start);
        schedstat_set(se->wait_start, 0);
 }
 
@@ -434,6 +439,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
 #ifdef CONFIG_SCHEDSTATS
        if (se->sleep_start) {
                u64 delta = rq_of(cfs_rq)->clock - se->sleep_start;
+               struct task_struct *tsk = task_of(se);
 
                if ((s64)delta < 0)
                        delta = 0;
@@ -443,9 +449,12 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
 
                se->sleep_start = 0;
                se->sum_sleep_runtime += delta;
+
+               account_scheduler_latency(tsk, delta >> 10, 1);
        }
        if (se->block_start) {
                u64 delta = rq_of(cfs_rq)->clock - se->block_start;
+               struct task_struct *tsk = task_of(se);
 
                if ((s64)delta < 0)
                        delta = 0;
@@ -462,11 +471,11 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
                 * time that the task spent sleeping:
                 */
                if (unlikely(prof_on == SLEEP_PROFILING)) {
-                       struct task_struct *tsk = task_of(se);
 
                        profile_hits(SLEEP_PROFILING, (void *)get_wchan(tsk),
                                     delta >> 20);
                }
+               account_scheduler_latency(tsk, delta >> 10, 0);
        }
 #endif
 }
@@ -642,13 +651,29 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
        cfs_rq->curr = NULL;
 }
 
-static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
+static void
+entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
 {
        /*
         * Update run-time statistics of the 'current'.
         */
        update_curr(cfs_rq);
 
+#ifdef CONFIG_SCHED_HRTICK
+       /*
+        * queued ticks are scheduled to match the slice, so don't bother
+        * validating it and just reschedule.
+        */
+       if (queued)
+               return resched_task(rq_of(cfs_rq)->curr);
+       /*
+        * don't let the period tick interfere with the hrtick preemption
+        */
+       if (!sched_feat(DOUBLE_TICK) &&
+                       hrtimer_active(&rq_of(cfs_rq)->hrtick_timer))
+               return;
+#endif
+
        if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT))
                check_preempt_tick(cfs_rq, curr);
 }
@@ -690,7 +715,7 @@ static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
 
 /* Iterate thr' all leaf cfs_rq's on a runqueue */
 #define for_each_leaf_cfs_rq(rq, cfs_rq) \
-       list_for_each_entry(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
+       list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
 
 /* Do the two (enqueued) entities belong to the same group ? */
 static inline int
@@ -707,6 +732,8 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se)
        return se->parent;
 }
 
+#define GROUP_IMBALANCE_PCT    20
+
 #else  /* CONFIG_FAIR_GROUP_SCHED */
 
 #define for_each_sched_entity(se) \
@@ -752,6 +779,43 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se)
 
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
+#ifdef CONFIG_SCHED_HRTICK
+static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
+{
+       int requeue = rq->curr == p;
+       struct sched_entity *se = &p->se;
+       struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+       WARN_ON(task_rq(p) != rq);
+
+       if (hrtick_enabled(rq) && cfs_rq->nr_running > 1) {
+               u64 slice = sched_slice(cfs_rq, se);
+               u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
+               s64 delta = slice - ran;
+
+               if (delta < 0) {
+                       if (rq->curr == p)
+                               resched_task(p);
+                       return;
+               }
+
+               /*
+                * Don't schedule slices shorter than 10000ns, that just
+                * doesn't make sense. Rely on vruntime for fairness.
+                */
+               if (!requeue)
+                       delta = max(10000LL, delta);
+
+               hrtick_start(rq, delta, requeue);
+       }
+}
+#else
+static inline void
+hrtick_start_fair(struct rq *rq, struct task_struct *p)
+{
+}
+#endif
+
 /*
  * The enqueue_task method is called before nr_running is
  * increased. Here we update the fair scheduling stats and
@@ -760,15 +824,28 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se)
 static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup)
 {
        struct cfs_rq *cfs_rq;
-       struct sched_entity *se = &p->se;
+       struct sched_entity *se = &p->se,
+                           *topse = NULL;      /* Highest schedulable entity */
+       int incload = 1;
 
        for_each_sched_entity(se) {
-               if (se->on_rq)
+               topse = se;
+               if (se->on_rq) {
+                       incload = 0;
                        break;
+               }
                cfs_rq = cfs_rq_of(se);
                enqueue_entity(cfs_rq, se, wakeup);
                wakeup = 1;
        }
+       /* Increment cpu load if we just enqueued the first task of a group on
+        * 'rq->cpu'. 'topse' represents the group to which task 'p' belongs
+        * at the highest grouping level.
+        */
+       if (incload)
+               inc_cpu_load(rq, topse->load.weight);
+
+       hrtick_start_fair(rq, rq->curr);
 }
 
 /*
@@ -779,16 +856,30 @@ static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup)
 static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
 {
        struct cfs_rq *cfs_rq;
-       struct sched_entity *se = &p->se;
+       struct sched_entity *se = &p->se,
+                           *topse = NULL;      /* Highest schedulable entity */
+       int decload = 1;
 
        for_each_sched_entity(se) {
+               topse = se;
                cfs_rq = cfs_rq_of(se);
                dequeue_entity(cfs_rq, se, sleep);
                /* Don't dequeue parent if it has other entities besides us */
-               if (cfs_rq->load.weight)
+               if (cfs_rq->load.weight) {
+                       if (parent_entity(se))
+                               decload = 0;
                        break;
+               }
                sleep = 1;
        }
+       /* Decrement cpu load if we just dequeued the last task of a group on
+        * 'rq->cpu'. 'topse' represents the group to which task 'p' belongs
+        * at the highest grouping level.
+        */
+       if (decload)
+               dec_cpu_load(rq, topse->load.weight);
+
+       hrtick_start_fair(rq, rq->curr);
 }
 
 /*
@@ -835,6 +926,154 @@ static void yield_task_fair(struct rq *rq)
        se->vruntime = rightmost->vruntime + 1;
 }
 
+/*
+ * wake_idle() will wake a task on an idle cpu if task->cpu is
+ * not idle and an idle cpu is available.  The span of cpus to
+ * search starts with cpus closest then further out as needed,
+ * so we always favor a closer, idle cpu.
+ *
+ * Returns the CPU we should wake onto.
+ */
+#if defined(ARCH_HAS_SCHED_WAKE_IDLE)
+static int wake_idle(int cpu, struct task_struct *p)
+{
+       cpumask_t tmp;
+       struct sched_domain *sd;
+       int i;
+
+       /*
+        * If it is idle, then it is the best cpu to run this task.
+        *
+        * This cpu is also the best, if it has more than one task already.
+        * Siblings must be also busy(in most cases) as they didn't already
+        * pickup the extra load from this cpu and hence we need not check
+        * sibling runqueue info. This will avoid the checks and cache miss
+        * penalities associated with that.
+        */
+       if (idle_cpu(cpu) || cpu_rq(cpu)->nr_running > 1)
+               return cpu;
+
+       for_each_domain(cpu, sd) {
+               if (sd->flags & SD_WAKE_IDLE) {
+                       cpus_and(tmp, sd->span, p->cpus_allowed);
+                       for_each_cpu_mask(i, tmp) {
+                               if (idle_cpu(i)) {
+                                       if (i != task_cpu(p)) {
+                                               schedstat_inc(p,
+                                                      se.nr_wakeups_idle);
+                                       }
+                                       return i;
+                               }
+                       }
+               } else {
+                       break;
+               }
+       }
+       return cpu;
+}
+#else
+static inline int wake_idle(int cpu, struct task_struct *p)
+{
+       return cpu;
+}
+#endif
+
+#ifdef CONFIG_SMP
+static int select_task_rq_fair(struct task_struct *p, int sync)
+{
+       int cpu, this_cpu;
+       struct rq *rq;
+       struct sched_domain *sd, *this_sd = NULL;
+       int new_cpu;
+
+       cpu      = task_cpu(p);
+       rq       = task_rq(p);
+       this_cpu = smp_processor_id();
+       new_cpu  = cpu;
+
+       if (cpu == this_cpu)
+               goto out_set_cpu;
+
+       for_each_domain(this_cpu, sd) {
+               if (cpu_isset(cpu, sd->span)) {
+                       this_sd = sd;
+                       break;
+               }
+       }
+
+       if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
+               goto out_set_cpu;
+
+       /*
+        * Check for affine wakeup and passive balancing possibilities.
+        */
+       if (this_sd) {
+               int idx = this_sd->wake_idx;
+               unsigned int imbalance;
+               unsigned long load, this_load;
+
+               imbalance = 100 + (this_sd->imbalance_pct - 100) / 2;
+
+               load = source_load(cpu, idx);
+               this_load = target_load(this_cpu, idx);
+
+               new_cpu = this_cpu; /* Wake to this CPU if we can */
+
+               if (this_sd->flags & SD_WAKE_AFFINE) {
+                       unsigned long tl = this_load;
+                       unsigned long tl_per_task;
+
+                       /*
+                        * Attract cache-cold tasks on sync wakeups:
+                        */
+                       if (sync && !task_hot(p, rq->clock, this_sd))
+                               goto out_set_cpu;
+
+                       schedstat_inc(p, se.nr_wakeups_affine_attempts);
+                       tl_per_task = cpu_avg_load_per_task(this_cpu);
+
+                       /*
+                        * If sync wakeup then subtract the (maximum possible)
+                        * effect of the currently running task from the load
+                        * of the current CPU:
+                        */
+                       if (sync)
+                               tl -= current->se.load.weight;
+
+                       if ((tl <= load &&
+                               tl + target_load(cpu, idx) <= tl_per_task) ||
+                              100*(tl + p->se.load.weight) <= imbalance*load) {
+                               /*
+                                * This domain has SD_WAKE_AFFINE and
+                                * p is cache cold in this domain, and
+                                * there is no bad imbalance.
+                                */
+                               schedstat_inc(this_sd, ttwu_move_affine);
+                               schedstat_inc(p, se.nr_wakeups_affine);
+                               goto out_set_cpu;
+                       }
+               }
+
+               /*
+                * Start passive balancing when half the imbalance_pct
+                * limit is reached.
+                */
+               if (this_sd->flags & SD_WAKE_BALANCE) {
+                       if (imbalance*this_load <= 100*load) {
+                               schedstat_inc(this_sd, ttwu_move_balance);
+                               schedstat_inc(p, se.nr_wakeups_passive);
+                               goto out_set_cpu;
+                       }
+               }
+       }
+
+       new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */
+out_set_cpu:
+       return wake_idle(new_cpu, p);
+}
+#endif /* CONFIG_SMP */
+
+
 /*
  * Preempt the current task with a newly woken task if needed:
  */
@@ -876,6 +1115,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
 
 static struct task_struct *pick_next_task_fair(struct rq *rq)
 {
+       struct task_struct *p;
        struct cfs_rq *cfs_rq = &rq->cfs;
        struct sched_entity *se;
 
@@ -887,7 +1127,10 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)
                cfs_rq = group_cfs_rq(se);
        } while (cfs_rq);
 
-       return task_of(se);
+       p = task_of(se);
+       hrtick_start_fair(rq, p);
+
+       return p;
 }
 
 /*
@@ -944,25 +1187,6 @@ static struct task_struct *load_balance_next_fair(void *arg)
        return __load_balance_iterator(cfs_rq, cfs_rq->rb_load_balance_curr);
 }
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-static int cfs_rq_best_prio(struct cfs_rq *cfs_rq)
-{
-       struct sched_entity *curr;
-       struct task_struct *p;
-
-       if (!cfs_rq->nr_running)
-               return MAX_PRIO;
-
-       curr = cfs_rq->curr;
-       if (!curr)
-               curr = __pick_next_entity(cfs_rq);
-
-       p = task_of(curr);
-
-       return p->prio;
-}
-#endif
-
 static unsigned long
 load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
                  unsigned long max_load_move,
@@ -972,28 +1196,45 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
        struct cfs_rq *busy_cfs_rq;
        long rem_load_move = max_load_move;
        struct rq_iterator cfs_rq_iterator;
+       unsigned long load_moved;
 
        cfs_rq_iterator.start = load_balance_start_fair;
        cfs_rq_iterator.next = load_balance_next_fair;
 
        for_each_leaf_cfs_rq(busiest, busy_cfs_rq) {
 #ifdef CONFIG_FAIR_GROUP_SCHED
-               struct cfs_rq *this_cfs_rq;
-               long imbalance;
-               unsigned long maxload;
+               struct cfs_rq *this_cfs_rq = busy_cfs_rq->tg->cfs_rq[this_cpu];
+               unsigned long maxload, task_load, group_weight;
+               unsigned long thisload, per_task_load;
+               struct sched_entity *se = busy_cfs_rq->tg->se[busiest->cpu];
+
+               task_load = busy_cfs_rq->load.weight;
+               group_weight = se->load.weight;
 
-               this_cfs_rq = cpu_cfs_rq(busy_cfs_rq, this_cpu);
+               /*
+                * 'group_weight' is contributed by tasks of total weight
+                * 'task_load'. To move 'rem_load_move' worth of weight only,
+                * we need to move a maximum task load of:
+                *
+                *      maxload = (remload / group_weight) * task_load;
+                */
+               maxload = (rem_load_move * task_load) / group_weight;
 
-               imbalance = busy_cfs_rq->load.weight - this_cfs_rq->load.weight;
-               /* Don't pull if this_cfs_rq has more load than busy_cfs_rq */
-               if (imbalance <= 0)
+               if (!maxload || !task_load)
                        continue;
 
-               /* Don't pull more than imbalance/2 */
-               imbalance /= 2;
-               maxload = min(rem_load_move, imbalance);
+               per_task_load = task_load / busy_cfs_rq->nr_running;
+               /*
+                * balance_tasks will try to forcibly move atleast one task if
+                * possible (because of SCHED_LOAD_SCALE_FUZZ). Avoid that if
+                * maxload is less than GROUP_IMBALANCE_FUZZ% the per_task_load.
+                */
+                if (100 * maxload < GROUP_IMBALANCE_PCT * per_task_load)
+                       continue;
 
-               *this_best_prio = cfs_rq_best_prio(this_cfs_rq);
+               /* Disable priority-based load balance */
+               *this_best_prio = 0;
+               thisload = this_cfs_rq->load.weight;
 #else
 # define maxload rem_load_move
 #endif
@@ -1002,11 +1243,33 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
                 * load_balance_[start|next]_fair iterators
                 */
                cfs_rq_iterator.arg = busy_cfs_rq;
-               rem_load_move -= balance_tasks(this_rq, this_cpu, busiest,
+               load_moved = balance_tasks(this_rq, this_cpu, busiest,
                                               maxload, sd, idle, all_pinned,
                                               this_best_prio,
                                               &cfs_rq_iterator);
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+               /*
+                * load_moved holds the task load that was moved. The
+                * effective (group) weight moved would be:
+                *      load_moved_eff = load_moved/task_load * group_weight;
+                */
+               load_moved = (group_weight * load_moved) / task_load;
+
+               /* Adjust shares on both cpus to reflect load_moved */
+               group_weight -= load_moved;
+               set_se_shares(se, group_weight);
+
+               se = busy_cfs_rq->tg->se[this_cpu];
+               if (!thisload)
+                       group_weight = load_moved;
+               else
+                       group_weight = se->load.weight + load_moved;
+               set_se_shares(se, group_weight);
+#endif
+
+               rem_load_move -= load_moved;
+
                if (rem_load_move <= 0)
                        break;
        }
@@ -1042,14 +1305,14 @@ move_one_task_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
 /*
  * scheduler tick hitting a task of our scheduling class:
  */
-static void task_tick_fair(struct rq *rq, struct task_struct *curr)
+static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
 {
        struct cfs_rq *cfs_rq;
        struct sched_entity *se = &curr->se;
 
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
-               entity_tick(cfs_rq, se);
+               entity_tick(cfs_rq, se, queued);
        }
 }
 
@@ -1087,6 +1350,42 @@ static void task_new_fair(struct rq *rq, struct task_struct *p)
        resched_task(rq->curr);
 }
 
+/*
+ * Priority of the task has changed. Check to see if we preempt
+ * the current task.
+ */
+static void prio_changed_fair(struct rq *rq, struct task_struct *p,
+                             int oldprio, int running)
+{
+       /*
+        * Reschedule if we are currently running on this runqueue and
+        * our priority decreased, or if we are not currently running on
+        * this runqueue and our priority is higher than the current's
+        */
+       if (running) {
+               if (p->prio > oldprio)
+                       resched_task(rq->curr);
+       } else
+               check_preempt_curr(rq, p);
+}
+
+/*
+ * We switched to the sched_fair class.
+ */
+static void switched_to_fair(struct rq *rq, struct task_struct *p,
+                            int running)
+{
+       /*
+        * We were most likely switched from sched_rt, so
+        * kick off the schedule if running, otherwise just see
+        * if we can still preempt the current task.
+        */
+       if (running)
+               resched_task(rq->curr);
+       else
+               check_preempt_curr(rq, p);
+}
+
 /* Account for a task changing its policy or group.
  *
  * This routine is mostly called to set cfs_rq->curr field when a task
@@ -1108,6 +1407,9 @@ static const struct sched_class fair_sched_class = {
        .enqueue_task           = enqueue_task_fair,
        .dequeue_task           = dequeue_task_fair,
        .yield_task             = yield_task_fair,
+#ifdef CONFIG_SMP
+       .select_task_rq         = select_task_rq_fair,
+#endif /* CONFIG_SMP */
 
        .check_preempt_curr     = check_preempt_wakeup,
 
@@ -1122,6 +1424,9 @@ static const struct sched_class fair_sched_class = {
        .set_curr_task          = set_curr_task_fair,
        .task_tick              = task_tick_fair,
        .task_new               = task_new_fair,
+
+       .prio_changed           = prio_changed_fair,
+       .switched_to            = switched_to_fair,
 };
 
 #ifdef CONFIG_SCHED_DEBUG
@@ -1132,7 +1437,9 @@ static void print_cfs_stats(struct seq_file *m, int cpu)
 #ifdef CONFIG_FAIR_GROUP_SCHED
        print_cfs_rq(m, cpu, &cpu_rq(cpu)->cfs);
 #endif
+       rcu_read_lock();
        for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
                print_cfs_rq(m, cpu, cfs_rq);
+       rcu_read_unlock();
 }
 #endif
index bf9c25c15b8badfc340dabcb9067ff2437b6d431..2bcafa375633896af9c0bcea45fbdf389d9b11fd 100644 (file)
@@ -5,6 +5,12 @@
  *  handled in sched_fair.c)
  */
 
+#ifdef CONFIG_SMP
+static int select_task_rq_idle(struct task_struct *p, int sync)
+{
+       return task_cpu(p); /* IDLE tasks as never migrated */
+}
+#endif /* CONFIG_SMP */
 /*
  * Idle tasks are unconditionally rescheduled:
  */
@@ -55,7 +61,7 @@ move_one_task_idle(struct rq *this_rq, int this_cpu, struct rq *busiest,
 }
 #endif
 
-static void task_tick_idle(struct rq *rq, struct task_struct *curr)
+static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued)
 {
 }
 
@@ -63,6 +69,33 @@ static void set_curr_task_idle(struct rq *rq)
 {
 }
 
+static void switched_to_idle(struct rq *rq, struct task_struct *p,
+                            int running)
+{
+       /* Can this actually happen?? */
+       if (running)
+               resched_task(rq->curr);
+       else
+               check_preempt_curr(rq, p);
+}
+
+static void prio_changed_idle(struct rq *rq, struct task_struct *p,
+                             int oldprio, int running)
+{
+       /* This can happen for hot plug CPUS */
+
+       /*
+        * Reschedule if we are currently running on this runqueue and
+        * our priority decreased, or if we are not currently running on
+        * this runqueue and our priority is higher than the current's
+        */
+       if (running) {
+               if (p->prio > oldprio)
+                       resched_task(rq->curr);
+       } else
+               check_preempt_curr(rq, p);
+}
+
 /*
  * Simple, special scheduling class for the per-CPU idle tasks:
  */
@@ -72,6 +105,9 @@ const struct sched_class idle_sched_class = {
 
        /* dequeue is not valid, we print a debug message there: */
        .dequeue_task           = dequeue_task_idle,
+#ifdef CONFIG_SMP
+       .select_task_rq         = select_task_rq_idle,
+#endif /* CONFIG_SMP */
 
        .check_preempt_curr     = check_preempt_curr_idle,
 
@@ -85,5 +121,9 @@ const struct sched_class idle_sched_class = {
 
        .set_curr_task          = set_curr_task_idle,
        .task_tick              = task_tick_idle,
+
+       .prio_changed           = prio_changed_idle,
+       .switched_to            = switched_to_idle,
+
        /* no .task_new for idle tasks */
 };
index 9ba3daa03475cfeed642eeaacbd21f5b3aa118eb..274b40d7bef23a3d2f5dbb10c45cd3516669b460 100644 (file)
@@ -3,6 +3,217 @@
  * policies)
  */
 
+#ifdef CONFIG_SMP
+
+static inline int rt_overloaded(struct rq *rq)
+{
+       return atomic_read(&rq->rd->rto_count);
+}
+
+static inline void rt_set_overload(struct rq *rq)
+{
+       cpu_set(rq->cpu, rq->rd->rto_mask);
+       /*
+        * Make sure the mask is visible before we set
+        * the overload count. That is checked to determine
+        * if we should look at the mask. It would be a shame
+        * if we looked at the mask, but the mask was not
+        * updated yet.
+        */
+       wmb();
+       atomic_inc(&rq->rd->rto_count);
+}
+
+static inline void rt_clear_overload(struct rq *rq)
+{
+       /* the order here really doesn't matter */
+       atomic_dec(&rq->rd->rto_count);
+       cpu_clear(rq->cpu, rq->rd->rto_mask);
+}
+
+static void update_rt_migration(struct rq *rq)
+{
+       if (rq->rt.rt_nr_migratory && (rq->rt.rt_nr_running > 1)) {
+               if (!rq->rt.overloaded) {
+                       rt_set_overload(rq);
+                       rq->rt.overloaded = 1;
+               }
+       } else if (rq->rt.overloaded) {
+               rt_clear_overload(rq);
+               rq->rt.overloaded = 0;
+       }
+}
+#endif /* CONFIG_SMP */
+
+static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se)
+{
+       return container_of(rt_se, struct task_struct, rt);
+}
+
+static inline int on_rt_rq(struct sched_rt_entity *rt_se)
+{
+       return !list_empty(&rt_se->run_list);
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+static inline unsigned int sched_rt_ratio(struct rt_rq *rt_rq)
+{
+       if (!rt_rq->tg)
+               return SCHED_RT_FRAC;
+
+       return rt_rq->tg->rt_ratio;
+}
+
+#define for_each_leaf_rt_rq(rt_rq, rq) \
+       list_for_each_entry(rt_rq, &rq->leaf_rt_rq_list, leaf_rt_rq_list)
+
+static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
+{
+       return rt_rq->rq;
+}
+
+static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se)
+{
+       return rt_se->rt_rq;
+}
+
+#define for_each_sched_rt_entity(rt_se) \
+       for (; rt_se; rt_se = rt_se->parent)
+
+static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se)
+{
+       return rt_se->my_q;
+}
+
+static void enqueue_rt_entity(struct sched_rt_entity *rt_se);
+static void dequeue_rt_entity(struct sched_rt_entity *rt_se);
+
+static void sched_rt_ratio_enqueue(struct rt_rq *rt_rq)
+{
+       struct sched_rt_entity *rt_se = rt_rq->rt_se;
+
+       if (rt_se && !on_rt_rq(rt_se) && rt_rq->rt_nr_running) {
+               struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr;
+
+               enqueue_rt_entity(rt_se);
+               if (rt_rq->highest_prio < curr->prio)
+                       resched_task(curr);
+       }
+}
+
+static void sched_rt_ratio_dequeue(struct rt_rq *rt_rq)
+{
+       struct sched_rt_entity *rt_se = rt_rq->rt_se;
+
+       if (rt_se && on_rt_rq(rt_se))
+               dequeue_rt_entity(rt_se);
+}
+
+#else
+
+static inline unsigned int sched_rt_ratio(struct rt_rq *rt_rq)
+{
+       return sysctl_sched_rt_ratio;
+}
+
+#define for_each_leaf_rt_rq(rt_rq, rq) \
+       for (rt_rq = &rq->rt; rt_rq; rt_rq = NULL)
+
+static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
+{
+       return container_of(rt_rq, struct rq, rt);
+}
+
+static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se)
+{
+       struct task_struct *p = rt_task_of(rt_se);
+       struct rq *rq = task_rq(p);
+
+       return &rq->rt;
+}
+
+#define for_each_sched_rt_entity(rt_se) \
+       for (; rt_se; rt_se = NULL)
+
+static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se)
+{
+       return NULL;
+}
+
+static inline void sched_rt_ratio_enqueue(struct rt_rq *rt_rq)
+{
+}
+
+static inline void sched_rt_ratio_dequeue(struct rt_rq *rt_rq)
+{
+}
+
+#endif
+
+static inline int rt_se_prio(struct sched_rt_entity *rt_se)
+{
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       struct rt_rq *rt_rq = group_rt_rq(rt_se);
+
+       if (rt_rq)
+               return rt_rq->highest_prio;
+#endif
+
+       return rt_task_of(rt_se)->prio;
+}
+
+static int sched_rt_ratio_exceeded(struct rt_rq *rt_rq)
+{
+       unsigned int rt_ratio = sched_rt_ratio(rt_rq);
+       u64 period, ratio;
+
+       if (rt_ratio == SCHED_RT_FRAC)
+               return 0;
+
+       if (rt_rq->rt_throttled)
+               return 1;
+
+       period = (u64)sysctl_sched_rt_period * NSEC_PER_MSEC;
+       ratio = (period * rt_ratio) >> SCHED_RT_FRAC_SHIFT;
+
+       if (rt_rq->rt_time > ratio) {
+               struct rq *rq = rq_of_rt_rq(rt_rq);
+
+               rq->rt_throttled = 1;
+               rt_rq->rt_throttled = 1;
+
+               sched_rt_ratio_dequeue(rt_rq);
+               return 1;
+       }
+
+       return 0;
+}
+
+static void update_sched_rt_period(struct rq *rq)
+{
+       struct rt_rq *rt_rq;
+       u64 period;
+
+       while (rq->clock > rq->rt_period_expire) {
+               period = (u64)sysctl_sched_rt_period * NSEC_PER_MSEC;
+               rq->rt_period_expire += period;
+
+               for_each_leaf_rt_rq(rt_rq, rq) {
+                       unsigned long rt_ratio = sched_rt_ratio(rt_rq);
+                       u64 ratio = (period * rt_ratio) >> SCHED_RT_FRAC_SHIFT;
+
+                       rt_rq->rt_time -= min(rt_rq->rt_time, ratio);
+                       if (rt_rq->rt_throttled) {
+                               rt_rq->rt_throttled = 0;
+                               sched_rt_ratio_enqueue(rt_rq);
+                       }
+               }
+
+               rq->rt_throttled = 0;
+       }
+}
+
 /*
  * Update the current task's runtime statistics. Skip current tasks that
  * are not in our scheduling class.
 static void update_curr_rt(struct rq *rq)
 {
        struct task_struct *curr = rq->curr;
+       struct sched_rt_entity *rt_se = &curr->rt;
+       struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
        u64 delta_exec;
 
        if (!task_has_rt_policy(curr))
@@ -24,47 +237,228 @@ static void update_curr_rt(struct rq *rq)
        curr->se.sum_exec_runtime += delta_exec;
        curr->se.exec_start = rq->clock;
        cpuacct_charge(curr, delta_exec);
+
+       rt_rq->rt_time += delta_exec;
+       /*
+        * might make it a tad more accurate:
+        *
+        * update_sched_rt_period(rq);
+        */
+       if (sched_rt_ratio_exceeded(rt_rq))
+               resched_task(curr);
 }
 
-static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup)
+static inline
+void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
+{
+       WARN_ON(!rt_prio(rt_se_prio(rt_se)));
+       rt_rq->rt_nr_running++;
+#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED
+       if (rt_se_prio(rt_se) < rt_rq->highest_prio)
+               rt_rq->highest_prio = rt_se_prio(rt_se);
+#endif
+#ifdef CONFIG_SMP
+       if (rt_se->nr_cpus_allowed > 1) {
+               struct rq *rq = rq_of_rt_rq(rt_rq);
+               rq->rt.rt_nr_migratory++;
+       }
+
+       update_rt_migration(rq_of_rt_rq(rt_rq));
+#endif
+}
+
+static inline
+void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
+{
+       WARN_ON(!rt_prio(rt_se_prio(rt_se)));
+       WARN_ON(!rt_rq->rt_nr_running);
+       rt_rq->rt_nr_running--;
+#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED
+       if (rt_rq->rt_nr_running) {
+               struct rt_prio_array *array;
+
+               WARN_ON(rt_se_prio(rt_se) < rt_rq->highest_prio);
+               if (rt_se_prio(rt_se) == rt_rq->highest_prio) {
+                       /* recalculate */
+                       array = &rt_rq->active;
+                       rt_rq->highest_prio =
+                               sched_find_first_bit(array->bitmap);
+               } /* otherwise leave rq->highest prio alone */
+       } else
+               rt_rq->highest_prio = MAX_RT_PRIO;
+#endif
+#ifdef CONFIG_SMP
+       if (rt_se->nr_cpus_allowed > 1) {
+               struct rq *rq = rq_of_rt_rq(rt_rq);
+               rq->rt.rt_nr_migratory--;
+       }
+
+       update_rt_migration(rq_of_rt_rq(rt_rq));
+#endif /* CONFIG_SMP */
+}
+
+static void enqueue_rt_entity(struct sched_rt_entity *rt_se)
+{
+       struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
+       struct rt_prio_array *array = &rt_rq->active;
+       struct rt_rq *group_rq = group_rt_rq(rt_se);
+
+       if (group_rq && group_rq->rt_throttled)
+               return;
+
+       list_add_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se));
+       __set_bit(rt_se_prio(rt_se), array->bitmap);
+
+       inc_rt_tasks(rt_se, rt_rq);
+}
+
+static void dequeue_rt_entity(struct sched_rt_entity *rt_se)
 {
-       struct rt_prio_array *array = &rq->rt.active;
+       struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
+       struct rt_prio_array *array = &rt_rq->active;
+
+       list_del_init(&rt_se->run_list);
+       if (list_empty(array->queue + rt_se_prio(rt_se)))
+               __clear_bit(rt_se_prio(rt_se), array->bitmap);
 
-       list_add_tail(&p->run_list, array->queue + p->prio);
-       __set_bit(p->prio, array->bitmap);
+       dec_rt_tasks(rt_se, rt_rq);
+}
+
+/*
+ * Because the prio of an upper entry depends on the lower
+ * entries, we must remove entries top - down.
+ *
+ * XXX: O(1/2 h^2) because we can only walk up, not down the chain.
+ *      doesn't matter much for now, as h=2 for GROUP_SCHED.
+ */
+static void dequeue_rt_stack(struct task_struct *p)
+{
+       struct sched_rt_entity *rt_se, *top_se;
+
+       /*
+        * dequeue all, top - down.
+        */
+       do {
+               rt_se = &p->rt;
+               top_se = NULL;
+               for_each_sched_rt_entity(rt_se) {
+                       if (on_rt_rq(rt_se))
+                               top_se = rt_se;
+               }
+               if (top_se)
+                       dequeue_rt_entity(top_se);
+       } while (top_se);
 }
 
 /*
  * Adding/removing a task to/from a priority array:
  */
+static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup)
+{
+       struct sched_rt_entity *rt_se = &p->rt;
+
+       if (wakeup)
+               rt_se->timeout = 0;
+
+       dequeue_rt_stack(p);
+
+       /*
+        * enqueue everybody, bottom - up.
+        */
+       for_each_sched_rt_entity(rt_se)
+               enqueue_rt_entity(rt_se);
+
+       inc_cpu_load(rq, p->se.load.weight);
+}
+
 static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep)
 {
-       struct rt_prio_array *array = &rq->rt.active;
+       struct sched_rt_entity *rt_se = &p->rt;
+       struct rt_rq *rt_rq;
 
        update_curr_rt(rq);
 
-       list_del(&p->run_list);
-       if (list_empty(array->queue + p->prio))
-               __clear_bit(p->prio, array->bitmap);
+       dequeue_rt_stack(p);
+
+       /*
+        * re-enqueue all non-empty rt_rq entities.
+        */
+       for_each_sched_rt_entity(rt_se) {
+               rt_rq = group_rt_rq(rt_se);
+               if (rt_rq && rt_rq->rt_nr_running)
+                       enqueue_rt_entity(rt_se);
+       }
+
+       dec_cpu_load(rq, p->se.load.weight);
 }
 
 /*
  * Put task to the end of the run list without the overhead of dequeue
  * followed by enqueue.
  */
+static
+void requeue_rt_entity(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se)
+{
+       struct rt_prio_array *array = &rt_rq->active;
+
+       list_move_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se));
+}
+
 static void requeue_task_rt(struct rq *rq, struct task_struct *p)
 {
-       struct rt_prio_array *array = &rq->rt.active;
+       struct sched_rt_entity *rt_se = &p->rt;
+       struct rt_rq *rt_rq;
 
-       list_move_tail(&p->run_list, array->queue + p->prio);
+       for_each_sched_rt_entity(rt_se) {
+               rt_rq = rt_rq_of_se(rt_se);
+               requeue_rt_entity(rt_rq, rt_se);
+       }
 }
 
-static void
-yield_task_rt(struct rq *rq)
+static void yield_task_rt(struct rq *rq)
 {
        requeue_task_rt(rq, rq->curr);
 }
 
+#ifdef CONFIG_SMP
+static int find_lowest_rq(struct task_struct *task);
+
+static int select_task_rq_rt(struct task_struct *p, int sync)
+{
+       struct rq *rq = task_rq(p);
+
+       /*
+        * If the current task is an RT task, then
+        * try to see if we can wake this RT task up on another
+        * runqueue. Otherwise simply start this RT task
+        * on its current runqueue.
+        *
+        * We want to avoid overloading runqueues. Even if
+        * the RT task is of higher priority than the current RT task.
+        * RT tasks behave differently than other tasks. If
+        * one gets preempted, we try to push it off to another queue.
+        * So trying to keep a preempting RT task on the same
+        * cache hot CPU will force the running RT task to
+        * a cold CPU. So we waste all the cache for the lower
+        * RT task in hopes of saving some of a RT task
+        * that is just being woken and probably will have
+        * cold cache anyway.
+        */
+       if (unlikely(rt_task(rq->curr)) &&
+           (p->rt.nr_cpus_allowed > 1)) {
+               int cpu = find_lowest_rq(p);
+
+               return (cpu == -1) ? task_cpu(p) : cpu;
+       }
+
+       /*
+        * Otherwise, just let it ride on the affined RQ and the
+        * post-schedule router will push the preempted task away
+        */
+       return task_cpu(p);
+}
+#endif /* CONFIG_SMP */
+
 /*
  * Preempt the current task with a newly woken task if needed:
  */
@@ -74,25 +468,48 @@ static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p)
                resched_task(rq->curr);
 }
 
-static struct task_struct *pick_next_task_rt(struct rq *rq)
+static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq,
+                                                  struct rt_rq *rt_rq)
 {
-       struct rt_prio_array *array = &rq->rt.active;
-       struct task_struct *next;
+       struct rt_prio_array *array = &rt_rq->active;
+       struct sched_rt_entity *next = NULL;
        struct list_head *queue;
        int idx;
 
        idx = sched_find_first_bit(array->bitmap);
-       if (idx >= MAX_RT_PRIO)
-               return NULL;
+       BUG_ON(idx >= MAX_RT_PRIO);
 
        queue = array->queue + idx;
-       next = list_entry(queue->next, struct task_struct, run_list);
-
-       next->se.exec_start = rq->clock;
+       next = list_entry(queue->next, struct sched_rt_entity, run_list);
 
        return next;
 }
 
+static struct task_struct *pick_next_task_rt(struct rq *rq)
+{
+       struct sched_rt_entity *rt_se;
+       struct task_struct *p;
+       struct rt_rq *rt_rq;
+
+       rt_rq = &rq->rt;
+
+       if (unlikely(!rt_rq->rt_nr_running))
+               return NULL;
+
+       if (sched_rt_ratio_exceeded(rt_rq))
+               return NULL;
+
+       do {
+               rt_se = pick_next_rt_entity(rq, rt_rq);
+               BUG_ON(!rt_se);
+               rt_rq = group_rt_rq(rt_se);
+       } while (rt_rq);
+
+       p = rt_task_of(rt_se);
+       p->se.exec_start = rq->clock;
+       return p;
+}
+
 static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
 {
        update_curr_rt(rq);
@@ -100,76 +517,448 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
 }
 
 #ifdef CONFIG_SMP
-/*
- * Load-balancing iterator. Note: while the runqueue stays locked
- * during the whole iteration, the current task might be
- * dequeued so the iterator has to be dequeue-safe. Here we
- * achieve that by always pre-iterating before returning
- * the current task:
- */
-static struct task_struct *load_balance_start_rt(void *arg)
+
+/* Only try algorithms three times */
+#define RT_MAX_TRIES 3
+
+static int double_lock_balance(struct rq *this_rq, struct rq *busiest);
+static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep);
+
+static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
 {
-       struct rq *rq = arg;
-       struct rt_prio_array *array = &rq->rt.active;
-       struct list_head *head, *curr;
-       struct task_struct *p;
+       if (!task_running(rq, p) &&
+           (cpu < 0 || cpu_isset(cpu, p->cpus_allowed)) &&
+           (p->rt.nr_cpus_allowed > 1))
+               return 1;
+       return 0;
+}
+
+/* Return the second highest RT task, NULL otherwise */
+static struct task_struct *pick_next_highest_task_rt(struct rq *rq, int cpu)
+{
+       struct task_struct *next = NULL;
+       struct sched_rt_entity *rt_se;
+       struct rt_prio_array *array;
+       struct rt_rq *rt_rq;
        int idx;
 
-       idx = sched_find_first_bit(array->bitmap);
-       if (idx >= MAX_RT_PRIO)
-               return NULL;
+       for_each_leaf_rt_rq(rt_rq, rq) {
+               array = &rt_rq->active;
+               idx = sched_find_first_bit(array->bitmap);
+ next_idx:
+               if (idx >= MAX_RT_PRIO)
+                       continue;
+               if (next && next->prio < idx)
+                       continue;
+               list_for_each_entry(rt_se, array->queue + idx, run_list) {
+                       struct task_struct *p = rt_task_of(rt_se);
+                       if (pick_rt_task(rq, p, cpu)) {
+                               next = p;
+                               break;
+                       }
+               }
+               if (!next) {
+                       idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1);
+                       goto next_idx;
+               }
+       }
 
-       head = array->queue + idx;
-       curr = head->prev;
+       return next;
+}
 
-       p = list_entry(curr, struct task_struct, run_list);
+static DEFINE_PER_CPU(cpumask_t, local_cpu_mask);
 
-       curr = curr->prev;
+static int find_lowest_cpus(struct task_struct *task, cpumask_t *lowest_mask)
+{
+       int       lowest_prio = -1;
+       int       lowest_cpu  = -1;
+       int       count       = 0;
+       int       cpu;
 
-       rq->rt.rt_load_balance_idx = idx;
-       rq->rt.rt_load_balance_head = head;
-       rq->rt.rt_load_balance_curr = curr;
+       cpus_and(*lowest_mask, task_rq(task)->rd->online, task->cpus_allowed);
 
-       return p;
+       /*
+        * Scan each rq for the lowest prio.
+        */
+       for_each_cpu_mask(cpu, *lowest_mask) {
+               struct rq *rq = cpu_rq(cpu);
+
+               /* We look for lowest RT prio or non-rt CPU */
+               if (rq->rt.highest_prio >= MAX_RT_PRIO) {
+                       /*
+                        * if we already found a low RT queue
+                        * and now we found this non-rt queue
+                        * clear the mask and set our bit.
+                        * Otherwise just return the queue as is
+                        * and the count==1 will cause the algorithm
+                        * to use the first bit found.
+                        */
+                       if (lowest_cpu != -1) {
+                               cpus_clear(*lowest_mask);
+                               cpu_set(rq->cpu, *lowest_mask);
+                       }
+                       return 1;
+               }
+
+               /* no locking for now */
+               if ((rq->rt.highest_prio > task->prio)
+                   && (rq->rt.highest_prio >= lowest_prio)) {
+                       if (rq->rt.highest_prio > lowest_prio) {
+                               /* new low - clear old data */
+                               lowest_prio = rq->rt.highest_prio;
+                               lowest_cpu = cpu;
+                               count = 0;
+                       }
+                       count++;
+               } else
+                       cpu_clear(cpu, *lowest_mask);
+       }
+
+       /*
+        * Clear out all the set bits that represent
+        * runqueues that were of higher prio than
+        * the lowest_prio.
+        */
+       if (lowest_cpu > 0) {
+               /*
+                * Perhaps we could add another cpumask op to
+                * zero out bits. Like cpu_zero_bits(cpumask, nrbits);
+                * Then that could be optimized to use memset and such.
+                */
+               for_each_cpu_mask(cpu, *lowest_mask) {
+                       if (cpu >= lowest_cpu)
+                               break;
+                       cpu_clear(cpu, *lowest_mask);
+               }
+       }
+
+       return count;
 }
 
-static struct task_struct *load_balance_next_rt(void *arg)
+static inline int pick_optimal_cpu(int this_cpu, cpumask_t *mask)
 {
-       struct rq *rq = arg;
-       struct rt_prio_array *array = &rq->rt.active;
-       struct list_head *head, *curr;
-       struct task_struct *p;
-       int idx;
+       int first;
+
+       /* "this_cpu" is cheaper to preempt than a remote processor */
+       if ((this_cpu != -1) && cpu_isset(this_cpu, *mask))
+               return this_cpu;
+
+       first = first_cpu(*mask);
+       if (first != NR_CPUS)
+               return first;
+
+       return -1;
+}
+
+static int find_lowest_rq(struct task_struct *task)
+{
+       struct sched_domain *sd;
+       cpumask_t *lowest_mask = &__get_cpu_var(local_cpu_mask);
+       int this_cpu = smp_processor_id();
+       int cpu      = task_cpu(task);
+       int count    = find_lowest_cpus(task, lowest_mask);
 
-       idx = rq->rt.rt_load_balance_idx;
-       head = rq->rt.rt_load_balance_head;
-       curr = rq->rt.rt_load_balance_curr;
+       if (!count)
+               return -1; /* No targets found */
 
        /*
-        * If we arrived back to the head again then
-        * iterate to the next queue (if any):
+        * There is no sense in performing an optimal search if only one
+        * target is found.
         */
-       if (unlikely(head == curr)) {
-               int next_idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1);
+       if (count == 1)
+               return first_cpu(*lowest_mask);
 
-               if (next_idx >= MAX_RT_PRIO)
-                       return NULL;
+       /*
+        * At this point we have built a mask of cpus representing the
+        * lowest priority tasks in the system.  Now we want to elect
+        * the best one based on our affinity and topology.
+        *
+        * We prioritize the last cpu that the task executed on since
+        * it is most likely cache-hot in that location.
+        */
+       if (cpu_isset(cpu, *lowest_mask))
+               return cpu;
+
+       /*
+        * Otherwise, we consult the sched_domains span maps to figure
+        * out which cpu is logically closest to our hot cache data.
+        */
+       if (this_cpu == cpu)
+               this_cpu = -1; /* Skip this_cpu opt if the same */
+
+       for_each_domain(cpu, sd) {
+               if (sd->flags & SD_WAKE_AFFINE) {
+                       cpumask_t domain_mask;
+                       int       best_cpu;
 
-               idx = next_idx;
-               head = array->queue + idx;
-               curr = head->prev;
+                       cpus_and(domain_mask, sd->span, *lowest_mask);
 
-               rq->rt.rt_load_balance_idx = idx;
-               rq->rt.rt_load_balance_head = head;
+                       best_cpu = pick_optimal_cpu(this_cpu,
+                                                   &domain_mask);
+                       if (best_cpu != -1)
+                               return best_cpu;
+               }
        }
 
-       p = list_entry(curr, struct task_struct, run_list);
+       /*
+        * And finally, if there were no matches within the domains
+        * just give the caller *something* to work with from the compatible
+        * locations.
+        */
+       return pick_optimal_cpu(this_cpu, lowest_mask);
+}
 
-       curr = curr->prev;
+/* Will lock the rq it finds */
+static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
+{
+       struct rq *lowest_rq = NULL;
+       int tries;
+       int cpu;
 
-       rq->rt.rt_load_balance_curr = curr;
+       for (tries = 0; tries < RT_MAX_TRIES; tries++) {
+               cpu = find_lowest_rq(task);
 
-       return p;
+               if ((cpu == -1) || (cpu == rq->cpu))
+                       break;
+
+               lowest_rq = cpu_rq(cpu);
+
+               /* if the prio of this runqueue changed, try again */
+               if (double_lock_balance(rq, lowest_rq)) {
+                       /*
+                        * We had to unlock the run queue. In
+                        * the mean time, task could have
+                        * migrated already or had its affinity changed.
+                        * Also make sure that it wasn't scheduled on its rq.
+                        */
+                       if (unlikely(task_rq(task) != rq ||
+                                    !cpu_isset(lowest_rq->cpu,
+                                               task->cpus_allowed) ||
+                                    task_running(rq, task) ||
+                                    !task->se.on_rq)) {
+
+                               spin_unlock(&lowest_rq->lock);
+                               lowest_rq = NULL;
+                               break;
+                       }
+               }
+
+               /* If this rq is still suitable use it. */
+               if (lowest_rq->rt.highest_prio > task->prio)
+                       break;
+
+               /* try again */
+               spin_unlock(&lowest_rq->lock);
+               lowest_rq = NULL;
+       }
+
+       return lowest_rq;
+}
+
+/*
+ * If the current CPU has more than one RT task, see if the non
+ * running task can migrate over to a CPU that is running a task
+ * of lesser priority.
+ */
+static int push_rt_task(struct rq *rq)
+{
+       struct task_struct *next_task;
+       struct rq *lowest_rq;
+       int ret = 0;
+       int paranoid = RT_MAX_TRIES;
+
+       if (!rq->rt.overloaded)
+               return 0;
+
+       next_task = pick_next_highest_task_rt(rq, -1);
+       if (!next_task)
+               return 0;
+
+ retry:
+       if (unlikely(next_task == rq->curr)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       /*
+        * It's possible that the next_task slipped in of
+        * higher priority than current. If that's the case
+        * just reschedule current.
+        */
+       if (unlikely(next_task->prio < rq->curr->prio)) {
+               resched_task(rq->curr);
+               return 0;
+       }
+
+       /* We might release rq lock */
+       get_task_struct(next_task);
+
+       /* find_lock_lowest_rq locks the rq if found */
+       lowest_rq = find_lock_lowest_rq(next_task, rq);
+       if (!lowest_rq) {
+               struct task_struct *task;
+               /*
+                * find lock_lowest_rq releases rq->lock
+                * so it is possible that next_task has changed.
+                * If it has, then try again.
+                */
+               task = pick_next_highest_task_rt(rq, -1);
+               if (unlikely(task != next_task) && task && paranoid--) {
+                       put_task_struct(next_task);
+                       next_task = task;
+                       goto retry;
+               }
+               goto out;
+       }
+
+       deactivate_task(rq, next_task, 0);
+       set_task_cpu(next_task, lowest_rq->cpu);
+       activate_task(lowest_rq, next_task, 0);
+
+       resched_task(lowest_rq->curr);
+
+       spin_unlock(&lowest_rq->lock);
+
+       ret = 1;
+out:
+       put_task_struct(next_task);
+
+       return ret;
+}
+
+/*
+ * TODO: Currently we just use the second highest prio task on
+ *       the queue, and stop when it can't migrate (or there's
+ *       no more RT tasks).  There may be a case where a lower
+ *       priority RT task has a different affinity than the
+ *       higher RT task. In this case the lower RT task could
+ *       possibly be able to migrate where as the higher priority
+ *       RT task could not.  We currently ignore this issue.
+ *       Enhancements are welcome!
+ */
+static void push_rt_tasks(struct rq *rq)
+{
+       /* push_rt_task will return true if it moved an RT */
+       while (push_rt_task(rq))
+               ;
+}
+
+static int pull_rt_task(struct rq *this_rq)
+{
+       int this_cpu = this_rq->cpu, ret = 0, cpu;
+       struct task_struct *p, *next;
+       struct rq *src_rq;
+
+       if (likely(!rt_overloaded(this_rq)))
+               return 0;
+
+       next = pick_next_task_rt(this_rq);
+
+       for_each_cpu_mask(cpu, this_rq->rd->rto_mask) {
+               if (this_cpu == cpu)
+                       continue;
+
+               src_rq = cpu_rq(cpu);
+               /*
+                * We can potentially drop this_rq's lock in
+                * double_lock_balance, and another CPU could
+                * steal our next task - hence we must cause
+                * the caller to recalculate the next task
+                * in that case:
+                */
+               if (double_lock_balance(this_rq, src_rq)) {
+                       struct task_struct *old_next = next;
+
+                       next = pick_next_task_rt(this_rq);
+                       if (next != old_next)
+                               ret = 1;
+               }
+
+               /*
+                * Are there still pullable RT tasks?
+                */
+               if (src_rq->rt.rt_nr_running <= 1)
+                       goto skip;
+
+               p = pick_next_highest_task_rt(src_rq, this_cpu);
+
+               /*
+                * Do we have an RT task that preempts
+                * the to-be-scheduled task?
+                */
+               if (p && (!next || (p->prio < next->prio))) {
+                       WARN_ON(p == src_rq->curr);
+                       WARN_ON(!p->se.on_rq);
+
+                       /*
+                        * There's a chance that p is higher in priority
+                        * than what's currently running on its cpu.
+                        * This is just that p is wakeing up and hasn't
+                        * had a chance to schedule. We only pull
+                        * p if it is lower in priority than the
+                        * current task on the run queue or
+                        * this_rq next task is lower in prio than
+                        * the current task on that rq.
+                        */
+                       if (p->prio < src_rq->curr->prio ||
+                           (next && next->prio < src_rq->curr->prio))
+                               goto skip;
+
+                       ret = 1;
+
+                       deactivate_task(src_rq, p, 0);
+                       set_task_cpu(p, this_cpu);
+                       activate_task(this_rq, p, 0);
+                       /*
+                        * We continue with the search, just in
+                        * case there's an even higher prio task
+                        * in another runqueue. (low likelyhood
+                        * but possible)
+                        *
+                        * Update next so that we won't pick a task
+                        * on another cpu with a priority lower (or equal)
+                        * than the one we just picked.
+                        */
+                       next = p;
+
+               }
+ skip:
+               spin_unlock(&src_rq->lock);
+       }
+
+       return ret;
+}
+
+static void pre_schedule_rt(struct rq *rq, struct task_struct *prev)
+{
+       /* Try to pull RT tasks here if we lower this rq's prio */
+       if (unlikely(rt_task(prev)) && rq->rt.highest_prio > prev->prio)
+               pull_rt_task(rq);
+}
+
+static void post_schedule_rt(struct rq *rq)
+{
+       /*
+        * If we have more than one rt_task queued, then
+        * see if we can push the other rt_tasks off to other CPUS.
+        * Note we may release the rq lock, and since
+        * the lock was owned by prev, we need to release it
+        * first via finish_lock_switch and then reaquire it here.
+        */
+       if (unlikely(rq->rt.overloaded)) {
+               spin_lock_irq(&rq->lock);
+               push_rt_tasks(rq);
+               spin_unlock_irq(&rq->lock);
+       }
+}
+
+
+static void task_wake_up_rt(struct rq *rq, struct task_struct *p)
+{
+       if (!task_running(rq, p) &&
+           (p->prio >= rq->rt.highest_prio) &&
+           rq->rt.overloaded)
+               push_rt_tasks(rq);
 }
 
 static unsigned long
@@ -178,38 +967,170 @@ load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest,
                struct sched_domain *sd, enum cpu_idle_type idle,
                int *all_pinned, int *this_best_prio)
 {
-       struct rq_iterator rt_rq_iterator;
-
-       rt_rq_iterator.start = load_balance_start_rt;
-       rt_rq_iterator.next = load_balance_next_rt;
-       /* pass 'busiest' rq argument into
-        * load_balance_[start|next]_rt iterators
-        */
-       rt_rq_iterator.arg = busiest;
-
-       return balance_tasks(this_rq, this_cpu, busiest, max_load_move, sd,
-                            idle, all_pinned, this_best_prio, &rt_rq_iterator);
+       /* don't touch RT tasks */
+       return 0;
 }
 
 static int
 move_one_task_rt(struct rq *this_rq, int this_cpu, struct rq *busiest,
                 struct sched_domain *sd, enum cpu_idle_type idle)
 {
-       struct rq_iterator rt_rq_iterator;
+       /* don't touch RT tasks */
+       return 0;
+}
+
+static void set_cpus_allowed_rt(struct task_struct *p, cpumask_t *new_mask)
+{
+       int weight = cpus_weight(*new_mask);
+
+       BUG_ON(!rt_task(p));
 
-       rt_rq_iterator.start = load_balance_start_rt;
-       rt_rq_iterator.next = load_balance_next_rt;
-       rt_rq_iterator.arg = busiest;
+       /*
+        * Update the migration status of the RQ if we have an RT task
+        * which is running AND changing its weight value.
+        */
+       if (p->se.on_rq && (weight != p->rt.nr_cpus_allowed)) {
+               struct rq *rq = task_rq(p);
+
+               if ((p->rt.nr_cpus_allowed <= 1) && (weight > 1)) {
+                       rq->rt.rt_nr_migratory++;
+               } else if ((p->rt.nr_cpus_allowed > 1) && (weight <= 1)) {
+                       BUG_ON(!rq->rt.rt_nr_migratory);
+                       rq->rt.rt_nr_migratory--;
+               }
+
+               update_rt_migration(rq);
+       }
 
-       return iter_move_one_task(this_rq, this_cpu, busiest, sd, idle,
-                                 &rt_rq_iterator);
+       p->cpus_allowed    = *new_mask;
+       p->rt.nr_cpus_allowed = weight;
 }
-#endif
 
-static void task_tick_rt(struct rq *rq, struct task_struct *p)
+/* Assumes rq->lock is held */
+static void join_domain_rt(struct rq *rq)
+{
+       if (rq->rt.overloaded)
+               rt_set_overload(rq);
+}
+
+/* Assumes rq->lock is held */
+static void leave_domain_rt(struct rq *rq)
+{
+       if (rq->rt.overloaded)
+               rt_clear_overload(rq);
+}
+
+/*
+ * When switch from the rt queue, we bring ourselves to a position
+ * that we might want to pull RT tasks from other runqueues.
+ */
+static void switched_from_rt(struct rq *rq, struct task_struct *p,
+                          int running)
+{
+       /*
+        * If there are other RT tasks then we will reschedule
+        * and the scheduling of the other RT tasks will handle
+        * the balancing. But if we are the last RT task
+        * we may need to handle the pulling of RT tasks
+        * now.
+        */
+       if (!rq->rt.rt_nr_running)
+               pull_rt_task(rq);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * When switching a task to RT, we may overload the runqueue
+ * with RT tasks. In this case we try to push them off to
+ * other runqueues.
+ */
+static void switched_to_rt(struct rq *rq, struct task_struct *p,
+                          int running)
+{
+       int check_resched = 1;
+
+       /*
+        * If we are already running, then there's nothing
+        * that needs to be done. But if we are not running
+        * we may need to preempt the current running task.
+        * If that current running task is also an RT task
+        * then see if we can move to another run queue.
+        */
+       if (!running) {
+#ifdef CONFIG_SMP
+               if (rq->rt.overloaded && push_rt_task(rq) &&
+                   /* Don't resched if we changed runqueues */
+                   rq != task_rq(p))
+                       check_resched = 0;
+#endif /* CONFIG_SMP */
+               if (check_resched && p->prio < rq->curr->prio)
+                       resched_task(rq->curr);
+       }
+}
+
+/*
+ * Priority of the task has changed. This may cause
+ * us to initiate a push or pull.
+ */
+static void prio_changed_rt(struct rq *rq, struct task_struct *p,
+                           int oldprio, int running)
+{
+       if (running) {
+#ifdef CONFIG_SMP
+               /*
+                * If our priority decreases while running, we
+                * may need to pull tasks to this runqueue.
+                */
+               if (oldprio < p->prio)
+                       pull_rt_task(rq);
+               /*
+                * If there's a higher priority task waiting to run
+                * then reschedule.
+                */
+               if (p->prio > rq->rt.highest_prio)
+                       resched_task(p);
+#else
+               /* For UP simply resched on drop of prio */
+               if (oldprio < p->prio)
+                       resched_task(p);
+#endif /* CONFIG_SMP */
+       } else {
+               /*
+                * This task is not running, but if it is
+                * greater than the current running task
+                * then reschedule.
+                */
+               if (p->prio < rq->curr->prio)
+                       resched_task(rq->curr);
+       }
+}
+
+static void watchdog(struct rq *rq, struct task_struct *p)
+{
+       unsigned long soft, hard;
+
+       if (!p->signal)
+               return;
+
+       soft = p->signal->rlim[RLIMIT_RTTIME].rlim_cur;
+       hard = p->signal->rlim[RLIMIT_RTTIME].rlim_max;
+
+       if (soft != RLIM_INFINITY) {
+               unsigned long next;
+
+               p->rt.timeout++;
+               next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ);
+               if (p->rt.timeout > next)
+                       p->it_sched_expires = p->se.sum_exec_runtime;
+       }
+}
+
+static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
 {
        update_curr_rt(rq);
 
+       watchdog(rq, p);
+
        /*
         * RR tasks need a special form of timeslice management.
         * FIFO tasks have no timeslices.
@@ -217,16 +1138,16 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p)
        if (p->policy != SCHED_RR)
                return;
 
-       if (--p->time_slice)
+       if (--p->rt.time_slice)
                return;
 
-       p->time_slice = DEF_TIMESLICE;
+       p->rt.time_slice = DEF_TIMESLICE;
 
        /*
         * Requeue to the end of queue if we are not the only element
         * on the queue:
         */
-       if (p->run_list.prev != p->run_list.next) {
+       if (p->rt.run_list.prev != p->rt.run_list.next) {
                requeue_task_rt(rq, p);
                set_tsk_need_resched(p);
        }
@@ -244,6 +1165,9 @@ const struct sched_class rt_sched_class = {
        .enqueue_task           = enqueue_task_rt,
        .dequeue_task           = dequeue_task_rt,
        .yield_task             = yield_task_rt,
+#ifdef CONFIG_SMP
+       .select_task_rq         = select_task_rq_rt,
+#endif /* CONFIG_SMP */
 
        .check_preempt_curr     = check_preempt_curr_rt,
 
@@ -253,8 +1177,18 @@ const struct sched_class rt_sched_class = {
 #ifdef CONFIG_SMP
        .load_balance           = load_balance_rt,
        .move_one_task          = move_one_task_rt,
+       .set_cpus_allowed       = set_cpus_allowed_rt,
+       .join_domain            = join_domain_rt,
+       .leave_domain           = leave_domain_rt,
+       .pre_schedule           = pre_schedule_rt,
+       .post_schedule          = post_schedule_rt,
+       .task_wake_up           = task_wake_up_rt,
+       .switched_from          = switched_from_rt,
 #endif
 
        .set_curr_task          = set_curr_task_rt,
        .task_tick              = task_tick_rt,
+
+       .prio_changed           = prio_changed_rt,
+       .switched_to            = switched_to_rt,
 };
index 11df812263c8fd3eed16f4f1a57d36a68f6eaedc..c1d76552446e592bc132d8de37073ecb589a1629 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <linux/mm.h>
 #include <linux/cpu.h>
+#include <linux/nmi.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/freezer.h>
@@ -23,8 +24,8 @@ static DEFINE_PER_CPU(unsigned long, touch_timestamp);
 static DEFINE_PER_CPU(unsigned long, print_timestamp);
 static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
 
-static int did_panic;
-int softlockup_thresh = 10;
+static int __read_mostly did_panic;
+unsigned long __read_mostly softlockup_thresh = 60;
 
 static int
 softlock_panic(struct notifier_block *this, unsigned long event, void *ptr)
@@ -45,7 +46,7 @@ static struct notifier_block panic_block = {
  */
 static unsigned long get_timestamp(int this_cpu)
 {
-       return cpu_clock(this_cpu) >> 30;  /* 2^30 ~= 10^9 */
+       return cpu_clock(this_cpu) >> 30LL;  /* 2^30 ~= 10^9 */
 }
 
 void touch_softlockup_watchdog(void)
@@ -100,11 +101,7 @@ void softlockup_tick(void)
 
        now = get_timestamp(this_cpu);
 
-       /* Wake up the high-prio watchdog task every second: */
-       if (now > (touch_timestamp + 1))
-               wake_up_process(per_cpu(watchdog_task, this_cpu));
-
-       /* Warn about unreasonable 10+ seconds delays: */
+       /* Warn about unreasonable delays: */
        if (now <= (touch_timestamp + softlockup_thresh))
                return;
 
@@ -121,12 +118,94 @@ void softlockup_tick(void)
        spin_unlock(&print_lock);
 }
 
+/*
+ * Have a reasonable limit on the number of tasks checked:
+ */
+unsigned long __read_mostly sysctl_hung_task_check_count = 1024;
+
+/*
+ * Zero means infinite timeout - no checking done:
+ */
+unsigned long __read_mostly sysctl_hung_task_timeout_secs = 120;
+
+unsigned long __read_mostly sysctl_hung_task_warnings = 10;
+
+/*
+ * Only do the hung-tasks check on one CPU:
+ */
+static int check_cpu __read_mostly = -1;
+
+static void check_hung_task(struct task_struct *t, unsigned long now)
+{
+       unsigned long switch_count = t->nvcsw + t->nivcsw;
+
+       if (t->flags & PF_FROZEN)
+               return;
+
+       if (switch_count != t->last_switch_count || !t->last_switch_timestamp) {
+               t->last_switch_count = switch_count;
+               t->last_switch_timestamp = now;
+               return;
+       }
+       if ((long)(now - t->last_switch_timestamp) <
+                                       sysctl_hung_task_timeout_secs)
+               return;
+       if (sysctl_hung_task_warnings < 0)
+               return;
+       sysctl_hung_task_warnings--;
+
+       /*
+        * Ok, the task did not get scheduled for more than 2 minutes,
+        * complain:
+        */
+       printk(KERN_ERR "INFO: task %s:%d blocked for more than "
+                       "%ld seconds.\n", t->comm, t->pid,
+                       sysctl_hung_task_timeout_secs);
+       printk(KERN_ERR "\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
+                       " disables this message.\n");
+       sched_show_task(t);
+       __debug_show_held_locks(t);
+
+       t->last_switch_timestamp = now;
+       touch_nmi_watchdog();
+}
+
+/*
+ * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for
+ * a really long time (120 seconds). If that happens, print out
+ * a warning.
+ */
+static void check_hung_uninterruptible_tasks(int this_cpu)
+{
+       int max_count = sysctl_hung_task_check_count;
+       unsigned long now = get_timestamp(this_cpu);
+       struct task_struct *g, *t;
+
+       /*
+        * If the system crashed already then all bets are off,
+        * do not report extra hung tasks:
+        */
+       if ((tainted & TAINT_DIE) || did_panic)
+               return;
+
+       read_lock(&tasklist_lock);
+       do_each_thread(g, t) {
+               if (!--max_count)
+                       break;
+               if (t->state & TASK_UNINTERRUPTIBLE)
+                       check_hung_task(t, now);
+       } while_each_thread(g, t);
+
+       read_unlock(&tasklist_lock);
+}
+
 /*
  * The watchdog thread - runs every second and touches the timestamp.
  */
 static int watchdog(void *__bind_cpu)
 {
        struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+       int this_cpu = (long)__bind_cpu;
 
        sched_setscheduler(current, SCHED_FIFO, &param);
 
@@ -135,13 +214,18 @@ static int watchdog(void *__bind_cpu)
 
        /*
         * Run briefly once per second to reset the softlockup timestamp.
-        * If this gets delayed for more than 10 seconds then the
+        * If this gets delayed for more than 60 seconds then the
         * debug-printout triggers in softlockup_tick().
         */
        while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
                touch_softlockup_watchdog();
-               schedule();
+               msleep_interruptible(10000);
+
+               if (this_cpu != check_cpu)
+                       continue;
+
+               if (sysctl_hung_task_timeout_secs)
+                       check_hung_uninterruptible_tasks(this_cpu);
        }
 
        return 0;
@@ -171,6 +255,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
+               check_cpu = any_online_cpu(cpu_online_map);
                wake_up_process(per_cpu(watchdog_task, hotcpu));
                break;
 #ifdef CONFIG_HOTPLUG_CPU
@@ -181,6 +266,15 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                /* Unbind so it can run.  Fall thru. */
                kthread_bind(per_cpu(watchdog_task, hotcpu),
                             any_online_cpu(cpu_online_map));
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               if (hotcpu == check_cpu) {
+                       cpumask_t temp_cpu_online_map = cpu_online_map;
+
+                       cpu_clear(hotcpu, temp_cpu_online_map);
+                       check_cpu = any_online_cpu(temp_cpu_online_map);
+               }
+               break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                p = per_cpu(watchdog_task, hotcpu);
index 319821ef78afc9e0a7488cbf9b2ea1c5853b65c1..51b5ee53571a63558cef49075de15c4dc25396a6 100644 (file)
@@ -203,13 +203,13 @@ int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
        int ret;
 
        /* No CPUs can come up or down during this. */
-       lock_cpu_hotplug();
+       get_online_cpus();
        p = __stop_machine_run(fn, data, cpu);
        if (!IS_ERR(p))
                ret = kthread_stop(p);
        else
                ret = PTR_ERR(p);
-       unlock_cpu_hotplug();
+       put_online_cpus();
 
        return ret;
 }
index c68f68dcc605052c9bcc81d1719b343acb482e5b..8e96558cb8f395394e92676349fefcc887feca50 100644 (file)
@@ -81,6 +81,7 @@ extern int compat_log;
 extern int maps_protect;
 extern int sysctl_stat_interval;
 extern int audit_argv_kb;
+extern int latencytop_enabled;
 
 /* Constants used for minimum and  maximum */
 #ifdef CONFIG_DETECT_SOFTLOCKUP
@@ -306,9 +307,43 @@ static struct ctl_table kern_table[] = {
                .procname       = "sched_nr_migrate",
                .data           = &sysctl_sched_nr_migrate,
                .maxlen         = sizeof(unsigned int),
-               .mode           = 644,
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_rt_period_ms",
+               .data           = &sysctl_sched_rt_period,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_rt_ratio",
+               .data           = &sysctl_sched_rt_ratio,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP)
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_min_bal_int_shares",
+               .data           = &sysctl_sched_min_bal_int_shares,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "sched_max_bal_int_shares",
+               .data           = &sysctl_sched_max_bal_int_shares,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
 #endif
        {
                .ctl_name       = CTL_UNNUMBERED,
@@ -382,6 +417,15 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec_taint,
        },
 #endif
+#ifdef CONFIG_LATENCYTOP
+       {
+               .procname       = "latencytop",
+               .data           = &latencytop_enabled,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
 #ifdef CONFIG_SECURITY_CAPABILITIES
        {
                .procname       = "cap-bound",
@@ -728,13 +772,40 @@ static struct ctl_table kern_table[] = {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "softlockup_thresh",
                .data           = &softlockup_thresh,
-               .maxlen         = sizeof(int),
+               .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
+               .proc_handler   = &proc_doulongvec_minmax,
                .strategy       = &sysctl_intvec,
                .extra1         = &one,
                .extra2         = &sixty,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "hung_task_check_count",
+               .data           = &sysctl_hung_task_check_count,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .strategy       = &sysctl_intvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "hung_task_timeout_secs",
+               .data           = &sysctl_hung_task_timeout_secs,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .strategy       = &sysctl_intvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "hung_task_warnings",
+               .data           = &sysctl_hung_task_warnings,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .strategy       = &sysctl_intvec,
+       },
 #endif
 #ifdef CONFIG_COMPAT
        {
index a68425a5cc1d7f114fb26c9d515758ff56bcbeb5..d8a5558a47b4d772e4b00356f8430cc23ab281e7 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/stat.h>
 #include <linux/sysctl.h>
-#include "../arch/s390/appldata/appldata.h"
 #include "../fs/xfs/linux-2.6/xfs_sysctl.h"
 #include <linux/sunrpc/debug.h>
 #include <linux/string.h>
index c8a9d13874dfdcf85c6b2ab9d7d03f92a8f39401..8d6125ad2cf0cf3c76368e582d9750066d176232 100644 (file)
@@ -441,7 +441,7 @@ static SYSDEV_ATTR(available_clocksource, 0600,
                   sysfs_show_available_clocksources, NULL);
 
 static struct sysdev_class clocksource_sysclass = {
-       set_kset_name("clocksource"),
+       .name = "clocksource",
 };
 
 static struct sys_device device_clocksource = {
index cb89fa8db110a98df702bbd4bed884d1b45b25dd..1a21b6fdb674b878d566789bac2c799da7593adf 100644 (file)
@@ -153,6 +153,7 @@ void tick_nohz_update_jiffies(void)
 void tick_nohz_stop_sched_tick(void)
 {
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
+       unsigned long rt_jiffies;
        struct tick_sched *ts;
        ktime_t last_update, expires, now, delta;
        struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
@@ -216,6 +217,10 @@ void tick_nohz_stop_sched_tick(void)
        next_jiffies = get_next_timer_interrupt(last_jiffies);
        delta_jiffies = next_jiffies - last_jiffies;
 
+       rt_jiffies = rt_needs_cpu(cpu);
+       if (rt_jiffies && rt_jiffies < delta_jiffies)
+               delta_jiffies = rt_jiffies;
+
        if (rcu_needs_cpu(cpu))
                delta_jiffies = 1;
        /*
@@ -509,7 +514,6 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
 {
        struct tick_sched *ts =
                container_of(timer, struct tick_sched, sched_timer);
-       struct hrtimer_cpu_base *base = timer->base->cpu_base;
        struct pt_regs *regs = get_irq_regs();
        ktime_t now = ktime_get();
        int cpu = smp_processor_id();
@@ -547,15 +551,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
                        touch_softlockup_watchdog();
                        ts->idle_jiffies++;
                }
-               /*
-                * update_process_times() might take tasklist_lock, hence
-                * drop the base lock. sched-tick hrtimers are per-CPU and
-                * never accessible by userspace APIs, so this is safe to do.
-                */
-               spin_unlock(&base->lock);
                update_process_times(user_mode(regs));
                profile_tick(CPU_PROFILING);
-               spin_lock(&base->lock);
        }
 
        /* Do not restart, when we are in the idle loop */
index e5e466b2759893ccd21cea1e2242b8fbf7dac9a5..ab46ae8c062b0b971aaae2fc28071d0cc01260ed 100644 (file)
@@ -335,9 +335,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
 
 /* sysfs resume/suspend bits for timekeeping */
 static struct sysdev_class timekeeping_sysclass = {
+       .name           = "timekeeping",
        .resume         = timekeeping_resume,
        .suspend        = timekeeping_suspend,
-       set_kset_name("timekeeping"),
 };
 
 static struct sys_device device_timer = {
index d4527dcef1af8b325115ad37adb1b034a199d7b3..f739dfb539cec7dd1f6c737b9b6fccfe017aebf8 100644 (file)
@@ -896,7 +896,7 @@ static void run_timer_softirq(struct softirq_action *h)
 {
        tvec_base_t *base = __get_cpu_var(tvec_bases);
 
-       hrtimer_run_queues();
+       hrtimer_run_pending();
 
        if (time_after_eq(jiffies, base->timer_jiffies))
                __run_timers(base);
@@ -907,6 +907,7 @@ static void run_timer_softirq(struct softirq_action *h)
  */
 void run_local_timers(void)
 {
+       hrtimer_run_queues();
        raise_softirq(TIMER_SOFTIRQ);
        softlockup_tick();
 }
@@ -978,7 +979,7 @@ asmlinkage long sys_getppid(void)
        int pid;
 
        rcu_read_lock();
-       pid = task_ppid_nr_ns(current, current->nsproxy->pid_ns);
+       pid = task_tgid_nr_ns(current->real_parent, current->nsproxy->pid_ns);
        rcu_read_unlock();
 
        return pid;
@@ -1289,7 +1290,7 @@ static void migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
        }
 }
 
-static void __devinit migrate_timers(int cpu)
+static void __cpuinit migrate_timers(int cpu)
 {
        tvec_base_t *old_base;
        tvec_base_t *new_base;
index 8320a87f3e5a11f11e2159488cf2dc3f6d9371d3..bc1c48d35cb32726623b37b47a09d4325aaf4074 100644 (file)
@@ -115,7 +115,7 @@ static void sched_switch_user(struct task_struct *p) { }
 
 #if defined(CONFIG_FAIR_USER_SCHED) && defined(CONFIG_SYSFS)
 
-static struct kobject uids_kobject; /* represents /sys/kernel/uids directory */
+static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
 static DEFINE_MUTEX(uids_mutex);
 
 static inline void uids_mutex_lock(void)
@@ -128,86 +128,83 @@ static inline void uids_mutex_unlock(void)
        mutex_unlock(&uids_mutex);
 }
 
-/* return cpu shares held by the user */
-static ssize_t cpu_shares_show(struct kset *kset, char *buffer)
+/* uid directory attributes */
+static ssize_t cpu_shares_show(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              char *buf)
 {
-       struct user_struct *up = container_of(kset, struct user_struct, kset);
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
 
-       return sprintf(buffer, "%lu\n", sched_group_shares(up->tg));
+       return sprintf(buf, "%lu\n", sched_group_shares(up->tg));
 }
 
-/* modify cpu shares held by the user */
-static ssize_t cpu_shares_store(struct kset *kset, const char *buffer,
-                               size_t size)
+static ssize_t cpu_shares_store(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               const char *buf, size_t size)
 {
-       struct user_struct *up = container_of(kset, struct user_struct, kset);
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
        unsigned long shares;
        int rc;
 
-       sscanf(buffer, "%lu", &shares);
+       sscanf(buf, "%lu", &shares);
 
        rc = sched_group_set_shares(up->tg, shares);
 
        return (rc ? rc : size);
 }
 
-static void user_attr_init(struct subsys_attribute *sa, char *name, int mode)
+static struct kobj_attribute cpu_share_attr =
+       __ATTR(cpu_share, 0644, cpu_shares_show, cpu_shares_store);
+
+/* default attributes per uid directory */
+static struct attribute *uids_attributes[] = {
+       &cpu_share_attr.attr,
+       NULL
+};
+
+/* the lifetime of user_struct is not managed by the core (now) */
+static void uids_release(struct kobject *kobj)
 {
-       sa->attr.name = name;
-       sa->attr.mode = mode;
-       sa->show = cpu_shares_show;
-       sa->store = cpu_shares_store;
+       return;
 }
 
-/* Create "/sys/kernel/uids/<uid>" directory and
- *  "/sys/kernel/uids/<uid>/cpu_share" file for this user.
- */
-static int user_kobject_create(struct user_struct *up)
+static struct kobj_type uids_ktype = {
+       .sysfs_ops = &kobj_sysfs_ops,
+       .default_attrs = uids_attributes,
+       .release = uids_release,
+};
+
+/* create /sys/kernel/uids/<uid>/cpu_share file for this user */
+static int uids_user_create(struct user_struct *up)
 {
-       struct kset *kset = &up->kset;
-       struct kobject *kobj = &kset->kobj;
+       struct kobject *kobj = &up->kobj;
        int error;
 
-       memset(kset, 0, sizeof(struct kset));
-       kobj->parent = &uids_kobject;   /* create under /sys/kernel/uids dir */
-       kobject_set_name(kobj, "%d", up->uid);
-       kset_init(kset);
-       user_attr_init(&up->user_attr, "cpu_share", 0644);
-
-       error = kobject_add(kobj);
-       if (error)
+       memset(kobj, 0, sizeof(struct kobject));
+       kobj->kset = uids_kset;
+       error = kobject_init_and_add(kobj, &uids_ktype, NULL, "%d", up->uid);
+       if (error) {
+               kobject_put(kobj);
                goto done;
-
-       error = sysfs_create_file(kobj, &up->user_attr.attr);
-       if (error)
-               kobject_del(kobj);
+       }
 
        kobject_uevent(kobj, KOBJ_ADD);
-
 done:
        return error;
 }
 
-/* create these in sysfs filesystem:
+/* create these entries in sysfs:
  *     "/sys/kernel/uids" directory
  *     "/sys/kernel/uids/0" directory (for root user)
  *     "/sys/kernel/uids/0/cpu_share" file (for root user)
  */
-int __init uids_kobject_init(void)
+int __init uids_sysfs_init(void)
 {
-       int error;
-
-       /* create under /sys/kernel dir */
-       uids_kobject.parent = &kernel_subsys.kobj;
-       uids_kobject.kset = &kernel_subsys;
-       kobject_set_name(&uids_kobject, "uids");
-       kobject_init(&uids_kobject);
+       uids_kset = kset_create_and_add("uids", NULL, kernel_kobj);
+       if (!uids_kset)
+               return -ENOMEM;
 
-       error = kobject_add(&uids_kobject);
-       if (!error)
-               error = user_kobject_create(&root_user);
-
-       return error;
+       return uids_user_create(&root_user);
 }
 
 /* work function to remove sysfs directory for a user and free up
@@ -216,7 +213,6 @@ int __init uids_kobject_init(void)
 static void remove_user_sysfs_dir(struct work_struct *w)
 {
        struct user_struct *up = container_of(w, struct user_struct, work);
-       struct kobject *kobj = &up->kset.kobj;
        unsigned long flags;
        int remove_user = 0;
 
@@ -238,9 +234,9 @@ static void remove_user_sysfs_dir(struct work_struct *w)
        if (!remove_user)
                goto done;
 
-       sysfs_remove_file(kobj, &up->user_attr.attr);
-       kobject_uevent(kobj, KOBJ_REMOVE);
-       kobject_del(kobj);
+       kobject_uevent(&up->kobj, KOBJ_REMOVE);
+       kobject_del(&up->kobj);
+       kobject_put(&up->kobj);
 
        sched_destroy_user(up);
        key_put(up->uid_keyring);
@@ -267,7 +263,8 @@ static inline void free_user(struct user_struct *up, unsigned long flags)
 
 #else  /* CONFIG_FAIR_USER_SCHED && CONFIG_SYSFS */
 
-static inline int user_kobject_create(struct user_struct *up) { return 0; }
+int uids_sysfs_init(void) { return 0; }
+static inline int uids_user_create(struct user_struct *up) { return 0; }
 static inline void uids_mutex_lock(void) { }
 static inline void uids_mutex_unlock(void) { }
 
@@ -322,9 +319,9 @@ void free_uid(struct user_struct *up)
 struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
 {
        struct hlist_head *hashent = uidhashentry(ns, uid);
-       struct user_struct *up;
+       struct user_struct *up, *new;
 
-       /* Make uid_hash_find() + user_kobject_create() + uid_hash_insert()
+       /* Make uid_hash_find() + uids_user_create() + uid_hash_insert()
         * atomic.
         */
        uids_mutex_lock();
@@ -334,13 +331,9 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
        spin_unlock_irq(&uidhash_lock);
 
        if (!up) {
-               struct user_struct *new;
-
                new = kmem_cache_alloc(uid_cachep, GFP_KERNEL);
-               if (!new) {
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               if (!new)
+                       goto out_unlock;
 
                new->uid = uid;
                atomic_set(&new->__count, 1);
@@ -356,28 +349,14 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
 #endif
                new->locked_shm = 0;
 
-               if (alloc_uid_keyring(new, current) < 0) {
-                       kmem_cache_free(uid_cachep, new);
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               if (alloc_uid_keyring(new, current) < 0)
+                       goto out_free_user;
 
-               if (sched_create_user(new) < 0) {
-                       key_put(new->uid_keyring);
-                       key_put(new->session_keyring);
-                       kmem_cache_free(uid_cachep, new);
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               if (sched_create_user(new) < 0)
+                       goto out_put_keys;
 
-               if (user_kobject_create(new)) {
-                       sched_destroy_user(new);
-                       key_put(new->uid_keyring);
-                       key_put(new->session_keyring);
-                       kmem_cache_free(uid_cachep, new);
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               if (uids_user_create(new))
+                       goto out_destoy_sched;
 
                /*
                 * Before adding this, check whether we raced
@@ -405,6 +384,17 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
        uids_mutex_unlock();
 
        return up;
+
+out_destoy_sched:
+       sched_destroy_user(new);
+out_put_keys:
+       key_put(new->uid_keyring);
+       key_put(new->session_keyring);
+out_free_user:
+       kmem_cache_free(uid_cachep, new);
+out_unlock:
+       uids_mutex_unlock();
+       return NULL;
 }
 
 void switch_uid(struct user_struct *new_user)
index 52d5e7c9a8e6e82e68a0cb88ba0cdbad508eded5..52db48e7f6e79b5dc78da41903dc162c5e97d755 100644 (file)
@@ -67,9 +67,8 @@ struct workqueue_struct {
 #endif
 };
 
-/* All the per-cpu workqueues on the system, for hotplug cpu to add/remove
-   threads to each one as cpus come/go. */
-static DEFINE_MUTEX(workqueue_mutex);
+/* Serializes the accesses to the list of workqueues. */
+static DEFINE_SPINLOCK(workqueue_lock);
 static LIST_HEAD(workqueues);
 
 static int singlethread_cpu __read_mostly;
@@ -592,8 +591,6 @@ EXPORT_SYMBOL(schedule_delayed_work_on);
  * Returns zero on success.
  * Returns -ve errno on failure.
  *
- * Appears to be racy against CPU hotplug.
- *
  * schedule_on_each_cpu() is very slow.
  */
 int schedule_on_each_cpu(work_func_t func)
@@ -605,7 +602,7 @@ int schedule_on_each_cpu(work_func_t func)
        if (!works)
                return -ENOMEM;
 
-       preempt_disable();              /* CPU hotplug */
+       get_online_cpus();
        for_each_online_cpu(cpu) {
                struct work_struct *work = per_cpu_ptr(works, cpu);
 
@@ -613,8 +610,8 @@ int schedule_on_each_cpu(work_func_t func)
                set_bit(WORK_STRUCT_PENDING, work_data_bits(work));
                __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work);
        }
-       preempt_enable();
        flush_workqueue(keventd_wq);
+       put_online_cpus();
        free_percpu(works);
        return 0;
 }
@@ -722,7 +719,8 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 struct workqueue_struct *__create_workqueue_key(const char *name,
                                                int singlethread,
                                                int freezeable,
-                                               struct lock_class_key *key)
+                                               struct lock_class_key *key,
+                                               const char *lock_name)
 {
        struct workqueue_struct *wq;
        struct cpu_workqueue_struct *cwq;
@@ -739,7 +737,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
        }
 
        wq->name = name;
-       lockdep_init_map(&wq->lockdep_map, name, key, 0);
+       lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
        wq->singlethread = singlethread;
        wq->freezeable = freezeable;
        INIT_LIST_HEAD(&wq->list);
@@ -749,8 +747,10 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
                err = create_workqueue_thread(cwq, singlethread_cpu);
                start_workqueue_thread(cwq, -1);
        } else {
-               mutex_lock(&workqueue_mutex);
+               get_online_cpus();
+               spin_lock(&workqueue_lock);
                list_add(&wq->list, &workqueues);
+               spin_unlock(&workqueue_lock);
 
                for_each_possible_cpu(cpu) {
                        cwq = init_cpu_workqueue(wq, cpu);
@@ -759,7 +759,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
                        err = create_workqueue_thread(cwq, cpu);
                        start_workqueue_thread(cwq, cpu);
                }
-               mutex_unlock(&workqueue_mutex);
+               put_online_cpus();
        }
 
        if (err) {
@@ -774,7 +774,7 @@ static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 {
        /*
         * Our caller is either destroy_workqueue() or CPU_DEAD,
-        * workqueue_mutex protects cwq->thread
+        * get_online_cpus() protects cwq->thread.
         */
        if (cwq->thread == NULL)
                return;
@@ -809,9 +809,11 @@ void destroy_workqueue(struct workqueue_struct *wq)
        struct cpu_workqueue_struct *cwq;
        int cpu;
 
-       mutex_lock(&workqueue_mutex);
+       get_online_cpus();
+       spin_lock(&workqueue_lock);
        list_del(&wq->list);
-       mutex_unlock(&workqueue_mutex);
+       spin_unlock(&workqueue_lock);
+       put_online_cpus();
 
        for_each_cpu_mask(cpu, *cpu_map) {
                cwq = per_cpu_ptr(wq->cpu_wq, cpu);
@@ -834,13 +836,6 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
        action &= ~CPU_TASKS_FROZEN;
 
        switch (action) {
-       case CPU_LOCK_ACQUIRE:
-               mutex_lock(&workqueue_mutex);
-               return NOTIFY_OK;
-
-       case CPU_LOCK_RELEASE:
-               mutex_unlock(&workqueue_mutex);
-               return NOTIFY_OK;
 
        case CPU_UP_PREPARE:
                cpu_set(cpu, cpu_populated_map);
@@ -853,7 +848,8 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
                case CPU_UP_PREPARE:
                        if (!create_workqueue_thread(cwq, cpu))
                                break;
-                       printk(KERN_ERR "workqueue for %i failed\n", cpu);
+                       printk(KERN_ERR "workqueue [%s] for %i failed\n",
+                               wq->name, cpu);
                        return NOTIFY_BAD;
 
                case CPU_ONLINE:
index a60109307d329dda8d0a616018a83090499fcced..14fb355e3caacc1311adfcaf52435e974c715dce 100644 (file)
@@ -517,4 +517,18 @@ config FAULT_INJECTION_STACKTRACE_FILTER
        help
          Provide stacktrace filter for fault-injection capabilities
 
+config LATENCYTOP
+       bool "Latency measuring infrastructure"
+       select FRAME_POINTER if !MIPS
+       select KALLSYMS
+       select KALLSYMS_ALL
+       select STACKTRACE
+       select SCHEDSTATS
+       select SCHED_DEBUG
+       depends on X86 || X86_64
+       help
+         Enable this option if you want to use the LatencyTOP tool
+         to find out which userspace is blocking on what kernel operations.
+
+
 source "samples/Kconfig"
index f73e2f8c308f2e3b17e0cd21b5f0ab7131872f08..812dbf00844bc08a4a844bda6729377b1923a5c5 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 
-#ifdef CONFIG_PREEMPT_BKL
 /*
  * The 'big kernel semaphore'
  *
@@ -86,128 +85,6 @@ void __lockfunc unlock_kernel(void)
                up(&kernel_sem);
 }
 
-#else
-
-/*
- * The 'big kernel lock'
- *
- * This spinlock is taken and released recursively by lock_kernel()
- * and unlock_kernel().  It is transparently dropped and reacquired
- * over schedule().  It is used to protect legacy code that hasn't
- * been migrated to a proper locking design yet.
- *
- * Don't use in new code.
- */
-static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(kernel_flag);
-
-
-/*
- * Acquire/release the underlying lock from the scheduler.
- *
- * This is called with preemption disabled, and should
- * return an error value if it cannot get the lock and
- * TIF_NEED_RESCHED gets set.
- *
- * If it successfully gets the lock, it should increment
- * the preemption count like any spinlock does.
- *
- * (This works on UP too - _raw_spin_trylock will never
- * return false in that case)
- */
-int __lockfunc __reacquire_kernel_lock(void)
-{
-       while (!_raw_spin_trylock(&kernel_flag)) {
-               if (test_thread_flag(TIF_NEED_RESCHED))
-                       return -EAGAIN;
-               cpu_relax();
-       }
-       preempt_disable();
-       return 0;
-}
-
-void __lockfunc __release_kernel_lock(void)
-{
-       _raw_spin_unlock(&kernel_flag);
-       preempt_enable_no_resched();
-}
-
-/*
- * These are the BKL spinlocks - we try to be polite about preemption. 
- * If SMP is not on (ie UP preemption), this all goes away because the
- * _raw_spin_trylock() will always succeed.
- */
-#ifdef CONFIG_PREEMPT
-static inline void __lock_kernel(void)
-{
-       preempt_disable();
-       if (unlikely(!_raw_spin_trylock(&kernel_flag))) {
-               /*
-                * If preemption was disabled even before this
-                * was called, there's nothing we can be polite
-                * about - just spin.
-                */
-               if (preempt_count() > 1) {
-                       _raw_spin_lock(&kernel_flag);
-                       return;
-               }
-
-               /*
-                * Otherwise, let's wait for the kernel lock
-                * with preemption enabled..
-                */
-               do {
-                       preempt_enable();
-                       while (spin_is_locked(&kernel_flag))
-                               cpu_relax();
-                       preempt_disable();
-               } while (!_raw_spin_trylock(&kernel_flag));
-       }
-}
-
-#else
-
-/*
- * Non-preemption case - just get the spinlock
- */
-static inline void __lock_kernel(void)
-{
-       _raw_spin_lock(&kernel_flag);
-}
-#endif
-
-static inline void __unlock_kernel(void)
-{
-       /*
-        * the BKL is not covered by lockdep, so we open-code the
-        * unlocking sequence (and thus avoid the dep-chain ops):
-        */
-       _raw_spin_unlock(&kernel_flag);
-       preempt_enable();
-}
-
-/*
- * Getting the big kernel lock.
- *
- * This cannot happen asynchronously, so we only need to
- * worry about other CPU's.
- */
-void __lockfunc lock_kernel(void)
-{
-       int depth = current->lock_depth+1;
-       if (likely(!depth))
-               __lock_kernel();
-       current->lock_depth = depth;
-}
-
-void __lockfunc unlock_kernel(void)
-{
-       BUG_ON(current->lock_depth < 0);
-       if (likely(--current->lock_depth < 0))
-               __unlock_kernel();
-}
-
-#endif
-
 EXPORT_SYMBOL(lock_kernel);
 EXPORT_SYMBOL(unlock_kernel);
 
index 3590f022a609cf7828c259b9485503fd3cda9683..1d63ead1815e4f5cb8aae5ea2d86a1541eed23a2 100644 (file)
 #include <linux/stat.h>
 #include <linux/slab.h>
 
-/**
- *     populate_dir - populate directory with attributes.
- *     @kobj:  object we're working on.
- *
- *     Most subsystems have a set of default attributes that 
- *     are associated with an object that registers with them.
- *     This is a helper called during object registration that 
- *     loops through the default attributes of the subsystem 
- *     and creates attributes files for them in sysfs.
+/*
+ * populate_dir - populate directory with attributes.
+ * @kobj: object we're working on.
  *
+ * Most subsystems have a set of default attributes that are associated
+ * with an object that registers with them.  This is a helper called during
+ * object registration that loops through the default attributes of the
+ * subsystem and creates attributes files for them in sysfs.
  */
-
-static int populate_dir(struct kobject * kobj)
+static int populate_dir(struct kobject *kobj)
 {
-       struct kobj_type * t = get_ktype(kobj);
-       struct attribute * attr;
+       struct kobj_type *t = get_ktype(kobj);
+       struct attribute *attr;
        int error = 0;
        int i;
-       
+
        if (t && t->default_attrs) {
                for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
-                       if ((error = sysfs_create_file(kobj,attr)))
+                       error = sysfs_create_file(kobj, attr);
+                       if (error)
                                break;
                }
        }
        return error;
 }
 
-static int create_dir(struct kobject * kobj)
+static int create_dir(struct kobject *kobj)
 {
        int error = 0;
        if (kobject_name(kobj)) {
                error = sysfs_create_dir(kobj);
                if (!error) {
-                       if ((error = populate_dir(kobj)))
+                       error = populate_dir(kobj);
+                       if (error)
                                sysfs_remove_dir(kobj);
                }
        }
        return error;
 }
 
-static inline struct kobject * to_kobj(struct list_head * entry)
+static inline struct kobject *to_kobj(struct list_head *entry)
 {
-       return container_of(entry,struct kobject,entry);
+       return container_of(entry, struct kobject, entry);
 }
 
 static int get_kobj_path_length(struct kobject *kobj)
 {
        int length = 1;
-       struct kobject * parent = kobj;
+       struct kobject *parent = kobj;
 
-       /* walk up the ancestors until we hit the one pointing to the 
+       /* walk up the ancestors until we hit the one pointing to the
         * root.
         * Add 1 to strlen for leading '/' of each level.
         */
@@ -84,18 +83,19 @@ static int get_kobj_path_length(struct kobject *kobj)
 
 static void fill_kobj_path(struct kobject *kobj, char *path, int length)
 {
-       struct kobject * parent;
+       struct kobject *parent;
 
        --length;
        for (parent = kobj; parent; parent = parent->parent) {
                int cur = strlen(kobject_name(parent));
                /* back up enough to print this name with '/' */
                length -= cur;
-               strncpy (path + length, kobject_name(parent), cur);
+               strncpy(path + length, kobject_name(parent), cur);
                *(path + --length) = '/';
        }
 
-       pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
+       pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj),
+                kobj, __FUNCTION__, path);
 }
 
 /**
@@ -123,179 +123,286 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL_GPL(kobject_get_path);
 
-/**
- *     kobject_init - initialize object.
- *     @kobj:  object in question.
- */
-void kobject_init(struct kobject * kobj)
+/* add the kobject to its kset's list */
+static void kobj_kset_join(struct kobject *kobj)
 {
-       if (!kobj)
+       if (!kobj->kset)
                return;
-       kref_init(&kobj->kref);
-       INIT_LIST_HEAD(&kobj->entry);
-       kobj->kset = kset_get(kobj->kset);
+
+       kset_get(kobj->kset);
+       spin_lock(&kobj->kset->list_lock);
+       list_add_tail(&kobj->entry, &kobj->kset->list);
+       spin_unlock(&kobj->kset->list_lock);
 }
 
+/* remove the kobject from its kset's list */
+static void kobj_kset_leave(struct kobject *kobj)
+{
+       if (!kobj->kset)
+               return;
 
-/**
- *     unlink - remove kobject from kset list.
- *     @kobj:  kobject.
- *
- *     Remove the kobject from the kset list and decrement
- *     its parent's refcount.
- *     This is separated out, so we can use it in both 
- *     kobject_del() and kobject_add() on error.
- */
+       spin_lock(&kobj->kset->list_lock);
+       list_del_init(&kobj->entry);
+       spin_unlock(&kobj->kset->list_lock);
+       kset_put(kobj->kset);
+}
 
-static void unlink(struct kobject * kobj)
+static void kobject_init_internal(struct kobject *kobj)
 {
-       if (kobj->kset) {
-               spin_lock(&kobj->kset->list_lock);
-               list_del_init(&kobj->entry);
-               spin_unlock(&kobj->kset->list_lock);
-       }
-       kobject_put(kobj);
+       if (!kobj)
+               return;
+       kref_init(&kobj->kref);
+       INIT_LIST_HEAD(&kobj->entry);
 }
 
-/**
- *     kobject_add - add an object to the hierarchy.
- *     @kobj:  object.
- */
 
-int kobject_add(struct kobject * kobj)
+static int kobject_add_internal(struct kobject *kobj)
 {
        int error = 0;
-       struct kobject * parent;
+       struct kobject *parent;
 
-       if (!(kobj = kobject_get(kobj)))
+       if (!kobj)
                return -ENOENT;
-       if (!kobj->k_name)
-               kobject_set_name(kobj, "NO_NAME");
-       if (!*kobj->k_name) {
-               pr_debug("kobject attempted to be registered with no name!\n");
+
+       if (!kobj->name || !kobj->name[0]) {
+               pr_debug("kobject: (%p): attempted to be registered with empty "
+                        "name!\n", kobj);
                WARN_ON(1);
-               kobject_put(kobj);
                return -EINVAL;
        }
-       parent = kobject_get(kobj->parent);
 
-       pr_debug("kobject %s: registering. parent: %s, set: %s\n",
-                kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", 
-                kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" );
+       parent = kobject_get(kobj->parent);
 
+       /* join kset if set, use it as parent if we do not already have one */
        if (kobj->kset) {
-               spin_lock(&kobj->kset->list_lock);
-
                if (!parent)
                        parent = kobject_get(&kobj->kset->kobj);
-
-               list_add_tail(&kobj->entry,&kobj->kset->list);
-               spin_unlock(&kobj->kset->list_lock);
+               kobj_kset_join(kobj);
                kobj->parent = parent;
        }
 
+       pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
+                kobject_name(kobj), kobj, __FUNCTION__,
+                parent ? kobject_name(parent) : "<NULL>",
+                kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
+
        error = create_dir(kobj);
        if (error) {
-               /* unlink does the kobject_put() for us */
-               unlink(kobj);
+               kobj_kset_leave(kobj);
                kobject_put(parent);
+               kobj->parent = NULL;
 
                /* be noisy on error issues */
                if (error == -EEXIST)
-                       printk(KERN_ERR "kobject_add failed for %s with "
+                       printk(KERN_ERR "%s failed for %s with "
                               "-EEXIST, don't try to register things with "
                               "the same name in the same directory.\n",
-                              kobject_name(kobj));
+                              __FUNCTION__, kobject_name(kobj));
                else
-                       printk(KERN_ERR "kobject_add failed for %s (%d)\n",
-                              kobject_name(kobj), error);
+                       printk(KERN_ERR "%s failed for %s (%d)\n",
+                              __FUNCTION__, kobject_name(kobj), error);
                dump_stack();
-       }
+       } else
+               kobj->state_in_sysfs = 1;
 
        return error;
 }
 
 /**
- *     kobject_register - initialize and add an object.
- *     @kobj:  object in question.
+ * kobject_set_name_vargs - Set the name of an kobject
+ * @kobj: struct kobject to set the name of
+ * @fmt: format string used to build the name
+ * @vargs: vargs to format the string.
  */
-
-int kobject_register(struct kobject * kobj)
+static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+                                 va_list vargs)
 {
-       int error = -EINVAL;
-       if (kobj) {
-               kobject_init(kobj);
-               error = kobject_add(kobj);
-               if (!error)
-                       kobject_uevent(kobj, KOBJ_ADD);
-       }
-       return error;
-}
+       va_list aq;
+       char *name;
+
+       va_copy(aq, vargs);
+       name = kvasprintf(GFP_KERNEL, fmt, vargs);
+       va_end(aq);
 
+       if (!name)
+               return -ENOMEM;
+
+       /* Free the old name, if necessary. */
+       kfree(kobj->name);
+
+       /* Now, set the new name */
+       kobj->name = name;
+
+       return 0;
+}
 
 /**
  * kobject_set_name - Set the name of a kobject
- * @kobj: kobject to name
+ * @kobj: struct kobject to set the name of
  * @fmt: format string used to build the name
  *
  * This sets the name of the kobject.  If you have already added the
  * kobject to the system, you must call kobject_rename() in order to
  * change the name of the kobject.
  */
-int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
+int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
 {
-       int error = 0;
-       int limit;
-       int need;
        va_list args;
-       char *name;
+       int retval;
 
-       /* find out how big a buffer we need */
-       name = kmalloc(1024, GFP_KERNEL);
-       if (!name) {
-               error = -ENOMEM;
-               goto done;
-       }
        va_start(args, fmt);
-       need = vsnprintf(name, 1024, fmt, args);
+       retval = kobject_set_name_vargs(kobj, fmt, args);
        va_end(args);
-       kfree(name);
 
-       /* Allocate the new space and copy the string in */
-       limit = need + 1;
-       name = kmalloc(limit, GFP_KERNEL);
-       if (!name) {
-               error = -ENOMEM;
-               goto done;
+       return retval;
+}
+EXPORT_SYMBOL(kobject_set_name);
+
+/**
+ * kobject_init - initialize a kobject structure
+ * @kobj: pointer to the kobject to initialize
+ * @ktype: pointer to the ktype for this kobject.
+ *
+ * This function will properly initialize a kobject such that it can then
+ * be passed to the kobject_add() call.
+ *
+ * After this function is called, the kobject MUST be cleaned up by a call
+ * to kobject_put(), not by a call to kfree directly to ensure that all of
+ * the memory is cleaned up properly.
+ */
+void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
+{
+       char *err_str;
+
+       if (!kobj) {
+               err_str = "invalid kobject pointer!";
+               goto error;
+       }
+       if (!ktype) {
+               err_str = "must have a ktype to be initialized properly!\n";
+               goto error;
+       }
+       if (kobj->state_initialized) {
+               /* do not error out as sometimes we can recover */
+               printk(KERN_ERR "kobject (%p): tried to init an initialized "
+                      "object, something is seriously wrong.\n", kobj);
+               dump_stack();
        }
-       va_start(args, fmt);
-       need = vsnprintf(name, limit, fmt, args);
-       va_end(args);
 
-       /* something wrong with the string we copied? */
-       if (need >= limit) {
-               kfree(name);
-               error = -EFAULT;
-               goto done;
+       kref_init(&kobj->kref);
+       INIT_LIST_HEAD(&kobj->entry);
+       kobj->ktype = ktype;
+       kobj->state_in_sysfs = 0;
+       kobj->state_add_uevent_sent = 0;
+       kobj->state_remove_uevent_sent = 0;
+       kobj->state_initialized = 1;
+       return;
+
+error:
+       printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
+       dump_stack();
+}
+EXPORT_SYMBOL(kobject_init);
+
+static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
+                           const char *fmt, va_list vargs)
+{
+       va_list aq;
+       int retval;
+
+       va_copy(aq, vargs);
+       retval = kobject_set_name_vargs(kobj, fmt, aq);
+       va_end(aq);
+       if (retval) {
+               printk(KERN_ERR "kobject: can not set name properly!\n");
+               return retval;
        }
+       kobj->parent = parent;
+       return kobject_add_internal(kobj);
+}
 
-       /* Free the old name, if necessary. */
-       kfree(kobj->k_name);
+/**
+ * kobject_add - the main kobject add function
+ * @kobj: the kobject to add
+ * @parent: pointer to the parent of the kobject.
+ * @fmt: format to name the kobject with.
+ *
+ * The kobject name is set and added to the kobject hierarchy in this
+ * function.
+ *
+ * If @parent is set, then the parent of the @kobj will be set to it.
+ * If @parent is NULL, then the parent of the @kobj will be set to the
+ * kobject associted with the kset assigned to this kobject.  If no kset
+ * is assigned to the kobject, then the kobject will be located in the
+ * root of the sysfs tree.
+ *
+ * If this function returns an error, kobject_put() must be called to
+ * properly clean up the memory associated with the object.
+ * Under no instance should the kobject that is passed to this function
+ * be directly freed with a call to kfree(), that can leak memory.
+ *
+ * Note, no "add" uevent will be created with this call, the caller should set
+ * up all of the necessary sysfs files for the object and then call
+ * kobject_uevent() with the UEVENT_ADD parameter to ensure that
+ * userspace is properly notified of this kobject's creation.
+ */
+int kobject_add(struct kobject *kobj, struct kobject *parent,
+               const char *fmt, ...)
+{
+       va_list args;
+       int retval;
 
-       /* Now, set the new name */
-       kobj->k_name = name;
-done:
-       return error;
+       if (!kobj)
+               return -EINVAL;
+
+       if (!kobj->state_initialized) {
+               printk(KERN_ERR "kobject '%s' (%p): tried to add an "
+                      "uninitialized object, something is seriously wrong.\n",
+                      kobject_name(kobj), kobj);
+               dump_stack();
+               return -EINVAL;
+       }
+       va_start(args, fmt);
+       retval = kobject_add_varg(kobj, parent, fmt, args);
+       va_end(args);
+
+       return retval;
 }
-EXPORT_SYMBOL(kobject_set_name);
+EXPORT_SYMBOL(kobject_add);
 
 /**
- *     kobject_rename - change the name of an object
- *     @kobj:  object in question.
- *     @new_name: object's new name
+ * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
+ * @kobj: pointer to the kobject to initialize
+ * @ktype: pointer to the ktype for this kobject.
+ * @parent: pointer to the parent of this kobject.
+ * @fmt: the name of the kobject.
+ *
+ * This function combines the call to kobject_init() and
+ * kobject_add().  The same type of error handling after a call to
+ * kobject_add() and kobject lifetime rules are the same here.
  */
+int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+                        struct kobject *parent, const char *fmt, ...)
+{
+       va_list args;
+       int retval;
+
+       kobject_init(kobj, ktype);
+
+       va_start(args, fmt);
+       retval = kobject_add_varg(kobj, parent, fmt, args);
+       va_end(args);
+
+       return retval;
+}
+EXPORT_SYMBOL_GPL(kobject_init_and_add);
 
-int kobject_rename(struct kobject * kobj, const char *new_name)
+/**
+ * kobject_rename - change the name of an object
+ * @kobj: object in question.
+ * @new_name: object's new name
+ */
+int kobject_rename(struct kobject *kobj, const char *new_name)
 {
        int error = 0;
        const char *devpath = NULL;
@@ -334,8 +441,6 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
        sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
        envp[0] = devpath_string;
        envp[1] = NULL;
-       /* Note : if we want to send the new name alone, not the full path,
-        * we could probably use kobject_name(kobj); */
 
        error = sysfs_rename_dir(kobj, new_name);
 
@@ -354,11 +459,10 @@ out:
 }
 
 /**
- *     kobject_move - move object to another parent
- *     @kobj:  object in question.
- *     @new_parent: object's new parent (can be NULL)
+ * kobject_move - move object to another parent
+ * @kobj: object in question.
+ * @new_parent: object's new parent (can be NULL)
  */
-
 int kobject_move(struct kobject *kobj, struct kobject *new_parent)
 {
        int error;
@@ -406,68 +510,74 @@ out:
 }
 
 /**
- *     kobject_del - unlink kobject from hierarchy.
- *     @kobj:  object.
+ * kobject_del - unlink kobject from hierarchy.
+ * @kobj: object.
  */
-
-void kobject_del(struct kobject * kobj)
+void kobject_del(struct kobject *kobj)
 {
        if (!kobj)
                return;
-       sysfs_remove_dir(kobj);
-       unlink(kobj);
-}
 
-/**
- *     kobject_unregister - remove object from hierarchy and decrement refcount.
- *     @kobj:  object going away.
- */
-
-void kobject_unregister(struct kobject * kobj)
-{
-       if (!kobj)
-               return;
-       pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
-       kobject_uevent(kobj, KOBJ_REMOVE);
-       kobject_del(kobj);
-       kobject_put(kobj);
+       sysfs_remove_dir(kobj);
+       kobj->state_in_sysfs = 0;
+       kobj_kset_leave(kobj);
+       kobject_put(kobj->parent);
+       kobj->parent = NULL;
 }
 
 /**
- *     kobject_get - increment refcount for object.
- *     @kobj:  object.
+ * kobject_get - increment refcount for object.
+ * @kobj: object.
  */
-
-struct kobject * kobject_get(struct kobject * kobj)
+struct kobject *kobject_get(struct kobject *kobj)
 {
        if (kobj)
                kref_get(&kobj->kref);
        return kobj;
 }
 
-/**
- *     kobject_cleanup - free kobject resources. 
- *     @kobj:  object.
+/*
+ * kobject_cleanup - free kobject resources.
+ * @kobj: object to cleanup
  */
-
-void kobject_cleanup(struct kobject * kobj)
+static void kobject_cleanup(struct kobject *kobj)
 {
-       struct kobj_type * t = get_ktype(kobj);
-       struct kset * s = kobj->kset;
-       struct kobject * parent = kobj->parent;
-       const char *name = kobj->k_name;
+       struct kobj_type *t = get_ktype(kobj);
+       const char *name = kobj->name;
+
+       pr_debug("kobject: '%s' (%p): %s\n",
+                kobject_name(kobj), kobj, __FUNCTION__);
+
+       if (t && !t->release)
+               pr_debug("kobject: '%s' (%p): does not have a release() "
+                        "function, it is broken and must be fixed.\n",
+                        kobject_name(kobj), kobj);
+
+       /* send "remove" if the caller did not do it but sent "add" */
+       if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
+               pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n",
+                        kobject_name(kobj), kobj);
+               kobject_uevent(kobj, KOBJ_REMOVE);
+       }
+
+       /* remove from sysfs if the caller did not do it */
+       if (kobj->state_in_sysfs) {
+               pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
+                        kobject_name(kobj), kobj);
+               kobject_del(kobj);
+       }
 
-       pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
        if (t && t->release) {
+               pr_debug("kobject: '%s' (%p): calling ktype release\n",
+                        kobject_name(kobj), kobj);
                t->release(kobj);
-               /* If we have a release function, we can guess that this was
-                * not a statically allocated kobject, so we should be safe to
-                * free the name */
+       }
+
+       /* free name if we allocated it */
+       if (name) {
+               pr_debug("kobject: '%s': free name\n", name);
                kfree(name);
        }
-       if (s)
-               kset_put(s);
-       kobject_put(parent);
 }
 
 static void kobject_release(struct kref *kref)
@@ -476,107 +586,130 @@ static void kobject_release(struct kref *kref)
 }
 
 /**
- *     kobject_put - decrement refcount for object.
- *     @kobj:  object.
+ * kobject_put - decrement refcount for object.
+ * @kobj: object.
  *
- *     Decrement the refcount, and if 0, call kobject_cleanup().
+ * Decrement the refcount, and if 0, call kobject_cleanup().
  */
-void kobject_put(struct kobject * kobj)
+void kobject_put(struct kobject *kobj)
 {
        if (kobj)
                kref_put(&kobj->kref, kobject_release);
 }
 
-
-static void dir_release(struct kobject *kobj)
+static void dynamic_kobj_release(struct kobject *kobj)
 {
+       pr_debug("kobject: (%p): %s\n", kobj, __FUNCTION__);
        kfree(kobj);
 }
 
-static struct kobj_type dir_ktype = {
-       .release        = dir_release,
-       .sysfs_ops      = NULL,
-       .default_attrs  = NULL,
+static struct kobj_type dynamic_kobj_ktype = {
+       .release        = dynamic_kobj_release,
+       .sysfs_ops      = &kobj_sysfs_ops,
 };
 
 /**
- *     kobject_kset_add_dir - add sub directory of object.
- *     @kset:          kset the directory is belongs to.
- *     @parent:        object in which a directory is created.
- *     @name:  directory name.
+ * kobject_create - create a struct kobject dynamically
  *
- *     Add a plain directory object as child of given object.
+ * This function creates a kobject structure dynamically and sets it up
+ * to be a "dynamic" kobject with a default release function set up.
+ *
+ * If the kobject was not able to be created, NULL will be returned.
+ * The kobject structure returned from here must be cleaned up with a
+ * call to kobject_put() and not kfree(), as kobject_init() has
+ * already been called on this structure.
  */
-struct kobject *kobject_kset_add_dir(struct kset *kset,
-                                    struct kobject *parent, const char *name)
+struct kobject *kobject_create(void)
 {
-       struct kobject *k;
-       int ret;
-
-       if (!parent)
-               return NULL;
-
-       k = kzalloc(sizeof(*k), GFP_KERNEL);
-       if (!k)
-               return NULL;
+       struct kobject *kobj;
 
-       k->kset = kset;
-       k->parent = parent;
-       k->ktype = &dir_ktype;
-       kobject_set_name(k, name);
-       ret = kobject_register(k);
-       if (ret < 0) {
-               printk(KERN_WARNING "%s: kobject_register error: %d\n",
-                       __func__, ret);
-               kobject_del(k);
+       kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+       if (!kobj)
                return NULL;
-       }
 
-       return k;
+       kobject_init(kobj, &dynamic_kobj_ktype);
+       return kobj;
 }
 
 /**
- *     kobject_add_dir - add sub directory of object.
- *     @parent:        object in which a directory is created.
- *     @name:  directory name.
+ * kobject_create_and_add - create a struct kobject dynamically and register it with sysfs
+ *
+ * @name: the name for the kset
+ * @parent: the parent kobject of this kobject, if any.
+ *
+ * This function creates a kset structure dynamically and registers it
+ * with sysfs.  When you are finished with this structure, call
+ * kobject_put() and the structure will be dynamically freed when
+ * it is no longer being used.
  *
- *     Add a plain directory object as child of given object.
+ * If the kobject was not able to be created, NULL will be returned.
  */
-struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
 {
-       return kobject_kset_add_dir(NULL, parent, name);
+       struct kobject *kobj;
+       int retval;
+
+       kobj = kobject_create();
+       if (!kobj)
+               return NULL;
+
+       retval = kobject_add(kobj, parent, "%s", name);
+       if (retval) {
+               printk(KERN_WARNING "%s: kobject_add error: %d\n",
+                      __FUNCTION__, retval);
+               kobject_put(kobj);
+               kobj = NULL;
+       }
+       return kobj;
 }
+EXPORT_SYMBOL_GPL(kobject_create_and_add);
 
 /**
- *     kset_init - initialize a kset for use
- *     @k:     kset 
+ * kset_init - initialize a kset for use
+ * @k: kset
  */
-
-void kset_init(struct kset * k)
+void kset_init(struct kset *k)
 {
-       kobject_init(&k->kobj);
+       kobject_init_internal(&k->kobj);
        INIT_LIST_HEAD(&k->list);
        spin_lock_init(&k->list_lock);
 }
 
+/* default kobject attribute operations */
+static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
+                             char *buf)
+{
+       struct kobj_attribute *kattr;
+       ssize_t ret = -EIO;
 
-/**
- *     kset_add - add a kset object to the hierarchy.
- *     @k:     kset.
- */
+       kattr = container_of(attr, struct kobj_attribute, attr);
+       if (kattr->show)
+               ret = kattr->show(kobj, kattr, buf);
+       return ret;
+}
 
-int kset_add(struct kset * k)
+static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
+                              const char *buf, size_t count)
 {
-       return kobject_add(&k->kobj);
+       struct kobj_attribute *kattr;
+       ssize_t ret = -EIO;
+
+       kattr = container_of(attr, struct kobj_attribute, attr);
+       if (kattr->store)
+               ret = kattr->store(kobj, kattr, buf, count);
+       return ret;
 }
 
+struct sysfs_ops kobj_sysfs_ops = {
+       .show   = kobj_attr_show,
+       .store  = kobj_attr_store,
+};
 
 /**
- *     kset_register - initialize and add a kset.
- *     @k:     kset.
+ * kset_register - initialize and add a kset.
+ * @k: kset.
  */
-
-int kset_register(struct kset * k)
+int kset_register(struct kset *k)
 {
        int err;
 
@@ -584,46 +717,42 @@ int kset_register(struct kset * k)
                return -EINVAL;
 
        kset_init(k);
-       err = kset_add(k);
+       err = kobject_add_internal(&k->kobj);
        if (err)
                return err;
        kobject_uevent(&k->kobj, KOBJ_ADD);
        return 0;
 }
 
-
 /**
- *     kset_unregister - remove a kset.
- *     @k:     kset.
+ * kset_unregister - remove a kset.
+ * @k: kset.
  */
-
-void kset_unregister(struct kset * k)
+void kset_unregister(struct kset *k)
 {
        if (!k)
                return;
-       kobject_unregister(&k->kobj);
+       kobject_put(&k->kobj);
 }
 
-
 /**
- *     kset_find_obj - search for object in kset.
- *     @kset:  kset we're looking in.
- *     @name:  object's name.
+ * kset_find_obj - search for object in kset.
+ * @kset: kset we're looking in.
+ * @name: object's name.
  *
- *     Lock kset via @kset->subsys, and iterate over @kset->list,
- *     looking for a matching kobject. If matching object is found
- *     take a reference and return the object.
+ * Lock kset via @kset->subsys, and iterate over @kset->list,
+ * looking for a matching kobject. If matching object is found
+ * take a reference and return the object.
  */
-
-struct kobject * kset_find_obj(struct kset * kset, const char * name)
+struct kobject *kset_find_obj(struct kset *kset, const char *name)
 {
-       struct list_head * entry;
-       struct kobject * ret = NULL;
+       struct list_head *entry;
+       struct kobject *ret = NULL;
 
        spin_lock(&kset->list_lock);
-       list_for_each(entry,&kset->list) {
-               struct kobject * k = to_kobj(entry);
-               if (kobject_name(k) && !strcmp(kobject_name(k),name)) {
+       list_for_each(entry, &kset->list) {
+               struct kobject *k = to_kobj(entry);
+               if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
                        ret = kobject_get(k);
                        break;
                }
@@ -632,47 +761,94 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
        return ret;
 }
 
-int subsystem_register(struct kset *s)
+static void kset_release(struct kobject *kobj)
 {
-       return kset_register(s);
+       struct kset *kset = container_of(kobj, struct kset, kobj);
+       pr_debug("kobject: '%s' (%p): %s\n",
+                kobject_name(kobj), kobj, __FUNCTION__);
+       kfree(kset);
 }
 
-void subsystem_unregister(struct kset *s)
+static struct kobj_type kset_ktype = {
+       .sysfs_ops      = &kobj_sysfs_ops,
+       .release = kset_release,
+};
+
+/**
+ * kset_create - create a struct kset dynamically
+ *
+ * @name: the name for the kset
+ * @uevent_ops: a struct kset_uevent_ops for the kset
+ * @parent_kobj: the parent kobject of this kset, if any.
+ *
+ * This function creates a kset structure dynamically.  This structure can
+ * then be registered with the system and show up in sysfs with a call to
+ * kset_register().  When you are finished with this structure, if
+ * kset_register() has been called, call kset_unregister() and the
+ * structure will be dynamically freed when it is no longer being used.
+ *
+ * If the kset was not able to be created, NULL will be returned.
+ */
+static struct kset *kset_create(const char *name,
+                               struct kset_uevent_ops *uevent_ops,
+                               struct kobject *parent_kobj)
 {
-       kset_unregister(s);
+       struct kset *kset;
+
+       kset = kzalloc(sizeof(*kset), GFP_KERNEL);
+       if (!kset)
+               return NULL;
+       kobject_set_name(&kset->kobj, name);
+       kset->uevent_ops = uevent_ops;
+       kset->kobj.parent = parent_kobj;
+
+       /*
+        * The kobject of this kset will have a type of kset_ktype and belong to
+        * no kset itself.  That way we can properly free it when it is
+        * finished being used.
+        */
+       kset->kobj.ktype = &kset_ktype;
+       kset->kobj.kset = NULL;
+
+       return kset;
 }
 
 /**
- *     subsystem_create_file - export sysfs attribute file.
- *     @s:     subsystem.
- *     @a:     subsystem attribute descriptor.
+ * kset_create_and_add - create a struct kset dynamically and add it to sysfs
+ *
+ * @name: the name for the kset
+ * @uevent_ops: a struct kset_uevent_ops for the kset
+ * @parent_kobj: the parent kobject of this kset, if any.
+ *
+ * This function creates a kset structure dynamically and registers it
+ * with sysfs.  When you are finished with this structure, call
+ * kset_unregister() and the structure will be dynamically freed when it
+ * is no longer being used.
+ *
+ * If the kset was not able to be created, NULL will be returned.
  */
-
-int subsys_create_file(struct kset *s, struct subsys_attribute *a)
+struct kset *kset_create_and_add(const char *name,
+                                struct kset_uevent_ops *uevent_ops,
+                                struct kobject *parent_kobj)
 {
-       int error = 0;
-
-       if (!s || !a)
-               return -EINVAL;
+       struct kset *kset;
+       int error;
 
-       if (kset_get(s)) {
-               error = sysfs_create_file(&s->kobj, &a->attr);
-               kset_put(s);
+       kset = kset_create(name, uevent_ops, parent_kobj);
+       if (!kset)
+               return NULL;
+       error = kset_register(kset);
+       if (error) {
+               kfree(kset);
+               return NULL;
        }
-       return error;
+       return kset;
 }
+EXPORT_SYMBOL_GPL(kset_create_and_add);
 
-EXPORT_SYMBOL(kobject_init);
-EXPORT_SYMBOL(kobject_register);
-EXPORT_SYMBOL(kobject_unregister);
 EXPORT_SYMBOL(kobject_get);
 EXPORT_SYMBOL(kobject_put);
-EXPORT_SYMBOL(kobject_add);
 EXPORT_SYMBOL(kobject_del);
 
 EXPORT_SYMBOL(kset_register);
 EXPORT_SYMBOL(kset_unregister);
-
-EXPORT_SYMBOL(subsystem_register);
-EXPORT_SYMBOL(subsystem_unregister);
-EXPORT_SYMBOL(subsys_create_file);
index 5886147252d0d643598e408b63bf193aa49b5f34..5a402e2982afb4a1a82a28092260bb66bd921269 100644 (file)
@@ -98,7 +98,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        int i = 0;
        int retval = 0;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("kobject: '%s' (%p): %s\n",
+                kobject_name(kobj), kobj, __FUNCTION__);
 
        /* search the kset we belong to */
        top_kobj = kobj;
@@ -106,7 +107,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                top_kobj = top_kobj->parent;
 
        if (!top_kobj->kset) {
-               pr_debug("kobject attempted to send uevent without kset!\n");
+               pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
+                        "without kset!\n", kobject_name(kobj), kobj,
+                        __FUNCTION__);
                return -EINVAL;
        }
 
@@ -116,7 +119,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        /* skip the event, if the filter returns zero. */
        if (uevent_ops && uevent_ops->filter)
                if (!uevent_ops->filter(kset, kobj)) {
-                       pr_debug("kobject filter function caused the event to drop!\n");
+                       pr_debug("kobject: '%s' (%p): %s: filter function "
+                                "caused the event to drop!\n",
+                                kobject_name(kobj), kobj, __FUNCTION__);
                        return 0;
                }
 
@@ -126,7 +131,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        else
                subsystem = kobject_name(&kset->kobj);
        if (!subsystem) {
-               pr_debug("unset subsystem caused the event to drop!\n");
+               pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
+                        "event to drop!\n", kobject_name(kobj), kobj,
+                        __FUNCTION__);
                return 0;
        }
 
@@ -166,12 +173,24 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        if (uevent_ops && uevent_ops->uevent) {
                retval = uevent_ops->uevent(kset, kobj, env);
                if (retval) {
-                       pr_debug ("%s - uevent() returned %d\n",
-                                 __FUNCTION__, retval);
+                       pr_debug("kobject: '%s' (%p): %s: uevent() returned "
+                                "%d\n", kobject_name(kobj), kobj,
+                                __FUNCTION__, retval);
                        goto exit;
                }
        }
 
+       /*
+        * Mark "add" and "remove" events in the object to ensure proper
+        * events to userspace during automatic cleanup. If the object did
+        * send an "add" event, "remove" will automatically generated by
+        * the core, if not already done by the caller.
+        */
+       if (action == KOBJ_ADD)
+               kobj->state_add_uevent_sent = 1;
+       else if (action == KOBJ_REMOVE)
+               kobj->state_remove_uevent_sent = 1;
+
        /* we will send an event, so request a new sequence number */
        spin_lock(&sequence_lock);
        seq = ++uevent_seqnum;
@@ -219,11 +238,12 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                retval = add_uevent_var(env, "HOME=/");
                if (retval)
                        goto exit;
-               retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+               retval = add_uevent_var(env,
+                                       "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
                if (retval)
                        goto exit;
 
-               call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
+               call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC);
        }
 
 exit:
@@ -231,7 +251,6 @@ exit:
        kfree(env);
        return retval;
 }
-
 EXPORT_SYMBOL_GPL(kobject_uevent_env);
 
 /**
@@ -247,7 +266,6 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 {
        return kobject_uevent_env(kobj, action, NULL);
 }
-
 EXPORT_SYMBOL_GPL(kobject_uevent);
 
 /**
index a6dc3ec328e05fc8da4d69d185d13a5758ac0464..9ecd6e86561034f2a097bcc027765704e124f7df 100644 (file)
 #include <linux/kref.h>
 #include <linux/module.h>
 
+/**
+ * kref_set - initialize object and set refcount to requested number.
+ * @kref: object in question.
+ * @num: initial reference counter
+ */
+void kref_set(struct kref *kref, int num)
+{
+       atomic_set(&kref->refcount, num);
+       smp_mb();
+}
+
 /**
  * kref_init - initialize object.
  * @kref: object in question.
  */
 void kref_init(struct kref *kref)
 {
-       atomic_set(&kref->refcount,1);
-       smp_mb();
+       kref_set(kref, 1);
 }
 
 /**
@@ -61,6 +71,7 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref))
        return 0;
 }
 
+EXPORT_SYMBOL(kref_set);
 EXPORT_SYMBOL(kref_init);
 EXPORT_SYMBOL(kref_get);
 EXPORT_SYMBOL(kref_put);
index e233fff61b4bd036382a26811849653ebfd4b9e5..f874ae818ad3812f7cd051972c823c743a154d33 100644 (file)
@@ -25,14 +25,15 @@ static struct page *__xip_sparse_page;
 static struct page *xip_sparse_page(void)
 {
        if (!__xip_sparse_page) {
-               unsigned long zeroes = get_zeroed_page(GFP_HIGHUSER);
-               if (zeroes) {
+               struct page *page = alloc_page(GFP_HIGHUSER | __GFP_ZERO);
+
+               if (page) {
                        static DEFINE_SPINLOCK(xip_alloc_lock);
                        spin_lock(&xip_alloc_lock);
                        if (!__xip_sparse_page)
-                               __xip_sparse_page = virt_to_page(zeroes);
+                               __xip_sparse_page = page;
                        else
-                               free_page(zeroes);
+                               __free_page(page);
                        spin_unlock(&xip_alloc_lock);
                }
        }
index 7224a4f071067c3d60a017d949daa2e97f0e8a5d..db861d8b6c2824f460cc177f0d4008fd8850cc3e 100644 (file)
@@ -418,9 +418,14 @@ static struct page *alloc_huge_page_private(struct vm_area_struct *vma,
        if (free_huge_pages > resv_huge_pages)
                page = dequeue_huge_page(vma, addr);
        spin_unlock(&hugetlb_lock);
-       if (!page)
+       if (!page) {
                page = alloc_buddy_huge_page(vma, addr);
-       return page ? page : ERR_PTR(-VM_FAULT_OOM);
+               if (!page) {
+                       hugetlb_put_quota(vma->vm_file->f_mapping, 1);
+                       return ERR_PTR(-VM_FAULT_OOM);
+               }
+       }
+       return page;
 }
 
 static struct page *alloc_huge_page(struct vm_area_struct *vma,
@@ -694,6 +699,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
                dst_pte = huge_pte_alloc(dst, addr);
                if (!dst_pte)
                        goto nomem;
+
+               /* If the pagetables are shared don't copy or take references */
+               if (dst_pte == src_pte)
+                       continue;
+
                spin_lock(&dst->page_table_lock);
                spin_lock(&src->page_table_lock);
                if (!pte_none(*src_pte)) {
@@ -1206,8 +1216,10 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to)
        if (hugetlb_get_quota(inode->i_mapping, chg))
                return -ENOSPC;
        ret = hugetlb_acct_memory(chg);
-       if (ret < 0)
+       if (ret < 0) {
+               hugetlb_put_quota(inode->i_mapping, chg);
                return ret;
+       }
        region_add(&inode->i_mapping->private_list, from, to);
        return 0;
 }
index 4bf0b6d0eb2a675bbd1083099448d54979dff304..4b0144b24c123681dcd9e95e715ae56b009355d7 100644 (file)
@@ -392,6 +392,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
                        return NULL;
        }
 
+#ifdef CONFIG_DEBUG_VM
        /*
         * Add some anal sanity checks for now. Eventually,
         * we should just do "return pfn_to_page(pfn)", but
@@ -402,6 +403,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
                print_bad_pte(vma, pte, addr);
                return NULL;
        }
+#endif
 
        /*
         * NOTE! We still have PageReserved() pages in the page 
@@ -1668,6 +1670,9 @@ gotten:
 unlock:
        pte_unmap_unlock(page_table, ptl);
        if (dirty_page) {
+               if (vma->vm_file)
+                       file_update_time(vma->vm_file);
+
                /*
                 * Yes, Virginia, this is actually required to prevent a race
                 * with clear_page_dirty_for_io() from clearing the page dirty
@@ -2341,6 +2346,9 @@ out_unlocked:
        if (anon)
                page_cache_release(vmf.page);
        else if (dirty_page) {
+               if (vma->vm_file)
+                       file_update_time(vma->vm_file);
+
                set_page_dirty_balance(dirty_page, page_mkwrite);
                put_page(dirty_page);
        }
index 15678aa6ec73a4389d1c523fe542144cd3050836..bfa389fc6ded6a2a5892eec57ed6cd90bbd34d1e 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1620,7 +1620,7 @@ static inline int expand_downwards(struct vm_area_struct *vma,
                return -ENOMEM;
 
        address &= PAGE_MASK;
-       error = security_file_mmap(0, 0, 0, 0, address, 1);
+       error = security_file_mmap(NULL, 0, 0, 0, address, 1);
        if (error)
                return error;
 
@@ -1941,7 +1941,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        if (is_hugepage_only_range(mm, addr, len))
                return -EINVAL;
 
-       error = security_file_mmap(0, 0, 0, 0, addr, 1);
+       error = security_file_mmap(NULL, 0, 0, 0, addr, 1);
        if (error)
                return error;
 
index 91a081a82f55a330706f92d92cd54186ea6339af..96473b482099793384af969b8158e1306e2d4f58 100644 (file)
@@ -286,7 +286,7 @@ static void __oom_kill_task(struct task_struct *p, int verbose)
         * all the memory it needs. That way it should be able to
         * exit() and clear out its resources quickly...
         */
-       p->time_slice = HZ;
+       p->rt.time_slice = HZ;
        set_tsk_thread_flag(p, TIF_MEMDIE);
 
        force_sig(SIGKILL, p);
index d55cfcae2ef1fea2082d28173dd2f94e1e6666ce..3d3848fa6324ee30c8bfa4f39ac867808af84627 100644 (file)
@@ -558,7 +558,6 @@ static void background_writeout(unsigned long _min_pages)
                        global_page_state(NR_UNSTABLE_NFS) < background_thresh
                                && min_pages <= 0)
                        break;
-               wbc.more_io = 0;
                wbc.encountered_congestion = 0;
                wbc.nr_to_write = MAX_WRITEBACK_PAGES;
                wbc.pages_skipped = 0;
@@ -566,9 +565,8 @@ static void background_writeout(unsigned long _min_pages)
                min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
                if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
                        /* Wrote less than expected */
-                       if (wbc.encountered_congestion || wbc.more_io)
-                               congestion_wait(WRITE, HZ/10);
-                       else
+                       congestion_wait(WRITE, HZ/10);
+                       if (!wbc.encountered_congestion)
                                break;
                }
        }
@@ -633,12 +631,11 @@ static void wb_kupdate(unsigned long arg)
                        global_page_state(NR_UNSTABLE_NFS) +
                        (inodes_stat.nr_inodes - inodes_stat.nr_unused);
        while (nr_to_write > 0) {
-               wbc.more_io = 0;
                wbc.encountered_congestion = 0;
                wbc.nr_to_write = MAX_WRITEBACK_PAGES;
                writeback_inodes(&wbc);
                if (wbc.nr_to_write > 0) {
-                       if (wbc.encountered_congestion || wbc.more_io)
+                       if (wbc.encountered_congestion)
                                congestion_wait(WRITE, HZ/10);
                        else
                                break;  /* All the old data is written */
index d73bfad1c32f2e2254aaa1f47de3bda7db0b8b88..b2838c24e582c11b8e0680ca5d5b5f97389145ba 100644 (file)
@@ -2566,7 +2566,7 @@ static void __meminit zone_init_free_lists(struct pglist_data *pgdat,
        memmap_init_zone((size), (nid), (zone), (start_pfn), MEMMAP_EARLY)
 #endif
 
-static int __devinit zone_batchsize(struct zone *zone)
+static int zone_batchsize(struct zone *zone)
 {
        int batch;
 
@@ -3438,7 +3438,7 @@ static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
                mem_map = NODE_DATA(0)->node_mem_map;
 #ifdef CONFIG_ARCH_POPULATES_NODE_MAP
                if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
-                       mem_map -= pgdat->node_start_pfn;
+                       mem_map -= (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
 #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
        }
 #endif
index ae8189c2799e99d936c01b76330b607593980a73..3f703f7cb398056547af212577909a3d6c46b116 100644 (file)
@@ -26,9 +26,17 @@ DEFINE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
 static unsigned long max_pages(unsigned long min_pages)
 {
        unsigned long node_free_pages, max;
+       struct zone *zones = NODE_DATA(numa_node_id())->node_zones;
+
+       node_free_pages =
+#ifdef CONFIG_ZONE_DMA
+               zone_page_state(&zones[ZONE_DMA], NR_FREE_PAGES) +
+#endif
+#ifdef CONFIG_ZONE_DMA32
+               zone_page_state(&zones[ZONE_DMA32], NR_FREE_PAGES) +
+#endif
+               zone_page_state(&zones[ZONE_NORMAL], NR_FREE_PAGES);
 
-       node_free_pages = node_page_state(numa_node_id(),
-                       NR_FREE_PAGES);
        max = node_free_pages / FRACTION_OF_NODE_MEM;
        return max(max, min_pages);
 }
index 2e338a5f7b14c6d29216f4c54a74ef5259be01fa..40c00dacbe4b9a478ea2655f86979bd00307f9e4 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -304,11 +304,11 @@ struct kmem_list3 {
 /*
  * Need this for bootstrapping a per node allocator.
  */
-#define NUM_INIT_LISTS (2 * MAX_NUMNODES + 1)
+#define NUM_INIT_LISTS (3 * MAX_NUMNODES)
 struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS];
 #define        CACHE_CACHE 0
-#define        SIZE_AC 1
-#define        SIZE_L3 (1 + MAX_NUMNODES)
+#define        SIZE_AC MAX_NUMNODES
+#define        SIZE_L3 (2 * MAX_NUMNODES)
 
 static int drain_freelist(struct kmem_cache *cache,
                        struct kmem_list3 *l3, int tofree);
@@ -730,8 +730,7 @@ static inline void init_lock_keys(void)
 #endif
 
 /*
- * 1. Guard access to the cache-chain.
- * 2. Protect sanity of cpu_online_map against cpu hotplug events
+ * Guard access to the cache-chain.
  */
 static DEFINE_MUTEX(cache_chain_mutex);
 static struct list_head cache_chain;
@@ -1331,12 +1330,11 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
        int err = 0;
 
        switch (action) {
-       case CPU_LOCK_ACQUIRE:
-               mutex_lock(&cache_chain_mutex);
-               break;
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
+               mutex_lock(&cache_chain_mutex);
                err = cpuup_prepare(cpu);
+               mutex_unlock(&cache_chain_mutex);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
@@ -1373,9 +1371,8 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
 #endif
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
+               mutex_lock(&cache_chain_mutex);
                cpuup_canceled(cpu);
-               break;
-       case CPU_LOCK_RELEASE:
                mutex_unlock(&cache_chain_mutex);
                break;
        }
@@ -1409,6 +1406,22 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list,
        local_irq_enable();
 }
 
+/*
+ * For setting up all the kmem_list3s for cache whose buffer_size is same as
+ * size of kmem_list3.
+ */
+static void __init set_up_list3s(struct kmem_cache *cachep, int index)
+{
+       int node;
+
+       for_each_online_node(node) {
+               cachep->nodelists[node] = &initkmem_list3[index + node];
+               cachep->nodelists[node]->next_reap = jiffies +
+                   REAPTIMEOUT_LIST3 +
+                   ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
+       }
+}
+
 /*
  * Initialisation.  Called after the page allocator have been initialised and
  * before smp_init().
@@ -1432,6 +1445,7 @@ void __init kmem_cache_init(void)
                if (i < MAX_NUMNODES)
                        cache_cache.nodelists[i] = NULL;
        }
+       set_up_list3s(&cache_cache, CACHE_CACHE);
 
        /*
         * Fragmentation resistance on low memory - only use bigger
@@ -1587,10 +1601,9 @@ void __init kmem_cache_init(void)
        {
                int nid;
 
-               /* Replace the static kmem_list3 structures for the boot cpu */
-               init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);
+               for_each_online_node(nid) {
+                       init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], nid);
 
-               for_each_node_state(nid, N_NORMAL_MEMORY) {
                        init_list(malloc_sizes[INDEX_AC].cs_cachep,
                                  &initkmem_list3[SIZE_AC + nid], nid);
 
@@ -1960,22 +1973,6 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp)
        }
 }
 
-/*
- * For setting up all the kmem_list3s for cache whose buffer_size is same as
- * size of kmem_list3.
- */
-static void __init set_up_list3s(struct kmem_cache *cachep, int index)
-{
-       int node;
-
-       for_each_node_state(node, N_NORMAL_MEMORY) {
-               cachep->nodelists[node] = &initkmem_list3[index + node];
-               cachep->nodelists[node]->next_reap = jiffies +
-                   REAPTIMEOUT_LIST3 +
-                   ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
-       }
-}
-
 static void __kmem_cache_destroy(struct kmem_cache *cachep)
 {
        int i;
@@ -2099,7 +2096,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
                        g_cpucache_up = PARTIAL_L3;
                } else {
                        int node;
-                       for_each_node_state(node, N_NORMAL_MEMORY) {
+                       for_each_online_node(node) {
                                cachep->nodelists[node] =
                                    kmalloc_node(sizeof(struct kmem_list3),
                                                GFP_KERNEL, node);
@@ -2170,6 +2167,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
         * We use cache_chain_mutex to ensure a consistent view of
         * cpu_online_map as well.  Please see cpuup_callback
         */
+       get_online_cpus();
        mutex_lock(&cache_chain_mutex);
 
        list_for_each_entry(pc, &cache_chain, next) {
@@ -2396,6 +2394,7 @@ oops:
                panic("kmem_cache_create(): failed to create slab `%s'\n",
                      name);
        mutex_unlock(&cache_chain_mutex);
+       put_online_cpus();
        return cachep;
 }
 EXPORT_SYMBOL(kmem_cache_create);
@@ -2547,9 +2546,11 @@ int kmem_cache_shrink(struct kmem_cache *cachep)
        int ret;
        BUG_ON(!cachep || in_interrupt());
 
+       get_online_cpus();
        mutex_lock(&cache_chain_mutex);
        ret = __cache_shrink(cachep);
        mutex_unlock(&cache_chain_mutex);
+       put_online_cpus();
        return ret;
 }
 EXPORT_SYMBOL(kmem_cache_shrink);
@@ -2575,6 +2576,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
        BUG_ON(!cachep || in_interrupt());
 
        /* Find the cache in the chain of caches. */
+       get_online_cpus();
        mutex_lock(&cache_chain_mutex);
        /*
         * the chain is never empty, cache_cache is never destroyed
@@ -2584,6 +2586,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
                slab_error(cachep, "Can't free all objects");
                list_add(&cachep->next, &cache_chain);
                mutex_unlock(&cache_chain_mutex);
+               put_online_cpus();
                return;
        }
 
@@ -2592,6 +2595,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 
        __kmem_cache_destroy(cachep);
        mutex_unlock(&cache_chain_mutex);
+       put_online_cpus();
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
 
@@ -3815,7 +3819,7 @@ static int alloc_kmemlist(struct kmem_cache *cachep)
        struct array_cache *new_shared;
        struct array_cache **new_alien = NULL;
 
-       for_each_node_state(node, N_NORMAL_MEMORY) {
+       for_each_online_node(node) {
 
                 if (use_alien_caches) {
                         new_alien = alloc_alien_cache(node, cachep->limit);
@@ -4105,7 +4109,7 @@ out:
        schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC));
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_SLABINFO
 
 static void print_slabinfo_header(struct seq_file *m)
 {
index 3655ad359f03b7a776b93fc3bc192d683400859b..5cc4b7dddb505dc08a9a05bdfeb2cc1f91faf9c2 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3076,6 +3076,19 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        return slab_alloc(s, gfpflags, node, caller);
 }
 
+static unsigned long count_partial(struct kmem_cache_node *n)
+{
+       unsigned long flags;
+       unsigned long x = 0;
+       struct page *page;
+
+       spin_lock_irqsave(&n->list_lock, flags);
+       list_for_each_entry(page, &n->partial, lru)
+               x += page->inuse;
+       spin_unlock_irqrestore(&n->list_lock, flags);
+       return x;
+}
+
 #if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
 static int validate_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
@@ -3458,19 +3471,6 @@ static int list_locations(struct kmem_cache *s, char *buf,
        return n;
 }
 
-static unsigned long count_partial(struct kmem_cache_node *n)
-{
-       unsigned long flags;
-       unsigned long x = 0;
-       struct page *page;
-
-       spin_lock_irqsave(&n->list_lock, flags);
-       list_for_each_entry(page, &n->partial, lru)
-               x += page->inuse;
-       spin_unlock_irqrestore(&n->list_lock, flags);
-       return x;
-}
-
 enum slab_stat_type {
        SL_FULL,
        SL_PARTIAL,
@@ -3962,7 +3962,7 @@ static struct kset_uevent_ops slab_uevent_ops = {
        .filter = uevent_filter,
 };
 
-static decl_subsys(slab, &slab_ktype, &slab_uevent_ops);
+static struct kset *slab_kset;
 
 #define ID_STR_LENGTH 64
 
@@ -4015,7 +4015,7 @@ static int sysfs_slab_add(struct kmem_cache *s)
                 * This is typically the case for debug situations. In that
                 * case we can catch duplicate names easily.
                 */
-               sysfs_remove_link(&slab_subsys.kobj, s->name);
+               sysfs_remove_link(&slab_kset->kobj, s->name);
                name = s->name;
        } else {
                /*
@@ -4025,12 +4025,12 @@ static int sysfs_slab_add(struct kmem_cache *s)
                name = create_unique_id(s);
        }
 
-       kobj_set_kset_s(s, slab_subsys);
-       kobject_set_name(&s->kobj, name);
-       kobject_init(&s->kobj);
-       err = kobject_add(&s->kobj);
-       if (err)
+       s->kobj.kset = slab_kset;
+       err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, name);
+       if (err) {
+               kobject_put(&s->kobj);
                return err;
+       }
 
        err = sysfs_create_group(&s->kobj, &slab_attr_group);
        if (err)
@@ -4070,9 +4070,8 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
                /*
                 * If we have a leftover link then remove it.
                 */
-               sysfs_remove_link(&slab_subsys.kobj, name);
-               return sysfs_create_link(&slab_subsys.kobj,
-                                               &s->kobj, name);
+               sysfs_remove_link(&slab_kset->kobj, name);
+               return sysfs_create_link(&slab_kset->kobj, &s->kobj, name);
        }
 
        al = kmalloc(sizeof(struct saved_alias), GFP_KERNEL);
@@ -4091,8 +4090,8 @@ static int __init slab_sysfs_init(void)
        struct kmem_cache *s;
        int err;
 
-       err = subsystem_register(&slab_subsys);
-       if (err) {
+       slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj);
+       if (!slab_kset) {
                printk(KERN_ERR "Cannot register slab subsystem.\n");
                return -ENOSYS;
        }
@@ -4123,3 +4122,89 @@ static int __init slab_sysfs_init(void)
 
 __initcall(slab_sysfs_init);
 #endif
+
+/*
+ * The /proc/slabinfo ABI
+ */
+#ifdef CONFIG_SLABINFO
+
+ssize_t slabinfo_write(struct file *file, const char __user * buffer,
+                       size_t count, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+
+static void print_slabinfo_header(struct seq_file *m)
+{
+       seq_puts(m, "slabinfo - version: 2.1\n");
+       seq_puts(m, "# name            <active_objs> <num_objs> <objsize> "
+                "<objperslab> <pagesperslab>");
+       seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
+       seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
+       seq_putc(m, '\n');
+}
+
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t n = *pos;
+
+       down_read(&slub_lock);
+       if (!n)
+               print_slabinfo_header(m);
+
+       return seq_list_start(&slab_caches, *pos);
+}
+
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+{
+       return seq_list_next(p, &slab_caches, pos);
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+       up_read(&slub_lock);
+}
+
+static int s_show(struct seq_file *m, void *p)
+{
+       unsigned long nr_partials = 0;
+       unsigned long nr_slabs = 0;
+       unsigned long nr_inuse = 0;
+       unsigned long nr_objs;
+       struct kmem_cache *s;
+       int node;
+
+       s = list_entry(p, struct kmem_cache, list);
+
+       for_each_online_node(node) {
+               struct kmem_cache_node *n = get_node(s, node);
+
+               if (!n)
+                       continue;
+
+               nr_partials += n->nr_partial;
+               nr_slabs += atomic_long_read(&n->nr_slabs);
+               nr_inuse += count_partial(n);
+       }
+
+       nr_objs = nr_slabs * s->objects;
+       nr_inuse += (nr_slabs - nr_partials) * s->objects;
+
+       seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", s->name, nr_inuse,
+                  nr_objs, s->size, s->objects, (1 << s->order));
+       seq_printf(m, " : tunables %4u %4u %4u", 0, 0, 0);
+       seq_printf(m, " : slabdata %6lu %6lu %6lu", nr_slabs, nr_slabs,
+                  0UL);
+       seq_putc(m, '\n');
+       return 0;
+}
+
+const struct seq_operations slabinfo_op = {
+       .start = s_start,
+       .next = s_next,
+       .stop = s_stop,
+       .show = s_show,
+};
+
+#endif /* CONFIG_SLABINFO */
index a2bd0f2e3af84c85e5e0077963b2bd3616b69d93..1e115e5beab635aeb67baede5c4aa36881545efe 100644 (file)
@@ -642,7 +642,7 @@ struct net_device *alloc_trdev(int sizeof_priv)
 static int __init rif_init(void)
 {
        init_timer(&rif_timer);
-       rif_timer.expires  = sysctl_tr_rif_timeout;
+       rif_timer.expires  = jiffies + sysctl_tr_rif_timeout;
        rif_timer.data     = 0L;
        rif_timer.function = rif_check_expire;
        add_timer(&rif_timer);
index 4add9bd4bc8d51c8785c65028211578e4bbe4508..032bf44eca5e4e3cbbf39b825435f1f2cb573960 100644 (file)
@@ -323,6 +323,7 @@ static const struct header_ops vlan_header_ops = {
 static int vlan_dev_init(struct net_device *dev)
 {
        struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
+       int subclass = 0;
 
        /* IFF_BROADCAST|IFF_MULTICAST; ??? */
        dev->flags  = real_dev->flags & ~IFF_UP;
@@ -349,7 +350,11 @@ static int vlan_dev_init(struct net_device *dev)
                dev->hard_start_xmit = vlan_dev_hard_start_xmit;
        }
 
-       lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
+       if (real_dev->priv_flags & IFF_802_1Q_VLAN)
+               subclass = 1;
+
+       lockdep_set_class_and_subclass(&dev->_xmit_lock,
+                               &vlan_netdev_xmit_lock_key, subclass);
        return 0;
 }
 
index 2086396de177557a71d9e1da1a7c52bf218ae359..9c7f712fc7e9c331e4dcd3c3b1d9c0fbdae3b01b 100644 (file)
@@ -542,6 +542,13 @@ static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
        if (eth->h_proto != htons(ETH_P_IP))
                goto non_ip; /* Multi-Protocol Over ATM :-) */
 
+       /* Weed out funny packets (e.g., AF_PACKET or raw). */
+       if (skb->len < ETH_HLEN + sizeof(struct iphdr))
+               goto non_ip;
+       skb_set_network_header(skb, ETH_HLEN);
+       if (skb->len < ETH_HLEN + ip_hdr(skb)->ihl * 4 || ip_hdr(skb)->ihl < 5)
+               goto non_ip;
+
        while (i < mpc->number_of_mps_macs) {
                if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN)))
                        if ( send_via_shortcut(skb, mpc) == 0 )           /* try shortcut */
index 8378afd54b3014139eadf74f1414252a088e2966..b4725ff317c06a648ef225744651da76412b7068 100644 (file)
@@ -87,10 +87,22 @@ static void ax25_kill_by_device(struct net_device *dev)
                return;
 
        spin_lock_bh(&ax25_list_lock);
+again:
        ax25_for_each(s, node, &ax25_list) {
                if (s->ax25_dev == ax25_dev) {
                        s->ax25_dev = NULL;
+                       spin_unlock_bh(&ax25_list_lock);
                        ax25_disconnect(s, ENETUNREACH);
+                       spin_lock_bh(&ax25_list_lock);
+
+                       /* The entry could have been deleted from the
+                        * list meanwhile and thus the next pointer is
+                        * no longer valid.  Play it safe and restart
+                        * the scan.  Forward progress is ensured
+                        * because we set s->ax25_dev to NULL and we
+                        * are never passed a NULL 'dev' argument.
+                        */
+                       goto again;
                }
        }
        spin_unlock_bh(&ax25_list_lock);
@@ -1109,21 +1121,19 @@ static int __must_check ax25_connect(struct socket *sock,
         * some sanity checks. code further down depends on this
         */
 
-       if (addr_len == sizeof(struct sockaddr_ax25)) {
-               /* support for this will go away in early 2.5.x */
-               printk(KERN_WARNING "ax25_connect(): %s uses obsolete socket structure\n",
-                       current->comm);
-       }
-       else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
-               /* support for old structure may go away some time */
+       if (addr_len == sizeof(struct sockaddr_ax25))
+               /* support for this will go away in early 2.5.x
+                * ax25_connect(): uses obsolete socket structure
+                */
+               ;
+       else if (addr_len != sizeof(struct full_sockaddr_ax25))
+               /* support for old structure may go away some time
+                * ax25_connect(): uses old (6 digipeater) socket structure.
+                */
                if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
-                   (addr_len > sizeof(struct full_sockaddr_ax25))) {
+                   (addr_len > sizeof(struct full_sockaddr_ax25)))
                        return -EINVAL;
-               }
 
-               printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n",
-                       current->comm);
-       }
 
        if (fsa->fsa_ax25.sax25_family != AF_AX25)
                return -EINVAL;
@@ -1467,21 +1477,20 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
                        goto out;
                }
 
-               if (addr_len == sizeof(struct sockaddr_ax25)) {
-                       printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n",
-                               current->comm);
-               }
-               else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
-                       /* support for old structure may go away some time */
+               if (addr_len == sizeof(struct sockaddr_ax25))
+                       /* ax25_sendmsg(): uses obsolete socket structure */
+                       ;
+               else if (addr_len != sizeof(struct full_sockaddr_ax25))
+                       /* support for old structure may go away some time
+                        * ax25_sendmsg(): uses old (6 digipeater)
+                        * socket structure.
+                        */
                        if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
                            (addr_len > sizeof(struct full_sockaddr_ax25))) {
                                err = -EINVAL;
                                goto out;
                        }
 
-                       printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
-                               current->comm);
-               }
 
                if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) {
                        int ct           = 0;
index cad510309dcf88bafa2c3c056fa0ae4828e962a4..17f7fb7205535ce35f0fc9a7b96cdbf9d261c820 100644 (file)
@@ -316,9 +316,26 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
        schedule_work(&conn->work);
 }
 
+static int __match_tty(struct device *dev, void *data)
+{
+       /* The rfcomm tty device will possibly retain even when conn
+        * is down, and sysfs doesn't support move zombie device,
+        * so we should move the device before conn device is destroyed.
+        * Due to the only child device of hci_conn dev is rfcomm
+        * tty_dev, here just return 1
+        */
+       return 1;
+}
+
 static void del_conn(struct work_struct *work)
 {
+       struct device *dev;
        struct hci_conn *conn = container_of(work, struct hci_conn, work);
+
+       while (dev = device_find_child(&conn->dev, NULL, __match_tty)) {
+               device_move(dev, NULL);
+               put_device(dev);
+       }
        device_del(&conn->dev);
        put_device(&conn->dev);
 }
index e447651a2dbe86705a0ad35706b73d06928d8b94..788c70321858f39576867de05e4ec2c885d9445e 100644 (file)
@@ -95,9 +95,10 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
 
        BT_DBG("dev %p dlc %p", dev, dlc);
 
-       write_lock_bh(&rfcomm_dev_lock);
-       list_del_init(&dev->list);
-       write_unlock_bh(&rfcomm_dev_lock);
+       /* Refcount should only hit zero when called from rfcomm_dev_del()
+          which will have taken us off the list. Everything else are
+          refcounting bugs. */
+       BUG_ON(!list_empty(&dev->list));
 
        rfcomm_dlc_lock(dlc);
        /* Detach DLC if it's owned by this dev */
@@ -109,11 +110,6 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
 
        tty_unregister_device(rfcomm_tty_driver, dev->id);
 
-       /* Refcount should only hit zero when called from rfcomm_dev_del()
-          which will have taken us off the list. Everything else are
-          refcounting bugs. */
-       BUG_ON(!list_empty(&dev->list));
-
        kfree(dev);
 
        /* It's safe to call module_put() here because socket still
@@ -313,7 +309,15 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
 {
        BT_DBG("dev %p", dev);
 
-       set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
+       if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+               BUG_ON(1);
+       else
+               set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
+
+       write_lock_bh(&rfcomm_dev_lock);
+       list_del_init(&dev->list);
+       write_unlock_bh(&rfcomm_dev_lock);
+
        rfcomm_dev_put(dev);
 }
 
@@ -692,7 +696,8 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
        BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
 
        if (--dev->opened == 0) {
-               device_move(dev->tty_dev, NULL);
+               if (dev->tty_dev->parent)
+                       device_move(dev->tty_dev, NULL);
 
                /* Close DLC and dettach TTY */
                rfcomm_dlc_close(dev->dlc, 0);
index 935784f736b3d0f88cff37c76140a5c22a167dd2..298e0f463c56e0aa67d7e876fee6255255b12bc1 100644 (file)
@@ -133,7 +133,7 @@ static void del_nbp(struct net_bridge_port *p)
        struct net_bridge *br = p->br;
        struct net_device *dev = p->dev;
 
-       sysfs_remove_link(&br->ifobj, dev->name);
+       sysfs_remove_link(br->ifobj, dev->name);
 
        dev_set_promiscuity(dev, -1);
 
@@ -258,12 +258,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        p->state = BR_STATE_DISABLED;
        br_stp_port_timer_init(p);
 
-       kobject_init(&p->kobj);
-       kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
-       p->kobj.ktype = &brport_ktype;
-       p->kobj.parent = &(dev->dev.kobj);
-       p->kobj.kset = NULL;
-
        return p;
 }
 
@@ -379,7 +373,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (IS_ERR(p))
                return PTR_ERR(p);
 
-       err = kobject_add(&p->kobj);
+       err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
+                                  SYSFS_BRIDGE_PORT_ATTR);
        if (err)
                goto err0;
 
@@ -416,6 +411,7 @@ err2:
        br_fdb_delete_by_port(br, p, 1);
 err1:
        kobject_del(&p->kobj);
+       return err;
 err0:
        kobject_put(&p->kobj);
        return err;
index c1757c79dfbb3eaf7f857441f9a71966155b24a0..9f78a69d6b8b570ff20e0be70d7a68471cc45d4c 100644 (file)
@@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
        return skb->nf_bridge;
 }
 
+static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
+{
+       struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+
+       if (atomic_read(&nf_bridge->use) > 1) {
+               struct nf_bridge_info *tmp = nf_bridge_alloc(skb);
+
+               if (tmp) {
+                       memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info));
+                       atomic_set(&tmp->use, 1);
+                       nf_bridge_put(nf_bridge);
+               }
+               nf_bridge = tmp;
+       }
+       return nf_bridge;
+}
+
 static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
 {
        unsigned int len = nf_bridge_encap_header_len(skb);
@@ -247,8 +264,9 @@ static void __br_dnat_complain(void)
  * Let us first consider the case that ip_route_input() succeeds:
  *
  * If skb->dst->dev equals the logical bridge device the packet
- * came in on, we can consider this bridging. We then call
- * skb->dst->output() which will make the packet enter br_nf_local_out()
+ * came in on, we can consider this bridging. The packet is passed
+ * through the neighbour output function to build a new destination
+ * MAC address, which will make the packet enter br_nf_local_out()
  * not much later. In that function it is assured that the iptables
  * FORWARD chain is traversed for the packet.
  *
@@ -285,12 +303,17 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
        skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 
        skb->dev = bridge_parent(skb->dev);
-       if (!skb->dev)
-               kfree_skb(skb);
-       else {
+       if (skb->dev) {
+               struct dst_entry *dst = skb->dst;
+
                nf_bridge_pull_encap_header(skb);
-               skb->dst->output(skb);
+
+               if (dst->hh)
+                       return neigh_hh_output(dst->hh, skb);
+               else if (dst->neighbour)
+                       return dst->neighbour->output(skb);
        }
+       kfree_skb(skb);
        return 0;
 }
 
@@ -631,6 +654,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
        if (!skb->nf_bridge)
                return NF_ACCEPT;
 
+       /* Need exclusive nf_bridge_info since we might have multiple
+        * different physoutdevs. */
+       if (!nf_bridge_unshare(skb))
+               return NF_DROP;
+
        parent = bridge_parent(out);
        if (!parent)
                return NF_DROP;
@@ -712,6 +740,11 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb,
        if (!skb->nf_bridge)
                return NF_ACCEPT;
 
+       /* Need exclusive nf_bridge_info since we might have multiple
+        * different physoutdevs. */
+       if (!nf_bridge_unshare(skb))
+               return NF_DROP;
+
        nf_bridge = skb->nf_bridge;
        if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT))
                return NF_ACCEPT;
index f666f7b28ff584d7222a9763c95288c6d63da11d..c11b554fd109d4f1b587c8b254a5352889a29b86 100644 (file)
@@ -124,7 +124,7 @@ struct net_bridge
        struct timer_list               tcn_timer;
        struct timer_list               topology_change_timer;
        struct timer_list               gc_timer;
-       struct kobject                  ifobj;
+       struct kobject                  *ifobj;
 };
 
 extern struct notifier_block br_device_notifier;
index 3312e8f2abe47b46e2af85212b93de67adf6c3de..9cf0538d1717e4b633c6bc2e732bd64582b1ca42 100644 (file)
@@ -426,16 +426,10 @@ int br_sysfs_addbr(struct net_device *dev)
                goto out2;
        }
 
-
-       kobject_set_name(&br->ifobj, SYSFS_BRIDGE_PORT_SUBDIR);
-       br->ifobj.ktype = NULL;
-       br->ifobj.kset = NULL;
-       br->ifobj.parent = brobj;
-
-       err = kobject_register(&br->ifobj);
-       if (err) {
+       br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
+       if (!br->ifobj) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
-                       __FUNCTION__, dev->name, kobject_name(&br->ifobj));
+                       __FUNCTION__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
                goto out3;
        }
        return 0;
@@ -453,7 +447,7 @@ void br_sysfs_delbr(struct net_device *dev)
        struct kobject *kobj = &dev->dev.kobj;
        struct net_bridge *br = netdev_priv(dev);
 
-       kobject_unregister(&br->ifobj);
+       kobject_put(br->ifobj);
        sysfs_remove_bin_file(kobj, &bridge_forward);
        sysfs_remove_group(kobj, &bridge_group);
 }
index 79db51fcb4768dabb001c5afb17325c6ad00a634..02b2d50cce4da640f4b62a6652253d217e890af2 100644 (file)
@@ -229,7 +229,7 @@ int br_sysfs_addif(struct net_bridge_port *p)
                        goto out2;
        }
 
-       err= sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name);
+       err = sysfs_create_link(br->ifobj, &p->kobj, p->dev->name);
 out2:
        return err;
 }
index be9d3015beaa101318c58ce2827f5d96321de264..0879f52115eb9bada2f73bb3de2188ef9bf9a910 100644 (file)
@@ -2207,8 +2207,12 @@ static void net_rx_action(struct softirq_action *h)
                 * still "owns" the NAPI instance and therefore can
                 * move the instance around on the list at-will.
                 */
-               if (unlikely(work == weight))
-                       list_move_tail(&n->poll_list, list);
+               if (unlikely(work == weight)) {
+                       if (unlikely(napi_disable_pending(n)))
+                               __napi_complete(n);
+                       else
+                               list_move_tail(&n->poll_list, list);
+               }
 
                netpoll_poll_unlock(have);
        }
index 3ed2b4b1d6d4f1c05b557f14d1dacaedaabbd473..6489f4e24ecf118f98a457284d130973ca841130 100644 (file)
@@ -293,7 +293,7 @@ void flow_cache_flush(void)
        static DEFINE_MUTEX(flow_flush_sem);
 
        /* Don't want cpus going down or up during this. */
-       lock_cpu_hotplug();
+       get_online_cpus();
        mutex_lock(&flow_flush_sem);
        atomic_set(&info.cpuleft, num_online_cpus());
        init_completion(&info.completion);
@@ -305,7 +305,7 @@ void flow_cache_flush(void)
 
        wait_for_completion(&info.completion);
        mutex_unlock(&flow_flush_sem);
-       unlock_cpu_hotplug();
+       put_online_cpus();
 }
 
 static void __devinit flow_cache_cpu_prepare(int cpu)
index 383252b50411b89c5c18835bcbe4c9837ed16ad0..ec936ae92458fb6325b33495b09216bb5fc09831 100644 (file)
@@ -18,7 +18,7 @@ static DEFINE_MUTEX(net_mutex);
 LIST_HEAD(net_namespace_list);
 
 struct net init_net;
-EXPORT_SYMBOL_GPL(init_net);
+EXPORT_SYMBOL(init_net);
 
 /*
  * setup_net runs the initializers for the network namespace object.
index e1ba26fb4bf28052fd0150f08ed5d6eaa057fa19..fed95a323b281049f8245ba2fc1619c21decf2c9 100644 (file)
@@ -308,9 +308,12 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops)
        struct net *net;
 
        for_each_net(net) {
+restart:
                for_each_netdev_safe(net, dev, n) {
-                       if (dev->rtnl_link_ops == ops)
+                       if (dev->rtnl_link_ops == ops) {
                                ops->dellink(dev);
+                               goto restart;
+                       }
                }
        }
        list_del(&ops->list);
index 5b4ce9b4dd2060c9fd5920bfad967493b7e7eea6..b6283779e93d4432f9f9cad9f4c7a1610b3d1763 100644 (file)
@@ -416,16 +416,17 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        C(len);
        C(data_len);
        C(mac_len);
-       n->cloned = 1;
        n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
+       n->cloned = 1;
        n->nohdr = 0;
        n->destructor = NULL;
-       C(truesize);
-       atomic_set(&n->users, 1);
-       C(head);
-       C(data);
+       C(iif);
        C(tail);
        C(end);
+       C(head);
+       C(data);
+       C(truesize);
+       atomic_set(&n->users, 1);
 
        atomic_inc(&(skb_shinfo(skb)->dataref));
        skb->cloned = 1;
index 66663e5d7acdc8cb20349b62c86690fe82a1b770..0e10ff21e29204d227bf7558b8fc5d9d6ea076ac 100644 (file)
@@ -1665,12 +1665,12 @@ static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
                        break;
                rcu_read_unlock_bh();
        }
-       return rt;
+       return rcu_dereference(rt);
 }
 
 static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
 {
-       struct dn_rt_cache_iter_state *s = rcu_dereference(seq->private);
+       struct dn_rt_cache_iter_state *s = seq->private;
 
        rt = rt->u.dst.dn_next;
        while(!rt) {
@@ -1680,7 +1680,7 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou
                rcu_read_lock_bh();
                rt = dn_rt_hash_table[s->bucket].chain;
        }
-       return rt;
+       return rcu_dereference(rt);
 }
 
 static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
index 08174a2aa8789ad8b3adb49b9f1d0fc1ac6edd06..54a76b8b803ab23d530471cdd4c507ccfad5e3f0 100644 (file)
@@ -211,7 +211,7 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
                ip_tr_mc_map(addr, haddr);
                return 0;
        case ARPHRD_INFINIBAND:
-               ip_ib_mc_map(addr, haddr);
+               ip_ib_mc_map(addr, dev->broadcast, haddr);
                return 0;
        default:
                if (dir) {
index 3168c3de49193922a0b1ca641bcc3680e6a5107e..b42f74617bacfffaaf3af90856cc014ecf239dd5 100644 (file)
@@ -1027,7 +1027,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
                if (named++ == 0)
                        continue;
-               dot = strchr(ifa->ifa_label, ':');
+               dot = strchr(old, ':');
                if (dot == NULL) {
                        sprintf(old, ":%d", named);
                        dot = old;
index 527a6e0af5b60eb48b9e15459e8877db10c29db8..0dfee27cfbcd8c80364ddf2bace37e955b8b55d8 100644 (file)
@@ -444,6 +444,9 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
                        struct fib_info *fi_drop;
                        u8 state;
 
+                       if (fi->fib_treeref > 1)
+                               goto out;
+
                        write_lock_bh(&fib_hash_lock);
                        fi_drop = fa->fa_info;
                        fa->fa_info = fi;
@@ -718,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
 {
        int h, s_h;
 
+       if (fz->fz_hash == NULL)
+               return skb->len;
        s_h = cb->args[3];
-       for (h=0; h < fz->fz_divisor; h++) {
-               if (h < s_h) continue;
-               if (h > s_h)
-                       memset(&cb->args[4], 0,
-                              sizeof(cb->args) - 4*sizeof(cb->args[0]));
-               if (fz->fz_hash == NULL ||
-                   hlist_empty(&fz->fz_hash[h]))
+       for (h = s_h; h < fz->fz_divisor; h++) {
+               if (hlist_empty(&fz->fz_hash[h]))
                        continue;
-               if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) {
+               if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) {
                        cb->args[3] = h;
                        return -1;
                }
+               memset(&cb->args[4], 0,
+                      sizeof(cb->args) - 4*sizeof(cb->args[0]));
        }
        cb->args[3] = h;
        return skb->len;
@@ -746,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
        read_lock(&fib_hash_lock);
        for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
                if (m < s_m) continue;
-               if (m > s_m)
-                       memset(&cb->args[3], 0,
-                              sizeof(cb->args) - 3*sizeof(cb->args[0]));
                if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
                        cb->args[2] = m;
                        read_unlock(&fib_hash_lock);
                        return -1;
                }
+               memset(&cb->args[3], 0,
+                      sizeof(cb->args) - 3*sizeof(cb->args[0]));
        }
        read_unlock(&fib_hash_lock);
        cb->args[2] = m;
index 8d8c2915e064f98d16d1409c2524f2277107185b..1010b469d7d3440a4f9980c13bfaf280fd6a3e0e 100644 (file)
@@ -1214,6 +1214,9 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                        struct fib_info *fi_drop;
                        u8 state;
 
+                       if (fi->fib_treeref > 1)
+                               goto out;
+
                        err = -ENOBUFS;
                        new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
                        if (new_fa == NULL)
index 233de06342989ec9a4067ed7e5a7b7f45fed6797..82baea026484d6b311986f24db8855dbf184b611 100644 (file)
@@ -540,7 +540,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
        icmp_param.data.icmph.checksum   = 0;
        icmp_param.skb    = skb_in;
        icmp_param.offset = skb_network_offset(skb_in);
-       icmp_out_count(icmp_param.data.icmph.type);
        inet_sk(icmp_socket->sk)->tos = tos;
        ipc.addr = iph->saddr;
        ipc.opt = &icmp_param.replyopts;
index 9a96c277393d3d72a5d622087c3df0a263e824a5..4a4d49fca1f2518a12eebbfbae02211eace06a19 100644 (file)
@@ -310,7 +310,7 @@ static void lro_flush(struct net_lro_mgr *lro_mgr,
        skb_shinfo(lro_desc->parent)->gso_size = lro_desc->mss;
 
        if (lro_desc->vgrp) {
-               if (test_bit(LRO_F_NAPI, &lro_mgr->features))
+               if (lro_mgr->features & LRO_F_NAPI)
                        vlan_hwaccel_receive_skb(lro_desc->parent,
                                                 lro_desc->vgrp,
                                                 lro_desc->vlan_tag);
@@ -320,7 +320,7 @@ static void lro_flush(struct net_lro_mgr *lro_mgr,
                                        lro_desc->vlan_tag);
 
        } else {
-               if (test_bit(LRO_F_NAPI, &lro_mgr->features))
+               if (lro_mgr->features & LRO_F_NAPI)
                        netif_receive_skb(lro_desc->parent);
                else
                        netif_rx(lro_desc->parent);
@@ -352,7 +352,7 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
                goto out;
 
        if ((skb->protocol == htons(ETH_P_8021Q))
-           && !test_bit(LRO_F_EXTRACT_VLAN_ID, &lro_mgr->features))
+           && !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID))
                vlan_hdr_len = VLAN_HLEN;
 
        if (!lro_desc->active) { /* start new lro session */
@@ -474,7 +474,7 @@ static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr,
                        goto out;
 
                if ((skb->protocol == htons(ETH_P_8021Q))
-                   && !test_bit(LRO_F_EXTRACT_VLAN_ID, &lro_mgr->features))
+                   && !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID))
                        vlan_hdr_len = VLAN_HLEN;
 
                iph = (void *)(skb->data + vlan_hdr_len);
@@ -516,7 +516,7 @@ void lro_receive_skb(struct net_lro_mgr *lro_mgr,
                     void *priv)
 {
        if (__lro_proc_skb(lro_mgr, skb, NULL, 0, priv)) {
-               if (test_bit(LRO_F_NAPI, &lro_mgr->features))
+               if (lro_mgr->features & LRO_F_NAPI)
                        netif_receive_skb(skb);
                else
                        netif_rx(skb);
@@ -531,7 +531,7 @@ void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr,
                                  void *priv)
 {
        if (__lro_proc_skb(lro_mgr, skb, vgrp, vlan_tag, priv)) {
-               if (test_bit(LRO_F_NAPI, &lro_mgr->features))
+               if (lro_mgr->features & LRO_F_NAPI)
                        vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag);
                else
                        vlan_hwaccel_rx(skb, vgrp, vlan_tag);
@@ -550,7 +550,7 @@ void lro_receive_frags(struct net_lro_mgr *lro_mgr,
        if (!skb)
                return;
 
-       if (test_bit(LRO_F_NAPI, &lro_mgr->features))
+       if (lro_mgr->features & LRO_F_NAPI)
                netif_receive_skb(skb);
        else
                netif_rx(skb);
@@ -570,7 +570,7 @@ void lro_vlan_hwaccel_receive_frags(struct net_lro_mgr *lro_mgr,
        if (!skb)
                return;
 
-       if (test_bit(LRO_F_NAPI, &lro_mgr->features))
+       if (lro_mgr->features & LRO_F_NAPI)
                vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag);
        else
                vlan_hwaccel_rx(skb, vgrp, vlan_tag);
index fd99fbd685ea9512cc03aa57db5347d34dd1e2cb..bc9e57550e86d9b4f5b9ee965466f3d4f52f2585 100644 (file)
@@ -1016,8 +1016,6 @@ alloc_new_skb:
 
                                skb_fill_page_desc(skb, i, page, 0, 0);
                                frag = &skb_shinfo(skb)->frags[i];
-                               skb->truesize += PAGE_SIZE;
-                               atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
                        } else {
                                err = -EMSGSIZE;
                                goto error;
@@ -1030,6 +1028,8 @@ alloc_new_skb:
                        frag->size += copy;
                        skb->len += copy;
                        skb->data_len += copy;
+                       skb->truesize += copy;
+                       atomic_add(copy, &sk->sk_wmem_alloc);
                }
                offset += copy;
                length -= copy;
@@ -1172,6 +1172,8 @@ ssize_t   ip_append_page(struct sock *sk, struct page *page,
 
                skb->len += len;
                skb->data_len += len;
+               skb->truesize += len;
+               atomic_add(len, &sk->sk_wmem_alloc);
                offset += len;
                size -= len;
        }
index 56a675734ea555ba256576a33f39cccd4c60cf91..b8f7763b2261474e4e5d35961193bcdcbebf26cd 100644 (file)
@@ -1404,8 +1404,7 @@ static int __init ic_proto_name(char *name)
                return 1;
        }
        if (!strcmp(name, "off") || !strcmp(name, "none")) {
-               ic_enable = 0;
-               return 1;
+               return 0;
        }
 #ifdef CONFIG_IP_PNP_DHCP
        else if (!strcmp(name, "dhcp")) {
@@ -1442,10 +1441,22 @@ static int __init ip_auto_config_setup(char *addrs)
        ic_set_manually = 1;
        ic_enable = 1;
 
+       /*
+        * If any dhcp, bootp etc options are set, leave autoconfig on
+        * and skip the below static IP processing.
+        */
        if (ic_proto_name(addrs))
                return 1;
 
-       /* Parse the whole string */
+       /* If no static IP is given, turn off autoconfig and bail.  */
+       if (*addrs == 0 ||
+           strcmp(addrs, "off") == 0 ||
+           strcmp(addrs, "none") == 0) {
+               ic_enable = 0;
+               return 1;
+       }
+
+       /* Parse string for static IP assignment.  */
        ip = addrs;
        while (ip && *ip) {
                if ((cp = strchr(ip, ':')))
@@ -1483,7 +1494,10 @@ static int __init ip_auto_config_setup(char *addrs)
                                strlcpy(user_dev_name, ip, sizeof(user_dev_name));
                                break;
                        case 6:
-                               ic_proto_name(ip);
+                               if (ic_proto_name(ip) == 0 &&
+                                   ic_myaddr == NONE) {
+                                       ic_enable = 0;
+                               }
                                break;
                        }
                }
index 66b42f547bf9c0b21bd2462a4534e54978b2813f..e7050f8eabebb63c6d0e3f46b55e4aef65da96b4 100644 (file)
@@ -271,6 +271,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        int hh_len;
        struct iphdr *iph;
        struct sk_buff *skb;
+       unsigned int iphlen;
        int err;
 
        if (length > rt->u.dst.dev->mtu) {
@@ -304,7 +305,8 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
                goto error_fault;
 
        /* We don't modify invalid header */
-       if (length >= sizeof(*iph) && iph->ihl * 4U <= length) {
+       iphlen = iph->ihl * 4;
+       if (iphlen >= sizeof(*iph) && iphlen <= length) {
                if (!iph->saddr)
                        iph->saddr = rt->rt_src;
                iph->check   = 0;
index d2bc6148a7378452bde89de27cd7a0876a18c78d..28484f396b048e1dd49210e5caffc24e29148f2b 100644 (file)
@@ -283,12 +283,12 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq)
                        break;
                rcu_read_unlock_bh();
        }
-       return r;
+       return rcu_dereference(r);
 }
 
 static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
 {
-       struct rt_cache_iter_state *st = rcu_dereference(seq->private);
+       struct rt_cache_iter_state *st = seq->private;
 
        r = r->u.dst.rt_next;
        while (!r) {
@@ -298,7 +298,7 @@ static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
                rcu_read_lock_bh();
                r = rt_hash_table[st->bucket].chain;
        }
-       return r;
+       return rcu_dereference(r);
 }
 
 static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos)
@@ -2626,11 +2626,10 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
        int idx, s_idx;
 
        s_h = cb->args[0];
+       if (s_h < 0)
+               s_h = 0;
        s_idx = idx = cb->args[1];
-       for (h = 0; h <= rt_hash_mask; h++) {
-               if (h < s_h) continue;
-               if (h > s_h)
-                       s_idx = 0;
+       for (h = s_h; h <= rt_hash_mask; h++) {
                rcu_read_lock_bh();
                for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt;
                     rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
@@ -2647,6 +2646,7 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
                        dst_release(xchg(&skb->dst, NULL));
                }
                rcu_read_unlock_bh();
+               s_idx = 0;
        }
 
 done:
index 2ed689ac449ec67cd6e0519b1a4ddab4d156e43d..5d4245ab4183fa0d47b4557471ac2b09f4459b47 100644 (file)
@@ -123,11 +123,11 @@ ipv4_connected:
                                goto out;
                        }
                        sk->sk_bound_dev_if = usin->sin6_scope_id;
-                       if (!sk->sk_bound_dev_if &&
-                           (addr_type & IPV6_ADDR_MULTICAST))
-                               fl.oif = np->mcast_oif;
                }
 
+               if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST))
+                       sk->sk_bound_dev_if = np->mcast_oif;
+
                /* Connect to link-local address requires an interface */
                if (!sk->sk_bound_dev_if) {
                        err = -EINVAL;
index 9bb031fa1c2f538c827402e3ecc8f90774fd6a55..f1240688dc5849ca469566f9830b473ac36a0814 100644 (file)
@@ -458,8 +458,6 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
        }
        err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr));
 
-       ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
-
 out_put:
        if (likely(idev != NULL))
                in6_dev_put(idev);
index adc73adadfae47a892da6527309396e57a530590..0765d8bd380f623ad6b29291af39daa4ee77ad69 100644 (file)
@@ -193,7 +193,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
                   sk2->sk_family              == PF_INET6       &&
                   ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)     &&
                   ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
-                  sk2->sk_bound_dev_if == sk->sk_bound_dev_if) {
+                  (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) {
                        if (twsk_unique(sk, sk2, twp))
                                goto unique;
                        else
index 6338a9c1aa14e2a0f832db6d40d69df678dc09be..3bef30e4a23d870e6c8d55c253412ce1356f01ca 100644 (file)
@@ -1316,8 +1316,6 @@ alloc_new_skb:
 
                                skb_fill_page_desc(skb, i, page, 0, 0);
                                frag = &skb_shinfo(skb)->frags[i];
-                               skb->truesize += PAGE_SIZE;
-                               atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
                        } else {
                                err = -EMSGSIZE;
                                goto error;
@@ -1330,6 +1328,8 @@ alloc_new_skb:
                        frag->size += copy;
                        skb->len += copy;
                        skb->data_len += copy;
+                       skb->truesize += copy;
+                       atomic_add(copy, &sk->sk_wmem_alloc);
                }
                offset += copy;
                length -= copy;
index 777ed733b2d72b3c57a0efb8086d0074669defab..85947eae5bf7d2922f25c88a0d6283cd810395a2 100644 (file)
@@ -337,7 +337,7 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
                ipv6_arcnet_mc_map(addr, buf);
                return 0;
        case ARPHRD_INFINIBAND:
-               ipv6_ib_mc_map(addr, buf);
+               ipv6_ib_mc_map(addr, dev->broadcast, buf);
                return 0;
        default:
                if (dir) {
index 34ba150bfe5d9089e65301a47648a31747de73ba..41df9a578c7aa8f630f48a825b36d9111e90a032 100644 (file)
@@ -47,7 +47,7 @@ match(const struct sk_buff *skb,
                        memcpy(eui64 + 5, eth_hdr(skb)->h_source + 3, 3);
                        eui64[3] = 0xff;
                        eui64[4] = 0xfe;
-                       eui64[0] |= 0x02;
+                       eui64[0] ^= 0x02;
 
                        i = 0;
                        while (ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i]
index 8631ed7fe8a9a84b65b398c9557e1f45ad20e220..44937616057e77fb8d5fc61272ad7f1a30f9a8d2 100644 (file)
@@ -88,7 +88,7 @@ static char *icmp6type2name[256] = {
        [ICMPV6_PKT_TOOBIG] = "PktTooBigs",
        [ICMPV6_TIME_EXCEED] = "TimeExcds",
        [ICMPV6_PARAMPROB] = "ParmProblems",
-       [ICMPV6_ECHO_REQUEST] = "EchoRequest",
+       [ICMPV6_ECHO_REQUEST] = "Echos",
        [ICMPV6_ECHO_REPLY] = "EchoReplies",
        [ICMPV6_MGM_QUERY] = "GroupMembQueries",
        [ICMPV6_MGM_REPORT] = "GroupMembResponses",
@@ -98,7 +98,7 @@ static char *icmp6type2name[256] = {
        [NDISC_ROUTER_SOLICITATION] = "RouterSolicits",
        [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements",
        [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits",
-       [NDISC_REDIRECT] = "NeighborRedirects",
+       [NDISC_REDIRECT] = "Redirects",
 };
 
 
index 6ecb5e6fae2eb9feff63496bd0749d02237af156..20083e0d3995cf13fcb3c3853b04925c3b2612bc 100644 (file)
@@ -329,7 +329,7 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif)
 static inline int rt6_check_neigh(struct rt6_info *rt)
 {
        struct neighbour *neigh = rt->rt6i_nexthop;
-       int m = 0;
+       int m;
        if (rt->rt6i_flags & RTF_NONEXTHOP ||
            !(rt->rt6i_flags & RTF_GATEWAY))
                m = 1;
@@ -337,10 +337,15 @@ static inline int rt6_check_neigh(struct rt6_info *rt)
                read_lock_bh(&neigh->lock);
                if (neigh->nud_state & NUD_VALID)
                        m = 2;
-               else if (!(neigh->nud_state & NUD_FAILED))
+#ifdef CONFIG_IPV6_ROUTER_PREF
+               else if (neigh->nud_state & NUD_FAILED)
+                       m = 0;
+#endif
+               else
                        m = 1;
                read_unlock_bh(&neigh->lock);
-       }
+       } else
+               m = 0;
        return m;
 }
 
index 48ce59a6e0265bf6bef19fa79b2e056e85aa9bdd..07dfa7fdd2a02181c2448e74e7a371b25926cbaa 100644 (file)
@@ -802,12 +802,18 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        }
 #endif /* CONFIG_IRDA_ULTRA */
 
+       self->ias_obj = irias_new_object(addr->sir_name, jiffies);
+       if (self->ias_obj == NULL)
+               return -ENOMEM;
+
        err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);
-       if (err < 0)
+       if (err < 0) {
+               kfree(self->ias_obj->name);
+               kfree(self->ias_obj);
                return err;
+       }
 
        /*  Register with LM-IAS */
-       self->ias_obj = irias_new_object(addr->sir_name, jiffies);
        irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel",
                                 self->stsap_sel, IAS_KERNEL_ATTR);
        irias_insert_object(self->ias_obj);
@@ -1118,8 +1124,6 @@ static int irda_create(struct net *net, struct socket *sock, int protocol)
                        self->max_sdu_size_rx = TTP_SAR_UNBOUND;
                        break;
                default:
-                       IRDA_ERROR("%s: protocol not supported!\n",
-                                  __FUNCTION__);
                        return -ESOCKTNOSUPPORT;
                }
                break;
@@ -1827,7 +1831,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
        struct irda_ias_set    *ias_opt;
        struct ias_object      *ias_obj;
        struct ias_attrib *     ias_attr;       /* Attribute in IAS object */
-       int opt;
+       int opt, free_ias = 0;
 
        IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
@@ -1883,11 +1887,20 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
                        /* Create a new object */
                        ias_obj = irias_new_object(ias_opt->irda_class_name,
                                                   jiffies);
+                       if (ias_obj == NULL) {
+                               kfree(ias_opt);
+                               return -ENOMEM;
+                       }
+                       free_ias = 1;
                }
 
                /* Do we have the attribute already ? */
                if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
                        kfree(ias_opt);
+                       if (free_ias) {
+                               kfree(ias_obj->name);
+                               kfree(ias_obj);
+                       }
                        return -EINVAL;
                }
 
@@ -1906,6 +1919,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
                        if(ias_opt->attribute.irda_attrib_octet_seq.len >
                           IAS_MAX_OCTET_STRING) {
                                kfree(ias_opt);
+                               if (free_ias) {
+                                       kfree(ias_obj->name);
+                                       kfree(ias_obj);
+                               }
+
                                return -EINVAL;
                        }
                        /* Add an octet sequence attribute */
@@ -1934,6 +1952,10 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
                        break;
                default :
                        kfree(ias_opt);
+                       if (free_ias) {
+                               kfree(ias_obj->name);
+                               kfree(ias_obj);
+                       }
                        return -EINVAL;
                }
                irias_insert_object(ias_obj);
index 26d5e63c4cc5d946c61e5bdf6702dacb8d32640a..76dcd882f87b97e3c5195fe96e9e0a9eb5178c78 100644 (file)
@@ -3593,27 +3593,29 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
                /* old ipsecrequest */
                int mode = pfkey_mode_from_xfrm(mp->mode);
                if (mode < 0)
-                       return -EINVAL;
+                       goto err;
                if (set_ipsecrequest(skb, mp->proto, mode,
                                     (mp->reqid ?  IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
                                     mp->reqid, mp->old_family,
-                                    &mp->old_saddr, &mp->old_daddr) < 0) {
-                       return -EINVAL;
-               }
+                                    &mp->old_saddr, &mp->old_daddr) < 0)
+                       goto err;
 
                /* new ipsecrequest */
                if (set_ipsecrequest(skb, mp->proto, mode,
                                     (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
                                     mp->reqid, mp->new_family,
-                                    &mp->new_saddr, &mp->new_daddr) < 0) {
-                       return -EINVAL;
-               }
+                                    &mp->new_saddr, &mp->new_daddr) < 0)
+                       goto err;
        }
 
        /* broadcast migrate message to sockets */
        pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
 
        return 0;
+
+err:
+       kfree_skb(skb);
+       return -EINVAL;
 }
 #else
 static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
index 7027eed4d4ae3a374fff7439110e80d44069a8fb..308bbe4a13333b103bd4d31f676da35fadcb4e48 100644 (file)
@@ -591,7 +591,7 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
        sdata->bss->force_unicast_rateidx = -1;
        if (rate->value < 0)
                return 0;
-       for (i=0; i< mode->num_rates; i++) {
+       for (i=0; i < mode->num_rates; i++) {
                struct ieee80211_rate *rates = &mode->rates[i];
                int this_rate = rates->rate;
 
@@ -599,10 +599,10 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
                        sdata->bss->max_ratectrl_rateidx = i;
                        if (rate->fixed)
                                sdata->bss->force_unicast_rateidx = i;
-                       break;
+                       return 0;
                }
        }
-       return 0;
+       return -EINVAL;
 }
 
 static int ieee80211_ioctl_giwrate(struct net_device *dev,
index a7263fc476bdd4a0936f983b3acf298a36faafa1..00f908d9275e3e69a92daf1cc4d6741015d051d5 100644 (file)
@@ -1443,7 +1443,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
        u8 *bssid;
-       int hdrlen;
 
        /*
         * key references and virtual interfaces are protected using RCU
@@ -1473,18 +1472,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
        rx.fc = le16_to_cpu(hdr->frame_control);
        type = rx.fc & IEEE80211_FCTL_FTYPE;
 
-       /*
-        * Drivers are required to align the payload data to a four-byte
-        * boundary, so the last two bits of the address where it starts
-        * may not be set. The header is required to be directly before
-        * the payload data, padding like atheros hardware adds which is
-        * inbetween the 802.11 header and the payload is not supported,
-        * the driver is required to move the 802.11 header further back
-        * in that case.
-        */
-       hdrlen = ieee80211_get_hdrlen(rx.fc);
-       WARN_ON_ONCE(((unsigned long)(skb->data + hdrlen)) & 3);
-
        if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
                local->dot11ReceivedFragmentCount++;
 
index 0a1f4c6bcdef415afae94b369cefb4ab133492bd..d842c4a6d63f6b97843db892dea44b36c7ac986b 100644 (file)
@@ -56,8 +56,8 @@ match(const struct sk_buff *skb,
        if (info->name[0] == '\0')
                ret = !ret;
        else
-               ret ^= !strncmp(master_help->helper->name, info->name,
-                               strlen(master_help->helper->name));
+               ret ^= !strncmp(helper->name, info->name,
+                               strlen(helper->name));
        return ret;
 }
 
index 4469a7be006c270c4be87700cdf7364aa0a5d765..d06d338812e975081ff20f771ea2c9069abede4c 100644 (file)
@@ -392,11 +392,14 @@ int rfkill_register(struct rfkill *rfkill)
        rfkill_led_trigger_register(rfkill);
 
        error = rfkill_add_switch(rfkill);
-       if (error)
+       if (error) {
+               rfkill_led_trigger_unregister(rfkill);
                return error;
+       }
 
        error = device_add(dev);
        if (error) {
+               rfkill_led_trigger_unregister(rfkill);
                rfkill_remove_switch(rfkill);
                return error;
        }
index ed7c9e30ebc963df397db4045a4e3ce5e5e03198..3cc629d3c9ff80593c24d128dfcdc729111b89dc 100644 (file)
@@ -210,6 +210,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
        chunksize += sizeof(ecap_param);
 
+       if (sctp_prsctp_enable)
+               chunksize += sizeof(prsctp_param);
+
        /* ADDIP: Section 4.2.7:
         *  An implementation supporting this extension [ADDIP] MUST list
         *  the ASCONF,the ASCONF-ACK, and the AUTH  chunks in its INIT and
@@ -369,6 +372,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (asoc->peer.ecn_capable)
                chunksize += sizeof(ecap_param);
 
+       if (sctp_prsctp_enable)
+               chunksize += sizeof(prsctp_param);
+
        if (sctp_addip_enable) {
                extensions[num_ext] = SCTP_CID_ASCONF;
                extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
index 5fb84778846d9b2e353a2346e1e6c4f458eaea0e..d247ed4ee42369c69aa8c8a3f26c83a370e906fc 100644 (file)
@@ -1309,26 +1309,6 @@ static void sctp_tietags_populate(struct sctp_association *new_asoc,
        new_asoc->c.initial_tsn         = asoc->c.initial_tsn;
 }
 
-static void sctp_auth_params_populate(struct sctp_association *new_asoc,
-                                   const struct sctp_association *asoc)
-{
-       /* Only perform this if AUTH extension is enabled */
-       if (!sctp_auth_enable)
-               return;
-
-       /* We need to provide the same parameter information as
-        * was in the original INIT.  This means that we need to copy
-        * the HMACS, CHUNKS, and RANDOM parameter from the original
-        * assocaition.
-        */
-       memcpy(new_asoc->c.auth_random, asoc->c.auth_random,
-               sizeof(asoc->c.auth_random));
-       memcpy(new_asoc->c.auth_hmacs, asoc->c.auth_hmacs,
-               sizeof(asoc->c.auth_hmacs));
-       memcpy(new_asoc->c.auth_chunks, asoc->c.auth_chunks,
-               sizeof(asoc->c.auth_chunks));
-}
-
 /*
  * Compare vtag/tietag values to determine unexpected COOKIE-ECHO
  * handling action.
@@ -1486,8 +1466,6 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
 
        sctp_tietags_populate(new_asoc, asoc);
 
-       sctp_auth_params_populate(new_asoc, asoc);
-
        /* B) "Z" shall respond immediately with an INIT ACK chunk.  */
 
        /* If there are errors need to be reported for unknown parameters,
index 2c17c7efad461b33f016c83401c4570068843e84..307314356e1662317c25be57050f79f366a9395e 100644 (file)
@@ -830,7 +830,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey(
        ak = (struct sctp_authkey_event *)
                skb_put(skb, sizeof(struct sctp_authkey_event));
 
-       ak->auth_type = SCTP_AUTHENTICATION_EVENT;
+       ak->auth_type = SCTP_AUTHENTICATION_INDICATION;
        ak->auth_flags = 0;
        ak->auth_length = sizeof(struct sctp_authkey_event);
 
index a6e57d1c2eb6210c86b174ac3b5eb2a132f23cbe..1f2d85e869c0a2760de7641f7d3c125d80d54adb 100644 (file)
@@ -625,7 +625,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
        err = -EINVAL;
        gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
        if (!gss_auth->mech) {
-               printk(KERN_WARNING "%s: Pseudoflavor %d not found!",
+               printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
                                __FUNCTION__, flavor);
                goto err_free;
        }
index 8738ec7ce69336dd1960d9e3c8c9a0e1fa68a0e4..34478035e05edd64131525b438eab2bedc55791c 100644 (file)
@@ -118,13 +118,14 @@ int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) {
                goto out;
 
        if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
-               goto out;
+               goto output;
 
        }
        x25_transmit_link(skbn, nb);
 
-       x25_neigh_put(nb);
        rc = 1;
+output:
+       x25_neigh_put(nb);
 out:
        return rc;
 }
index ee1e697539321d20de26511cf4927d4a7411eae6..f26aaaca1fae78dd92efe9d4e456e2dc1e60d822 100644 (file)
@@ -1749,6 +1749,7 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
 }
 EXPORT_SYMBOL(km_policy_expired);
 
+#ifdef CONFIG_XFRM_MIGRATE
 int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
               struct xfrm_migrate *m, int num_migrate)
 {
@@ -1768,6 +1769,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
        return err;
 }
 EXPORT_SYMBOL(km_migrate);
+#endif
 
 int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
 {
index e75dbdcb08a49674b846f2ce14b02598b2ba6b3e..c4f6419b176943bd54752c644f0b4cc937587327 100644 (file)
 #include <linux/in6.h>
 #endif
 
-static inline int alg_len(struct xfrm_algo *alg)
-{
-       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
-}
-
 static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
 {
        struct nlattr *rt = attrs[type];
@@ -45,7 +40,7 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
                return 0;
 
        algp = nla_data(rt);
-       if (nla_len(rt) < alg_len(algp))
+       if (nla_len(rt) < xfrm_alg_len(algp))
                return -EINVAL;
 
        switch (type) {
@@ -204,7 +199,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
                return -ENOSYS;
        *props = algo->desc.sadb_alg_id;
 
-       p = kmemdup(ualg, alg_len(ualg), GFP_KERNEL);
+       p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
 
@@ -516,9 +511,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
                NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
 
        if (x->aalg)
-               NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg);
+               NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
        if (x->ealg)
-               NLA_PUT(skb, XFRMA_ALG_CRYPT, alg_len(x->ealg), x->ealg);
+               NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
        if (x->calg)
                NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
 
@@ -1978,9 +1973,9 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
 {
        size_t l = 0;
        if (x->aalg)
-               l += nla_total_size(alg_len(x->aalg));
+               l += nla_total_size(xfrm_alg_len(x->aalg));
        if (x->ealg)
-               l += nla_total_size(alg_len(x->ealg));
+               l += nla_total_size(xfrm_alg_len(x->ealg));
        if (x->calg)
                l += nla_total_size(sizeof(*x->calg));
        if (x->encap)
index 57bb2236952ccc45aed86754855b7c1aff4eca81..74d97cc247872216fc179bf5fdce5b0b9c2cd671 100644 (file)
@@ -13,4 +13,14 @@ config SAMPLE_MARKERS
        help
          This build markers example modules.
 
+config SAMPLE_KOBJECT
+       tristate "Build kobject examples"
+       help
+         This config option will allow you to build a number of
+         different kobject sample modules showing how to use kobjects,
+         ksets, and ktypes properly.
+
+         If in doubt, say "N" here.
+
 endif # SAMPLES
+
index 5a4f0b6bcbedf955a83c39ae46dbca0e42bfb472..8652d0f268ad0fb25e24c65375828ec932df2e96 100644 (file)
@@ -1,3 +1,3 @@
 # Makefile for Linux samples code
 
-obj-$(CONFIG_SAMPLES)  += markers/
+obj-$(CONFIG_SAMPLES)  += markers/ kobject/
diff --git a/samples/kobject/Makefile b/samples/kobject/Makefile
new file mode 100644 (file)
index 0000000..4a19420
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SAMPLE_KOBJECT) += kobject-example.o kset-example.o
diff --git a/samples/kobject/kobject-example.c b/samples/kobject/kobject-example.c
new file mode 100644 (file)
index 0000000..08d0d3f
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Sample kobject implementation
+ *
+ * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2007 Novell Inc.
+ *
+ * Released under the GPL version 2 only.
+ *
+ */
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+/*
+ * This module shows how to create a simple subdirectory in sysfs called
+ * /sys/kernel/kobject-example  In that directory, 3 files are created:
+ * "foo", "baz", and "bar".  If an integer is written to these files, it can be
+ * later read out of it.
+ */
+
+static int foo;
+static int baz;
+static int bar;
+
+/*
+ * The "foo" file where a static variable is read from and written to.
+ */
+static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
+                       char *buf)
+{
+       return sprintf(buf, "%d\n", foo);
+}
+
+static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
+                        const char *buf, size_t count)
+{
+       sscanf(buf, "%du", &foo);
+       return count;
+}
+
+static struct kobj_attribute foo_attribute =
+       __ATTR(foo, 0666, foo_show, foo_store);
+
+/*
+ * More complex function where we determine which varible is being accessed by
+ * looking at the attribute for the "baz" and "bar" files.
+ */
+static ssize_t b_show(struct kobject *kobj, struct kobj_attribute *attr,
+                     char *buf)
+{
+       int var;
+
+       if (strcmp(attr->attr.name, "baz") == 0)
+               var = baz;
+       else
+               var = bar;
+       return sprintf(buf, "%d\n", var);
+}
+
+static ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr,
+                      const char *buf, size_t count)
+{
+       int var;
+
+       sscanf(buf, "%du", &var);
+       if (strcmp(attr->attr.name, "baz") == 0)
+               baz = var;
+       else
+               bar = var;
+       return count;
+}
+
+static struct kobj_attribute baz_attribute =
+       __ATTR(baz, 0666, b_show, b_store);
+static struct kobj_attribute bar_attribute =
+       __ATTR(bar, 0666, b_show, b_store);
+
+
+/*
+ * Create a group of attributes so that we can create and destory them all
+ * at once.
+ */
+static struct attribute *attrs[] = {
+       &foo_attribute.attr,
+       &baz_attribute.attr,
+       &bar_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+/*
+ * An unnamed attribute group will put all of the attributes directly in
+ * the kobject directory.  If we specify a name, a subdirectory will be
+ * created for the attributes with the directory being the name of the
+ * attribute group.
+ */
+static struct attribute_group attr_group = {
+       .attrs = attrs,
+};
+
+static struct kobject *example_kobj;
+
+static int example_init(void)
+{
+       int retval;
+
+       /*
+        * Create a simple kobject with the name of "kobject_example",
+        * located under /sys/kernel/
+        *
+        * As this is a simple directory, no uevent will be sent to
+        * userspace.  That is why this function should not be used for
+        * any type of dynamic kobjects, where the name and number are
+        * not known ahead of time.
+        */
+       example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);
+       if (!example_kobj)
+               return -ENOMEM;
+
+       /* Create the files associated with this kobject */
+       retval = sysfs_create_group(example_kobj, &attr_group);
+       if (retval)
+               kobject_put(example_kobj);
+
+       return retval;
+}
+
+static void example_exit(void)
+{
+       kobject_put(example_kobj);
+}
+
+module_init(example_init);
+module_exit(example_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
diff --git a/samples/kobject/kset-example.c b/samples/kobject/kset-example.c
new file mode 100644 (file)
index 0000000..b0a1b4f
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Sample kset and ktype implementation
+ *
+ * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2007 Novell Inc.
+ *
+ * Released under the GPL version 2 only.
+ *
+ */
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+/*
+ * This module shows how to create a kset in sysfs called
+ * /sys/kernel/kset-example
+ * Then tree kobjects are created and assigned to this kset, "foo", "baz",
+ * and "bar".  In those kobjects, attributes of the same name are also
+ * created and if an integer is written to these files, it can be later
+ * read out of it.
+ */
+
+
+/*
+ * This is our "object" that we will create a few of and register them with
+ * sysfs.
+ */
+struct foo_obj {
+       struct kobject kobj;
+       int foo;
+       int baz;
+       int bar;
+};
+#define to_foo_obj(x) container_of(x, struct foo_obj, kobj)
+
+/* a custom attribute that works just for a struct foo_obj. */
+struct foo_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf);
+       ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count);
+};
+#define to_foo_attr(x) container_of(x, struct foo_attribute, attr)
+
+/*
+ * The default show function that must be passed to sysfs.  This will be
+ * called by sysfs for whenever a show function is called by the user on a
+ * sysfs file associated with the kobjects we have registered.  We need to
+ * transpose back from a "default" kobject to our custom struct foo_obj and
+ * then call the show function for that specific object.
+ */
+static ssize_t foo_attr_show(struct kobject *kobj,
+                            struct attribute *attr,
+                            char *buf)
+{
+       struct foo_attribute *attribute;
+       struct foo_obj *foo;
+
+       attribute = to_foo_attr(attr);
+       foo = to_foo_obj(kobj);
+
+       if (!attribute->show)
+               return -EIO;
+
+       return attribute->show(foo, attribute, buf);
+}
+
+/*
+ * Just like the default show function above, but this one is for when the
+ * sysfs "store" is requested (when a value is written to a file.)
+ */
+static ssize_t foo_attr_store(struct kobject *kobj,
+                             struct attribute *attr,
+                             const char *buf, size_t len)
+{
+       struct foo_attribute *attribute;
+       struct foo_obj *foo;
+
+       attribute = to_foo_attr(attr);
+       foo = to_foo_obj(kobj);
+
+       if (!attribute->store)
+               return -EIO;
+
+       return attribute->store(foo, attribute, buf, len);
+}
+
+/* Our custom sysfs_ops that we will associate with our ktype later on */
+static struct sysfs_ops foo_sysfs_ops = {
+       .show = foo_attr_show,
+       .store = foo_attr_store,
+};
+
+/*
+ * The release function for our object.  This is REQUIRED by the kernel to
+ * have.  We free the memory held in our object here.
+ *
+ * NEVER try to get away with just a "blank" release function to try to be
+ * smarter than the kernel.  Turns out, no one ever is...
+ */
+static void foo_release(struct kobject *kobj)
+{
+       struct foo_obj *foo;
+
+       foo = to_foo_obj(kobj);
+       kfree(foo);
+}
+
+/*
+ * The "foo" file where the .foo variable is read from and written to.
+ */
+static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr,
+                       char *buf)
+{
+       return sprintf(buf, "%d\n", foo_obj->foo);
+}
+
+static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr,
+                        const char *buf, size_t count)
+{
+       sscanf(buf, "%du", &foo_obj->foo);
+       return count;
+}
+
+static struct foo_attribute foo_attribute =
+       __ATTR(foo, 0666, foo_show, foo_store);
+
+/*
+ * More complex function where we determine which varible is being accessed by
+ * looking at the attribute for the "baz" and "bar" files.
+ */
+static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr,
+                     char *buf)
+{
+       int var;
+
+       if (strcmp(attr->attr.name, "baz") == 0)
+               var = foo_obj->baz;
+       else
+               var = foo_obj->bar;
+       return sprintf(buf, "%d\n", var);
+}
+
+static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr,
+                      const char *buf, size_t count)
+{
+       int var;
+
+       sscanf(buf, "%du", &var);
+       if (strcmp(attr->attr.name, "baz") == 0)
+               foo_obj->baz = var;
+       else
+               foo_obj->bar = var;
+       return count;
+}
+
+static struct foo_attribute baz_attribute =
+       __ATTR(baz, 0666, b_show, b_store);
+static struct foo_attribute bar_attribute =
+       __ATTR(bar, 0666, b_show, b_store);
+
+/*
+ * Create a group of attributes so that we can create and destory them all
+ * at once.
+ */
+static struct attribute *foo_default_attrs[] = {
+       &foo_attribute.attr,
+       &baz_attribute.attr,
+       &bar_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+/*
+ * Our own ktype for our kobjects.  Here we specify our sysfs ops, the
+ * release function, and the set of default attributes we want created
+ * whenever a kobject of this type is registered with the kernel.
+ */
+static struct kobj_type foo_ktype = {
+       .sysfs_ops = &foo_sysfs_ops,
+       .release = foo_release,
+       .default_attrs = foo_default_attrs,
+};
+
+static struct kset *example_kset;
+static struct foo_obj *foo_obj;
+static struct foo_obj *bar_obj;
+static struct foo_obj *baz_obj;
+
+static struct foo_obj *create_foo_obj(const char *name)
+{
+       struct foo_obj *foo;
+       int retval;
+
+       /* allocate the memory for the whole object */
+       foo = kzalloc(sizeof(*foo), GFP_KERNEL);
+       if (!foo)
+               return NULL;
+
+       /*
+        * As we have a kset for this kobject, we need to set it before calling
+        * the kobject core.
+        */
+       foo->kobj.kset = example_kset;
+
+       /*
+        * Initialize and add the kobject to the kernel.  All the default files
+        * will be created here.  As we have already specified a kset for this
+        * kobject, we don't have to set a parent for the kobject, the kobject
+        * will be placed beneath that kset automatically.
+        */
+       retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name);
+       if (retval) {
+               kfree(foo);
+               return NULL;
+       }
+
+       /*
+        * We are always responsible for sending the uevent that the kobject
+        * was added to the system.
+        */
+       kobject_uevent(&foo->kobj, KOBJ_ADD);
+
+       return foo;
+}
+
+static void destroy_foo_obj(struct foo_obj *foo)
+{
+       kobject_put(&foo->kobj);
+}
+
+static int example_init(void)
+{
+       /*
+        * Create a kset with the name of "kset_example",
+        * located under /sys/kernel/
+        */
+       example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj);
+       if (!example_kset)
+               return -ENOMEM;
+
+       /*
+        * Create three objects and register them with our kset
+        */
+       foo_obj = create_foo_obj("foo");
+       if (!foo_obj)
+               goto foo_error;
+
+       bar_obj = create_foo_obj("bar");
+       if (!bar_obj)
+               goto bar_error;
+
+       baz_obj = create_foo_obj("baz");
+       if (!baz_obj)
+               goto baz_error;
+
+       return 0;
+
+baz_error:
+       destroy_foo_obj(bar_obj);
+bar_error:
+       destroy_foo_obj(foo_obj);
+foo_error:
+       return -EINVAL;
+}
+
+static void example_exit(void)
+{
+       destroy_foo_obj(baz_obj);
+       destroy_foo_obj(bar_obj);
+       destroy_foo_obj(foo_obj);
+       kset_unregister(example_kset);
+}
+
+module_init(example_init);
+module_exit(example_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
index 5bc1895f3f9ce0997afbf59448ad0053cb4aa56b..ea61bc73f6d3c4d1ecfe9d81964342b8cd306d74 100644 (file)
@@ -59,6 +59,12 @@ int cap_netlink_recv(struct sk_buff *skb, int cap)
 
 EXPORT_SYMBOL(cap_netlink_recv);
 
+/*
+ * NOTE WELL: cap_capable() cannot be used like the kernel's capable()
+ * function.  That is, it has the reverse semantics: cap_capable()
+ * returns 0 when a task has a capability, but the kernel's capable()
+ * returns 1 for this case.
+ */
 int cap_capable (struct task_struct *tsk, int cap)
 {
        /* Derived from include/linux/sched.h:capable. */
@@ -107,10 +113,11 @@ static inline int cap_block_setpcap(struct task_struct *target)
 static inline int cap_inh_is_capped(void)
 {
        /*
-        * return 1 if changes to the inheritable set are limited
-        * to the old permitted set.
+        * Return 1 if changes to the inheritable set are limited
+        * to the old permitted set. That is, if the current task
+        * does *not* possess the CAP_SETPCAP capability.
         */
-       return !cap_capable(current, CAP_SETPCAP);
+       return (cap_capable(current, CAP_SETPCAP) != 0);
 }
 
 #else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
index 3ccfbbe973b6d3014ea9b8cf77015b206688bf6f..48d4b0a52737b2e28a8fb2e32d589af2db2463f9 100644 (file)
@@ -225,22 +225,40 @@ static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,
 }
 
 
-static void dummy_sb_post_mountroot (void)
+static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
 {
        return;
 }
 
-static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
+static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+{
+       return 0;
+}
+
+static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
 {
        return;
 }
 
-static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+static int dummy_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options,
+                                int **flags, int *num_opts)
 {
+       *mount_options = NULL;
+       *flags = NULL;
+       *num_opts = 0;
        return 0;
 }
 
-static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+static int dummy_sb_set_mnt_opts(struct super_block *sb, char **mount_options,
+                                int *flags, int num_opts)
+{
+       if (unlikely(num_opts))
+               return -EOPNOTSUPP;
+       return 0;
+}
+
+static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb,
+                                   struct super_block *newsb)
 {
        return;
 }
@@ -928,6 +946,11 @@ static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
        return -EOPNOTSUPP;
 }
 
+static int dummy_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+       return -EOPNOTSUPP;
+}
+
 static void dummy_release_secctx(char *secdata, u32 seclen)
 {
 }
@@ -994,10 +1017,12 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, sb_umount_close);
        set_to_dummy_if_null(ops, sb_umount_busy);
        set_to_dummy_if_null(ops, sb_post_remount);
-       set_to_dummy_if_null(ops, sb_post_mountroot);
        set_to_dummy_if_null(ops, sb_post_addmount);
        set_to_dummy_if_null(ops, sb_pivotroot);
        set_to_dummy_if_null(ops, sb_post_pivotroot);
+       set_to_dummy_if_null(ops, sb_get_mnt_opts);
+       set_to_dummy_if_null(ops, sb_set_mnt_opts);
+       set_to_dummy_if_null(ops, sb_clone_mnt_opts);
        set_to_dummy_if_null(ops, inode_alloc_security);
        set_to_dummy_if_null(ops, inode_free_security);
        set_to_dummy_if_null(ops, inode_init_security);
@@ -1086,6 +1111,7 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, getprocattr);
        set_to_dummy_if_null(ops, setprocattr);
        set_to_dummy_if_null(ops, secid_to_secctx);
+       set_to_dummy_if_null(ops, secctx_to_secid);
        set_to_dummy_if_null(ops, release_secctx);
 #ifdef CONFIG_SECURITY_NETWORK
        set_to_dummy_if_null(ops, unix_stream_connect);
index b28a8acae34d7082dcb52519f1ebb927a2e1c9ae..acc6cf0d79001fa06d53c5b592fb4c90f5ea88a2 100644 (file)
@@ -315,20 +315,19 @@ void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
-static decl_subsys(security, NULL, NULL);
+static struct kobject *security_kobj;
 
 static int __init securityfs_init(void)
 {
        int retval;
 
-       kobj_set_kset_s(&security_subsys, kernel_subsys);
-       retval = subsystem_register(&security_subsys);
-       if (retval)
-               return retval;
+       security_kobj = kobject_create_and_add("security", kernel_kobj);
+       if (!security_kobj)
+               return -EINVAL;
 
        retval = register_filesystem(&fs_type);
        if (retval)
-               subsystem_unregister(&security_subsys);
+               kobject_put(security_kobj);
        return retval;
 }
 
index 3e0d0a6e224f5e36204c05526175d9382f6af6c6..694126003ed3bcfaacc980e3210540de38cda107 100644 (file)
@@ -26,7 +26,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
 static void proc_keys_stop(struct seq_file *p, void *v);
 static int proc_keys_show(struct seq_file *m, void *v);
 
-static struct seq_operations proc_keys_ops = {
+static const struct seq_operations proc_keys_ops = {
        .start  = proc_keys_start,
        .next   = proc_keys_next,
        .stop   = proc_keys_stop,
@@ -47,7 +47,7 @@ static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos);
 static void proc_key_users_stop(struct seq_file *p, void *v);
 static int proc_key_users_show(struct seq_file *m, void *v);
 
-static struct seq_operations proc_key_users_ops = {
+static const struct seq_operations proc_key_users_ops = {
        .start  = proc_key_users_start,
        .next   = proc_key_users_next,
        .stop   = proc_key_users_stop,
index 0e1f1f124368b03aa31df48552030ed17bf7946e..ca475ca206e4b3afe51ad7bdee1c30fe8398c892 100644 (file)
@@ -288,11 +288,6 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d
        security_ops->sb_post_remount(mnt, flags, data);
 }
 
-void security_sb_post_mountroot(void)
-{
-       security_ops->sb_post_mountroot();
-}
-
 void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd)
 {
        security_ops->sb_post_addmount(mnt, mountpoint_nd);
@@ -308,6 +303,26 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_
        security_ops->sb_post_pivotroot(old_nd, new_nd);
 }
 
+int security_sb_get_mnt_opts(const struct super_block *sb,
+                             char ***mount_options,
+                             int **flags, int *num_opts)
+{
+       return security_ops->sb_get_mnt_opts(sb, mount_options, flags, num_opts);
+}
+
+int security_sb_set_mnt_opts(struct super_block *sb,
+                             char **mount_options,
+                             int *flags, int num_opts)
+{
+       return security_ops->sb_set_mnt_opts(sb, mount_options, flags, num_opts);
+}
+
+void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+                               struct super_block *newsb)
+{
+       security_ops->sb_clone_mnt_opts(oldsb, newsb);
+}
+
 int security_inode_alloc(struct inode *inode)
 {
        inode->i_security = NULL;
@@ -816,6 +831,12 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 }
 EXPORT_SYMBOL(security_secid_to_secctx);
 
+int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+       return security_ops->secctx_to_secid(secdata, seclen, secid);
+}
+EXPORT_SYMBOL(security_secctx_to_secid);
+
 void security_release_secctx(char *secdata, u32 seclen)
 {
        return security_ops->release_secctx(secdata, seclen);
index 9f3124b08867536aca7cc580046d844e341ac6d5..0396354fff9521b7146ff1aff96e3f9c384a6857 100644 (file)
@@ -82,6 +82,8 @@
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 
+#define NUM_SEL_MNT_OPTS 4
+
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
 extern int selinux_compat_net;
@@ -321,8 +323,8 @@ enum {
        Opt_error = -1,
        Opt_context = 1,
        Opt_fscontext = 2,
-       Opt_defcontext = 4,
-       Opt_rootcontext = 8,
+       Opt_defcontext = 3,
+       Opt_rootcontext = 4,
 };
 
 static match_table_t tokens = {
@@ -366,150 +368,317 @@ static int may_context_mount_inode_relabel(u32 sid,
        return rc;
 }
 
-static int try_context_mount(struct super_block *sb, void *data)
+static int sb_finish_set_opts(struct super_block *sb)
 {
-       char *context = NULL, *defcontext = NULL;
-       char *fscontext = NULL, *rootcontext = NULL;
-       const char *name;
-       u32 sid;
-       int alloc = 0, rc = 0, seen = 0;
-       struct task_security_struct *tsec = current->security;
        struct superblock_security_struct *sbsec = sb->s_security;
+       struct dentry *root = sb->s_root;
+       struct inode *root_inode = root->d_inode;
+       int rc = 0;
 
-       if (!data)
-               goto out;
+       if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
+               /* Make sure that the xattr handler exists and that no
+                  error other than -ENODATA is returned by getxattr on
+                  the root directory.  -ENODATA is ok, as this may be
+                  the first boot of the SELinux kernel before we have
+                  assigned xattr values to the filesystem. */
+               if (!root_inode->i_op->getxattr) {
+                       printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
+                              "xattr support\n", sb->s_id, sb->s_type->name);
+                       rc = -EOPNOTSUPP;
+                       goto out;
+               }
+               rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
+               if (rc < 0 && rc != -ENODATA) {
+                       if (rc == -EOPNOTSUPP)
+                               printk(KERN_WARNING "SELinux: (dev %s, type "
+                                      "%s) has no security xattr handler\n",
+                                      sb->s_id, sb->s_type->name);
+                       else
+                               printk(KERN_WARNING "SELinux: (dev %s, type "
+                                      "%s) getxattr errno %d\n", sb->s_id,
+                                      sb->s_type->name, -rc);
+                       goto out;
+               }
+       }
 
-       name = sb->s_type->name;
+       sbsec->initialized = 1;
 
-       if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
+       if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
+               printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
+                      sb->s_id, sb->s_type->name);
+       else
+               printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
+                      sb->s_id, sb->s_type->name,
+                      labeling_behaviors[sbsec->behavior-1]);
 
-               /* NFS we understand. */
-               if (!strcmp(name, "nfs")) {
-                       struct nfs_mount_data *d = data;
+       /* Initialize the root inode. */
+       rc = inode_doinit_with_dentry(root_inode, root);
 
-                       if (d->version <  NFS_MOUNT_VERSION)
-                               goto out;
+       /* Initialize any other inodes associated with the superblock, e.g.
+          inodes created prior to initial policy load or inodes created
+          during get_sb by a pseudo filesystem that directly
+          populates itself. */
+       spin_lock(&sbsec->isec_lock);
+next_inode:
+       if (!list_empty(&sbsec->isec_head)) {
+               struct inode_security_struct *isec =
+                               list_entry(sbsec->isec_head.next,
+                                          struct inode_security_struct, list);
+               struct inode *inode = isec->inode;
+               spin_unlock(&sbsec->isec_lock);
+               inode = igrab(inode);
+               if (inode) {
+                       if (!IS_PRIVATE(inode))
+                               inode_doinit(inode);
+                       iput(inode);
+               }
+               spin_lock(&sbsec->isec_lock);
+               list_del_init(&isec->list);
+               goto next_inode;
+       }
+       spin_unlock(&sbsec->isec_lock);
+out:
+       return rc;
+}
 
-                       if (d->context[0]) {
-                               context = d->context;
-                               seen |= Opt_context;
-                       }
-               } else
-                       goto out;
+/*
+ * This function should allow an FS to ask what it's mount security
+ * options were so it can use those later for submounts, displaying
+ * mount options, or whatever.
+ */
+static int selinux_get_mnt_opts(const struct super_block *sb,
+                               char ***mount_options, int **mnt_opts_flags,
+                               int *num_opts)
+{
+       int rc = 0, i;
+       struct superblock_security_struct *sbsec = sb->s_security;
+       char *context = NULL;
+       u32 len;
+       char tmp;
 
-       } else {
-               /* Standard string-based options. */
-               char *p, *options = data;
+       *num_opts = 0;
+       *mount_options = NULL;
+       *mnt_opts_flags = NULL;
 
-               while ((p = strsep(&options, "|")) != NULL) {
-                       int token;
-                       substring_t args[MAX_OPT_ARGS];
+       if (!sbsec->initialized)
+               return -EINVAL;
 
-                       if (!*p)
-                               continue;
+       if (!ss_initialized)
+               return -EINVAL;
 
-                       token = match_token(p, tokens, args);
+       /*
+        * if we ever use sbsec flags for anything other than tracking mount
+        * settings this is going to need a mask
+        */
+       tmp = sbsec->flags;
+       /* count the number of mount options for this sb */
+       for (i = 0; i < 8; i++) {
+               if (tmp & 0x01)
+                       (*num_opts)++;
+               tmp >>= 1;
+       }
 
-                       switch (token) {
-                       case Opt_context:
-                               if (seen & (Opt_context|Opt_defcontext)) {
-                                       rc = -EINVAL;
-                                       printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
-                                       goto out_free;
-                               }
-                               context = match_strdup(&args[0]);
-                               if (!context) {
-                                       rc = -ENOMEM;
-                                       goto out_free;
-                               }
-                               if (!alloc)
-                                       alloc = 1;
-                               seen |= Opt_context;
-                               break;
+       *mount_options = kcalloc(*num_opts, sizeof(char *), GFP_ATOMIC);
+       if (!*mount_options) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
 
-                       case Opt_fscontext:
-                               if (seen & Opt_fscontext) {
-                                       rc = -EINVAL;
-                                       printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
-                                       goto out_free;
-                               }
-                               fscontext = match_strdup(&args[0]);
-                               if (!fscontext) {
-                                       rc = -ENOMEM;
-                                       goto out_free;
-                               }
-                               if (!alloc)
-                                       alloc = 1;
-                               seen |= Opt_fscontext;
-                               break;
+       *mnt_opts_flags = kcalloc(*num_opts, sizeof(int), GFP_ATOMIC);
+       if (!*mnt_opts_flags) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
 
-                       case Opt_rootcontext:
-                               if (seen & Opt_rootcontext) {
-                                       rc = -EINVAL;
-                                       printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
-                                       goto out_free;
-                               }
-                               rootcontext = match_strdup(&args[0]);
-                               if (!rootcontext) {
-                                       rc = -ENOMEM;
-                                       goto out_free;
-                               }
-                               if (!alloc)
-                                       alloc = 1;
-                               seen |= Opt_rootcontext;
-                               break;
+       i = 0;
+       if (sbsec->flags & FSCONTEXT_MNT) {
+               rc = security_sid_to_context(sbsec->sid, &context, &len);
+               if (rc)
+                       goto out_free;
+               (*mount_options)[i] = context;
+               (*mnt_opts_flags)[i++] = FSCONTEXT_MNT;
+       }
+       if (sbsec->flags & CONTEXT_MNT) {
+               rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
+               if (rc)
+                       goto out_free;
+               (*mount_options)[i] = context;
+               (*mnt_opts_flags)[i++] = CONTEXT_MNT;
+       }
+       if (sbsec->flags & DEFCONTEXT_MNT) {
+               rc = security_sid_to_context(sbsec->def_sid, &context, &len);
+               if (rc)
+                       goto out_free;
+               (*mount_options)[i] = context;
+               (*mnt_opts_flags)[i++] = DEFCONTEXT_MNT;
+       }
+       if (sbsec->flags & ROOTCONTEXT_MNT) {
+               struct inode *root = sbsec->sb->s_root->d_inode;
+               struct inode_security_struct *isec = root->i_security;
 
-                       case Opt_defcontext:
-                               if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
-                                       rc = -EINVAL;
-                                       printk(KERN_WARNING "SELinux:  "
-                                              "defcontext option is invalid "
-                                              "for this filesystem type\n");
-                                       goto out_free;
-                               }
-                               if (seen & (Opt_context|Opt_defcontext)) {
-                                       rc = -EINVAL;
-                                       printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
-                                       goto out_free;
-                               }
-                               defcontext = match_strdup(&args[0]);
-                               if (!defcontext) {
-                                       rc = -ENOMEM;
-                                       goto out_free;
-                               }
-                               if (!alloc)
-                                       alloc = 1;
-                               seen |= Opt_defcontext;
-                               break;
+               rc = security_sid_to_context(isec->sid, &context, &len);
+               if (rc)
+                       goto out_free;
+               (*mount_options)[i] = context;
+               (*mnt_opts_flags)[i++] = ROOTCONTEXT_MNT;
+       }
 
-                       default:
-                               rc = -EINVAL;
-                               printk(KERN_WARNING "SELinux:  unknown mount "
-                                      "option\n");
-                               goto out_free;
+       BUG_ON(i != *num_opts);
 
-                       }
-               }
-       }
+       return 0;
+
+out_free:
+       /* don't leak context string if security_sid_to_context had an error */
+       if (*mount_options && i)
+               for (; i > 0; i--)
+                       kfree((*mount_options)[i-1]);
+       kfree(*mount_options);
+       *mount_options = NULL;
+       kfree(*mnt_opts_flags);
+       *mnt_opts_flags = NULL;
+       *num_opts = 0;
+       return rc;
+}
+
+static int bad_option(struct superblock_security_struct *sbsec, char flag,
+                     u32 old_sid, u32 new_sid)
+{
+       /* check if the old mount command had the same options */
+       if (sbsec->initialized)
+               if (!(sbsec->flags & flag) ||
+                   (old_sid != new_sid))
+                       return 1;
+
+       /* check if we were passed the same options twice,
+        * aka someone passed context=a,context=b
+        */
+       if (!sbsec->initialized)
+               if (sbsec->flags & flag)
+                       return 1;
+       return 0;
+}
+/*
+ * Allow filesystems with binary mount data to explicitly set mount point
+ * labeling information.
+ */
+int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
+                                int *flags, int num_opts)
+{
+       int rc = 0, i;
+       struct task_security_struct *tsec = current->security;
+       struct superblock_security_struct *sbsec = sb->s_security;
+       const char *name = sb->s_type->name;
+       struct inode *inode = sbsec->sb->s_root->d_inode;
+       struct inode_security_struct *root_isec = inode->i_security;
+       u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
+       u32 defcontext_sid = 0;
 
-       if (!seen)
+       mutex_lock(&sbsec->lock);
+
+       if (!ss_initialized) {
+               if (!num_opts) {
+                       /* Defer initialization until selinux_complete_init,
+                          after the initial policy is loaded and the security
+                          server is ready to handle calls. */
+                       spin_lock(&sb_security_lock);
+                       if (list_empty(&sbsec->list))
+                               list_add(&sbsec->list, &superblock_security_head);
+                       spin_unlock(&sb_security_lock);
+                       goto out;
+               }
+               rc = -EINVAL;
+               printk(KERN_WARNING "Unable to set superblock options before "
+                      "the security server is initialized\n");
                goto out;
+       }
 
-       /* sets the context of the superblock for the fs being mounted. */
-       if (fscontext) {
-               rc = security_context_to_sid(fscontext, strlen(fscontext), &sid);
+       /*
+        * parse the mount options, check if they are valid sids.
+        * also check if someone is trying to mount the same sb more
+        * than once with different security options.
+        */
+       for (i = 0; i < num_opts; i++) {
+               u32 sid;
+               rc = security_context_to_sid(mount_options[i],
+                                            strlen(mount_options[i]), &sid);
                if (rc) {
                        printk(KERN_WARNING "SELinux: security_context_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
-                              fscontext, sb->s_id, name, rc);
-                       goto out_free;
+                              mount_options[i], sb->s_id, name, rc);
+                       goto out;
                }
+               switch (flags[i]) {
+               case FSCONTEXT_MNT:
+                       fscontext_sid = sid;
+
+                       if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+                                       fscontext_sid))
+                               goto out_double_mount;
+
+                       sbsec->flags |= FSCONTEXT_MNT;
+                       break;
+               case CONTEXT_MNT:
+                       context_sid = sid;
+
+                       if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+                                       context_sid))
+                               goto out_double_mount;
+
+                       sbsec->flags |= CONTEXT_MNT;
+                       break;
+               case ROOTCONTEXT_MNT:
+                       rootcontext_sid = sid;
+
+                       if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+                                       rootcontext_sid))
+                               goto out_double_mount;
+
+                       sbsec->flags |= ROOTCONTEXT_MNT;
+
+                       break;
+               case DEFCONTEXT_MNT:
+                       defcontext_sid = sid;
+
+                       if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+                                       defcontext_sid))
+                               goto out_double_mount;
+
+                       sbsec->flags |= DEFCONTEXT_MNT;
+
+                       break;
+               default:
+                       rc = -EINVAL;
+                       goto out;
+               }
+       }
+
+       if (sbsec->initialized) {
+               /* previously mounted with options, but not on this attempt? */
+               if (sbsec->flags && !num_opts)
+                       goto out_double_mount;
+               rc = 0;
+               goto out;
+       }
+
+       if (strcmp(sb->s_type->name, "proc") == 0)
+               sbsec->proc = 1;
+
+       /* Determine the labeling behavior to use for this filesystem type. */
+       rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+       if (rc) {
+               printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
+                      __FUNCTION__, sb->s_type->name, rc);
+               goto out;
+       }
+
+       /* sets the context of the superblock for the fs being mounted. */
+       if (fscontext_sid) {
 
-               rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+               rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
                if (rc)
-                       goto out_free;
+                       goto out;
 
-               sbsec->sid = sid;
+               sbsec->sid = fscontext_sid;
        }
 
        /*
@@ -517,182 +686,250 @@ static int try_context_mount(struct super_block *sb, void *data)
         * sets the label used on all file below the mountpoint, and will set
         * the superblock context if not already set.
         */
-       if (context) {
-               rc = security_context_to_sid(context, strlen(context), &sid);
-               if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
-                              "(%s) failed for (dev %s, type %s) errno=%d\n",
-                              context, sb->s_id, name, rc);
-                       goto out_free;
-               }
-
-               if (!fscontext) {
-                       rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+       if (context_sid) {
+               if (!fscontext_sid) {
+                       rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
                        if (rc)
-                               goto out_free;
-                       sbsec->sid = sid;
+                               goto out;
+                       sbsec->sid = context_sid;
                } else {
-                       rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+                       rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
                        if (rc)
-                               goto out_free;
+                               goto out;
                }
-               sbsec->mntpoint_sid = sid;
+               if (!rootcontext_sid)
+                       rootcontext_sid = context_sid;
 
+               sbsec->mntpoint_sid = context_sid;
                sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
        }
 
-       if (rootcontext) {
-               struct inode *inode = sb->s_root->d_inode;
-               struct inode_security_struct *isec = inode->i_security;
-               rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid);
-               if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
-                              "(%s) failed for (dev %s, type %s) errno=%d\n",
-                              rootcontext, sb->s_id, name, rc);
-                       goto out_free;
-               }
-
-               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+       if (rootcontext_sid) {
+               rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
                if (rc)
-                       goto out_free;
+                       goto out;
 
-               isec->sid = sid;
-               isec->initialized = 1;
+               root_isec->sid = rootcontext_sid;
+               root_isec->initialized = 1;
        }
 
-       if (defcontext) {
-               rc = security_context_to_sid(defcontext, strlen(defcontext), &sid);
-               if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
-                              "(%s) failed for (dev %s, type %s) errno=%d\n",
-                              defcontext, sb->s_id, name, rc);
-                       goto out_free;
+       if (defcontext_sid) {
+               if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
+                       rc = -EINVAL;
+                       printk(KERN_WARNING "SELinux: defcontext option is "
+                              "invalid for this filesystem type\n");
+                       goto out;
                }
 
-               if (sid == sbsec->def_sid)
-                       goto out_free;
-
-               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
-               if (rc)
-                       goto out_free;
+               if (defcontext_sid != sbsec->def_sid) {
+                       rc = may_context_mount_inode_relabel(defcontext_sid,
+                                                            sbsec, tsec);
+                       if (rc)
+                               goto out;
+               }
 
-               sbsec->def_sid = sid;
+               sbsec->def_sid = defcontext_sid;
        }
 
-out_free:
-       if (alloc) {
-               kfree(context);
-               kfree(defcontext);
-               kfree(fscontext);
-               kfree(rootcontext);
-       }
+       rc = sb_finish_set_opts(sb);
 out:
+       mutex_unlock(&sbsec->lock);
        return rc;
+out_double_mount:
+       rc = -EINVAL;
+       printk(KERN_WARNING "SELinux: mount invalid.  Same superblock, different "
+              "security settings for (dev %s, type %s)\n", sb->s_id, name);
+       goto out;
 }
 
-static int superblock_doinit(struct super_block *sb, void *data)
+static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
+                                       struct super_block *newsb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
-       struct dentry *root = sb->s_root;
-       struct inode *inode = root->d_inode;
-       int rc = 0;
+       const struct superblock_security_struct *oldsbsec = oldsb->s_security;
+       struct superblock_security_struct *newsbsec = newsb->s_security;
 
-       mutex_lock(&sbsec->lock);
-       if (sbsec->initialized)
-               goto out;
+       int set_fscontext =     (oldsbsec->flags & FSCONTEXT_MNT);
+       int set_context =       (oldsbsec->flags & CONTEXT_MNT);
+       int set_rootcontext =   (oldsbsec->flags & ROOTCONTEXT_MNT);
 
-       if (!ss_initialized) {
-               /* Defer initialization until selinux_complete_init,
-                  after the initial policy is loaded and the security
-                  server is ready to handle calls. */
-               spin_lock(&sb_security_lock);
-               if (list_empty(&sbsec->list))
-                       list_add(&sbsec->list, &superblock_security_head);
-               spin_unlock(&sb_security_lock);
-               goto out;
+       /* we can't error, we can't save the info, this shouldn't get called
+        * this early in the boot process. */
+       BUG_ON(!ss_initialized);
+
+       /* this might go away sometime down the line if there is a new user
+        * of clone, but for now, nfs better not get here... */
+       BUG_ON(newsbsec->initialized);
+
+       /* how can we clone if the old one wasn't set up?? */
+       BUG_ON(!oldsbsec->initialized);
+
+       mutex_lock(&newsbsec->lock);
+
+       newsbsec->flags = oldsbsec->flags;
+
+       newsbsec->sid = oldsbsec->sid;
+       newsbsec->def_sid = oldsbsec->def_sid;
+       newsbsec->behavior = oldsbsec->behavior;
+
+       if (set_context) {
+               u32 sid = oldsbsec->mntpoint_sid;
+
+               if (!set_fscontext)
+                       newsbsec->sid = sid;
+               if (!set_rootcontext) {
+                       struct inode *newinode = newsb->s_root->d_inode;
+                       struct inode_security_struct *newisec = newinode->i_security;
+                       newisec->sid = sid;
+               }
+               newsbsec->mntpoint_sid = sid;
        }
+       if (set_rootcontext) {
+               const struct inode *oldinode = oldsb->s_root->d_inode;
+               const struct inode_security_struct *oldisec = oldinode->i_security;
+               struct inode *newinode = newsb->s_root->d_inode;
+               struct inode_security_struct *newisec = newinode->i_security;
 
-       /* Determine the labeling behavior to use for this filesystem type. */
-       rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
-       if (rc) {
-               printk(KERN_WARNING "%s:  security_fs_use(%s) returned %d\n",
-                      __FUNCTION__, sb->s_type->name, rc);
-               goto out;
+               newisec->sid = oldisec->sid;
        }
 
-       rc = try_context_mount(sb, data);
-       if (rc)
+       sb_finish_set_opts(newsb);
+       mutex_unlock(&newsbsec->lock);
+}
+
+/*
+ * string mount options parsing and call set the sbsec
+ */
+static int superblock_doinit(struct super_block *sb, void *data)
+{
+       char *context = NULL, *defcontext = NULL;
+       char *fscontext = NULL, *rootcontext = NULL;
+       int rc = 0;
+       char *p, *options = data;
+       /* selinux only know about a fixed number of mount options */
+       char *mnt_opts[NUM_SEL_MNT_OPTS];
+       int mnt_opts_flags[NUM_SEL_MNT_OPTS], num_mnt_opts = 0;
+
+       if (!data)
                goto out;
 
-       if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
-               /* Make sure that the xattr handler exists and that no
-                  error other than -ENODATA is returned by getxattr on
-                  the root directory.  -ENODATA is ok, as this may be
-                  the first boot of the SELinux kernel before we have
-                  assigned xattr values to the filesystem. */
-               if (!inode->i_op->getxattr) {
-                       printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
-                              "xattr support\n", sb->s_id, sb->s_type->name);
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-               rc = inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
-               if (rc < 0 && rc != -ENODATA) {
-                       if (rc == -EOPNOTSUPP)
-                               printk(KERN_WARNING "SELinux: (dev %s, type "
-                                      "%s) has no security xattr handler\n",
-                                      sb->s_id, sb->s_type->name);
-                       else
-                               printk(KERN_WARNING "SELinux: (dev %s, type "
-                                      "%s) getxattr errno %d\n", sb->s_id,
-                                      sb->s_type->name, -rc);
+       /* with the nfs patch this will become a goto out; */
+       if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
+               const char *name = sb->s_type->name;
+               /* NFS we understand. */
+               if (!strcmp(name, "nfs")) {
+                       struct nfs_mount_data *d = data;
+
+                       if (d->version !=  NFS_MOUNT_VERSION)
+                               goto out;
+
+                       if (d->context[0]) {
+                               context = kstrdup(d->context, GFP_KERNEL);
+                               if (!context) {
+                                       rc = -ENOMEM;
+                                       goto out;
+                               }
+                       }
+                       goto build_flags;
+               } else
                        goto out;
-               }
        }
 
-       if (strcmp(sb->s_type->name, "proc") == 0)
-               sbsec->proc = 1;
+       /* Standard string-based options. */
+       while ((p = strsep(&options, "|")) != NULL) {
+               int token;
+               substring_t args[MAX_OPT_ARGS];
 
-       sbsec->initialized = 1;
+               if (!*p)
+                       continue;
 
-       if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) {
-               printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
-                      sb->s_id, sb->s_type->name);
-       }
-       else {
-               printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
-                      sb->s_id, sb->s_type->name,
-                      labeling_behaviors[sbsec->behavior-1]);
-       }
+               token = match_token(p, tokens, args);
 
-       /* Initialize the root inode. */
-       rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root);
+               switch (token) {
+               case Opt_context:
+                       if (context || defcontext) {
+                               rc = -EINVAL;
+                               printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+                               goto out_err;
+                       }
+                       context = match_strdup(&args[0]);
+                       if (!context) {
+                               rc = -ENOMEM;
+                               goto out_err;
+                       }
+                       break;
+
+               case Opt_fscontext:
+                       if (fscontext) {
+                               rc = -EINVAL;
+                               printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+                               goto out_err;
+                       }
+                       fscontext = match_strdup(&args[0]);
+                       if (!fscontext) {
+                               rc = -ENOMEM;
+                               goto out_err;
+                       }
+                       break;
+
+               case Opt_rootcontext:
+                       if (rootcontext) {
+                               rc = -EINVAL;
+                               printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+                               goto out_err;
+                       }
+                       rootcontext = match_strdup(&args[0]);
+                       if (!rootcontext) {
+                               rc = -ENOMEM;
+                               goto out_err;
+                       }
+                       break;
+
+               case Opt_defcontext:
+                       if (context || defcontext) {
+                               rc = -EINVAL;
+                               printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+                               goto out_err;
+                       }
+                       defcontext = match_strdup(&args[0]);
+                       if (!defcontext) {
+                               rc = -ENOMEM;
+                               goto out_err;
+                       }
+                       break;
+
+               default:
+                       rc = -EINVAL;
+                       printk(KERN_WARNING "SELinux:  unknown mount option\n");
+                       goto out_err;
 
-       /* Initialize any other inodes associated with the superblock, e.g.
-          inodes created prior to initial policy load or inodes created
-          during get_sb by a pseudo filesystem that directly
-          populates itself. */
-       spin_lock(&sbsec->isec_lock);
-next_inode:
-       if (!list_empty(&sbsec->isec_head)) {
-               struct inode_security_struct *isec =
-                               list_entry(sbsec->isec_head.next,
-                                          struct inode_security_struct, list);
-               struct inode *inode = isec->inode;
-               spin_unlock(&sbsec->isec_lock);
-               inode = igrab(inode);
-               if (inode) {
-                       if (!IS_PRIVATE (inode))
-                               inode_doinit(inode);
-                       iput(inode);
                }
-               spin_lock(&sbsec->isec_lock);
-               list_del_init(&isec->list);
-               goto next_inode;
        }
-       spin_unlock(&sbsec->isec_lock);
+
+build_flags:
+       if (fscontext) {
+               mnt_opts[num_mnt_opts] = fscontext;
+               mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
+       }
+       if (context) {
+               mnt_opts[num_mnt_opts] = context;
+               mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
+       }
+       if (rootcontext) {
+               mnt_opts[num_mnt_opts] = rootcontext;
+               mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
+       }
+       if (defcontext) {
+               mnt_opts[num_mnt_opts] = defcontext;
+               mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
+       }
+
 out:
-       mutex_unlock(&sbsec->lock);
+       rc = selinux_set_mnt_opts(sb, mnt_opts, mnt_opts_flags, num_mnt_opts);
+out_err:
+       kfree(context);
+       kfree(defcontext);
+       kfree(fscontext);
+       kfree(rootcontext);
        return rc;
 }
 
@@ -4710,6 +4947,11 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
        return security_sid_to_context(secid, secdata, seclen);
 }
 
+static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+       return security_context_to_sid(secdata, seclen, secid);
+}
+
 static void selinux_release_secctx(char *secdata, u32 seclen)
 {
        kfree(secdata);
@@ -4800,6 +5042,9 @@ static struct security_operations selinux_ops = {
        .sb_statfs =                    selinux_sb_statfs,
        .sb_mount =                     selinux_mount,
        .sb_umount =                    selinux_umount,
+       .sb_get_mnt_opts =              selinux_get_mnt_opts,
+       .sb_set_mnt_opts =              selinux_set_mnt_opts,
+       .sb_clone_mnt_opts =            selinux_sb_clone_mnt_opts,
 
        .inode_alloc_security =         selinux_inode_alloc_security,
        .inode_free_security =          selinux_inode_free_security,
@@ -4898,6 +5143,7 @@ static struct security_operations selinux_ops = {
        .setprocattr =                  selinux_setprocattr,
 
        .secid_to_secctx =              selinux_secid_to_secctx,
+       .secctx_to_secid =              selinux_secctx_to_secid,
        .release_secctx =               selinux_release_secctx,
 
         .unix_stream_connect =         selinux_socket_unix_stream_connect,
index 642a9fd319adea8dccd3ad84d9228f7e71274c4e..4138a80f8e2706061666f5a3b83d731ff9204afb 100644 (file)
@@ -65,6 +65,7 @@ struct superblock_security_struct {
        u32 mntpoint_sid;               /* SECURITY_FS_USE_MNTPOINT context for files */
        unsigned int behavior;          /* labeling behavior */
        unsigned char initialized;      /* initialization flag */
+       unsigned char flags;            /* which mount options were specified */
        unsigned char proc;             /* proc fs */
        struct mutex lock;
        struct list_head isec_head;
index d243ddc723a55c06c507dbc2cdcca14c425d54f9..66e013d6f6f6f081665a62c7b3a733b14b4d2cb7 100644 (file)
@@ -53,10 +53,11 @@ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
        struct sk_security_struct *sksec = sk->sk_security;
        struct netlbl_lsm_secattr secattr;
 
+       netlbl_secattr_init(&secattr);
+
        rc = security_netlbl_sid_to_secattr(sid, &secattr);
        if (rc != 0)
-               return rc;
-
+               goto sock_setsid_return;
        rc = netlbl_sock_setattr(sk, &secattr);
        if (rc == 0) {
                spin_lock_bh(&sksec->nlbl_lock);
@@ -64,6 +65,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
                spin_unlock_bh(&sksec->nlbl_lock);
        }
 
+sock_setsid_return:
+       netlbl_secattr_destroy(&secattr);
        return rc;
 }
 
index 2fa483f26113c1656d950e11579bda5c7903cf8c..397fd4955fe1fb9dc9e57b95189084435f648294 100644 (file)
@@ -1222,7 +1222,7 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
 static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
 { }
 
-static struct seq_operations sel_avc_cache_stats_seq_ops = {
+static const struct seq_operations sel_avc_cache_stats_seq_ops = {
        .start          = sel_avc_stats_seq_start,
        .next           = sel_avc_stats_seq_next,
        .show           = sel_avc_stats_seq_show,
index 9e70a160d7da4e5f90d9c57ad816b4e2ec4d5b16..cd10e27fc9e630002395db667e9fd85f78eadeeb 100644 (file)
@@ -280,7 +280,7 @@ int avtab_alloc(struct avtab *h, u32 nrules)
        h->nel = 0;
        h->nslot = nslot;
        h->mask = mask;
-       printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
+       printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. "
               "Num of rules:%d\n", h->nslot, nrules);
        return 0;
 }
index fb5d70a6628dfe79a31a5209f20e38eccdc00bbc..3bbcb5369af9eb6ae2f230a2b0d0ea5099a55273 100644 (file)
@@ -537,15 +537,8 @@ int mls_compute_sid(struct context *scontext,
                        /* Use the process effective MLS attributes. */
                        return mls_context_cpy_low(newcontext, scontext);
        case AVTAB_MEMBER:
-               /* Only polyinstantiate the MLS attributes if
-                  the type is being polyinstantiated */
-               if (newcontext->type != tcontext->type) {
-                       /* Use the process effective MLS attributes. */
-                       return mls_context_cpy_low(newcontext, scontext);
-               } else {
-                       /* Use the related object MLS attributes. */
-                       return mls_context_cpy(newcontext, tcontext);
-               }
+               /* Use the process effective MLS attributes. */
+               return mls_context_cpy_low(newcontext, scontext);
        default:
                return -EINVAL;
        }
index d572dc908f313f7f1aa9db88042ba920982240b9..4bf715d4cf29e2090ab2d7d97b346a5e4087f9dd 100644 (file)
@@ -1744,6 +1744,9 @@ int security_genfs_sid(const char *fstype,
        struct ocontext *c;
        int rc = 0, cmp = 0;
 
+       while (path[0] == '/' && path[1] == '/')
+               path++;
+
        POLICY_RDLOCK;
 
        for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
@@ -2606,8 +2609,6 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
        int rc = -ENOENT;
        struct context *ctx;
 
-       netlbl_secattr_init(secattr);
-
        if (!ss_initialized)
                return 0;
 
index 3ace4a5680ba532ec394e2dcaef8d8b21eb18c08..c5a5ab9cae8cace6edc773a4eb9a3e9b3a700f9a 100644 (file)
@@ -925,6 +925,68 @@ static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
        rslot->number = idx;
 }
 
+/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
+   snd_mixer_oss_build_input! */
+static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
+                                       struct snd_mixer_oss_assign_table *ptr,
+                                       struct slot *slot)
+{
+       char str[64];
+       int err;
+
+       err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GLOBAL);
+       if (err)
+               return err;
+       sprintf(str, "%s Switch", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GSWITCH);
+       if (err)
+               return err;
+       sprintf(str, "%s Route", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GROUTE);
+       if (err)
+               return err;
+       sprintf(str, "%s Volume", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GVOLUME);
+       if (err)
+               return err;
+       sprintf(str, "%s Playback Switch", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_PSWITCH);
+       if (err)
+               return err;
+       sprintf(str, "%s Playback Route", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_PROUTE);
+       if (err)
+               return err;
+       sprintf(str, "%s Playback Volume", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_PVOLUME);
+       if (err)
+               return err;
+       sprintf(str, "%s Capture Switch", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_CSWITCH);
+       if (err)
+               return err;
+       sprintf(str, "%s Capture Route", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_CROUTE);
+       if (err)
+               return err;
+       sprintf(str, "%s Capture Volume", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_CVOLUME);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 /*
  * build an OSS mixer element.
  * ptr_allocated means the entry is dynamically allocated (change via proc file).
@@ -944,44 +1006,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
 
        memset(&slot, 0, sizeof(slot));
        memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
-       if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GLOBAL))
-               return 0;
-       sprintf(str, "%s Switch", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GSWITCH))
-               return 0;
-       sprintf(str, "%s Route", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GROUTE))
-               return 0;
-       sprintf(str, "%s Volume", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GVOLUME))
-               return 0;
-       sprintf(str, "%s Playback Switch", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_PSWITCH))
-               return 0;
-       sprintf(str, "%s Playback Route", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_PROUTE))
-               return 0;
-       sprintf(str, "%s Playback Volume", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_PVOLUME))
-               return 0;
-       sprintf(str, "%s Capture Switch", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_CSWITCH))
-               return 0;
-       sprintf(str, "%s Capture Route", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_CROUTE))
-               return 0;
-       sprintf(str, "%s Capture Volume", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_CVOLUME))
+       if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
                return 0;
        down_read(&mixer->card->controls_rwsem);
        if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
index af37cd09bdddc58f1d09424df5338fd5b68784f1..857008bb7167aa5162ef6e2a6e3b005262a5c993 100644 (file)
@@ -75,7 +75,7 @@ config SOUND_TRIDENT
 
 
          This driver differs slightly from OSS/Free, so PLEASE READ the
-         comments at the top of <file:drivers/sound/trident.c>.
+         comments at the top of <file:sound/oss/trident.c>.
 
 config SOUND_MSNDCLAS
        tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
@@ -564,7 +564,7 @@ config SOUND_AEDSP16
          questions.
 
          Read the <file:Documentation/sound/oss/README.OSS> file and the head of
-         <file:drivers/sound/aedsp16.c> as well as
+         <file:sound/oss/aedsp16.c> as well as
          <file:Documentation/sound/oss/AudioExcelDSP16> to get more information
          about this driver and its configuration.
 
index 05cf7865be5e60c3df82172b163d288a0670d43a..d0ca582c4583e302f171c21e653ea4e5c43f7959 100644 (file)
@@ -233,8 +233,8 @@ typedef struct multisound_dev {
        spinlock_t lock;
        int nresets;
        unsigned long recsrc;
-       int left_levels[16];
-       int right_levels[16];
+       int left_levels[32];
+       int right_levels[32];
        int mixer_mod_count;
        int calibrate_signal;
        int play_sample_size, play_sample_rate, play_channels;