]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'x86/numa' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 Nov 2008 02:53:02 +0000 (18:53 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 Nov 2008 02:53:02 +0000 (18:53 -0800)
* 'x86/numa' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86: make NUMA on 32-bit depend on EXPERIMENTAL again
  x86, hibernate: fix breakage on x86_32 with CONFIG_NUMA set

358 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-c2port [new file with mode: 0644]
Documentation/PCI/00-INDEX
Documentation/PCI/MSI-HOWTO.txt [moved from Documentation/MSI-HOWTO.txt with 100% similarity]
Documentation/blockdev/00-INDEX [new file with mode: 0644]
Documentation/blockdev/README.DAC960 [moved from Documentation/README.DAC960 with 100% similarity]
Documentation/blockdev/cciss.txt [moved from Documentation/cciss.txt with 100% similarity]
Documentation/blockdev/cpqarray.txt [moved from Documentation/cpqarray.txt with 100% similarity]
Documentation/blockdev/floppy.txt [moved from Documentation/floppy.txt with 100% similarity]
Documentation/blockdev/nbd.txt [moved from Documentation/nbd.txt with 100% similarity]
Documentation/blockdev/paride.txt [moved from Documentation/paride.txt with 100% similarity]
Documentation/blockdev/ramdisk.txt [moved from Documentation/ramdisk.txt with 100% similarity]
Documentation/c2port.txt [new file with mode: 0644]
Documentation/cgroups/freezer-subsystem.txt
Documentation/filesystems/xip.txt
Documentation/hwmon/adt7462 [new file with mode: 0644]
Documentation/hwmon/lis3lv02d [new file with mode: 0644]
Documentation/ics932s401 [new file with mode: 0644]
Documentation/ioctl/00-INDEX [new file with mode: 0644]
Documentation/ioctl/ioctl-number.txt [moved from Documentation/ioctl-number.txt with 100% similarity]
Documentation/kernel-parameters.txt
Documentation/printk-formats.txt [new file with mode: 0644]
Documentation/serial/00-INDEX [new file with mode: 0644]
Documentation/serial/README.cycladesZ [moved from Documentation/README.cycladesZ with 100% similarity]
Documentation/serial/computone.txt [moved from Documentation/computone.txt with 99% similarity]
Documentation/serial/digiepca.txt [moved from Documentation/digiepca.txt with 100% similarity]
Documentation/serial/hayes-esp.txt [moved from Documentation/hayes-esp.txt with 100% similarity]
Documentation/serial/moxa-smartio [moved from Documentation/moxa-smartio with 100% similarity]
Documentation/serial/riscom8.txt [moved from Documentation/riscom8.txt with 100% similarity]
Documentation/serial/rocket.txt [moved from Documentation/rocket.txt with 100% similarity]
Documentation/serial/specialix.txt [moved from Documentation/specialix.txt with 100% similarity]
Documentation/serial/stallion.txt [moved from Documentation/stallion.txt with 100% similarity]
Documentation/serial/sx.txt [moved from Documentation/sx.txt with 100% similarity]
Documentation/serial/tty.txt [moved from Documentation/tty.txt with 100% similarity]
Documentation/w1/masters/omap-hdq [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/hardware/iop3xx-adma.h
arch/arm/include/asm/hardware/iop_adma.h
arch/arm/include/asm/mach/map.h
arch/arm/mach-clps711x/include/mach/hardware.h
arch/arm/mach-clps7500/core.c
arch/arm/mach-clps7500/include/mach/hardware.h
arch/arm/mach-h720x/include/mach/boards.h
arch/arm/mach-integrator/include/mach/platform.h
arch/arm/mach-iop13xx/include/mach/adma.h
arch/arm/mach-realview/clock.c
arch/arm/mach-realview/include/mach/platform.h
arch/arm/mach-versatile/clock.c
arch/arm/mach-versatile/include/mach/platform.h
arch/arm/mm/cache-feroceon-l2.c
arch/arm/mm/mmu.c
arch/arm/plat-iop/setup.c
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/dma-mapping.h
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/cplb-nompu/cplbinit.c
arch/blackfin/kernel/process.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/traps.c
arch/blackfin/mach-common/cache.S
arch/blackfin/mach-common/cpufreq.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mm/sram-alloc.c
arch/m68k/kernel/ints.c
arch/parisc/include/asm/smp.h
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/process.c
arch/s390/kernel/setup.c
arch/s390/kernel/sys_s390.c
arch/s390/kernel/topology.c
arch/sh/include/asm/io.h
arch/sh/include/asm/pgtable.h
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/early_printk.c
arch/sh/kernel/timers/timer-tmu.c
arch/sh/lib/copy_page.S
arch/sh/mm/Makefile_32
arch/sh/mm/Makefile_64
arch/sh/mm/init.c
arch/sh/mm/mmap.c [new file with mode: 0644]
arch/sh/mm/pg-sh4.c
arch/sparc/include/asm/termbits.h
arch/sparc/include/asm/unistd_32.h
arch/sparc/include/asm/unistd_64.h
arch/sparc/kernel/of_device.c
arch/sparc/kernel/systbls.S
arch/sparc64/kernel/sys32.S
arch/sparc64/kernel/systbls.S
arch/x86/Kconfig
arch/x86/include/asm/iomap.h [moved from include/asm-x86/iomap.h with 100% similarity]
arch/x86/include/asm/iommu.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/ds.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/es7000_32.c
arch/x86/kernel/setup.c
arch/x86/kernel/tsc_sync.c
arch/x86/mach-voyager/voyager_smp.c
block/blk-map.c
block/genhd.c
block/ioctl.c
drivers/acpi/sleep/proc.c
drivers/ata/libata-sff.c
drivers/block/Kconfig
drivers/block/cciss.c
drivers/block/floppy.c
drivers/block/ub.c
drivers/block/xen-blkfront.c
drivers/char/Kconfig
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/specialix.c
drivers/dma/dmaengine.c
drivers/dma/dmatest.c
drivers/dma/iop-adma.c
drivers/edac/i5000_edac.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpiolib.c
drivers/gpio/xilinx_gpio.c [new file with mode: 0644]
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adt7462.c [new file with mode: 0644]
drivers/hwmon/adt7470.c
drivers/hwmon/adt7473.c
drivers/hwmon/applesmc.c
drivers/hwmon/ibmaem.c
drivers/hwmon/lis3lv02d.c [new file with mode: 0644]
drivers/hwmon/lis3lv02d.h [new file with mode: 0644]
drivers/hwmon/lm85.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/ide/ide-cs.c
drivers/isdn/i4l/isdn_net.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-stripe.c
drivers/md/dm.c
drivers/media/video/tvaudio.c
drivers/mfd/da903x.c
drivers/mfd/wm8350-i2c.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/c2port/Kconfig [new file with mode: 0644]
drivers/misc/c2port/Makefile [new file with mode: 0644]
drivers/misc/c2port/c2port-duramar2150.c [new file with mode: 0644]
drivers/misc/c2port/core.c [new file with mode: 0644]
drivers/misc/ics932s401.c [new file with mode: 0644]
drivers/misc/sgi-gru/Makefile
drivers/mtd/maps/cdb89712.c
drivers/mtd/maps/h720x-flash.c
drivers/net/atl1e/atl1e_hw.c
drivers/net/atlx/atl1.c
drivers/net/bnx2.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/t3_hw.c
drivers/net/e100.c
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/e1000.h
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/param.c
drivers/net/gianfar.c
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_params.c
drivers/net/mlx4/mlx4_en.h
drivers/net/myri10ge/myri10ge.c
drivers/net/niu.c
drivers/net/niu.h
drivers/net/phy/marvell.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy_device.c
drivers/net/qla3xxx.c
drivers/net/smc911x.c
drivers/net/ucc_geth_ethtool.c
drivers/net/usb/asix.c
drivers/net/via-velocity.c
drivers/net/wireless/hostap/hostap_wlan.h
drivers/net/wireless/rtl8187_dev.c
drivers/parport/Kconfig
drivers/pci/pci-acpi.c
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/ds.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ds1390.c [new file with mode: 0644]
drivers/rtc/rtc-rx8581.c [new file with mode: 0644]
drivers/rtc/rtc-sun4v.c
drivers/rtc/rtc-wm8350.c [new file with mode: 0644]
drivers/s390/block/dasd.c
drivers/s390/char/sclp_cmd.c
drivers/s390/cio/device.c
drivers/s390/kvm/kvm_virtio.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_dbf.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/dpt_i2o.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/scsi_error.c
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
drivers/spi/atmel_spi.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi_imx.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/gadget/f_acm.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp1760-if.c
drivers/usb/host/ohci-ps3.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/vstusb.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_debug.h
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_host.h
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/option.c
drivers/usb/storage/Kconfig
drivers/usb/storage/unusual_devs.h
drivers/video/atmel_lcdfb.c
drivers/video/backlight/da903x.c
drivers/video/backlight/lcd.c
drivers/video/cirrusfb.c
drivers/video/fbmem.c
drivers/video/tmiofb.c
drivers/video/via/viafbdev.c
drivers/w1/masters/Kconfig
drivers/w1/masters/Makefile
drivers/w1/masters/omap_hdq.c [new file with mode: 0644]
drivers/w1/slaves/Kconfig
drivers/w1/slaves/Makefile
drivers/w1/slaves/w1_bq27000.c [new file with mode: 0644]
drivers/w1/w1.h
drivers/w1/w1_io.c
drivers/xen/balloon.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/misc.c
fs/dlm/lockspace.c
fs/ecryptfs/keystore.c
fs/ext3/super.c
fs/hostfs/hostfs.h
fs/hostfs/hostfs_kern.c
fs/hostfs/hostfs_user.c
fs/inotify.c
fs/namei.c
fs/namespace.c
fs/partitions/check.c
fs/proc/proc_sysctl.c
include/linux/c2port.h [new file with mode: 0644]
include/linux/cpuset.h
include/linux/genhd.h
include/linux/hrtimer.h
include/linux/inotify.h
include/linux/input.h
include/linux/kernel.h
include/linux/lockdep.h
include/linux/mfd/wm8350/rtc.h
include/linux/net.h
include/linux/ratelimit.h
include/linux/ring_buffer.h
include/linux/serial_core.h
include/linux/slab.h
include/linux/syscalls.h
include/linux/usb.h
include/net/sock.h
include/video/atmel_lcdc.h
init/Kconfig
ipc/util.c
kernel/Makefile
kernel/audit_tree.c
kernel/auditfilter.c
kernel/cgroup.c
kernel/cgroup_freezer.c
kernel/cpuset.c
kernel/exit.c
kernel/fork.c
kernel/hrtimer.c
kernel/kallsyms.c
kernel/kprobes.c
kernel/posix-cpu-timers.c
kernel/power/main.c
kernel/profile.c
kernel/relay.c
kernel/sched.c
kernel/sched_debug.c
kernel/sched_stats.h
kernel/stop_machine.c
kernel/sys_ni.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
lib/scatterlist.c
lib/swiotlb.c
mm/hugetlb.c
mm/memory_hotplug.c
mm/migrate.c
mm/mlock.c
mm/page_alloc.c
mm/page_cgroup.c
mm/vmalloc.c
mm/vmscan.c
net/9p/Kconfig
net/compat.c
net/core/rtnetlink.c
net/core/scm.c
net/core/sock.c
net/ipv4/ip_input.c
net/ipv4/tcp_htcp.c
net/ipv6/datagram.c
net/ipv6/ipv6_sockglue.c
net/mac80211/mlme.c
net/phonet/af_phonet.c
net/socket.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/patch_sigmatel.c
sound/pci/pcxhr/pcxhr.c

index edef85ce1195e0a0e98f2f135d4051c1b5844947..2a39aeba1464b8f66ed9cfe1dc7f20d40bbeb15f 100644 (file)
@@ -42,14 +42,8 @@ IRQ.txt
        - description of what an IRQ is.
 ManagementStyle
        - how to (attempt to) manage kernel hackers.
-MSI-HOWTO.txt
-       - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ.
 RCU/
        - directory with info on RCU (read-copy update).
-README.DAC960
-       - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux.
-README.cycladesZ
-       - info on Cyclades-Z firmware loading.
 SAK.txt
        - info on Secure Attention Keys.
 SM501.txt
@@ -86,20 +80,16 @@ blackfin/
        - directory with documentation for the Blackfin arch.
 block/
        - info on the Block I/O (BIO) layer.
+blockdev/
+       - info on block devices & drivers
 cachetlb.txt
        - describes the cache/TLB flushing interfaces Linux uses.
-cciss.txt
-       - info, major/minor #'s for Compaq's SMART Array Controllers.
 cdrom/
        - directory with information on the CD-ROM drivers that Linux has.
-computone.txt
-       - info on Computone Intelliport II/Plus Multiport Serial Driver.
 connector/
        - docs on the netlink based userspace<->kernel space communication mod.
 console/
        - documentation on Linux console drivers.
-cpqarray.txt
-       - info on using Compaq's SMART2 Intelligent Disk Array Controllers.
 cpu-freq/
        - info on CPU frequency and voltage scaling.
 cpu-hotplug.txt
@@ -126,8 +116,6 @@ device-mapper/
        - directory with info on Device Mapper.
 devices.txt
        - plain ASCII listing of all the nodes in /dev/ with major minor #'s.
-digiepca.txt
-       - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 dontdiff
        - file containing a list of files that should never be diff'ed.
 driver-model/
@@ -152,14 +140,10 @@ filesystems/
        - info on the vfs and the various filesystems that Linux supports.
 firmware_class/
        - request_firmware() hotplug interface info.
-floppy.txt
-       - notes and driver options for the floppy disk driver.
 frv/
        - Fujitsu FR-V Linux documentation.
 gpio.txt
        - overview of GPIO (General Purpose Input/Output) access conventions.
-hayes-esp.txt
-       - info on using the Hayes ESP serial driver.
 highuid.txt
        - notes on the change from 16 bit to 32 bit user/group IDs.
 timers/
@@ -186,8 +170,6 @@ io_ordering.txt
        - info on ordering I/O writes to memory-mapped addresses.
 ioctl/
        - directory with documents describing various IOCTL calls.
-ioctl-number.txt
-       - how to implement and register device/driver ioctl calls.
 iostats.txt
        - info on I/O statistics Linux kernel provides.
 irqflags-tracing.txt
@@ -250,14 +232,10 @@ mips/
        - directory with info about Linux on MIPS architecture.
 mono.txt
        - how to execute Mono-based .NET binaries with the help of BINFMT_MISC.
-moxa-smartio
-       - file with info on installing/using Moxa multiport serial driver.
 mutex-design.txt
        - info on the generic mutex subsystem.
 namespaces/
        - directory with various information about namespaces
-nbd.txt
-       - info on a TCP implementation of a network block device.
 netlabel/
        - directory with information on the NetLabel subsystem.
 networking/
@@ -270,8 +248,6 @@ numastat.txt
        - info on how to read Numa policy hit/miss statistics in sysfs.
 oops-tracing.txt
        - how to decode those nasty internal kernel error dump messages.
-paride.txt
-       - information about the parallel port IDE subsystem.
 parisc/
        - directory with info on using Linux on PA-RISC architecture.
 parport.txt
@@ -290,20 +266,16 @@ powerpc/
        - directory with info on using Linux with the PowerPC.
 preempt-locking.txt
        - info on locking under a preemptive kernel.
+printk-formats.txt
+       - how to get printk format specifiers right
 prio_tree.txt
        - info on radix-priority-search-tree use for indexing vmas.
-ramdisk.txt
-       - short guide on how to set up and use the RAM disk.
 rbtree.txt
        - info on what red-black trees are and what they are for.
-riscom8.txt
-       - notes on using the RISCom/8 multi-port serial driver.
 robust-futex-ABI.txt
        - documentation of the robust futex ABI.
 robust-futexes.txt
        - a description of what robust futexes are.
-rocket.txt
-       - info on the Comtrol RocketPort multiport serial driver.
 rt-mutex-design.txt
        - description of the RealTime mutex implementation design.
 rt-mutex.txt
@@ -332,8 +304,6 @@ sparc/
        - directory with info on using Linux on Sparc architecture.
 sparse.txt
        - info on how to obtain and use the sparse tool for typechecking.
-specialix.txt
-       - info on hardware/driver for specialix IO8+ multiport serial card.
 spi/
        - overview of Linux kernel Serial Peripheral Interface (SPI) support.
 spinlocks.txt
@@ -342,14 +312,10 @@ stable_api_nonsense.txt
        - info on why the kernel does not have a stable in-kernel api or abi.
 stable_kernel_rules.txt
        - rules and procedures for the -stable kernel releases.
-stallion.txt
-       - info on using the Stallion multiport serial driver.
 svga.txt
        - short guide on selecting video modes at boot via VGA BIOS.
 sysfs-rules.txt
        - How not to use sysfs.
-sx.txt
-       - info on the Specialix SX/SI multiport serial driver.
 sysctl/
        - directory with info on the /proc/sys/* files.
 sysrq.txt
@@ -358,8 +324,6 @@ telephony/
        - directory with info on telephony (e.g. voice over IP) support.
 time_interpolators.txt
        - info on time interpolators.
-tty.txt
-       - guide to the locking policies of the tty layer.
 uml/
        - directory with information about User Mode Linux.
 unicode.txt
diff --git a/Documentation/ABI/testing/sysfs-c2port b/Documentation/ABI/testing/sysfs-c2port
new file mode 100644 (file)
index 0000000..716cffc
--- /dev/null
@@ -0,0 +1,88 @@
+What:          /sys/class/c2port/
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/ directory will contain files and
+               directories that will provide a unified interface to
+               the C2 port interface.
+
+What:          /sys/class/c2port/c2portX
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/ directory is related to X-th
+               C2 port into the system. Each directory will contain files to
+               manage and control its C2 port.
+
+What:          /sys/class/c2port/c2portX/access
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/access file enable the access
+               to the C2 port from the system. No commands can be sent
+               till this entry is set to 0.
+
+What:          /sys/class/c2port/c2portX/dev_id
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/dev_id file show the device ID
+               of the connected micro.
+
+What:          /sys/class/c2port/c2portX/flash_access
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/flash_access file enable the
+               access to the on-board flash of the connected micro.
+               No commands can be sent till this entry is set to 0.
+
+What:          /sys/class/c2port/c2portX/flash_block_size
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/flash_block_size file show
+               the on-board flash block size of the connected micro.
+
+What:          /sys/class/c2port/c2portX/flash_blocks_num
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/flash_blocks_num file show
+               the on-board flash blocks number of the connected micro.
+
+What:          /sys/class/c2port/c2portX/flash_data
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/flash_data file export
+               the content of the on-board flash of the connected micro.
+
+What:          /sys/class/c2port/c2portX/flash_erase
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/flash_erase file execute
+               the "erase" command on the on-board flash of the connected
+               micro.
+
+What:          /sys/class/c2port/c2portX/flash_erase
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/flash_erase file show the
+               on-board flash size of the connected micro.
+
+What:          /sys/class/c2port/c2portX/reset
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/reset file execute a "reset"
+               command on the connected micro.
+
+What:          /sys/class/c2port/c2portX/rev_id
+Date:          October 2008
+Contact:       Rodolfo Giometti <giometti@linux.it>
+Description:
+               The /sys/class/c2port/c2portX/rev_id file show the revision ID
+               of the connected micro.
index 49f43946c6b62b0ce8ca4e58c1a66281c324cf2c..812b17fe3ed0d55703d188e3a03b24937c1f1abc 100644 (file)
@@ -1,5 +1,7 @@
 00-INDEX
        - this file
+MSI-HOWTO.txt
+       - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ.
 PCI-DMA-mapping.txt
        - info for PCI drivers using DMA portably across all platforms
 PCIEBUS-HOWTO.txt
diff --git a/Documentation/blockdev/00-INDEX b/Documentation/blockdev/00-INDEX
new file mode 100644 (file)
index 0000000..86f054c
--- /dev/null
@@ -0,0 +1,16 @@
+00-INDEX
+       - this file
+README.DAC960
+       - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux.
+cciss.txt
+       - info, major/minor #'s for Compaq's SMART Array Controllers.
+cpqarray.txt
+       - info on using Compaq's SMART2 Intelligent Disk Array Controllers.
+floppy.txt
+       - notes and driver options for the floppy disk driver.
+nbd.txt
+       - info on a TCP implementation of a network block device.
+paride.txt
+       - information about the parallel port IDE subsystem.
+ramdisk.txt
+       - short guide on how to set up and use the RAM disk.
diff --git a/Documentation/c2port.txt b/Documentation/c2port.txt
new file mode 100644 (file)
index 0000000..d9bf93e
--- /dev/null
@@ -0,0 +1,90 @@
+                       C2 port support
+                       ---------------
+
+(C) Copyright 2007 Rodolfo Giometti <giometti@enneenne.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.
+
+
+
+Overview
+--------
+
+This driver implements the support for Linux of Silicon Labs (Silabs)
+C2 Interface used for in-system programming of micro controllers.
+
+By using this driver you can reprogram the in-system flash without EC2
+or EC3 debug adapter. This solution is also useful in those systems
+where the micro controller is connected via special GPIOs pins.
+
+References
+----------
+
+The C2 Interface main references are at (http://www.silabs.com)
+Silicon Laboratories site], see:
+
+- AN127: FLASH Programming via the C2 Interface at
+http://www.silabs.com/public/documents/tpub_doc/anote/Microcontrollers/Small_Form_Factor/en/an127.pdf, and
+
+- C2 Specification at
+http://www.silabs.com/public/documents/tpub_doc/spec/Microcontrollers/en/C2spec.pdf,
+
+however it implements a two wire serial communication protocol (bit
+banging) designed to enable in-system programming, debugging, and
+boundary-scan testing on low pin-count Silicon Labs devices. Currently
+this code supports only flash programming but extensions are easy to
+add.
+
+Using the driver
+----------------
+
+Once the driver is loaded you can use sysfs support to get C2port's
+info or read/write in-system flash.
+
+# ls /sys/class/c2port/c2port0/
+access            flash_block_size  flash_erase       rev_id
+dev_id            flash_blocks_num  flash_size        subsystem/
+flash_access      flash_data        reset             uevent
+
+Initially the C2port access is disabled since you hardware may have
+such lines multiplexed with other devices so, to get access to the
+C2port, you need the command:
+
+# echo 1 > /sys/class/c2port/c2port0/access
+
+after that you should read the device ID and revision ID of the
+connected micro controller:
+
+# cat /sys/class/c2port/c2port0/dev_id
+8
+# cat /sys/class/c2port/c2port0/rev_id
+1
+
+However, for security reasons, the in-system flash access in not
+enabled yet, to do so you need the command:
+
+# echo 1 > /sys/class/c2port/c2port0/flash_access
+
+After that you can read the whole flash:
+
+# cat /sys/class/c2port/c2port0/flash_data > image
+
+erase it:
+
+# echo 1 > /sys/class/c2port/c2port0/flash_erase
+
+and write it:
+
+# cat image > /sys/class/c2port/c2port0/flash_data
+
+after writing you have to reset the device to execute the new code:
+
+# echo 1 > /sys/class/c2port/c2port0/reset
index c50ab58b72ebc26e0b03124f970e4d038f6df39e..41f37fea1276839b80cd4c220af27963f52c6a1d 100644 (file)
@@ -1,4 +1,4 @@
-       The cgroup freezer is useful to batch job management system which start
+The cgroup freezer is useful to batch job management system which start
 and stop sets of tasks in order to schedule the resources of a machine
 according to the desires of a system administrator. This sort of program
 is often used on HPC clusters to schedule access to the cluster as a
@@ -6,7 +6,7 @@ whole. The cgroup freezer uses cgroups to describe the set of tasks to
 be started/stopped by the batch job management system. It also provides
 a means to start and stop the tasks composing the job.
 
-       The cgroup freezer will also be useful for checkpointing running groups
+The cgroup freezer will also be useful for checkpointing running groups
 of tasks. The freezer allows the checkpoint code to obtain a consistent
 image of the tasks by attempting to force the tasks in a cgroup into a
 quiescent state. Once the tasks are quiescent another task can
@@ -16,7 +16,7 @@ recoverable error occur. This also allows the checkpointed tasks to be
 migrated between nodes in a cluster by copying the gathered information
 to another node and restarting the tasks there.
 
-       Sequences of SIGSTOP and SIGCONT are not always sufficient for stopping
+Sequences of SIGSTOP and SIGCONT are not always sufficient for stopping
 and resuming tasks in userspace. Both of these signals are observable
 from within the tasks we wish to freeze. While SIGSTOP cannot be caught,
 blocked, or ignored it can be seen by waiting or ptracing parent tasks.
@@ -37,26 +37,29 @@ demonstrate this problem using nested bash shells:
 
        <at this point 16990 exits and causes 16644 to exit too>
 
-       This happens because bash can observe both signals and choose how it
+This happens because bash can observe both signals and choose how it
 responds to them.
 
-       Another example of a program which catches and responds to these
+Another example of a program which catches and responds to these
 signals is gdb. In fact any program designed to use ptrace is likely to
 have a problem with this method of stopping and resuming tasks.
 
-        In contrast, the cgroup freezer uses the kernel freezer code to
+In contrast, the cgroup freezer uses the kernel freezer code to
 prevent the freeze/unfreeze cycle from becoming visible to the tasks
 being frozen. This allows the bash example above and gdb to run as
 expected.
 
-       The freezer subsystem in the container filesystem defines a file named
+The freezer subsystem in the container filesystem defines a file named
 freezer.state. Writing "FROZEN" to the state file will freeze all tasks in the
 cgroup. Subsequently writing "THAWED" will unfreeze the tasks in the cgroup.
 Reading will return the current state.
 
+Note freezer.state doesn't exist in root cgroup, which means root cgroup
+is non-freezable.
+
 * Examples of usage :
 
-   # mkdir /containers/freezer
+   # mkdir /containers
    # mount -t cgroup -ofreezer freezer  /containers
    # mkdir /containers/0
    # echo $some_pid > /containers/0/tasks
@@ -94,6 +97,6 @@ things happens:
                the freezer.state file
        2) Userspace retries the freezing operation by writing "FROZEN" to
                the freezer.state file (writing "FREEZING" is not legal
-               and returns EIO)
+               and returns EINVAL)
        3) The tasks that blocked the cgroup from entering the "FROZEN"
                state disappear from the cgroup's set of tasks.
index 3cc4010521a019562e68eb070aa83ad78b0e8c4b..0466ee569278e43b2ccf80d444ab3c38d1ad5e44 100644 (file)
@@ -39,10 +39,11 @@ The block device operation is optional, these block devices support it as of
 today:
 - dcssblk: s390 dcss block device driver
 
-An address space operation named get_xip_page is used to retrieve reference
-to a struct page. To address the target page, a reference to an address_space,
-and a sector number is provided. A 3rd argument indicates whether the
-function should allocate blocks if needed.
+An address space operation named get_xip_mem is used to retrieve references
+to a page frame number and a kernel address. To obtain these values a reference
+to an address_space is provided. This function assigns values to the kmem and
+pfn parameters. The third argument indicates whether the function should allocate
+blocks if needed.
 
 This address space operation is mutually exclusive with readpage&writepage that
 do page cache read/write operations.
diff --git a/Documentation/hwmon/adt7462 b/Documentation/hwmon/adt7462
new file mode 100644 (file)
index 0000000..ec660b3
--- /dev/null
@@ -0,0 +1,67 @@
+Kernel driver adt7462
+======================
+
+Supported chips:
+  * Analog Devices ADT7462
+    Prefix: 'adt7462'
+    Addresses scanned: I2C 0x58, 0x5C
+    Datasheet: Publicly available at the Analog Devices website
+
+Author: Darrick J. Wong
+
+Description
+-----------
+
+This driver implements support for the Analog Devices ADT7462 chip family.
+
+This chip is a bit of a beast.  It has 8 counters for measuring fan speed.  It
+can also measure 13 voltages or 4 temperatures, or various combinations of the
+two.  See the chip documentation for more details about the exact set of
+configurations.  This driver does not allow one to configure the chip; that is
+left to the system designer.
+
+A sophisticated control system for the PWM outputs is designed into the ADT7462
+that allows fan speed to be adjusted automatically based on any of the three
+temperature sensors. Each PWM output is individually adjustable and
+programmable. Once configured, the ADT7462 will adjust the PWM outputs in
+response to the measured temperatures without further host intervention.  This
+feature can also be disabled for manual control of the PWM's.
+
+Each of the measured inputs (voltage, temperature, fan speed) has
+corresponding high/low limit values. The ADT7462 will signal an ALARM if
+any measured value exceeds either limit.
+
+The ADT7462 samples all inputs continuously. The driver will not read
+the registers more often than once every other second. Further,
+configuration data is only read once per minute.
+
+Special Features
+----------------
+
+The ADT7462 have a 10-bit ADC and can therefore measure temperatures
+with 0.25 degC resolution.
+
+The Analog Devices datasheet is very detailed and describes a procedure for
+determining an optimal configuration for the automatic PWM control.
+
+The driver will report sensor labels when it is able to determine that
+information from the configuration registers.
+
+Configuration Notes
+-------------------
+
+Besides standard interfaces driver adds the following:
+
+* PWM Control
+
+* pwm#_auto_point1_pwm and temp#_auto_point1_temp and
+* pwm#_auto_point2_pwm and temp#_auto_point2_temp -
+
+point1: Set the pwm speed at a lower temperature bound.
+point2: Set the pwm speed at a higher temperature bound.
+
+The ADT7462 will scale the pwm between the lower and higher pwm speed when
+the temperature is between the two temperature boundaries.  PWM values range
+from 0 (off) to 255 (full speed).  Fan speed will be set to maximum when the
+temperature sensor associated with the PWM control exceeds temp#_max.
+
diff --git a/Documentation/hwmon/lis3lv02d b/Documentation/hwmon/lis3lv02d
new file mode 100644 (file)
index 0000000..65dfb0c
--- /dev/null
@@ -0,0 +1,49 @@
+Kernel driver lis3lv02d
+==================
+
+Supported chips:
+
+  * STMicroelectronics LIS3LV02DL and LIS3LV02DQ
+
+Author:
+        Yan Burman <burman.yan@gmail.com>
+       Eric Piel <eric.piel@tremplin-utc.net>
+
+
+Description
+-----------
+
+This driver provides support for the accelerometer found in various HP laptops
+sporting the feature officially called "HP Mobile Data Protection System 3D" or
+"HP 3D DriveGuard". It detect automatically laptops with this sensor. Known models
+(for now the HP 2133, nc6420, nc2510, nc8510, nc84x0, nw9440 and nx9420) will
+have their axis automatically oriented on standard way (eg: you can directly
+play neverball).  The accelerometer data is readable via
+/sys/devices/platform/lis3lv02d.
+
+Sysfs attributes under /sys/devices/platform/lis3lv02d/:
+position - 3D position that the accelerometer reports. Format: "(x,y,z)"
+calibrate - read: values (x, y, z) that are used as the base for input class device operation.
+            write: forces the base to be recalibrated with the current position.
+rate - reports the sampling rate of the accelerometer device in HZ
+
+This driver also provides an absolute input class device, allowing
+the laptop to act as a pinball machine-esque joystick.
+
+Axes orientation
+----------------
+
+For better compatibility between the various laptops. The values reported by
+the accelerometer are converted into a "standard" organisation of the axes
+(aka "can play neverball out of the box"):
+ * When the laptop is horizontal the position reported is about 0 for X and Y
+and a positive value for Z
+ * If the left side is elevated, X increases (becomes positive)
+ * If the front side (where the touchpad is) is elevated, Y decreases (becomes negative)
+ * If the laptop is put upside-down, Z becomes negative
+
+If your laptop model is not recognized (cf "dmesg"), you can send an email to the
+authors to add it to the database.  When reporting a new laptop, please include
+the output of "dmidecode" plus the value of /sys/devices/platform/lis3lv02d/position
+in these four cases.
+
diff --git a/Documentation/ics932s401 b/Documentation/ics932s401
new file mode 100644 (file)
index 0000000..07a739f
--- /dev/null
@@ -0,0 +1,31 @@
+Kernel driver ics932s401
+======================
+
+Supported chips:
+  * IDT ICS932S401
+    Prefix: 'ics932s401'
+    Addresses scanned: I2C 0x69
+    Datasheet: Publically available at the IDT website
+
+Author: Darrick J. Wong
+
+Description
+-----------
+
+This driver implements support for the IDT ICS932S401 chip family.
+
+This chip has 4 clock outputs--a base clock for the CPU (which is likely
+multiplied to get the real CPU clock), a system clock, a PCI clock, a USB
+clock, and a reference clock.  The driver reports selected and actual
+frequency.  If spread spectrum mode is enabled, the driver also reports by what
+percent the clock signal is being spread, which should be between 0 and -0.5%.
+All frequencies are reported in KHz.
+
+The ICS932S401 monitors all inputs continuously. The driver will not read
+the registers more often than once every other second.
+
+Special Features
+----------------
+
+The clocks could be reprogrammed to increase system speed.  I will not help you
+do this, as you risk damaging your system!
diff --git a/Documentation/ioctl/00-INDEX b/Documentation/ioctl/00-INDEX
new file mode 100644 (file)
index 0000000..d2fe4d4
--- /dev/null
@@ -0,0 +1,10 @@
+00-INDEX
+       - this file
+cdrom.txt
+       - summary of CDROM ioctl calls
+hdio.txt
+       - summary of HDIO_ ioctl calls
+ioctl-decoding.txt
+       - how to decode the bits of an IOCTL code
+ioctl-number.txt
+       - how to implement and register device/driver ioctl calls
index c600c4ffc6573a1b8cbf7ae811c31a047dbb1cfc..e0f346d201edb70fae654c55f6be842c4465a5ff 100644 (file)
@@ -294,7 +294,9 @@ and is between 256 and 4096 characters. It is defined in the file
                        Possible values are:
                        isolate - enable device isolation (each device, as far
                                  as possible, will get its own protection
-                                 domain)
+                                 domain) [default]
+                       share - put every device behind one IOMMU into the
+                               same protection domain
                        fullflush - enable flushing of IO/TLB entries when
                                    they are unmapped. Otherwise they are
                                    flushed before they will be reused, which
@@ -629,7 +631,7 @@ and is between 256 and 4096 characters. It is defined in the file
 
        digiepca=       [HW,SERIAL]
                        See drivers/char/README.epca and
-                       Documentation/digiepca.txt.
+                       Documentation/serial/digiepca.txt.
 
        disable_mtrr_cleanup [X86]
        enable_mtrr_cleanup [X86]
@@ -740,7 +742,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        See header of drivers/scsi/fdomain.c.
 
        floppy=         [HW]
-                       See Documentation/floppy.txt.
+                       See Documentation/blockdev/floppy.txt.
 
        force_pal_cache_flush
                        [IA-64] Avoid check_sal_cache_flush which may hang on
@@ -1101,7 +1103,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        the same attribute, the last one is used.
 
        load_ramdisk=   [RAM] List of ramdisks to load from floppy
-                       See Documentation/ramdisk.txt.
+                       See Documentation/blockdev/ramdisk.txt.
 
        lockd.nlm_grace_period=P  [NFS] Assign grace period.
                        Format: <integer>
@@ -1193,8 +1195,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        it is equivalent to "nosmp", which also disables
                        the IO APIC.
 
-       max_addr=[KMG]  [KNL,BOOT,ia64] All physical memory greater than or
-                       equal to this physical address is ignored.
+       max_addr=nn[KMG]        [KNL,BOOT,ia64] All physical memory greater than
+                       or equal to this physical address is ignored.
 
        max_luns=       [SCSI] Maximum number of LUNs to probe.
                        Should be between 1 and 2^32-1.
@@ -1294,6 +1296,9 @@ and is between 256 and 4096 characters. It is defined in the file
 
        mga=            [HW,DRM]
 
+       min_addr=nn[KMG]        [KNL,BOOT,ia64] All physical memory below this
+                       physical address is ignored.
+
        mminit_loglevel=
                        [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
                        parameter allows control of the logging verbosity for
@@ -1596,7 +1601,7 @@ and is between 256 and 4096 characters. It is defined in the file
 
        pcd.            [PARIDE]
                        See header of drivers/block/paride/pcd.c.
-                       See also Documentation/paride.txt.
+                       See also Documentation/blockdev/paride.txt.
 
        pci=option[,option...]  [PCI] various PCI subsystem options:
                off             [X86] don't probe for the PCI bus
@@ -1697,7 +1702,7 @@ and is between 256 and 4096 characters. It is defined in the file
        pcmv=           [HW,PCMCIA] BadgePAD 4
 
        pd.             [PARIDE]
-                       See Documentation/paride.txt.
+                       See Documentation/blockdev/paride.txt.
 
        pdcchassis=     [PARISC,HW] Disable/Enable PDC Chassis Status codes at
                        boot time.
@@ -1705,10 +1710,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        See arch/parisc/kernel/pdc_chassis.c
 
        pf.             [PARIDE]
-                       See Documentation/paride.txt.
+                       See Documentation/blockdev/paride.txt.
 
        pg.             [PARIDE]
-                       See Documentation/paride.txt.
+                       See Documentation/blockdev/paride.txt.
 
        pirq=           [SMP,APIC] Manual mp-table setup
                        See Documentation/x86/i386/IO-APIC.txt.
@@ -1778,7 +1783,7 @@ and is between 256 and 4096 characters. It is defined in the file
 
        prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk
                        before loading.
-                       See Documentation/ramdisk.txt.
+                       See Documentation/blockdev/ramdisk.txt.
 
        psmouse.proto=  [HW,MOUSE] Highest PS2 mouse protocol extension to
                        probe for; one of (bare|imps|exps|lifebook|any).
@@ -1798,7 +1803,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
 
        pt.             [PARIDE]
-                       See Documentation/paride.txt.
+                       See Documentation/blockdev/paride.txt.
 
        pty.legacy_count=
                        [KNL] Number of legacy pty's. Overwrites compiled-in
@@ -1812,10 +1817,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        See Documentation/md.txt.
 
        ramdisk_blocksize=      [RAM]
-                       See Documentation/ramdisk.txt.
+                       See Documentation/blockdev/ramdisk.txt.
 
        ramdisk_size=   [RAM] Sizes of RAM disks in kilobytes
-                       See Documentation/ramdisk.txt.
+                       See Documentation/blockdev/ramdisk.txt.
 
        rcupdate.blimit=        [KNL,BOOT]
                        Set maximum number of finished RCU callbacks to process
@@ -2147,7 +2152,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        See Documentation/sonypi.txt
 
        specialix=      [HW,SERIAL] Specialix multi-serial port adapter
-                       See Documentation/specialix.txt.
+                       See Documentation/serial/specialix.txt.
 
        spia_io_base=   [HW,MTD]
        spia_fio_base=
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
new file mode 100644 (file)
index 0000000..1b5a5dd
--- /dev/null
@@ -0,0 +1,35 @@
+If variable is of Type,                use printk format specifier:
+---------------------------------------------------------
+               int                     %d or %x
+               unsigned int            %u or %x
+               long                    %ld or %lx
+               unsigned long           %lu or %lx
+               long long               %lld or %llx
+               unsigned long long      %llu or %llx
+               size_t                  %zu or %zx
+               ssize_t                 %zd or %zx
+
+Raw pointer value SHOULD be printed with %p.
+
+u64 SHOULD be printed with %llu/%llx, (unsigned long long):
+
+       printk("%llu", (unsigned long long)u64_var);
+
+s64 SHOULD be printed with %lld/%llx, (long long):
+
+       printk("%lld", (long long)s64_var);
+
+If <type> is dependent on a config option for its size (e.g., sector_t,
+blkcnt_t, phys_addr_t, resource_size_t) or is architecture-dependent
+for its size (e.g., tcflag_t), use a format specifier of its largest
+possible type and explicitly cast to it.  Example:
+
+       printk("test: sector number/total blocks: %llu/%llu\n",
+               (unsigned long long)sector, (unsigned long long)blockcount);
+
+Reminder: sizeof() result is of type size_t.
+
+Thank you for your cooperation and attention.
+
+
+By Randy Dunlap <rdunlap@xenotime.net>
diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX
new file mode 100644 (file)
index 0000000..07dcdb0
--- /dev/null
@@ -0,0 +1,24 @@
+00-INDEX
+       - this file.
+README.cycladesZ
+       - info on Cyclades-Z firmware loading.
+computone.txt
+       - info on Computone Intelliport II/Plus Multiport Serial Driver.
+digiepca.txt
+       - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
+hayes-esp.txt
+       - info on using the Hayes ESP serial driver.
+moxa-smartio
+       - file with info on installing/using Moxa multiport serial driver.
+riscom8.txt
+       - notes on using the RISCom/8 multi-port serial driver.
+rocket.txt
+       - info on the Comtrol RocketPort multiport serial driver.
+specialix.txt
+       - info on hardware/driver for specialix IO8+ multiport serial card.
+stallion.txt
+       - info on using the Stallion multiport serial driver.
+sx.txt
+       - info on the Specialix SX/SI multiport serial driver.
+tty.txt
+       - guide to the locking policies of the tty layer.
similarity index 99%
rename from Documentation/computone.txt
rename to Documentation/serial/computone.txt
index 5e2a0c76bfa0b61a697772496a281ed42b6f13c4..c57ea4781e5d7426631eaf308b145fb05b921eef 100644 (file)
@@ -247,7 +247,7 @@ shar archive to make it easier to extract the script from the documentation.
 To create the ip2mkdev shell script change to a convenient directory (/tmp
 works just fine) and run the following command:
 
-       unshar Documentation/computone.txt
+       unshar Documentation/serial/computone.txt
                (This file)
 
 You should now have a file ip2mkdev in your current working directory with
diff --git a/Documentation/w1/masters/omap-hdq b/Documentation/w1/masters/omap-hdq
new file mode 100644 (file)
index 0000000..ca722e0
--- /dev/null
@@ -0,0 +1,46 @@
+Kernel driver for omap HDQ/1-wire module.
+========================================
+
+Supported chips:
+================
+       HDQ/1-wire controller on the TI OMAP 2430/3430 platforms.
+
+A useful link about HDQ basics:
+===============================
+http://focus.ti.com/lit/an/slua408/slua408.pdf
+
+Description:
+============
+The HDQ/1-Wire module of TI OMAP2430/3430 platforms implement the hardware
+protocol of the master functions of the Benchmark HDQ and the Dallas
+Semiconductor 1-Wire protocols. These protocols use a single wire for
+communication between the master (HDQ/1-Wire controller) and the slave
+(HDQ/1-Wire external compliant device).
+
+A typical application of the HDQ/1-Wire module is the communication with battery
+monitor (gas gauge) integrated circuits.
+
+The controller supports operation in both HDQ and 1-wire mode. The essential
+difference between the HDQ and 1-wire mode is how the slave device responds to
+initialization pulse.In HDQ mode, the firmware does not require the host to
+create an initialization pulse to the slave.However, the slave can be reset by
+using an initialization pulse (also referred to as a break pulse).The slave
+does not respond with a presence pulse as it does in the 1-Wire protocol.
+
+Remarks:
+========
+The driver (drivers/w1/masters/omap_hdq.c) supports the HDQ mode of the
+controller. In this mode, as we can not read the ID which obeys the W1
+spec(family:id:crc), a module parameter can be passed to the driver which will
+be used to calculate the CRC and pass back an appropriate slave ID to the W1
+core.
+
+By default the master driver and the BQ slave i/f
+driver(drivers/w1/slaves/w1_bq27000.c) sets the ID to 1.
+Please note to load both the modules with a different ID if required, but note
+that the ID used should be same for both master and slave driver loading.
+
+e.g:
+insmod omap_hdq.ko W1_ID=2
+inamod w1_bq27000.ko F_ID=2
+
index 272d04e95faa4bb161a7a4e9779cf1858a91fd70..618c1ef4a397502749b2d08a49e80806e99825d1 100644 (file)
@@ -1809,7 +1809,7 @@ S:        Maintained
 
 FTRACE
 P:     Steven Rostedt
-M:     srostedt@redhat.com
+M:     rostedt@goodmis.org
 S:     Maintained
 
 FUJITSU FR-V (FRV) PORT
@@ -2703,6 +2703,11 @@ P:       Arnaldo Carvalho de Melo
 M:     acme@ghostprotocols.net
 S:     Maintained
 
+LIS3LV02D ACCELEROMETER DRIVER
+P:     Eric Piel
+M:     eric.piel@tremplin-utc.net
+S:     Maintained
+
 LM83 HARDWARE MONITOR DRIVER
 P:     Jean Delvare
 M:     khali@linux-fr.org
@@ -3923,8 +3928,6 @@ M:        bootc@bootc.net
 S:     Maintained
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
-P:     Ingo Molnar
-M:     mingo@redhat.com
 P:     Neil Brown
 M:     neilb@suse.de
 L:     linux-raid@vger.kernel.org
index 7f9ff9bf1544049db441f9d0be0da6df628cd0d5..a9ae5dc0aa161e4f4c809fb6a1f9b8f6e8a0c9c7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 28
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc5
 NAME = Killer Bat of Doom
 
 # *DOCUMENTATION*
index 1cb8602dd9d5f5b0a29c56b3c8ac80c35f874e85..4ed149cbb32a401c26a6d91f062aa25151d994bf 100644 (file)
@@ -256,8 +256,17 @@ int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long,
 int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long,
                size_t, enum dma_data_direction);
 #else
-#define dmabounce_sync_for_cpu(dev,dma,off,sz,dir)     (1)
-#define dmabounce_sync_for_device(dev,dma,off,sz,dir)  (1)
+static inline int dmabounce_sync_for_cpu(struct device *d, dma_addr_t addr,
+       unsigned long offset, size_t size, enum dma_data_direction dir)
+{
+       return 1;
+}
+
+static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
+       unsigned long offset, size_t size, enum dma_data_direction dir)
+{
+       return 1;
+}
 
 
 /**
index 87bff09633aac50bdcffcdc0aae2891000cda161..83e6ba338e2c4c9c13c6e05cd0aadeea5ce461fc 100644 (file)
@@ -730,7 +730,8 @@ static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc,
 {
        /* hw_desc->next_desc is the same location for all channels */
        union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
-       BUG_ON(hw_desc.dma->next_desc);
+
+       iop_paranoia(hw_desc.dma->next_desc);
        hw_desc.dma->next_desc = next_desc_addr;
 }
 
@@ -760,7 +761,7 @@ static inline int iop_desc_get_zero_result(struct iop_adma_desc_slot *desc)
        struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
        struct iop3xx_aau_desc_ctrl desc_ctrl = hw_desc->desc_ctrl_field;
 
-       BUG_ON(!(desc_ctrl.tx_complete && desc_ctrl.zero_result_en));
+       iop_paranoia(!(desc_ctrl.tx_complete && desc_ctrl.zero_result_en));
        return desc_ctrl.zero_result_err;
 }
 
index cb7e3611bcba748352d4227c19104e46fc47d08e..385c6e8cbbd214357e798270ccac8845cb672cec 100644 (file)
 
 #define IOP_ADMA_SLOT_SIZE 32
 #define IOP_ADMA_THRESHOLD 4
+#ifdef DEBUG
+#define IOP_PARANOIA 1
+#else
+#define IOP_PARANOIA 0
+#endif
+#define iop_paranoia(x) BUG_ON(IOP_PARANOIA && (x))
 
 /**
  * struct iop_adma_device - internal representation of an ADMA device
index cb1139ac19432f555b32ccc188b12f838f1ee9d4..39d949b63e80bc0cb23a59b086a2bb24711493ef 100644 (file)
@@ -19,12 +19,13 @@ struct map_desc {
 };
 
 /* types 0-3 are defined in asm/io.h */
-#define MT_CACHECLEAN          4
-#define MT_MINICLEAN           5
-#define MT_LOW_VECTORS         6
-#define MT_HIGH_VECTORS                7
-#define MT_MEMORY              8
-#define MT_ROM                 9
+#define MT_UNCACHED            4
+#define MT_CACHECLEAN          5
+#define MT_MINICLEAN           6
+#define MT_LOW_VECTORS         7
+#define MT_HIGH_VECTORS                8
+#define MT_MEMORY              9
+#define MT_ROM                 10
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
index 4c3e101b96c9582fcaf6473a5824fa9e10705f56..b3ebe9e4871fe938585e5cad55eb7390424d25b3 100644 (file)
 #include <asm/hardware/ep7212.h>
 #include <asm/hardware/cs89712.h>
 
-/* dynamic ioremap() areas */
-#define FLASH_START      0x00000000
-#define FLASH_SIZE       0x800000
-#define FLASH_WIDTH      4
-
-#define SRAM_START       0x60000000
-#define SRAM_SIZE        0xc000
-#define SRAM_WIDTH       4
-
-#define BOOTROM_START    0x70000000
-#define BOOTROM_SIZE     0x80
-#define BOOTROM_WIDTH    4
-
-
 /* static cdb89712_map_io() areas */
 #define REGISTER_START   0x80000000
 #define REGISTER_SIZE    0x4000
 #define CEIVA_FLASH_SIZE        0x100000
 #define CEIVA_FLASH_WIDTH       2
 
-#define SRAM_START       0x60000000
-#define SRAM_SIZE        0xc000
-#define SRAM_WIDTH       4
-
-#define BOOTROM_START    0x70000000
-#define BOOTROM_SIZE     0x80
-#define BOOTROM_WIDTH    4
-
 /*
  * SED1355 LCD controller
  */
index c3a33b8a5aacc8406d3bcb7279e824cc7500513f..7e247c04d41c471312ff10161654ecc35b441c46 100644 (file)
@@ -275,9 +275,9 @@ static struct map_desc cl7500_io_desc[] __initdata = {
                .length         = ISA_SIZE,
                .type           = MT_DEVICE
        }, {    /* Flash        */
-               .virtual        = FLASH_BASE,
-               .pfn            = __phys_to_pfn(FLASH_START),
-               .length         = FLASH_SIZE,
+               .virtual        = CLPS7500_FLASH_BASE,
+               .pfn            = __phys_to_pfn(CLPS7500_FLASH_START),
+               .length         = CLPS7500_FLASH_SIZE,
                .type           = MT_DEVICE
        }, {    /* LED          */
                .virtual        = LED_BASE,
index d66578a3371c9f0a972a8266497e37519446875e..a6ad1d44badfd44e1fe140297517259652e3c63a 100644 (file)
@@ -39,9 +39,9 @@
 #define ISA_SIZE               0x00010000
 #define ISA_BASE               0xe1000000
 
-#define FLASH_START            0x01000000      /* XXX */
-#define FLASH_SIZE             0x01000000
-#define FLASH_BASE             0xe2000000
+#define CLPS7500_FLASH_START   0x01000000      /* XXX */
+#define CLPS7500_FLASH_SIZE    0x01000000
+#define CLPS7500_FLASH_BASE    0xe2000000
 
 #define LED_START              0x0302B000
 #define LED_SIZE               0x00001000
index 079b279e1242f8f681c0a0d7995cbe3d4cd1602c..38b8e0d61fbfc93f5d3b6cc89b8211bca0dae5c4 100644 (file)
@@ -19,9 +19,9 @@
 #ifdef CONFIG_ARCH_H7202
 
 /* FLASH */
-#define FLASH_VIRT             0xd0000000
-#define FLASH_PHYS             0x00000000
-#define FLASH_SIZE             0x02000000
+#define H720X_FLASH_VIRT       0xd0000000
+#define H720X_FLASH_PHYS       0x00000000
+#define H720X_FLASH_SIZE       0x02000000
 
 /* onboard LAN controller */
 # define ETH0_PHYS             0x08000000
index 028b87839c0f64b3ef421ee488b9e4c149d75899..e00a2624f269922d579cee9d154acb2d4852bfa9 100644 (file)
  */
 #define uHAL_MEMORY_SIZE                INTEGRATOR_SSRAM_SIZE
 
-/*
- *  Application Flash
- *
- */
-#define FLASH_BASE                      INTEGRATOR_FLASH_BASE
-#define FLASH_SIZE                      INTEGRATOR_FLASH_SIZE
-#define FLASH_END                       (FLASH_BASE + FLASH_SIZE - 1)
-#define FLASH_BLOCK_SIZE                SZ_128K
-
-/*
- *  Boot Flash
- *
- */
-#define EPROM_BASE                      INTEGRATOR_BOOT_ROM_HI
-#define EPROM_SIZE                      INTEGRATOR_BOOT_ROM_SIZE
-#define EPROM_END                       (EPROM_BASE + EPROM_SIZE - 1)
-
 /*
  *  Clean base - dummy
  *
  */
-#define CLEAN_BASE                      EPROM_BASE
+#define CLEAN_BASE                      INTEGRATOR_BOOT_ROM_HI
 
 /*
  *  Timer definitions
index 60019c8e6465f420be5d958ca7dd7432f4bc205d..5722e86f2174a93aa4b91975f2c2b608a5b4a1af 100644 (file)
@@ -404,7 +404,8 @@ static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc,
                                        u32 next_desc_addr)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
-       BUG_ON(hw_desc->next_desc);
+
+       iop_paranoia(hw_desc->next_desc);
        hw_desc->next_desc = next_desc_addr;
 }
 
index 3e706c57833aebc16a39e0f61a1fa1356e4ed730..3347c4236a60bd6cb2b34cbadc09d0d966614ebf 100644 (file)
@@ -104,7 +104,7 @@ static struct clk uart_clk = {
 
 static struct clk mmci_clk = {
        .name   = "MCLK",
-       .rate   = 33000000,
+       .rate   = 24000000,
 };
 
 int clk_register(struct clk *clk)
index 4034b54950c26d9d811856aceb9d77f5802c113e..793a3a3327121152072645828237c9d3f17c9e8d 100644 (file)
 #define REALVIEW_INTREG_OFFSET         0x8     /* Interrupt control */
 #define REALVIEW_DECODE_OFFSET         0xC     /* Fitted logic modules */
 
-/* 
- *  Application Flash
- * 
- */
-#define FLASH_BASE                      REALVIEW_FLASH_BASE
-#define FLASH_SIZE                      REALVIEW_FLASH_SIZE
-#define FLASH_END                       (FLASH_BASE + FLASH_SIZE - 1)
-#define FLASH_BLOCK_SIZE                SZ_128K
-
-/* 
- *  Boot Flash
- * 
- */
-#define EPROM_BASE                      REALVIEW_BOOT_ROM_HI
-#define EPROM_SIZE                      REALVIEW_BOOT_ROM_SIZE
-#define EPROM_END                       (EPROM_BASE + EPROM_SIZE - 1)
-
 /* 
  *  Clean base - dummy
  * 
  */
-#define CLEAN_BASE                      EPROM_BASE
+#define CLEAN_BASE                      REALVIEW_BOOT_ROM_HI
 
 /*
  * System controller bit assignment
index 9336508ec0b2b1311bbf6c0ceda0fdaa40d8910d..58937f1fb38ce7b4d805f86771d1ccdac9383457 100644 (file)
@@ -105,7 +105,7 @@ static struct clk uart_clk = {
 
 static struct clk mmci_clk = {
        .name   = "MCLK",
-       .rate   = 33000000,
+       .rate   = 24000000,
 };
 
 int clk_register(struct clk *clk)
index 27cbe6a3f2208f5abf4e4f33ce024b8c1498023e..f91ba930ca8a45221b8cb60074ec9bd186731eab 100644 (file)
 #define SIC_INTMASK_PCI1                (1 << SIC_INT_PCI1)
 #define SIC_INTMASK_PCI2                (1 << SIC_INT_PCI2)
 #define SIC_INTMASK_PCI3                (1 << SIC_INT_PCI3)
-/* 
- *  Application Flash
- * 
- */
-#define FLASH_BASE                      VERSATILE_FLASH_BASE
-#define FLASH_SIZE                      VERSATILE_FLASH_SIZE
-#define FLASH_END                       (FLASH_BASE + FLASH_SIZE - 1)
-#define FLASH_BLOCK_SIZE                SZ_128K
-
-/* 
- *  Boot Flash
- * 
- */
-#define EPROM_BASE                      VERSATILE_BOOT_ROM_HI
-#define EPROM_SIZE                      VERSATILE_BOOT_ROM_SIZE
-#define EPROM_END                       (EPROM_BASE + EPROM_SIZE - 1)
 
 /* 
  *  Clean base - dummy
  * 
  */
-#define CLEAN_BASE                      EPROM_BASE
+#define CLEAN_BASE                      VERSATILE_BOOT_ROM_HI
 
 /*
  * System controller bit assignment
index 13cdae8b0d44192107bdb0c626b9e6a3162d8b93..80cd207cbaea14c282e368fe08791d1ebcf09b2c 100644 (file)
@@ -150,7 +150,7 @@ static void feroceon_l2_inv_range(unsigned long start, unsigned long end)
        /*
         * Clean and invalidate partial last cache line.
         */
-       if (end & (CACHE_LINE_SIZE - 1)) {
+       if (start < end && end & (CACHE_LINE_SIZE - 1)) {
                l2_clean_inv_pa(end & ~(CACHE_LINE_SIZE - 1));
                end &= ~(CACHE_LINE_SIZE - 1);
        }
@@ -158,7 +158,7 @@ static void feroceon_l2_inv_range(unsigned long start, unsigned long end)
        /*
         * Invalidate all full cache lines between 'start' and 'end'.
         */
-       while (start != end) {
+       while (start < end) {
                unsigned long range_end = calc_range_end(start, end);
                l2_inv_pa_range(start, range_end - CACHE_LINE_SIZE);
                start = range_end;
index e63db11f16a808fc0de3b73ea841ad2797ca597b..7f36c825718d37e6f424c57d8e81e2547692a0e4 100644 (file)
@@ -208,6 +208,12 @@ static struct mem_type mem_types[] = {
                .prot_sect      = PROT_SECT_DEVICE,
                .domain         = DOMAIN_IO,
        },
+       [MT_UNCACHED] = {
+               .prot_pte       = PROT_PTE_DEVICE,
+               .prot_l1        = PMD_TYPE_TABLE,
+               .prot_sect      = PMD_TYPE_SECT | PMD_SECT_XN,
+               .domain         = DOMAIN_IO,
+       },
        [MT_CACHECLEAN] = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
                .domain    = DOMAIN_KERNEL,
index 4689db638e95216ebcf1008767e6f8acbcddb4e4..9e573e78176a65d4bfdb93ae19235f5e39d4ca2b 100644 (file)
 #include <asm/hardware/iop3xx.h>
 
 /*
- * Standard IO mapping for all IOP3xx based systems
+ * Standard IO mapping for all IOP3xx based systems.  Note that
+ * the IOP3xx OCCDR must be mapped uncached and unbuffered.
  */
 static struct map_desc iop3xx_std_desc[] __initdata = {
         {      /* mem mapped registers */
                .virtual        = IOP3XX_PERIPHERAL_VIRT_BASE,
                .pfn            = __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE),
                .length         = IOP3XX_PERIPHERAL_SIZE,
-               .type           = MT_DEVICE,
+               .type           = MT_UNCACHED,
         }, {   /* PCI IO space */
                .virtual        = IOP3XX_PCI_LOWER_IO_VA,
                .pfn            = __phys_to_pfn(IOP3XX_PCI_LOWER_IO_PA),
index 56dcb0a2d2449ced3d11097a889be0cde31d3017..77295666c34be11411d2f16c6833f5cd995f65ac 100644 (file)
@@ -101,7 +101,7 @@ extern u16 _bfin_swrst; /* shadow for Software Reset Register (SWRST) */
 extern unsigned long _ramstart, _ramend, _rambase;
 extern unsigned long memory_start, memory_end, physical_mem_end;
 extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
-       _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _ebss_b_l1[],
+       _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[],
        _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
        _ebss_l2[], _l2_lma_start[];
 
index ede748d67efdc6bed10051a746a9fa53499e7469..d7d9148e433c7aa7d567f0ab5fe346897b07fae9 100644 (file)
@@ -15,7 +15,11 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
-#define dma_mapping_error
+static inline
+int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return 0;
+}
 
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
index 6e08f425bb44076fa39443e23ab75d1db429afa1..5c0800adb4ddc428658f50c6f8aa29fd839ede65 100644 (file)
@@ -218,7 +218,7 @@ inline int check_gpio(unsigned gpio)
        if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15
            || gpio == GPIO_PH14 || gpio == GPIO_PH15
            || gpio == GPIO_PJ14 || gpio == GPIO_PJ15
-           || gpio > MAX_BLACKFIN_GPIOS)
+           || gpio >= MAX_BLACKFIN_GPIOS)
                return -EINVAL;
        return 0;
 }
index 512f8c92ead511f2286a4a9f688763becd9ca8ed..2debc900e246d2ae7d5fe81e55bf18b0437de4d3 100644 (file)
@@ -188,10 +188,11 @@ static struct cplb_desc cplb_data[] = {
 
 static u16 __init lock_kernel_check(u32 start, u32 end)
 {
-       if ((end   <= (u32) _end && end   >= (u32)_stext) ||
-           (start <= (u32) _end && start >= (u32)_stext))
-               return IN_KERNEL;
-       return 0;
+       if (start >= (u32)_end || end <= (u32)_stext)
+               return 0;
+
+       /* This cplb block overlapped with kernel area. */
+       return IN_KERNEL;
 }
 
 static unsigned short __init
index 77800dd83e578d49844edaceaec7fc4f3bcfe728..0c3ea118b657563f6486d6b2554180d1db0c2886 100644 (file)
@@ -351,9 +351,14 @@ int _access_ok(unsigned long addr, unsigned long size)
                return 1;
 #endif
 #if L1_DATA_B_LENGTH != 0
-       if (addr >= L1_DATA_B_START
+       if (addr >= L1_DATA_B_START + (_ebss_b_l1 - _sdata_b_l1)
            && addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)
                return 1;
+#endif
+#if L2_LENGTH != 0
+       if (addr >= L2_START + (_ebss_l2 - _stext_l2)
+           && addr + size <= L2_START + L2_LENGTH)
+               return 1;
 #endif
        return 0;
 }
index 7f35d1046cd87d1062df7520b577b72eac4bcdf7..71a9a8c53ceab8cd2456f578599267697f3d2bd3 100644 (file)
@@ -119,23 +119,23 @@ void __init bfin_relocate_l1_mem(void)
        /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
        dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
 
-       l1_data_a_length = _ebss_l1 - _sdata_l1;
+       l1_data_a_length = _sbss_l1 - _sdata_l1;
        if (l1_data_a_length > L1_DATA_A_LENGTH)
                panic("L1 Data SRAM Bank A Overflow\n");
 
-       /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
+       /* Copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
        dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
 
-       l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
+       l1_data_b_length = _sbss_b_l1 - _sdata_b_l1;
        if (l1_data_b_length > L1_DATA_B_LENGTH)
                panic("L1 Data SRAM Bank B Overflow\n");
 
-       /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
+       /* Copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
        dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
                        l1_data_a_length, l1_data_b_length);
 
        if (L2_LENGTH != 0) {
-               l2_length = _ebss_l2 - _stext_l2;
+               l2_length = _sbss_l2 - _stext_l2;
                if (l2_length > L2_LENGTH)
                        panic("L2 SRAM Overflow\n");
 
@@ -827,7 +827,7 @@ void __init setup_arch(char **cmdline_p)
                                printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
                                       bfin_compiled_revid(), bfin_revid());
                }
-               if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
+               if (bfin_revid() < CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
                        printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
                               CPU, bfin_revid());
        }
index 1aa2c788e228399f3ab00912fc50296e052cbf71..bef025b074432d467f30bb5e56c79a099492c0ff 100644 (file)
@@ -59,7 +59,7 @@
 #endif
 
 
-#ifdef CONFIG_VERBOSE_DEBUG
+#ifdef CONFIG_DEBUG_VERBOSE
 #define verbose_printk(fmt, arg...) \
        printk(fmt, ##arg)
 #else
@@ -147,9 +147,12 @@ static void decode_address(char *buf, unsigned long address)
                                char *name = p->comm;
                                struct file *file = vma->vm_file;
 
-                               if (file)
-                                       name = d_path(&file->f_path, _tmpbuf,
+                               if (file) {
+                                       char *d_name = d_path(&file->f_path, _tmpbuf,
                                                      sizeof(_tmpbuf));
+                                       if (!IS_ERR(d_name))
+                                               name = d_name;
+                               }
 
                                /* FLAT does not have its text aligned to the start of
                                 * the map while FDPIC ELF does ...
@@ -571,7 +574,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
 #endif
                        panic("Kernel exception");
                } else {
-#ifdef CONFIG_VERBOSE_DEBUG
+#ifdef CONFIG_DEBUG_VERBOSE
                        unsigned long *stack;
                        /* Dump the user space stack */
                        stack = (unsigned long *)rdusp();
index db532181fbdeb9200a6d445b6f7fd940cd088830..a028e9450419b498c1f4741ec64e9a69dc945374 100644 (file)
  */
 .macro do_flush flushins:req optflushins optnopins label
 
+       R2 = -L1_CACHE_BYTES;
+
+       /* start = (start & -L1_CACHE_BYTES) */
+       R0 = R0 & R2;
+
        /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
        R1 += -1;
-       R2 = -L1_CACHE_BYTES;
        R1 = R1 & R2;
        R1 += L1_CACHE_BYTES;
 
@@ -63,7 +67,7 @@ ENDPROC(_blackfin_icache_flush_range)
 
 /* Flush all cache lines assocoiated with this area of memory. */
 ENTRY(_blackfin_icache_dcache_flush_range)
-       do_flush IFLUSH, FLUSH
+       do_flush FLUSH, IFLUSH
 ENDPROC(_blackfin_icache_dcache_flush_range)
 
 /* Throw away all D-cached data in specified region without any obligation to
index c22c47b601273771d71306bbfbb264a6c66b8605..dda5443b37ed7ef6ad0bb30d8d4c0f6621f54373 100644 (file)
@@ -72,13 +72,13 @@ unsigned int __bfin_cycles_mod;
 
 /**************************************************************************/
 
-static unsigned int bfin_getfreq(unsigned int cpu)
+static unsigned int bfin_getfreq_khz(unsigned int cpu)
 {
        /* The driver only support single cpu */
        if (cpu != 0)
                return -1;
 
-       return get_cclk();
+       return get_cclk() / 1000;
 }
 
 
@@ -96,7 +96,7 @@ static int bfin_target(struct cpufreq_policy *policy,
 
        cclk_hz = bfin_freq_table[index].frequency;
 
-       freqs.old = bfin_getfreq(0);
+       freqs.old = bfin_getfreq_khz(0);
        freqs.new = cclk_hz;
        freqs.cpu = 0;
 
@@ -137,8 +137,8 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
 
-       cclk = get_cclk();
-       sclk = get_sclk();
+       cclk = get_cclk() / 1000;
+       sclk = get_sclk() / 1000;
 
 #if ANOMALY_05000273 || (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_DCACHE))
        min_cclk = sclk * 2;
@@ -152,7 +152,7 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
                dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
                dpm_state_table[index].tscale =  (TIME_SCALE / (1 << csel)) - 1;
 
-               pr_debug("cpufreq: freq:%d csel:%d tscale:%d\n",
+               pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n",
                                                 bfin_freq_table[index].frequency,
                                                 dpm_state_table[index].csel,
                                                 dpm_state_table[index].tscale);
@@ -173,7 +173,7 @@ static struct freq_attr *bfin_freq_attr[] = {
 static struct cpufreq_driver bfin_driver = {
        .verify = bfin_verify_speed,
        .target = bfin_target,
-       .get = bfin_getfreq,
+       .get = bfin_getfreq_khz,
        .init = __bfin_cpu_init,
        .name = "bfin cpufreq",
        .owner = THIS_MODULE,
index c13fa8da28c7fbbd7aae0377358e9e10f9babff5..bde6dc4e2614d45e1d39bf6dfc27430a4952dab1 100644 (file)
@@ -277,7 +277,7 @@ ENTRY(_bfin_return_from_exception)
        p5.h = hi(ILAT);
        r6 = [p5];
        r7 = 0x20;              /* Did I just cause anther HW error? */
-       r7 = r7 & r1;
+       r6 = r7 & r6;
        CC = R7 == R6;
        if CC JUMP _double_fault;
 #endif
index 0f1ca6930c16bc651529c814a1727694943b5f78..cc6f336e7313b483f1b9b98af708e043409c31ce 100644 (file)
@@ -183,10 +183,10 @@ static void __init l2_sram_init(void)
                return;
        }
 
-       free_l2_sram_head.next->paddr = (void *)L2_START +
-               (_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
-       free_l2_sram_head.next->size = L2_LENGTH -
-               (_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
+       free_l2_sram_head.next->paddr =
+               (void *)L2_START + (_ebss_l2 - _stext_l2);
+       free_l2_sram_head.next->size =
+               L2_LENGTH - (_ebss_l2 - _stext_l2);
        free_l2_sram_head.next->pid = 0;
        free_l2_sram_head.next->next = NULL;
 
index 7e8a0d394e6184cbf63a5fb257befa4082ce0148..761ee0440c996a29d4fe784f56571e2cab3358ee 100644 (file)
@@ -133,7 +133,7 @@ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
 {
        int i;
 
-       BUG_ON(IRQ_USER + cnt >= NR_IRQS);
+       BUG_ON(IRQ_USER + cnt > NR_IRQS);
        m68k_first_user_vec = vec;
        for (i = 0; i < cnt; i++)
                irq_controller[IRQ_USER + i] = &user_irq_controller;
index 398cdbaf4e540f6e6bccffdb84a7fbc8a88e5e98..409e698f436117bd2a18468f8a26ead3cf400d16 100644 (file)
@@ -44,8 +44,6 @@ extern void arch_send_call_function_ipi(cpumask_t mask);
  
 #define PROC_CHANGE_PENALTY    15              /* Schedule penalty */
 
-extern unsigned long cpu_present_mask;
-
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 #else /* CONFIG_SMP */
index ed500ef799b795a21f322ae0d8e818b8bd926a36..08844fc24a2e7b8f042364e7e0bf44a0ca4bbb3c 100644 (file)
@@ -61,22 +61,25 @@ STACK_SIZE  = 1 << STACK_SHIFT
 
 #ifdef CONFIG_TRACE_IRQFLAGS
        .macro  TRACE_IRQS_ON
-       l       %r1,BASED(.Ltrace_irq_on)
+       basr    %r2,%r0
+       l       %r1,BASED(.Ltrace_irq_on_caller)
        basr    %r14,%r1
        .endm
 
        .macro  TRACE_IRQS_OFF
-       l       %r1,BASED(.Ltrace_irq_off)
+       basr    %r2,%r0
+       l       %r1,BASED(.Ltrace_irq_off_caller)
        basr    %r14,%r1
        .endm
 
        .macro  TRACE_IRQS_CHECK
+       basr    %r2,%r0
        tm      SP_PSW(%r15),0x03       # irqs enabled?
        jz      0f
-       l       %r1,BASED(.Ltrace_irq_on)
+       l       %r1,BASED(.Ltrace_irq_on_caller)
        basr    %r14,%r1
        j       1f
-0:     l       %r1,BASED(.Ltrace_irq_off)
+0:     l       %r1,BASED(.Ltrace_irq_off_caller)
        basr    %r14,%r1
 1:
        .endm
@@ -1113,9 +1116,12 @@ cleanup_io_leave_insn:
 .Lschedtail:   .long   schedule_tail
 .Lsysc_table:  .long   sys_call_table
 #ifdef CONFIG_TRACE_IRQFLAGS
-.Ltrace_irq_on: .long  trace_hardirqs_on
-.Ltrace_irq_off:
-               .long   trace_hardirqs_off
+.Ltrace_irq_on_caller:
+               .long   trace_hardirqs_on_caller
+.Ltrace_irq_off_caller:
+               .long   trace_hardirqs_off_caller
+#endif
+#ifdef CONFIG_LOCKDEP
 .Llockdep_sys_exit:
                .long   lockdep_sys_exit
 #endif
index d7ce150453f2865bfa4c9e99f53c03cda198442d..41aca06682aa19e294ac54160500da46594cb97a 100644 (file)
@@ -61,19 +61,22 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 
 #ifdef CONFIG_TRACE_IRQFLAGS
        .macro  TRACE_IRQS_ON
-        brasl  %r14,trace_hardirqs_on
+        basr   %r2,%r0
+        brasl  %r14,trace_hardirqs_on_caller
        .endm
 
        .macro  TRACE_IRQS_OFF
-        brasl  %r14,trace_hardirqs_off
+        basr   %r2,%r0
+        brasl  %r14,trace_hardirqs_off_caller
        .endm
 
        .macro TRACE_IRQS_CHECK
+       basr    %r2,%r0
        tm      SP_PSW(%r15),0x03       # irqs enabled?
        jz      0f
-       brasl   %r14,trace_hardirqs_on
+       brasl   %r14,trace_hardirqs_on_caller
        j       1f
-0:     brasl   %r14,trace_hardirqs_off
+0:     brasl   %r14,trace_hardirqs_off_caller
 1:
        .endm
 #else
index 3e2c05cb6a8733683c57d2935536ee936cc52059..04f8c67a610180413788684390d64bc613b8ca30 100644 (file)
@@ -136,9 +136,12 @@ static void default_idle(void)
                return;
        }
        trace_hardirqs_on();
+       /* Don't trace preempt off for idle. */
+       stop_critical_timings();
        /* Wait for external, I/O or machine check interrupt. */
        __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
                        PSW_MASK_IO | PSW_MASK_EXT);
+       start_critical_timings();
 }
 
 void cpu_idle(void)
index 62122bad1e3316f2112ae66c22e51859c7214b52..400b040df7fa05b1028bb9a9744e002957b29f5b 100644 (file)
@@ -604,13 +604,13 @@ setup_memory(void)
                if (memory_chunk[i].type != CHUNK_READ_WRITE)
                        continue;
                start_chunk = PFN_DOWN(memory_chunk[i].addr);
-               end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1;
+               end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size);
                end_chunk = min(end_chunk, end_pfn);
                if (start_chunk >= end_chunk)
                        continue;
                add_active_range(0, start_chunk, end_chunk);
                pfn = max(start_chunk, start_pfn);
-               for (; pfn <= end_chunk; pfn++)
+               for (; pfn < end_chunk; pfn++)
                        page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
        }
 
index 5fdb799062b7abfa1471488fd2582660cd56b08a..4fe952e557ac3bf683bb9535ff89b553035aad25 100644 (file)
@@ -198,7 +198,7 @@ asmlinkage long s390x_newuname(struct new_utsname __user *name)
 {
        int ret = sys_newuname(name);
 
-       if (current->personality == PER_LINUX32 && !ret) {
+       if (personality(current->personality) == PER_LINUX32 && !ret) {
                ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
                if (ret) ret = -EFAULT;
        }
index 632b13e100538704758cea2eebd75c6cfdc15bf7..a947899dcba1d55f56f8e00af05ab738293df6a3 100644 (file)
@@ -65,18 +65,21 @@ static int machine_has_topology_irq;
 static struct timer_list topology_timer;
 static void set_topology_timer(void);
 static DECLARE_WORK(topology_work, topology_work_fn);
+/* topology_lock protects the core linked list */
+static DEFINE_SPINLOCK(topology_lock);
 
 cpumask_t cpu_core_map[NR_CPUS];
 
 cpumask_t cpu_coregroup_map(unsigned int cpu)
 {
        struct core_info *core = &core_info;
+       unsigned long flags;
        cpumask_t mask;
 
        cpus_clear(mask);
        if (!machine_has_topology)
                return cpu_present_map;
-       mutex_lock(&smp_cpu_state_mutex);
+       spin_lock_irqsave(&topology_lock, flags);
        while (core) {
                if (cpu_isset(cpu, core->mask)) {
                        mask = core->mask;
@@ -84,7 +87,7 @@ cpumask_t cpu_coregroup_map(unsigned int cpu)
                }
                core = core->next;
        }
-       mutex_unlock(&smp_cpu_state_mutex);
+       spin_unlock_irqrestore(&topology_lock, flags);
        if (cpus_empty(mask))
                mask = cpumask_of_cpu(cpu);
        return mask;
@@ -133,7 +136,7 @@ static void tl_to_cores(struct tl_info *info)
        union tl_entry *tle, *end;
        struct core_info *core = &core_info;
 
-       mutex_lock(&smp_cpu_state_mutex);
+       spin_lock_irq(&topology_lock);
        clear_cores();
        tle = info->tle;
        end = (union tl_entry *)((unsigned long)info + info->length);
@@ -157,7 +160,7 @@ static void tl_to_cores(struct tl_info *info)
                }
                tle = next_tle(tle);
        }
-       mutex_unlock(&smp_cpu_state_mutex);
+       spin_unlock_irq(&topology_lock);
 }
 
 static void topology_update_polarization_simple(void)
index 436c28539577ebf75e9d0aefa0514faf2351ec83..65eaae34e753035209455a1916dc68cc4e7b22d6 100644 (file)
@@ -293,6 +293,10 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
  */
 #define xlate_dev_kmem_ptr(p)  p
 
+#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+int valid_phys_addr_range(unsigned long addr, size_t size);
+int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_SH_IO_H */
index 52220d70a096a378f7dd9c4fbbda635177f4b808..b517ae08b9c0f1794a3c72b52aec0cfe181e4294 100644 (file)
@@ -148,6 +148,12 @@ extern void paging_init(void);
 extern void page_table_range_init(unsigned long start, unsigned long end,
                                  pgd_t *pgd);
 
+#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_CPU_SH4) && defined(CONFIG_MMU)
+extern void kmap_coherent_init(void);
+#else
+#define kmap_coherent_init()   do { } while (0)
+#endif
+
 #include <asm-generic/pgtable.h>
 
 #endif /* __ASM_SH_PGTABLE_H */
index a7412cede534f6cd5e3ef16d060cf1324f8bcd4b..6d9e6972cfc9d8d1cecf57bffb3fe8ab9f72136e 100644 (file)
@@ -119,17 +119,17 @@ static struct plat_sci_port sci_platform_data[] = {
        },{
                .mapbase        = 0xa4e30000,
                .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_SCI,
+               .type           = PORT_SCIFA,
                .irqs           = { 56, 56, 56, 56 },
        },{
                .mapbase        = 0xa4e40000,
                .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_SCI,
+               .type           = PORT_SCIFA,
                .irqs           = { 88, 88, 88, 88 },
        },{
                .mapbase        = 0xa4e50000,
                .flags          = UPF_BOOT_AUTOCONF,
-               .type           = PORT_SCI,
+               .type           = PORT_SCIFA,
                .irqs           = { 109, 109, 109, 109 },
        }, {
                .flags = 0,
index 6b7d166694e28fecc3f949b66cb94ae8c2e53950..a952dcf9999d43bedbef8ff275aa3517fb13ab91 100644 (file)
@@ -75,6 +75,7 @@ static struct console bios_console = {
 #endif
 
 static struct uart_port scif_port = {
+       .type           = PORT_SCIF,
        .mapbase        = CONFIG_EARLY_SCIF_CONSOLE_PORT,
        .membase        = (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT,
 };
@@ -84,9 +85,9 @@ static void scif_sercon_putc(int c)
        while (((sci_in(&scif_port, SCFDR) & EPK_FIFO_BITS) >= EPK_FIFO_SIZE))
                ;
 
-       sci_out(&scif_port, SCxTDR, c);
        sci_in(&scif_port, SCxSR);
        sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40));
+       sci_out(&scif_port, SCxTDR, c);
 
        while ((sci_in(&scif_port, SCxSR) & 0x40) == 0)
                ;
index aaaf90d06b85f89237e776125c27fd43e6eb8064..3c61ddd4d43e0459c3cd4355133a486f328bea50 100644 (file)
@@ -120,7 +120,7 @@ static void tmu_set_mode(enum clock_event_mode mode,
 {
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR);
+               ctrl_outl(tmu_latest_interval[TMU0], TMU0_TCOR);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                ctrl_outl(0, TMU0_TCOR);
index 5d12e657be34e051b8ba2ab676cf472d58ffe77b..43de7e8e4e17df58849aef36e69dd28895e46bab 100644 (file)
@@ -80,6 +80,11 @@ ENTRY(copy_page)
        .section __ex_table, "a";       \
        .long 9999b, 6000f      ;       \
        .previous
+#define EX_NO_POP(...)                 \
+       9999: __VA_ARGS__ ;             \
+       .section __ex_table, "a";       \
+       .long 9999b, 6005f      ;       \
+       .previous
 ENTRY(__copy_user)
        ! Check if small number of bytes
        mov     #11,r0
@@ -139,9 +144,9 @@ EX( mov.b   r1,@r4          )
        bt      1f
 
 2:
-EX(    mov.b   @r5+,r0         )
+EX_NO_POP(     mov.b   @r5+,r0         )
        dt      r6
-EX(    mov.b   r0,@r4          )
+EX_NO_POP(     mov.b   r0,@r4          )
        bf/s    2b
         add    #1,r4
 
@@ -150,7 +155,7 @@ EX( mov.b   r0,@r4          )
 
 # Exception handler:
 .section .fixup, "ax"
-6000:
+6005:
        mov.l   8000f,r1
        mov     r3,r0
        jmp     @r1
index 70e0906023ccc80282d11f2264176c0fa34e907f..f066e76da2044fb9430c80ec2481546ad963c275 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the Linux SuperH-specific parts of the memory manager.
 #
 
-obj-y                  := init.o extable_32.o consistent.o
+obj-y                  := init.o extable_32.o consistent.o mmap.o
 
 ifndef CONFIG_CACHE_OFF
 cache-$(CONFIG_CPU_SH2)                := cache-sh2.o
index 0d92a8a3ac9a1e312870740b7d982e1eafebb021..9481d0f54efdd8a5fd6e76b86c72f12be906604f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the Linux SuperH-specific parts of the memory manager.
 #
 
-obj-y                  := init.o consistent.o
+obj-y                  := init.o consistent.o mmap.o
 
 mmu-y                  := tlb-nommu.o pg-nommu.o extable_32.o
 mmu-$(CONFIG_MMU)      := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o \
index 4abf00031daef8521e39d09a1d032f1d937b26af..6cbef8caeb560e69776579d5525bbad028e9aaec 100644 (file)
@@ -137,6 +137,7 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
 void __init paging_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES];
+       unsigned long vaddr;
        int nid;
 
        /* We don't need to map the kernel through the TLB, as
@@ -148,10 +149,15 @@ void __init paging_init(void)
         * check for a null value. */
        set_TTB(swapper_pg_dir);
 
-       /* Populate the relevant portions of swapper_pg_dir so that
+       /*
+        * Populate the relevant portions of swapper_pg_dir so that
         * we can use the fixmap entries without calling kmalloc.
-        * pte's will be filled in by __set_fixmap(). */
-       page_table_range_init(FIXADDR_START, FIXADDR_TOP, swapper_pg_dir);
+        * pte's will be filled in by __set_fixmap().
+        */
+       vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+       page_table_range_init(vaddr, 0, swapper_pg_dir);
+
+       kmap_coherent_init();
 
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
 
diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c
new file mode 100644 (file)
index 0000000..8837d51
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * arch/sh/mm/mmap.c
+ *
+ * Copyright (C) 2008  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+
+/*
+ * You really shouldn't be using read() or write() on /dev/mem.  This
+ * might go away in the future.
+ */
+int valid_phys_addr_range(unsigned long addr, size_t count)
+{
+       if (addr < __MEMORY_START)
+               return 0;
+       if (addr + count > __pa(high_memory))
+               return 0;
+
+       return 1;
+}
+
+int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
+{
+       return 1;
+}
index 38870e0fc182af3347ed90986d9fb3b31578fadb..2fe14da1f83909826d352249ba849488103fb4c2 100644 (file)
@@ -7,6 +7,7 @@
  * Released under the terms of the GNU GPL v2.0.
  */
 #include <linux/mm.h>
+#include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/fs.h>
 #include <linux/highmem.h>
 
 #define CACHE_ALIAS (current_cpu_data.dcache.alias_mask)
 
+#define kmap_get_fixmap_pte(vaddr)                                     \
+       pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr))
+
+static pte_t *kmap_coherent_pte;
+
+void __init kmap_coherent_init(void)
+{
+       unsigned long vaddr;
+
+       /* cache the first coherent kmap pte */
+       vaddr = __fix_to_virt(FIX_CMAP_BEGIN);
+       kmap_coherent_pte = kmap_get_fixmap_pte(vaddr);
+}
+
 static inline void *kmap_coherent(struct page *page, unsigned long addr)
 {
        enum fixed_addresses idx;
@@ -34,6 +49,8 @@ static inline void *kmap_coherent(struct page *page, unsigned long addr)
 
        update_mmu_cache(NULL, vaddr, pte);
 
+       set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte);
+
        return (void *)vaddr;
 }
 
index d6ca3e2754f5f37e792f3a060fed8bfc68a76305..d72dfed1f9d7e6fc67106f2a17aeeba8d8662d0a 100644 (file)
@@ -29,10 +29,11 @@ struct termios {
        tcflag_t c_cflag;               /* control mode flags */
        tcflag_t c_lflag;               /* local mode flags */
        cc_t c_line;                    /* line discipline */
+#ifndef __KERNEL__
        cc_t c_cc[NCCS];                /* control characters */
-#ifdef __KERNEL__
+#else
+       cc_t c_cc[NCCS+2];      /* kernel needs 2 more to hold vmin/vtime */
 #define SIZEOF_USER_TERMIOS sizeof (struct termios) - (2*sizeof (cc_t))
-       cc_t _x_cc[2];                  /* We need them to hold vmin/vtime */
 #endif
 };
 
@@ -42,8 +43,7 @@ struct termios2 {
        tcflag_t c_cflag;               /* control mode flags */
        tcflag_t c_lflag;               /* local mode flags */
        cc_t c_line;                    /* line discipline */
-       cc_t c_cc[NCCS];                /* control characters */
-       cc_t _x_cc[2];                  /* padding to match ktermios */
+       cc_t c_cc[NCCS+2];              /* control characters */
        speed_t c_ispeed;               /* input speed */
        speed_t c_ospeed;               /* output speed */
 };
@@ -54,8 +54,7 @@ struct ktermios {
        tcflag_t c_cflag;               /* control mode flags */
        tcflag_t c_lflag;               /* local mode flags */
        cc_t c_line;                    /* line discipline */
-       cc_t c_cc[NCCS];                /* control characters */
-       cc_t _x_cc[2];                  /* We need them to hold vmin/vtime */
+       cc_t c_cc[NCCS+2];              /* control characters */
        speed_t c_ispeed;               /* input speed */
        speed_t c_ospeed;               /* output speed */
 };
index 648643a9f139b62930a6fd39ab6f4b614bd74c92..0d13d2a4c76f6e0f63f005e01e077bd9f565f6de 100644 (file)
 #define __NR_dup3              320
 #define __NR_pipe2             321
 #define __NR_inotify_init1     322
+#define __NR_accept4           323
 
-#define NR_SYSCALLS            323
+#define NR_SYSCALLS            324
 
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
  * it never had the plain ones and there is no value to adding those
index c5cc0e052321850157df1edaf92b6020b5fb22d0..fa5d3c0343c7ee33d09111b3bfab4a987839fcc2 100644 (file)
 #define __NR_dup3              320
 #define __NR_pipe2             321
 #define __NR_inotify_init1     322
+#define __NR_accept4           323
 
-#define NR_SYSCALLS            323
+#define NR_SYSCALLS            324
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
index 0837bd52e28f454e2f4fc18aa003970caf3a455b..0a83bd737654de487ec0ab1e857c278352438902 100644 (file)
@@ -563,9 +563,9 @@ build_resources:
        op->dev.parent = parent;
        op->dev.bus = &of_platform_bus_type;
        if (!parent)
-               strcpy(op->dev.bus_id, "root");
+               dev_set_name(&op->dev, "root");
        else
-               sprintf(op->dev.bus_id, "%08x", dp->node);
+               dev_set_name(&op->dev, "%08x", dp->node);
 
        if (of_device_register(op)) {
                printk("%s: Could not register of device.\n",
index e1b9233b90ab3133587481322f30d3a260fc6569..7d0807586442dda4d837e58cc9ac419c10c6bc20 100644 (file)
@@ -81,4 +81,4 @@ sys_call_table:
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
 /*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
 /*315*/        .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1
+/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4
index ade18ba0c68634db858ce2e226e00236e5d2a428..f061c4dda9efb96dd5d8a6317169af88332b6720 100644 (file)
@@ -150,7 +150,7 @@ sys32_mmap2:
 sys32_socketcall:      /* %o0=call, %o1=args */
        cmp             %o0, 1
        bl,pn           %xcc, do_einval
-        cmp            %o0, 17
+        cmp            %o0, 18
        bg,pn           %xcc, do_einval
         sub            %o0, 1, %o0
        sllx            %o0, 5, %o0
@@ -319,6 +319,15 @@ do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int)
        nop
        nop
        nop
+do_sys_accept4: /* sys_accept4(int, struct sockaddr *, int *, int) */
+63:    ldswa           [%o1 + 0x0] %asi, %o0
+       sethi           %hi(sys_accept4), %g1
+64:    lduwa           [%o1 + 0x8] %asi, %o2
+65:    ldswa           [%o1 + 0xc] %asi, %o3
+       jmpl            %g1 + %lo(sys_accept4), %g0
+66:     lduwa          [%o1 + 0x4] %asi, %o1
+       nop
+       nop
 
        .section        __ex_table,"a"
        .align          4
@@ -353,4 +362,6 @@ do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int)
        .word           57b, __retl_efault, 58b, __retl_efault
        .word           59b, __retl_efault, 60b, __retl_efault
        .word           61b, __retl_efault, 62b, __retl_efault
+       .word           63b, __retl_efault, 64b, __retl_efault
+       .word           65b, __retl_efault, 66b, __retl_efault
        .previous
index b2fa4c1636387f2e40bf52a09c8d80bae7dce36c..9fc78cf354bd1f63e034ad46320ff4ed38fa2ee1 100644 (file)
@@ -82,7 +82,7 @@ sys_call_table32:
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
 /*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
        .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1
+/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4
 
 #endif /* CONFIG_COMPAT */
 
@@ -156,4 +156,4 @@ sys_call_table:
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
 /*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
        .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1
+/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4
index 4cf0ab13d187a943f88afc1d9761c739fee41008..ac22bb7719f730e6b8d12b305ec9e08952a513a4 100644 (file)
@@ -167,9 +167,12 @@ config GENERIC_PENDING_IRQ
 config X86_SMP
        bool
        depends on SMP && ((X86_32 && !X86_VOYAGER) || X86_64)
-       select USE_GENERIC_SMP_HELPERS
        default y
 
+config USE_GENERIC_SMP_HELPERS
+       def_bool y
+       depends on SMP
+
 config X86_32_SMP
        def_bool y
        depends on X86_32 && SMP
index e4a552d44465b88b0f422a5cb51fcfba23598751..0b500c5b6446e6690846fe9d13a0a5483bef2f20 100644 (file)
@@ -6,7 +6,6 @@ extern void no_iommu_init(void);
 extern struct dma_mapping_ops nommu_dma_ops;
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
-extern int dmar_disabled;
 
 extern unsigned long iommu_nr_pages(unsigned long addr, unsigned long len);
 
index 834b2c1d89fb1a51cb32a47f647ad8b1e3c1bc4d..d2e415e6666f63d314270ef57a26dae73e3fac01 100644 (file)
@@ -639,8 +639,8 @@ __SYSCALL(__NR_fallocate, sys_fallocate)
 __SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
 #define __NR_timerfd_gettime                   287
 __SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
-#define __NR_paccept                           288
-__SYSCALL(__NR_paccept, sys_paccept)
+#define __NR_accept4                           288
+__SYSCALL(__NR_accept4, sys_accept4)
 #define __NR_signalfd4                         289
 __SYSCALL(__NR_signalfd4, sys_signalfd4)
 #define __NR_eventfd2                          290
index 331b318304eb180d5e4f022253360d2c4efc49e6..e4899e0e878740726bfa7ea56e655c53a6b88f37 100644 (file)
@@ -537,7 +537,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
        address >>= PAGE_SHIFT;
        iommu_area_free(dom->bitmap, address, pages);
 
-       if (address + pages >= dom->next_bit)
+       if (address >= dom->next_bit)
                dom->need_flush = true;
 }
 
index 0cdcda35a05fbcd01d6d4b32f6ba935f6e9d7cb4..30ae2701b3df1b8976400d5996ed72a4a98baeea 100644 (file)
@@ -121,7 +121,7 @@ u16 amd_iommu_last_bdf;                     /* largest PCI device id we have
 LIST_HEAD(amd_iommu_unity_map);                /* a list of required unity mappings
                                           we find in ACPI */
 unsigned amd_iommu_aperture_order = 26; /* size of aperture in power of 2 */
-int amd_iommu_isolate;                 /* if 1, device isolation is enabled */
+int amd_iommu_isolate = 1;             /* if 1, device isolation is enabled */
 bool amd_iommu_unmap_flush;            /* if true, flush on every unmap */
 
 LIST_HEAD(amd_iommu_list);             /* list of all AMD IOMMUs in the
@@ -1213,7 +1213,9 @@ static int __init parse_amd_iommu_options(char *str)
        for (; *str; ++str) {
                if (strncmp(str, "isolate", 7) == 0)
                        amd_iommu_isolate = 1;
-               if (strncmp(str, "fullflush", 11) == 0)
+               if (strncmp(str, "share", 5) == 0)
+                       amd_iommu_isolate = 0;
+               if (strncmp(str, "fullflush", 9) == 0)
                        amd_iommu_unmap_flush = true;
        }
 
index 2b69994fd3a800458f4d81abbebad357405eac69..d1a121443bde5b571c2e853734b006cbb100fbcb 100644 (file)
@@ -236,17 +236,33 @@ static inline struct ds_context *ds_alloc_context(struct task_struct *task)
        struct ds_context *context = *p_context;
 
        if (!context) {
+               spin_unlock(&ds_lock);
+
                context = kzalloc(sizeof(*context), GFP_KERNEL);
 
-               if (!context)
+               if (!context) {
+                       spin_lock(&ds_lock);
                        return NULL;
+               }
 
                context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL);
                if (!context->ds) {
                        kfree(context);
+                       spin_lock(&ds_lock);
                        return NULL;
                }
 
+               spin_lock(&ds_lock);
+               /*
+                * Check for race - another CPU could have allocated
+                * it meanwhile:
+                */
+               if (*p_context) {
+                       kfree(context->ds);
+                       kfree(context);
+                       return *p_context;
+               }
+
                *p_context = context;
 
                context->this = p_context;
@@ -384,14 +400,15 @@ static int ds_request(struct task_struct *task, void *base, size_t size,
 
        spin_lock(&ds_lock);
 
-       if (!check_tracer(task))
-               return -EPERM;
-
        error = -ENOMEM;
        context = ds_alloc_context(task);
        if (!context)
                goto out_unlock;
 
+       error = -EPERM;
+       if (!check_tracer(task))
+               goto out_unlock;
+
        error = -EALREADY;
        if (context->owner[qual] == current)
                goto out_unlock;
index 3ce029ffaa55b2085ef4de993b427f86a3cdfdb7..1b894b72c0f5df35a1d489def584086ebb2affe5 100644 (file)
@@ -188,20 +188,6 @@ static void __init ati_bugs_contd(int num, int slot, int func)
 }
 #endif
 
-#ifdef CONFIG_DMAR
-static void __init intel_g33_dmar(int num, int slot, int func)
-{
-       struct acpi_table_header *dmar_tbl;
-       acpi_status status;
-
-       status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl);
-       if (ACPI_SUCCESS(status)) {
-               printk(KERN_INFO "BIOS BUG: DMAR advertised on Intel G31/G33 chipset -- ignoring\n");
-               dmar_disabled = 1;
-       }
-}
-#endif
-
 #define QFLAG_APPLY_ONCE       0x1
 #define QFLAG_APPLIED          0x2
 #define QFLAG_DONE             (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
@@ -225,10 +211,6 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
          PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
-#ifdef CONFIG_DMAR
-       { PCI_VENDOR_ID_INTEL, 0x29c0,
-         PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
-#endif
        {}
 };
 
index f454c78fcef6c7172db2fc0088548974f2f083e1..0aa2c443d600c64dcf5b4ac440c18bb4f3d0e9d9 100644 (file)
@@ -250,31 +250,24 @@ int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
        struct acpi_table_header *header = NULL;
        int i = 0;
-       acpi_size tbl_size;
 
-       while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) {
+       while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
                if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
                        struct oem_table *t = (struct oem_table *)header;
 
                        oem_addrX = t->OEMTableAddr;
                        oem_size = t->OEMTableSize;
-                       early_acpi_os_unmap_memory(header, tbl_size);
 
                        *oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
                                                                    oem_size);
                        return 0;
                }
-               early_acpi_os_unmap_memory(header, tbl_size);
        }
        return -1;
 }
 
 void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
 {
-       if (!oem_addr)
-               return;
-
-       __acpi_unmap_table((char *)oem_addr, oem_size);
 }
 #endif
 
index 0fa6790c1dd37d76e257de661ba3ed9312de89e0..9d5674f7b6ccbfbdef7f5ad16901f9dc9dc08ad0 100644 (file)
@@ -764,7 +764,7 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
                .callback = dmi_low_memory_corruption,
                .ident = "Phoenix BIOS",
                .matches = {
-                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"),
                },
        },
 #endif
index 9ffb01c31c40a8c9083e9949d065a442a62f46b7..1c0dfbca87c18a05beb42cebaa8e9ffed6d508a1 100644 (file)
@@ -46,7 +46,9 @@ static __cpuinit void check_tsc_warp(void)
        cycles_t start, now, prev, end;
        int i;
 
+       rdtsc_barrier();
        start = get_cycles();
+       rdtsc_barrier();
        /*
         * The measurement runs for 20 msecs:
         */
@@ -61,7 +63,9 @@ static __cpuinit void check_tsc_warp(void)
                 */
                __raw_spin_lock(&sync_lock);
                prev = last_tsc;
+               rdtsc_barrier();
                now = get_cycles();
+               rdtsc_barrier();
                last_tsc = now;
                __raw_spin_unlock(&sync_lock);
 
index 0e331652681e4a247122f2381861b0403f88b93c..52145007bd7efb8e99a9516ddeb09af6ea1e445b 100644 (file)
@@ -7,6 +7,7 @@
  * This file provides all the same external entries as smp.c but uses
  * the voyager hal to provide the functionality
  */
+#include <linux/cpu.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
@@ -1790,6 +1791,17 @@ void __init smp_setup_processor_id(void)
        x86_write_percpu(cpu_number, hard_smp_processor_id());
 }
 
+static void voyager_send_call_func(cpumask_t callmask)
+{
+       __u32 mask = cpus_addr(callmask)[0] & ~(1 << smp_processor_id());
+       send_CPI(mask, VIC_CALL_FUNCTION_CPI);
+}
+
+static void voyager_send_call_func_single(int cpu)
+{
+       send_CPI(1 << cpu, VIC_CALL_FUNCTION_SINGLE_CPI);
+}
+
 struct smp_ops smp_ops = {
        .smp_prepare_boot_cpu = voyager_smp_prepare_boot_cpu,
        .smp_prepare_cpus = voyager_smp_prepare_cpus,
@@ -1799,6 +1811,6 @@ struct smp_ops smp_ops = {
        .smp_send_stop = voyager_smp_send_stop,
        .smp_send_reschedule = voyager_smp_send_reschedule,
 
-       .send_call_func_ipi = native_send_call_func_ipi,
-       .send_call_func_single_ipi = native_send_call_func_single_ipi,
+       .send_call_func_ipi = voyager_send_call_func,
+       .send_call_func_single_ipi = voyager_send_call_func_single,
 };
index 4849fa36161eb697b47b08efa27af085b58bed3c..0f4b4b88181178b0344127df63af79f7d95da915 100644 (file)
@@ -217,6 +217,12 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                return PTR_ERR(bio);
 
        if (bio->bi_size != len) {
+               /*
+                * Grab an extra reference to this bio, as bio_unmap_user()
+                * expects to be able to drop it twice as it happens on the
+                * normal IO completion path
+                */
+               bio_get(bio);
                bio_endio(bio, 0);
                bio_unmap_user(bio);
                return -EINVAL;
index 4e5e7493f6764e8f3a03b62e40bd40b724d15880..27549e470da54d858e3bccd99946e2db2a311fa6 100644 (file)
@@ -768,6 +768,8 @@ static int __init genhd_device_init(void)
        bdev_map = kobj_map_init(base_probe, &block_class_lock);
        blk_dev_init();
 
+       register_blkdev(BLOCK_EXT_MAJOR, "blkext");
+
 #ifndef CONFIG_SYSFS_DEPRECATED
        /* create top-level block dir */
        block_depr = kobject_create_and_add("block", NULL);
index c832d639b6e254eb375d9c69504172182ab14c4d..d03985b04d6768bd0966c3c75f27b6a1336ede1b 100644 (file)
@@ -18,7 +18,6 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
        struct disk_part_iter piter;
        long long start, length;
        int partno;
-       int err;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -61,10 +60,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
                        disk_part_iter_exit(&piter);
 
                        /* all seems OK */
-                       err = add_partition(disk, partno, start, length,
-                                           ADDPART_FLAG_NONE);
+                       part = add_partition(disk, partno, start, length,
+                                            ADDPART_FLAG_NONE);
                        mutex_unlock(&bdev->bd_mutex);
-                       return err;
+                       return IS_ERR(part) ? PTR_ERR(part) : 0;
                case BLKPG_DEL_PARTITION:
                        part = disk_get_part(disk, partno);
                        if (!part)
index 64e591ba86f24fffd6251f9b65288e1b965da94b..4dbc2271acf5009cda80e48fdf19048f28b722a7 100644 (file)
@@ -366,7 +366,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
                           dev->wakeup.state.enabled ? "enabled" : "disabled");
                if (ldev)
                        seq_printf(seq, "%s:%s",
-                                  dev_name(ldev) ? ldev->bus->name : "no-bus",
+                                  ldev->bus ? ldev->bus->name : "no-bus",
                                   dev_name(ldev));
                seq_printf(seq, "\n");
                put_device(ldev);
index 4b47394863279606dc7427d79789bdc8c8485d99..9033d164c4ece13f876777fd7fbb549e4c27456b 100644 (file)
@@ -1227,10 +1227,19 @@ fsm_start:
                        /* ATA PIO protocol */
                        if (unlikely((status & ATA_DRQ) == 0)) {
                                /* handle BSY=0, DRQ=0 as error */
-                               if (likely(status & (ATA_ERR | ATA_DF)))
+                               if (likely(status & (ATA_ERR | ATA_DF))) {
                                        /* device stops HSM for abort/error */
                                        qc->err_mask |= AC_ERR_DEV;
-                               else {
+
+                                       /* If diagnostic failed and this is
+                                        * IDENTIFY, it's likely a phantom
+                                        * device.  Mark hint.
+                                        */
+                                       if (qc->dev->horkage &
+                                           ATA_HORKAGE_DIAGNOSTIC)
+                                               qc->err_mask |=
+                                                       AC_ERR_NODEV_HINT;
+                               } else {
                                        /* HSM violation. Let EH handle this.
                                         * Phantom devices also trigger this
                                         * condition.  Mark hint.
index 61ad8d639ba39830ee96687d2ef18d3fcba8cad4..0344a8a8321d130b3833681708426becdcfa45d1 100644 (file)
@@ -21,7 +21,8 @@ config BLK_DEV_FD
        ---help---
          If you want to use the floppy disk drive(s) of your PC under Linux,
          say Y. Information about this driver, especially important for IBM
-         Thinkpad users, is contained in <file:Documentation/floppy.txt>.
+         Thinkpad users, is contained in
+         <file:Documentation/blockdev/floppy.txt>.
          That file also contains the location of the Floppy driver FAQ as
          well as location of the fdutils package used to configure additional
          parameters of the driver at run time.
@@ -76,7 +77,7 @@ config PARIDE
          your computer's parallel port. Most of them are actually IDE devices
          using a parallel port IDE adapter. This option enables the PARIDE
          subsystem which contains drivers for many of these external drives.
-         Read <file:Documentation/paride.txt> for more information.
+         Read <file:Documentation/blockdev/paride.txt> for more information.
 
          If you have said Y to the "Parallel-port support" configuration
          option, you may share a single port between your printer and other
@@ -114,9 +115,9 @@ config BLK_CPQ_DA
        help
          This is the driver for Compaq Smart Array controllers.  Everyone
          using these boards should say Y here.  See the file
-         <file:Documentation/cpqarray.txt> for the current list of boards
-         supported by this driver, and for further information on the use of
-         this driver.
+         <file:Documentation/blockdev/cpqarray.txt> for the current list of
+         boards supported by this driver, and for further information on the
+         use of this driver.
 
 config BLK_CPQ_CISS_DA
        tristate "Compaq Smart Array 5xxx support"
@@ -124,7 +125,7 @@ config BLK_CPQ_CISS_DA
        help
          This is the driver for Compaq Smart Array 5xxx controllers.
          Everyone using these boards should say Y here.
-         See <file:Documentation/cciss.txt> for the current list of
+         See <file:Documentation/blockdev/cciss.txt> for the current list of
          boards supported by this driver, and for further information
          on the use of this driver.
 
@@ -135,7 +136,7 @@ config CISS_SCSI_TAPE
        help
          When enabled (Y), this option allows SCSI tape drives and SCSI medium
          changers (tape robots) to be accessed via a Compaq 5xxx array 
-         controller.  (See <file:Documentation/cciss.txt> for more details.)
+         controller.  (See <file:Documentation/blockdev/cciss.txt> for more details.)
 
          "SCSI support" and "SCSI tape support" must also be enabled for this 
          option to work.
@@ -149,8 +150,8 @@ config BLK_DEV_DAC960
        help
          This driver adds support for the Mylex DAC960, AcceleRAID, and
          eXtremeRAID PCI RAID controllers.  See the file
-         <file:Documentation/README.DAC960> for further information about
-         this driver.
+         <file:Documentation/blockdev/README.DAC960> for further information
+         about this driver.
 
          To compile this driver as a module, choose M here: the
          module will be called DAC960.
@@ -278,9 +279,9 @@ config BLK_DEV_NBD
          userland (making server and client physically the same computer,
          communicating using the loopback network device).
 
-         Read <file:Documentation/nbd.txt> for more information, especially
-         about where to find the server code, which runs in user space and
-         does not need special kernel support.
+         Read <file:Documentation/blockdev/nbd.txt> for more information,
+         especially about where to find the server code, which runs in user
+         space and does not need special kernel support.
 
          Note that this has nothing to do with the network file systems NFS
          or Coda; you can say N here even if you intend to use NFS or Coda.
@@ -321,8 +322,8 @@ config BLK_DEV_RAM
          store a copy of a minimal root file system off of a floppy into RAM
          during the initial install of Linux.
 
-         Note that the kernel command line option "ramdisk=XX" is now
-         obsolete. For details, read <file:Documentation/ramdisk.txt>.
+         Note that the kernel command line option "ramdisk=XX" is now obsolete.
+         For details, read <file:Documentation/blockdev/ramdisk.txt>.
 
          To compile this driver as a module, choose M here: the
          module will be called rd.
index 12de1fdaa6c68b76479cdfed53140e7188207449..9364dc554257e5af44a3a4a2aff7fc3f6598fa27 100644 (file)
@@ -2847,7 +2847,7 @@ static void do_cciss_request(struct request_queue *q)
                h->maxSG = seg;
 
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n",
+       printk(KERN_DEBUG "cciss: Submitting %lu sectors in %d segments\n",
               creq->nr_sectors, seg);
 #endif                         /* CCISS_DEBUG */
 
@@ -3197,7 +3197,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 
        c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
 #ifdef CCISS_DEBUG
-       printk("address 0 = %x\n", c->paddr);
+       printk("address 0 = %lx\n", c->paddr);
 #endif                         /* CCISS_DEBUG */
        c->vaddr = remap_pci_mem(c->paddr, 0x250);
 
@@ -3224,7 +3224,8 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 #endif                         /* CCISS_DEBUG */
        cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
 #ifdef CCISS_DEBUG
-       printk("cfg base address index = %x\n", cfg_base_addr_index);
+       printk("cfg base address index = %llx\n",
+               (unsigned long long)cfg_base_addr_index);
 #endif                         /* CCISS_DEBUG */
        if (cfg_base_addr_index == -1) {
                printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n");
@@ -3234,7 +3235,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 
        cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);
 #ifdef CCISS_DEBUG
-       printk("cfg offset = %x\n", cfg_offset);
+       printk("cfg offset = %llx\n", (unsigned long long)cfg_offset);
 #endif                         /* CCISS_DEBUG */
        c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
                                                       cfg_base_addr_index) +
index 14db747a636e93a33766e4faf23dbd5b48e5e8bd..cf29cc4e6ab73d2d95e6d4778f576aae9c98b327 100644 (file)
@@ -4124,7 +4124,7 @@ static int __init floppy_setup(char *str)
                printk("\n");
        } else
                DPRINT("botched floppy option\n");
-       DPRINT("Read Documentation/floppy.txt\n");
+       DPRINT("Read Documentation/blockdev/floppy.txt\n");
        return 0;
 }
 
index fccac18d311121d01f28ca4ce819886f79cf300f..048d71d244d7335d3e719e916632ef1a71079465 100644 (file)
@@ -1546,8 +1546,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 
 /*
  * Reset management
- * XXX Move usb_reset_device to khubd. Hogging kevent is not a good thing.
- * XXX Make usb_sync_reset asynchronous.
  */
 
 static void ub_reset_enter(struct ub_dev *sc, int try)
@@ -1632,6 +1630,22 @@ static void ub_reset_task(struct work_struct *work)
        spin_unlock_irqrestore(sc->lock, flags);
 }
 
+/*
+ * XXX Reset brackets are too much hassle to implement, so just stub them
+ * in order to prevent forced unbinding (which deadlocks solid when our
+ * ->disconnect method waits for the reset to complete and this kills keventd).
+ *
+ * XXX Tell Alan to move usb_unlock_device inside of usb_reset_device,
+ * or else the post_reset is invoked, and restats I/O on a locked device.
+ */
+static int ub_pre_reset(struct usb_interface *iface) {
+       return 0;
+}
+
+static int ub_post_reset(struct usb_interface *iface) {
+       return 0;
+}
+
 /*
  * This is called from a process context.
  */
@@ -2446,6 +2460,8 @@ static struct usb_driver ub_driver = {
        .probe =        ub_probe,
        .disconnect =   ub_disconnect,
        .id_table =     ub_usb_ids,
+       .pre_reset =    ub_pre_reset,
+       .post_reset =   ub_post_reset,
 };
 
 static int __init ub_init(void)
index b220c686089d82b5ffc41eada6efd59c7f7ca7e5..2d19f0cc47f272c5ae4f96ee97ea34a1bce5a407 100644 (file)
@@ -338,12 +338,18 @@ wait:
 static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 {
        struct request_queue *rq;
+       elevator_t *old_e;
 
        rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
        if (rq == NULL)
                return -1;
 
-       elevator_init(rq, "noop");
+       old_e = rq->elevator;
+       if (IS_ERR_VALUE(elevator_init(rq, "noop")))
+               printk(KERN_WARNING
+                       "blkfront: Switch elevator failed, use default\n");
+       else
+               elevator_exit(old_e);
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
        blk_queue_hardsect_size(rq, sector_size);
index 43b35d0369d6c9486b3f5d677313ece83218130c..43d6ba83a1912ccbc5f668876e8e6cf7a82a3066 100644 (file)
@@ -124,7 +124,7 @@ config COMPUTONE
          which give you many serial ports. You would need something like this
          to connect more than two modems to your Linux box, for instance in
          order to become a dial-in server. If you have a card like that, say
-         Y here and read <file:Documentation/computone.txt>.
+         Y here and read <file:Documentation/serial/computone.txt>.
 
          To compile this driver as module, choose M here: the
          module will be called ip2.
@@ -136,7 +136,7 @@ config ROCKETPORT
          This driver supports Comtrol RocketPort and RocketModem PCI boards.   
           These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
           modems.  For information about the RocketPort/RocketModem  boards
-          and this driver read <file:Documentation/rocket.txt>.
+          and this driver read <file:Documentation/serial/rocket.txt>.
 
          To compile this driver as a module, choose M here: the
          module will be called rocket.
@@ -154,7 +154,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:Documentation/README.cycladesZ>.
+         <file:Documentation/serial/README.cycladesZ>.
 
          To compile this driver as a module, choose M here: the
          module will be called cyclades.
@@ -183,7 +183,7 @@ config DIGIEPCA
          box, for instance in order to become a dial-in server. This driver
          supports the original PC (ISA) boards as well as PCI, and EISA. If
          you have a card like this, say Y here and read the file
-         <file:Documentation/digiepca.txt>.
+         <file:Documentation/serial/digiepca.txt>.
 
          To compile this driver as a module, choose M here: the
          module will be called epca.
@@ -289,7 +289,7 @@ config RISCOM8
          which gives you many serial ports. You would need something like
          this to connect more than two modems to your Linux box, for instance
          in order to become a dial-in server. If you have a card like that,
-         say Y here and read the file <file:Documentation/riscom8.txt>.
+         say Y here and read the file <file:Documentation/serial/riscom8.txt>.
 
          Also it's possible to say M here and compile this driver as kernel
          loadable module; the module will be called riscom8.
@@ -304,8 +304,8 @@ config SPECIALIX
          your Linux box, for instance in order to become a dial-in server.
 
          If you have a card like that, say Y here and read the file
-         <file:Documentation/specialix.txt>. Also it's possible to say M here
-         and compile this driver as kernel loadable module which will be
+         <file:Documentation/serial/specialix.txt>. Also it's possible to say
+         M here and compile this driver as kernel loadable module which will be
          called specialix.
 
 config SX
@@ -313,7 +313,7 @@ config SX
        depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
        help
          This is a driver for the SX and SI multiport serial cards.
-         Please read the file <file:Documentation/sx.txt> for details.
+         Please read the file <file:Documentation/serial/sx.txt> for details.
 
          This driver can only be built as a module ( = code which can be
          inserted in and removed from the running kernel whenever you want).
@@ -344,8 +344,8 @@ config STALDRV
          like this to connect more than two modems to your Linux box, for
          instance in order to become a dial-in server.  If you say Y here,
          you will be asked for your specific card model in the next
-         questions.  Make sure to read <file:Documentation/stallion.txt> in
-         this case.  If you have never heard about all this, it's safe to
+         questions.  Make sure to read <file:Documentation/serial/stallion.txt>
+         in this case.  If you have never heard about all this, it's safe to
          say N.
 
 config STALLION
@@ -354,7 +354,7 @@ config STALLION
        help
          If you have an EasyIO or EasyConnection 8/32 multiport Stallion
          card, then this is for you; say Y.  Make sure to read
-         <file:Documentation/stallion.txt>.
+         <file:Documentation/serial/stallion.txt>.
 
          To compile this driver as a module, choose M here: the
          module will be called stallion.
@@ -365,7 +365,7 @@ config ISTALLION
        help
          If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
          serial multiport card, say Y here. Make sure to read
-         <file:Documentation/stallion.txt>.
+         <file:Documentation/serial/stallion.txt>.
 
          To compile this driver as a module, choose M here: the
          module will be called istallion.
index 8a59aaa21be5c79e337802eba20cc0e5ac860f67..7a88dfd4427b136c6e034b06d4f6e6e3a416cd39 100644 (file)
@@ -422,9 +422,11 @@ struct ipmi_smi {
 /**
  * The driver model view of the IPMI messaging driver.
  */
-static struct device_driver ipmidriver = {
-       .name = "ipmi",
-       .bus = &platform_bus_type
+static struct platform_driver ipmidriver = {
+       .driver = {
+               .name = "ipmi",
+               .bus = &platform_bus_type
+       }
 };
 static DEFINE_MUTEX(ipmidriver_mutex);
 
@@ -2384,9 +2386,9 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
         * representing the interfaced BMC already
         */
        if (bmc->guid_set)
-               old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
+               old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid);
        else
-               old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
+               old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver,
                                                    bmc->id.product_id,
                                                    bmc->id.device_id);
 
@@ -2416,7 +2418,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
                snprintf(name, sizeof(name),
                         "ipmi_bmc.%4.4x", bmc->id.product_id);
 
-               while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
+               while (ipmi_find_bmc_prod_dev_id(&ipmidriver.driver,
                                                 bmc->id.product_id,
                                                 bmc->id.device_id)) {
                        if (!warn_printed) {
@@ -2446,7 +2448,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
                               " Unable to allocate platform device\n");
                        return -ENOMEM;
                }
-               bmc->dev->dev.driver = &ipmidriver;
+               bmc->dev->dev.driver = &ipmidriver.driver;
                dev_set_drvdata(&bmc->dev->dev, bmc);
                kref_init(&bmc->refcount);
 
@@ -4247,7 +4249,7 @@ static int ipmi_init_msghandler(void)
        if (initialized)
                return 0;
 
-       rv = driver_register(&ipmidriver);
+       rv = driver_register(&ipmidriver.driver);
        if (rv) {
                printk(KERN_ERR PFX "Could not register IPMI driver\n");
                return rv;
@@ -4308,7 +4310,7 @@ static __exit void cleanup_ipmi(void)
        remove_proc_entry(proc_ipmi_root->name, NULL);
 #endif /* CONFIG_PROC_FS */
 
-       driver_unregister(&ipmidriver);
+       driver_unregister(&ipmidriver.driver);
 
        initialized = 0;
 
index 3123bf57ad91365039b9b227dc8fb3182a944c06..3000135f2ead3bcd98cd505b7fa89f11d0d2ab5e 100644 (file)
@@ -114,9 +114,11 @@ static char *si_to_str[] = { "kcs", "smic", "bt" };
 
 #define DEVICE_NAME "ipmi_si"
 
-static struct device_driver ipmi_driver = {
-       .name = DEVICE_NAME,
-       .bus = &platform_bus_type
+static struct platform_driver ipmi_driver = {
+       .driver = {
+               .name = DEVICE_NAME,
+               .bus = &platform_bus_type
+       }
 };
 
 
@@ -2868,7 +2870,7 @@ static int try_smi_init(struct smi_info *new_smi)
                        goto out_err;
                }
                new_smi->dev = &new_smi->pdev->dev;
-               new_smi->dev->driver = &ipmi_driver;
+               new_smi->dev->driver = &ipmi_driver.driver;
 
                rv = platform_device_add(new_smi->pdev);
                if (rv) {
@@ -2983,7 +2985,7 @@ static __devinit int init_ipmi_si(void)
        initialized = 1;
 
        /* Register the device drivers. */
-       rv = driver_register(&ipmi_driver);
+       rv = driver_register(&ipmi_driver.driver);
        if (rv) {
                printk(KERN_ERR
                       "init_ipmi_si: Unable to register driver: %d\n",
@@ -3052,7 +3054,7 @@ static __devinit int init_ipmi_si(void)
 #ifdef CONFIG_PPC_OF
                of_unregister_platform_driver(&ipmi_of_platform_driver);
 #endif
-               driver_unregister(&ipmi_driver);
+               driver_unregister(&ipmi_driver.driver);
                printk(KERN_WARNING
                       "ipmi_si: Unable to find any System Interface(s)\n");
                return -ENODEV;
@@ -3151,7 +3153,7 @@ static __exit void cleanup_ipmi_si(void)
                cleanup_one_si(e);
        mutex_unlock(&smi_infos_lock);
 
-       driver_unregister(&ipmi_driver);
+       driver_unregister(&ipmi_driver.driver);
 }
 module_exit(cleanup_ipmi_si);
 
index 242fd46fda22fef8747909efb71f29b8ded4c157..a16b94f12eb23e1fea8b99bfd6621a0b1bc8b7cd 100644 (file)
@@ -72,7 +72,7 @@
 /*
  * There is a bunch of documentation about the card, jumpers, config
  * settings, restrictions, cables, device names and numbers in
- * Documentation/specialix.txt
+ * Documentation/serial/specialix.txt
  */
 
 #include <linux/module.h>
index dc003a3a787d545207fed8be6e81bb4aacd970c1..5317e08221ecb2a34e699c77bac4f72a505f59e6 100644 (file)
@@ -399,8 +399,8 @@ int dma_async_device_register(struct dma_device *device)
                chan->chan_id = chancnt++;
                chan->dev.class = &dma_devclass;
                chan->dev.parent = device->dev;
-               snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d",
-                        device->dev_id, chan->chan_id);
+               dev_set_name(&chan->dev, "dma%dchan%d",
+                            device->dev_id, chan->chan_id);
 
                rc = device_register(&chan->dev);
                if (rc) {
index d1e381e35a9e1887e79667d3df734d3dd37ad5b9..ed9636bfb54af0e1805ed3ab4dc039b59e434213 100644 (file)
@@ -20,11 +20,11 @@ static unsigned int test_buf_size = 16384;
 module_param(test_buf_size, uint, S_IRUGO);
 MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
 
-static char test_channel[BUS_ID_SIZE];
+static char test_channel[20];
 module_param_string(channel, test_channel, sizeof(test_channel), S_IRUGO);
 MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
 
-static char test_device[BUS_ID_SIZE];
+static char test_device[20];
 module_param_string(device, test_device, sizeof(test_device), S_IRUGO);
 MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
 
@@ -80,14 +80,14 @@ static bool dmatest_match_channel(struct dma_chan *chan)
 {
        if (test_channel[0] == '\0')
                return true;
-       return strcmp(chan->dev.bus_id, test_channel) == 0;
+       return strcmp(dev_name(&chan->dev), test_channel) == 0;
 }
 
 static bool dmatest_match_device(struct dma_device *device)
 {
        if (test_device[0] == '\0')
                return true;
-       return strcmp(device->dev->bus_id, test_device) == 0;
+       return strcmp(dev_name(device->dev), test_device) == 0;
 }
 
 static unsigned long dmatest_random(void)
@@ -332,7 +332,7 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
 
        dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
        if (!dtc) {
-               pr_warning("dmatest: No memory for %s\n", chan->dev.bus_id);
+               pr_warning("dmatest: No memory for %s\n", dev_name(&chan->dev));
                return DMA_NAK;
        }
 
@@ -343,16 +343,16 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
                thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
                if (!thread) {
                        pr_warning("dmatest: No memory for %s-test%u\n",
-                                       chan->dev.bus_id, i);
+                                  dev_name(&chan->dev), i);
                        break;
                }
                thread->chan = dtc->chan;
                smp_wmb();
                thread->task = kthread_run(dmatest_func, thread, "%s-test%u",
-                               chan->dev.bus_id, i);
+                               dev_name(&chan->dev), i);
                if (IS_ERR(thread->task)) {
                        pr_warning("dmatest: Failed to run thread %s-test%u\n",
-                                       chan->dev.bus_id, i);
+                                       dev_name(&chan->dev), i);
                        kfree(thread);
                        break;
                }
@@ -362,7 +362,7 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
                list_add_tail(&thread->node, &dtc->threads);
        }
 
-       pr_info("dmatest: Started %u threads using %s\n", i, chan->dev.bus_id);
+       pr_info("dmatest: Started %u threads using %s\n", i, dev_name(&chan->dev));
 
        list_add_tail(&dtc->node, &dmatest_channels);
        nr_channels++;
@@ -379,7 +379,7 @@ static enum dma_state_client dmatest_remove_channel(struct dma_chan *chan)
                        list_del(&dtc->node);
                        dmatest_cleanup_channel(dtc);
                        pr_debug("dmatest: lost channel %s\n",
-                                       chan->dev.bus_id);
+                                       dev_name(&chan->dev));
                        return DMA_ACK;
                }
        }
@@ -418,7 +418,7 @@ dmatest_event(struct dma_client *client, struct dma_chan *chan,
 
        default:
                pr_info("dmatest: Unhandled event %u (%s)\n",
-                               state, chan->dev.bus_id);
+                               state, dev_name(&chan->dev));
                break;
        }
 
index 71fba82462cb98372568a2f2da6c8c325e1a10d8..c7a9306d951d2c61f622c601ef2d49af422b679e 100644 (file)
@@ -411,6 +411,7 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
        int slot_cnt;
        int slots_per_op;
        dma_cookie_t cookie;
+       dma_addr_t next_dma;
 
        grp_start = sw_desc->group_head;
        slot_cnt = grp_start->slot_cnt;
@@ -425,12 +426,12 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
                         &old_chain_tail->chain_node);
 
        /* fix up the hardware chain */
-       iop_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys);
+       next_dma = grp_start->async_tx.phys;
+       iop_desc_set_next_desc(old_chain_tail, next_dma);
+       BUG_ON(iop_desc_get_next_desc(old_chain_tail) != next_dma); /* flush */
 
-       /* 1/ don't add pre-chained descriptors
-        * 2/ dummy read to flush next_desc write
-        */
-       BUG_ON(iop_desc_get_next_desc(sw_desc));
+       /* check for pre-chained descriptors */
+       iop_paranoia(iop_desc_get_next_desc(sw_desc));
 
        /* increment the pending count by the number of slots
         * memcpy operations have a 1:1 (slot:operation) relation
index f0d9b415db50741bc18f73614be3e7730623b411..d335086f4a265c98cec4300ce2dc5e16d3137e35 100644 (file)
@@ -1381,6 +1381,7 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
+       kobject_get(&mci->edac_mci_kobj);
        debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
 
        mci->dev = &pdev->dev;  /* record ptr  to the generic device */
@@ -1453,6 +1454,7 @@ fail1:
        i5000_put_devices(mci);
 
 fail0:
+       kobject_put(&mci->edac_mci_kobj);
        edac_mc_free(mci);
        return -ENODEV;
 }
@@ -1498,7 +1500,7 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 
        /* retrieve references to resources, and free those resources */
        i5000_put_devices(mci);
-
+       kobject_put(&mci->edac_mci_kobj);
        edac_mc_free(mci);
 }
 
index 7f2ee27fe76be15a947db4f5fdf1f7690cbe4caa..48f49d93d249d8155fbdc1973310fab28319e6f3 100644 (file)
@@ -65,6 +65,14 @@ config GPIO_SYSFS
 
 # put expanders in the right section, in alphabetical order
 
+comment "Memory mapped GPIO expanders:"
+
+config GPIO_XILINX
+       bool "Xilinx GPIO support"
+       depends on PPC_OF
+       help
+         Say yes here to support the Xilinx FPGA GPIO device
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX732X
index 6aafdeb9ad03c04a4e932c33c7ff3d7f53954cd4..49ac64e515e6690a02fc96a33fa879a6cf0135d1 100644 (file)
@@ -10,4 +10,5 @@ obj-$(CONFIG_GPIO_MCP23S08)   += mcp23s08.o
 obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
 obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
+obj-$(CONFIG_GPIO_XILINX)      += xilinx_gpio.o
 obj-$(CONFIG_GPIO_BT8XX)       += bt8xxgpio.o
index faa1cc66e9cf43a527beb4ce824d966dc407b494..82020abc329efab1d95f56a1d67e71db2122dc1b 100644 (file)
@@ -1134,7 +1134,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                        continue;
 
                is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
-               seq_printf(s, " gpio-%-3d (%-12s) %s %s",
+               seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
                        gpio, gdesc->label,
                        is_out ? "out" : "in ",
                        chip->get
diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c
new file mode 100644 (file)
index 0000000..3c1177a
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Xilinx gpio driver
+ *
+ * Copyright 2008 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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/init.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+/* Register Offset Definitions */
+#define XGPIO_DATA_OFFSET   (0x0)      /* Data register  */
+#define XGPIO_TRI_OFFSET    (0x4)      /* I/O direction register  */
+
+struct xgpio_instance {
+       struct of_mm_gpio_chip mmchip;
+       u32 gpio_state;         /* GPIO state shadow register */
+       u32 gpio_dir;           /* GPIO direction shadow register */
+       spinlock_t gpio_lock;   /* Lock used for synchronization */
+};
+
+/**
+ * xgpio_get - Read the specified signal of the GPIO device.
+ * @gc:     Pointer to gpio_chip device structure.
+ * @gpio:   GPIO signal number.
+ *
+ * This function reads the specified signal of the GPIO device. It returns 0 if
+ * the signal clear, 1 if signal is set or negative value on error.
+ */
+static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+
+       return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
+}
+
+/**
+ * xgpio_set - Write the specified signal of the GPIO device.
+ * @gc:     Pointer to gpio_chip device structure.
+ * @gpio:   GPIO signal number.
+ * @val:    Value to be written to specified signal.
+ *
+ * This function writes the specified value in to the specified signal of the
+ * GPIO device.
+ */
+static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       unsigned long flags;
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct xgpio_instance *chip =
+           container_of(mm_gc, struct xgpio_instance, mmchip);
+
+       spin_lock_irqsave(&chip->gpio_lock, flags);
+
+       /* Write to GPIO signal and set its direction to output */
+       if (val)
+               chip->gpio_state |= 1 << gpio;
+       else
+               chip->gpio_state &= ~(1 << gpio);
+       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+
+       spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+/**
+ * xgpio_dir_in - Set the direction of the specified GPIO signal as input.
+ * @gc:     Pointer to gpio_chip device structure.
+ * @gpio:   GPIO signal number.
+ *
+ * This function sets the direction of specified GPIO signal as input.
+ * It returns 0 if direction of GPIO signals is set as input otherwise it
+ * returns negative error value.
+ */
+static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+       unsigned long flags;
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct xgpio_instance *chip =
+           container_of(mm_gc, struct xgpio_instance, mmchip);
+
+       spin_lock_irqsave(&chip->gpio_lock, flags);
+
+       /* Set the GPIO bit in shadow register and set direction as input */
+       chip->gpio_dir |= (1 << gpio);
+       out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+
+       spin_unlock_irqrestore(&chip->gpio_lock, flags);
+
+       return 0;
+}
+
+/**
+ * xgpio_dir_out - Set the direction of the specified GPIO signal as output.
+ * @gc:     Pointer to gpio_chip device structure.
+ * @gpio:   GPIO signal number.
+ * @val:    Value to be written to specified signal.
+ *
+ * This function sets the direction of specified GPIO signal as output. If all
+ * GPIO signals of GPIO chip is configured as input then it returns
+ * error otherwise it returns 0.
+ */
+static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       unsigned long flags;
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct xgpio_instance *chip =
+           container_of(mm_gc, struct xgpio_instance, mmchip);
+
+       spin_lock_irqsave(&chip->gpio_lock, flags);
+
+       /* Write state of GPIO signal */
+       if (val)
+               chip->gpio_state |= 1 << gpio;
+       else
+               chip->gpio_state &= ~(1 << gpio);
+       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+
+       /* Clear the GPIO bit in shadow register and set direction as output */
+       chip->gpio_dir &= (~(1 << gpio));
+       out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+
+       spin_unlock_irqrestore(&chip->gpio_lock, flags);
+
+       return 0;
+}
+
+/**
+ * xgpio_save_regs - Set initial values of GPIO pins
+ * @mm_gc: pointer to memory mapped GPIO chip structure
+ */
+static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+       struct xgpio_instance *chip =
+           container_of(mm_gc, struct xgpio_instance, mmchip);
+
+       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+       out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+}
+
+/**
+ * xgpio_of_probe - Probe method for the GPIO device.
+ * @np: pointer to device tree node
+ *
+ * This function probes the GPIO device in the device tree. It initializes the
+ * driver data structure. It returns 0, if the driver is bound to the GPIO
+ * device, or a negative value if there is an error.
+ */
+static int __devinit xgpio_of_probe(struct device_node *np)
+{
+       struct xgpio_instance *chip;
+       struct of_gpio_chip *ofchip;
+       int status = 0;
+       const u32 *tree_info;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+       ofchip = &chip->mmchip.of_gc;
+
+       /* Update GPIO state shadow register with default value */
+       tree_info = of_get_property(np, "xlnx,dout-default", NULL);
+       if (tree_info)
+               chip->gpio_state = *tree_info;
+
+       /* Update GPIO direction shadow register with default value */
+       chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
+       tree_info = of_get_property(np, "xlnx,tri-default", NULL);
+       if (tree_info)
+               chip->gpio_dir = *tree_info;
+
+       /* Check device node and parent device node for device width */
+       ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */
+       tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
+       if (!tree_info)
+               tree_info = of_get_property(np->parent,
+                                           "xlnx,gpio-width", NULL);
+       if (tree_info)
+               ofchip->gc.ngpio = *tree_info;
+
+       spin_lock_init(&chip->gpio_lock);
+
+       ofchip->gpio_cells = 2;
+       ofchip->gc.direction_input = xgpio_dir_in;
+       ofchip->gc.direction_output = xgpio_dir_out;
+       ofchip->gc.get = xgpio_get;
+       ofchip->gc.set = xgpio_set;
+
+       chip->mmchip.save_regs = xgpio_save_regs;
+
+       /* Call the OF gpio helper to setup and register the GPIO device */
+       status = of_mm_gpiochip_add(np, &chip->mmchip);
+       if (status) {
+               kfree(chip);
+               pr_err("%s: error in probe function with status %d\n",
+                      np->full_name, status);
+               return status;
+       }
+       pr_info("XGpio: %s: registered\n", np->full_name);
+       return 0;
+}
+
+static struct of_device_id xgpio_of_match[] __devinitdata = {
+       { .compatible = "xlnx,xps-gpio-1.00.a", },
+       { /* end of list */ },
+};
+
+static int __init xgpio_init(void)
+{
+       struct device_node *np;
+
+       for_each_matching_node(np, xgpio_of_match)
+               xgpio_of_probe(np);
+
+       return 0;
+}
+
+/* Make sure we get initialized before anyone else tries to use us */
+subsys_initcall(xgpio_init);
+/* No exit call at the moment as we cannot unregister of GPIO chips */
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx GPIO driver");
+MODULE_LICENSE("GPL");
index c6ab4ba60c52a296035b6d23cf7b0e9c4f0b4970..9b97795e45ad71dd604d55fe8ddd7f5ca460b3ee 100644 (file)
@@ -55,10 +55,11 @@ struct apple_key_translation {
 
 static struct apple_key_translation apple_fn_keys[] = {
        { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
        { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
        { KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
-       { KEY_F3,       KEY_FN_F5,          APPLE_FLAG_FKEY }, /* Exposé */
-       { KEY_F4,       KEY_FN_F4,          APPLE_FLAG_FKEY }, /* Dashboard */
+       { KEY_F3,       KEY_SCALE,          APPLE_FLAG_FKEY },
+       { KEY_F4,       KEY_DASHBOARD,      APPLE_FLAG_FKEY },
        { KEY_F5,       KEY_KBDILLUMDOWN,   APPLE_FLAG_FKEY },
        { KEY_F6,       KEY_KBDILLUMUP,     APPLE_FLAG_FKEY },
        { KEY_F7,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
@@ -418,6 +419,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
index d3671b4049c0ef4077f1cb68e2e38e8c27c198be..147ec591a8061df0b57e0741428cc46c046cfaeb 100644 (file)
@@ -1250,9 +1250,11 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
@@ -1265,7 +1267,6 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERIC_13BA, USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
@@ -1409,6 +1410,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
        { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
@@ -1486,6 +1488,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
        { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
@@ -1573,6 +1576,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
@@ -1730,7 +1736,7 @@ static int __init hid_init(void)
                goto err_bus;
 
 #ifdef CONFIG_HID_COMPAT
-       hid_compat_wq = create_workqueue("hid_compat");
+       hid_compat_wq = create_singlethread_workqueue("hid_compat");
        if (!hid_compat_wq) {
                hidraw_exit();
                goto err;
index f05bcbbbb0d5457e060c37852b57fdfba486d12f..d70075dd3d81579e21e704acc1556b33cf874310 100644 (file)
@@ -82,6 +82,9 @@
 #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI   0x0230
 #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO    0x0231
 #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS    0x0232
+#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI   0x0236
+#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO    0x0237
+#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS    0x0238
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL      0x8241
index 894d52e05bf9cd995586250011e8401227bd043a..7685ae6808c4d056ff00c8c33ebe544bb4e09167 100644 (file)
@@ -38,7 +38,7 @@ static int hidraw_major;
 static struct cdev hidraw_cdev;
 static struct class *hidraw_class;
 static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
-static DEFINE_SPINLOCK(minors_lock);
+static DEFINE_MUTEX(minors_lock);
 
 static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
@@ -159,13 +159,13 @@ static int hidraw_open(struct inode *inode, struct file *file)
        struct hidraw_list *list;
        int err = 0;
 
-       lock_kernel();
        if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
                err = -ENOMEM;
                goto out;
        }
 
-       spin_lock(&minors_lock);
+       lock_kernel();
+       mutex_lock(&minors_lock);
        if (!hidraw_table[minor]) {
                printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
                                minor);
@@ -180,13 +180,16 @@ static int hidraw_open(struct inode *inode, struct file *file)
        file->private_data = list;
 
        dev = hidraw_table[minor];
-       if (!dev->open++)
-               dev->hid->ll_driver->open(dev->hid);
+       if (!dev->open++) {
+               err = dev->hid->ll_driver->open(dev->hid);
+               if (err < 0)
+                       dev->open--;
+       }
 
 out_unlock:
-       spin_unlock(&minors_lock);
-out:
+       mutex_unlock(&minors_lock);
        unlock_kernel();
+out:
        return err;
 
 }
@@ -310,7 +313,7 @@ int hidraw_connect(struct hid_device *hid)
 
        result = -EINVAL;
 
-       spin_lock(&minors_lock);
+       mutex_lock(&minors_lock);
 
        for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
                if (hidraw_table[minor])
@@ -320,9 +323,8 @@ int hidraw_connect(struct hid_device *hid)
                break;
        }
 
-       spin_unlock(&minors_lock);
-
        if (result) {
+               mutex_unlock(&minors_lock);
                kfree(dev);
                goto out;
        }
@@ -331,14 +333,14 @@ int hidraw_connect(struct hid_device *hid)
                                 NULL, "%s%d", "hidraw", minor);
 
        if (IS_ERR(dev->dev)) {
-               spin_lock(&minors_lock);
                hidraw_table[minor] = NULL;
-               spin_unlock(&minors_lock);
+               mutex_unlock(&minors_lock);
                result = PTR_ERR(dev->dev);
                kfree(dev);
                goto out;
        }
 
+       mutex_unlock(&minors_lock);
        init_waitqueue_head(&dev->wait);
        INIT_LIST_HEAD(&dev->list);
 
@@ -360,9 +362,9 @@ void hidraw_disconnect(struct hid_device *hid)
 
        hidraw->exist = 0;
 
-       spin_lock(&minors_lock);
+       mutex_lock(&minors_lock);
        hidraw_table[hidraw->minor] = NULL;
-       spin_unlock(&minors_lock);
+       mutex_unlock(&minors_lock);
 
        device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 
index 18e5ddd722cd5887d71c38d2cbfbf46e20553f1a..d746bf8284dd31994999916a72cab2f2c753b8a0 100644 (file)
@@ -781,6 +781,8 @@ static int usbhid_start(struct hid_device *hid)
        unsigned int n, insize = 0;
        int ret;
 
+       clear_bit(HID_DISCONNECTED, &usbhid->iofl);
+
        usbhid->bufsize = HID_MIN_BUFFER_SIZE;
        hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
        hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
@@ -847,12 +849,6 @@ static int usbhid_start(struct hid_device *hid)
                }
        }
 
-       if (!usbhid->urbin) {
-               err_hid("couldn't find an input interrupt endpoint");
-               ret = -ENODEV;
-               goto fail;
-       }
-
        init_waitqueue_head(&usbhid->wait);
        INIT_WORK(&usbhid->reset_work, hid_reset);
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
@@ -888,6 +884,9 @@ fail:
        usb_free_urb(usbhid->urbin);
        usb_free_urb(usbhid->urbout);
        usb_free_urb(usbhid->urbctrl);
+       usbhid->urbin = NULL;
+       usbhid->urbout = NULL;
+       usbhid->urbctrl = NULL;
        hid_free_buffers(dev, hid);
        mutex_unlock(&usbhid->setup);
        return ret;
@@ -924,6 +923,9 @@ static void usbhid_stop(struct hid_device *hid)
        usb_free_urb(usbhid->urbin);
        usb_free_urb(usbhid->urbctrl);
        usb_free_urb(usbhid->urbout);
+       usbhid->urbin = NULL; /* don't mess up next start */
+       usbhid->urbctrl = NULL;
+       usbhid->urbout = NULL;
 
        hid_free_buffers(hid_to_usb_dev(hid), hid);
        mutex_unlock(&usbhid->setup);
@@ -940,15 +942,26 @@ static struct hid_ll_driver usb_hid_driver = {
 
 static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
+       struct usb_host_interface *interface = intf->cur_altsetting;
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usbhid_device *usbhid;
        struct hid_device *hid;
+       unsigned int n, has_in = 0;
        size_t len;
        int ret;
 
        dbg_hid("HID probe called for ifnum %d\n",
                        intf->altsetting->desc.bInterfaceNumber);
 
+       for (n = 0; n < interface->desc.bNumEndpoints; n++)
+               if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
+                       has_in++;
+       if (!has_in) {
+               dev_err(&intf->dev, "couldn't find an input interrupt "
+                               "endpoint\n");
+               return -ENODEV;
+       }
+
        hid = hid_allocate_device();
        if (IS_ERR(hid))
                return PTR_ERR(hid);
index 6de1e0ffd391efe9669fcae51df41beeb9a39407..c709e821f04bf6cd4c93db2fd6451be818fb7840 100644 (file)
@@ -159,6 +159,16 @@ config SENSORS_ADM9240
          This driver can also be built as a module.  If so, the module
          will be called adm9240.
 
+config SENSORS_ADT7462
+       tristate "Analog Devices ADT7462"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for the Analog Devices
+         ADT7462 temperature monitoring chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called adt7462.
+
 config SENSORS_ADT7470
        tristate "Analog Devices ADT7470"
        depends on I2C && EXPERIMENTAL
@@ -825,6 +835,25 @@ config SENSORS_HDAPS
          Say Y here if you have an applicable laptop and want to experience
          the awesome power of hdaps.
 
+config SENSORS_LIS3LV02D
+       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
+       depends on ACPI && INPUT
+       default n
+       help
+         This driver provides support for the LIS3LV02Dx accelerometer. In
+         particular, it can be found in a number of HP laptops, which have the
+         "Mobile Data Protection System 3D" or "3D DriveGuard" feature. On such
+         systems the driver should load automatically (via ACPI). The
+         accelerometer might also be found in other systems, connected via SPI
+         or I2C.  The accelerometer data is readable via
+         /sys/devices/platform/lis3lv02d.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lis3lv02d.
+
 config SENSORS_APPLESMC
        tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
        depends on INPUT && X86
index 042d5a78622e4614a397983b147109ff4e01ab20..58fc5be5355d29ec0ea686813fbc1dc651b0e232 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
+obj-$(CONFIG_SENSORS_ADT7462)  += adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)  += adt7470.o
 obj-$(CONFIG_SENSORS_ADT7473)  += adt7473.o
 obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_SENSORS_IBMAEM)  += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
+obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
 obj-$(CONFIG_SENSORS_LM70)     += lm70.o
 obj-$(CONFIG_SENSORS_LM75)     += lm75.o
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
new file mode 100644 (file)
index 0000000..66107b4
--- /dev/null
@@ -0,0 +1,2002 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7462
+ * Copyright (C) 2008 IBM
+ *
+ * Author: Darrick J. Wong <djwong@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.
+ *
+ * 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/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(adt7462);
+
+/* ADT7462 registers */
+#define ADT7462_REG_DEVICE                     0x3D
+#define ADT7462_REG_VENDOR                     0x3E
+#define ADT7462_REG_REVISION                   0x3F
+
+#define ADT7462_REG_MIN_TEMP_BASE_ADDR         0x44
+#define ADT7462_REG_MIN_TEMP_MAX_ADDR          0x47
+#define ADT7462_REG_MAX_TEMP_BASE_ADDR         0x48
+#define ADT7462_REG_MAX_TEMP_MAX_ADDR          0x4B
+#define ADT7462_REG_TEMP_BASE_ADDR             0x88
+#define ADT7462_REG_TEMP_MAX_ADDR              0x8F
+
+#define ADT7462_REG_FAN_BASE_ADDR              0x98
+#define ADT7462_REG_FAN_MAX_ADDR               0x9F
+#define ADT7462_REG_FAN2_BASE_ADDR             0xA2
+#define ADT7462_REG_FAN2_MAX_ADDR              0xA9
+#define ADT7462_REG_FAN_ENABLE                 0x07
+#define ADT7462_REG_FAN_MIN_BASE_ADDR          0x78
+#define ADT7462_REG_FAN_MIN_MAX_ADDR           0x7F
+
+#define ADT7462_REG_CFG2                       0x02
+#define                ADT7462_FSPD_MASK               0x20
+
+#define ADT7462_REG_PWM_BASE_ADDR              0xAA
+#define ADT7462_REG_PWM_MAX_ADDR               0xAD
+#define        ADT7462_REG_PWM_MIN_BASE_ADDR           0x28
+#define ADT7462_REG_PWM_MIN_MAX_ADDR           0x2B
+#define ADT7462_REG_PWM_MAX                    0x2C
+#define ADT7462_REG_PWM_TEMP_MIN_BASE_ADDR     0x5C
+#define ADT7462_REG_PWM_TEMP_MIN_MAX_ADDR      0x5F
+#define ADT7462_REG_PWM_TEMP_RANGE_BASE_ADDR   0x60
+#define ADT7462_REG_PWM_TEMP_RANGE_MAX_ADDR    0x63
+#define        ADT7462_PWM_HYST_MASK           0x0F
+#define        ADT7462_PWM_RANGE_MASK          0xF0
+#define                ADT7462_PWM_RANGE_SHIFT         4
+#define ADT7462_REG_PWM_CFG_BASE_ADDR          0x21
+#define ADT7462_REG_PWM_CFG_MAX_ADDR           0x24
+#define                ADT7462_PWM_CHANNEL_MASK        0xE0
+#define                ADT7462_PWM_CHANNEL_SHIFT       5
+
+#define ADT7462_REG_PIN_CFG_BASE_ADDR          0x10
+#define ADT7462_REG_PIN_CFG_MAX_ADDR           0x13
+#define                ADT7462_PIN7_INPUT              0x01    /* cfg0 */
+#define                ADT7462_DIODE3_INPUT            0x20
+#define                ADT7462_DIODE1_INPUT            0x40
+#define                ADT7462_VID_INPUT               0x80
+#define                ADT7462_PIN22_INPUT             0x04    /* cfg1 */
+#define                ADT7462_PIN21_INPUT             0x08
+#define                ADT7462_PIN19_INPUT             0x10
+#define                ADT7462_PIN15_INPUT             0x20
+#define                ADT7462_PIN13_INPUT             0x40
+#define                ADT7462_PIN8_INPUT              0x80
+#define        ADT7462_PIN23_MASK              0x03
+#define                ADT7462_PIN23_SHIFT             0
+#define                ADT7462_PIN26_MASK              0x0C    /* cfg2 */
+#define                ADT7462_PIN26_SHIFT             2
+#define                ADT7462_PIN25_MASK              0x30
+#define                ADT7462_PIN25_SHIFT             4
+#define                ADT7462_PIN24_MASK              0xC0
+#define                ADT7462_PIN24_SHIFT             6
+#define                ADT7462_PIN26_VOLT_INPUT        0x08
+#define                ADT7462_PIN25_VOLT_INPUT        0x20
+#define                ADT7462_PIN28_SHIFT             6       /* cfg3 */
+#define                ADT7462_PIN28_VOLT              0x5
+
+#define ADT7462_REG_ALARM1                     0xB8
+#define        ADT7462_LT_ALARM                0x02
+#define                ADT7462_R1T_ALARM               0x04
+#define                ADT7462_R2T_ALARM               0x08
+#define                ADT7462_R3T_ALARM               0x10
+#define ADT7462_REG_ALARM2                     0xBB
+#define                ADT7462_V0_ALARM                0x01
+#define                ADT7462_V1_ALARM                0x02
+#define                ADT7462_V2_ALARM                0x04
+#define                ADT7462_V3_ALARM                0x08
+#define                ADT7462_V4_ALARM                0x10
+#define                ADT7462_V5_ALARM                0x20
+#define                ADT7462_V6_ALARM                0x40
+#define                ADT7462_V7_ALARM                0x80
+#define ADT7462_REG_ALARM3                     0xBC
+#define                ADT7462_V8_ALARM                0x08
+#define                ADT7462_V9_ALARM                0x10
+#define                ADT7462_V10_ALARM               0x20
+#define                ADT7462_V11_ALARM               0x40
+#define                ADT7462_V12_ALARM               0x80
+#define ADT7462_REG_ALARM4                     0xBD
+#define                ADT7462_F0_ALARM                0x01
+#define                ADT7462_F1_ALARM                0x02
+#define                ADT7462_F2_ALARM                0x04
+#define                ADT7462_F3_ALARM                0x08
+#define                ADT7462_F4_ALARM                0x10
+#define                ADT7462_F5_ALARM                0x20
+#define                ADT7462_F6_ALARM                0x40
+#define                ADT7462_F7_ALARM                0x80
+#define ADT7462_ALARM1                         0x0000
+#define ADT7462_ALARM2                         0x0100
+#define ADT7462_ALARM3                         0x0200
+#define ADT7462_ALARM4                         0x0300
+#define ADT7462_ALARM_REG_SHIFT                        8
+#define ADT7462_ALARM_FLAG_MASK                        0x0F
+
+#define ADT7462_TEMP_COUNT             4
+#define ADT7462_TEMP_REG(x)            (ADT7462_REG_TEMP_BASE_ADDR + (x * 2))
+#define ADT7462_TEMP_MIN_REG(x)        (ADT7462_REG_MIN_TEMP_BASE_ADDR + (x))
+#define ADT7462_TEMP_MAX_REG(x)        (ADT7462_REG_MAX_TEMP_BASE_ADDR + (x))
+#define TEMP_FRAC_OFFSET               6
+
+#define ADT7462_FAN_COUNT              8
+#define ADT7462_REG_FAN_MIN(x)         (ADT7462_REG_FAN_MIN_BASE_ADDR + (x))
+
+#define ADT7462_PWM_COUNT              4
+#define ADT7462_REG_PWM(x)             (ADT7462_REG_PWM_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_MIN(x)         (ADT7462_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_TMIN(x)                \
+       (ADT7462_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_TRANGE(x)      \
+       (ADT7462_REG_PWM_TEMP_RANGE_BASE_ADDR + (x))
+
+#define ADT7462_PIN_CFG_REG_COUNT      4
+#define ADT7462_REG_PIN_CFG(x)         (ADT7462_REG_PIN_CFG_BASE_ADDR + (x))
+#define ADT7462_REG_PWM_CFG(x)         (ADT7462_REG_PWM_CFG_BASE_ADDR + (x))
+
+#define ADT7462_ALARM_REG_COUNT                4
+
+/*
+ * The chip can measure 13 different voltage sources:
+ *
+ * 1. +12V1 (pin 7)
+ * 2. Vccp1/+2.5V/+1.8V/+1.5V (pin 23)
+ * 3. +12V3 (pin 22)
+ * 4. +5V (pin 21)
+ * 5. +1.25V/+0.9V (pin 19)
+ * 6. +2.5V/+1.8V (pin 15)
+ * 7. +3.3v (pin 13)
+ * 8. +12V2 (pin 8)
+ * 9. Vbatt/FSB_Vtt (pin 26)
+ * A. +3.3V/+1.2V1 (pin 25)
+ * B. Vccp2/+2.5V/+1.8V/+1.5V (pin 24)
+ * C. +1.5V ICH (only if BOTH pin 28/29 are set to +1.5V)
+ * D. +1.5V 3GPIO (only if BOTH pin 28/29 are set to +1.5V)
+ *
+ * Each of these 13 has a factor to convert raw to voltage.  Even better,
+ * the pins can be connected to other sensors (tach/gpio/hot/etc), which
+ * makes the bookkeeping tricky.
+ *
+ * Some, but not all, of these voltages have low/high limits.
+ */
+#define ADT7462_VOLT_COUNT     12
+
+#define ADT7462_VENDOR         0x41
+#define ADT7462_DEVICE         0x62
+/* datasheet only mentions a revision 4 */
+#define ADT7462_REVISION       0x04
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL        (2 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL (60 * HZ)
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x)   ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD      FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID     65535
+#define FAN_DATA_VALID(x)      ((x) && (x) != FAN_PERIOD_INVALID)
+
+#define MASK_AND_SHIFT(value, prefix)  \
+       (((value) & prefix##_MASK) >> prefix##_SHIFT)
+
+#define ROUND_DIV(x, divisor)  (((x) + ((divisor) / 2)) / (divisor))
+
+struct adt7462_data {
+       struct device           *hwmon_dev;
+       struct attribute_group  attrs;
+       struct mutex            lock;
+       char                    sensors_valid;
+       char                    limits_valid;
+       unsigned long           sensors_last_updated;   /* In jiffies */
+       unsigned long           limits_last_updated;    /* In jiffies */
+
+       u8                      temp[ADT7462_TEMP_COUNT];
+                               /* bits 6-7 are quarter pieces of temp */
+       u8                      temp_frac[ADT7462_TEMP_COUNT];
+       u8                      temp_min[ADT7462_TEMP_COUNT];
+       u8                      temp_max[ADT7462_TEMP_COUNT];
+       u16                     fan[ADT7462_FAN_COUNT];
+       u8                      fan_enabled;
+       u8                      fan_min[ADT7462_FAN_COUNT];
+       u8                      cfg2;
+       u8                      pwm[ADT7462_PWM_COUNT];
+       u8                      pin_cfg[ADT7462_PIN_CFG_REG_COUNT];
+       u8                      voltages[ADT7462_VOLT_COUNT];
+       u8                      volt_max[ADT7462_VOLT_COUNT];
+       u8                      volt_min[ADT7462_VOLT_COUNT];
+       u8                      pwm_min[ADT7462_PWM_COUNT];
+       u8                      pwm_tmin[ADT7462_PWM_COUNT];
+       u8                      pwm_trange[ADT7462_PWM_COUNT];
+       u8                      pwm_max;        /* only one per chip */
+       u8                      pwm_cfg[ADT7462_PWM_COUNT];
+       u8                      alarms[ADT7462_ALARM_REG_COUNT];
+};
+
+static int adt7462_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id);
+static int adt7462_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info);
+static int adt7462_remove(struct i2c_client *client);
+
+static const struct i2c_device_id adt7462_id[] = {
+       { "adt7462", adt7462 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adt7462_id);
+
+static struct i2c_driver adt7462_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "adt7462",
+       },
+       .probe          = adt7462_probe,
+       .remove         = adt7462_remove,
+       .id_table       = adt7462_id,
+       .detect         = adt7462_detect,
+       .address_data   = &addr_data,
+};
+
+/*
+ * 16-bit registers on the ADT7462 are low-byte first.  The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7462_read_word_data(struct i2c_client *client, u8 reg)
+{
+       u16 foo;
+       foo = i2c_smbus_read_byte_data(client, reg);
+       foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+       return foo;
+}
+
+/* For some reason these registers are not contiguous. */
+static int ADT7462_REG_FAN(int fan)
+{
+       if (fan < 4)
+               return ADT7462_REG_FAN_BASE_ADDR + (2 * fan);
+       return ADT7462_REG_FAN2_BASE_ADDR + (2 * (fan - 4));
+}
+
+/* Voltage registers are scattered everywhere */
+static int ADT7462_REG_VOLT_MAX(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+               if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+                       return 0x7C;
+               break;
+       case 1:
+               return 0x69;
+       case 2:
+               if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+                       return 0x7F;
+               break;
+       case 3:
+               if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+                       return 0x7E;
+               break;
+       case 4:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT))
+                       return 0x4B;
+               break;
+       case 5:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT))
+                       return 0x49;
+               break;
+       case 6:
+               if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+                       return 0x68;
+               break;
+       case 7:
+               if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+                       return 0x7D;
+               break;
+       case 8:
+               if (!(data->pin_cfg[2] & ADT7462_PIN26_VOLT_INPUT))
+                       return 0x6C;
+               break;
+       case 9:
+               if (!(data->pin_cfg[2] & ADT7462_PIN25_VOLT_INPUT))
+                       return 0x6B;
+               break;
+       case 10:
+               return 0x6A;
+       case 11:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 0x50;
+               break;
+       case 12:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 0x4C;
+               break;
+       }
+       return -ENODEV;
+}
+
+static int ADT7462_REG_VOLT_MIN(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+               if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+                       return 0x6D;
+               break;
+       case 1:
+               return 0x72;
+       case 2:
+               if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+                       return 0x6F;
+               break;
+       case 3:
+               if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+                       return 0x71;
+               break;
+       case 4:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT))
+                       return 0x47;
+               break;
+       case 5:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT))
+                       return 0x45;
+               break;
+       case 6:
+               if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+                       return 0x70;
+               break;
+       case 7:
+               if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+                       return 0x6E;
+               break;
+       case 8:
+               if (!(data->pin_cfg[2] & ADT7462_PIN26_VOLT_INPUT))
+                       return 0x75;
+               break;
+       case 9:
+               if (!(data->pin_cfg[2] & ADT7462_PIN25_VOLT_INPUT))
+                       return 0x74;
+               break;
+       case 10:
+               return 0x73;
+       case 11:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 0x76;
+               break;
+       case 12:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 0x77;
+               break;
+       }
+       return -ENODEV;
+}
+
+static int ADT7462_REG_VOLT(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+               if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+                       return 0xA3;
+               break;
+       case 1:
+               return 0x90;
+       case 2:
+               if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+                       return 0xA9;
+               break;
+       case 3:
+               if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+                       return 0xA7;
+               break;
+       case 4:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT))
+                       return 0x8F;
+               break;
+       case 5:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT))
+                       return 0x8B;
+               break;
+       case 6:
+               if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+                       return 0x96;
+               break;
+       case 7:
+               if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+                       return 0xA5;
+               break;
+       case 8:
+               if (!(data->pin_cfg[2] & ADT7462_PIN26_VOLT_INPUT))
+                       return 0x93;
+               break;
+       case 9:
+               if (!(data->pin_cfg[2] & ADT7462_PIN25_VOLT_INPUT))
+                       return 0x92;
+               break;
+       case 10:
+               return 0x91;
+       case 11:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 0x94;
+               break;
+       case 12:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 0x95;
+               break;
+       }
+       return -ENODEV;
+}
+
+/* Provide labels for sysfs */
+static const char *voltage_label(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+               if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+                       return "+12V1";
+               break;
+       case 1:
+               switch (MASK_AND_SHIFT(data->pin_cfg[1], ADT7462_PIN23)) {
+               case 0:
+                       return "Vccp1";
+               case 1:
+                       return "+2.5V";
+               case 2:
+                       return "+1.8V";
+               case 3:
+                       return "+1.5V";
+               }
+       case 2:
+               if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+                       return "+12V3";
+               break;
+       case 3:
+               if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+                       return "+5V";
+               break;
+       case 4:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT)) {
+                       if (data->pin_cfg[1] & ADT7462_PIN19_INPUT)
+                               return "+0.9V";
+                       return "+1.25V";
+               }
+               break;
+       case 5:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT)) {
+                       if (data->pin_cfg[1] & ADT7462_PIN19_INPUT)
+                               return "+1.8V";
+                       return "+2.5V";
+               }
+               break;
+       case 6:
+               if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+                       return "+3.3V";
+               break;
+       case 7:
+               if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+                       return "+12V2";
+               break;
+       case 8:
+               switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN26)) {
+               case 0:
+                       return "Vbatt";
+               case 1:
+                       return "FSB_Vtt";
+               }
+               break;
+       case 9:
+               switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN25)) {
+               case 0:
+                       return "+3.3V";
+               case 1:
+                       return "+1.2V1";
+               }
+               break;
+       case 10:
+               switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN24)) {
+               case 0:
+                       return "Vccp2";
+               case 1:
+                       return "+2.5V";
+               case 2:
+                       return "+1.8V";
+               case 3:
+                       return "+1.5";
+               }
+       case 11:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return "+1.5V ICH";
+               break;
+       case 12:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return "+1.5V 3GPIO";
+               break;
+       }
+       return "N/A";
+}
+
+/* Multipliers are actually in uV, not mV. */
+static int voltage_multiplier(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+               if (!(data->pin_cfg[0] & ADT7462_PIN7_INPUT))
+                       return 62500;
+               break;
+       case 1:
+               switch (MASK_AND_SHIFT(data->pin_cfg[1], ADT7462_PIN23)) {
+               case 0:
+                       if (data->pin_cfg[0] & ADT7462_VID_INPUT)
+                               return 12500;
+                       return 6250;
+               case 1:
+                       return 13000;
+               case 2:
+                       return 9400;
+               case 3:
+                       return 7800;
+               }
+       case 2:
+               if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
+                       return 62500;
+               break;
+       case 3:
+               if (!(data->pin_cfg[1] & ADT7462_PIN21_INPUT))
+                       return 26000;
+               break;
+       case 4:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE3_INPUT)) {
+                       if (data->pin_cfg[1] & ADT7462_PIN19_INPUT)
+                               return 4690;
+                       return 6500;
+               }
+               break;
+       case 5:
+               if (!(data->pin_cfg[0] & ADT7462_DIODE1_INPUT)) {
+                       if (data->pin_cfg[1] & ADT7462_PIN15_INPUT)
+                               return 9400;
+                       return 13000;
+               }
+               break;
+       case 6:
+               if (!(data->pin_cfg[1] & ADT7462_PIN13_INPUT))
+                       return 17200;
+               break;
+       case 7:
+               if (!(data->pin_cfg[1] & ADT7462_PIN8_INPUT))
+                       return 62500;
+               break;
+       case 8:
+               switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN26)) {
+               case 0:
+                       return 15600;
+               case 1:
+                       return 6250;
+               }
+               break;
+       case 9:
+               switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN25)) {
+               case 0:
+                       return 17200;
+               case 1:
+                       return 6250;
+               }
+               break;
+       case 10:
+               switch (MASK_AND_SHIFT(data->pin_cfg[2], ADT7462_PIN24)) {
+               case 0:
+                       return 6250;
+               case 1:
+                       return 13000;
+               case 2:
+                       return 9400;
+               case 3:
+                       return 7800;
+               }
+       case 11:
+       case 12:
+               if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
+                                       ADT7462_PIN28_VOLT &&
+                   !(data->pin_cfg[0] & ADT7462_VID_INPUT))
+                       return 7800;
+       }
+       return 0;
+}
+
+static int temp_enabled(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+       case 2:
+               return 1;
+       case 1:
+               if (data->pin_cfg[0] & ADT7462_DIODE1_INPUT)
+                       return 1;
+               break;
+       case 3:
+               if (data->pin_cfg[0] & ADT7462_DIODE3_INPUT)
+                       return 1;
+               break;
+       }
+       return 0;
+}
+
+static const char *temp_label(struct adt7462_data *data, int which)
+{
+       switch (which) {
+       case 0:
+               return "local";
+       case 1:
+               if (data->pin_cfg[0] & ADT7462_DIODE1_INPUT)
+                       return "remote1";
+               break;
+       case 2:
+               return "remote2";
+       case 3:
+               if (data->pin_cfg[0] & ADT7462_DIODE3_INPUT)
+                       return "remote3";
+               break;
+       }
+       return "N/A";
+}
+
+/* Map Trange register values to mC */
+#define NUM_TRANGE_VALUES      16
+static const int trange_values[NUM_TRANGE_VALUES] = {
+       2000,
+       2500,
+       3300,
+       4000,
+       5000,
+       6700,
+       8000,
+       10000,
+       13300,
+       16000,
+       20000,
+       26700,
+       32000,
+       40000,
+       53300,
+       80000
+};
+
+static int find_trange_value(int trange)
+{
+       int i;
+
+       for (i = 0; i < NUM_TRANGE_VALUES; i++)
+               if (trange_values[i] == trange)
+                       return i;
+
+       return -ENODEV;
+}
+
+static struct adt7462_data *adt7462_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       unsigned long local_jiffies = jiffies;
+       int i;
+
+       mutex_lock(&data->lock);
+       if (time_before(local_jiffies, data->sensors_last_updated +
+               SENSOR_REFRESH_INTERVAL)
+               && data->sensors_valid)
+               goto no_sensor_update;
+
+       for (i = 0; i < ADT7462_TEMP_COUNT; i++) {
+               /*
+                * Reading the fractional register locks the integral
+                * register until both have been read.
+                */
+               data->temp_frac[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_TEMP_REG(i));
+               data->temp[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_TEMP_REG(i) + 1);
+       }
+
+       for (i = 0; i < ADT7462_FAN_COUNT; i++)
+               data->fan[i] = adt7462_read_word_data(client,
+                                               ADT7462_REG_FAN(i));
+
+       data->fan_enabled = i2c_smbus_read_byte_data(client,
+                                       ADT7462_REG_FAN_ENABLE);
+
+       for (i = 0; i < ADT7462_PWM_COUNT; i++)
+               data->pwm[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_REG_PWM(i));
+
+       for (i = 0; i < ADT7462_PIN_CFG_REG_COUNT; i++)
+               data->pin_cfg[i] = i2c_smbus_read_byte_data(client,
+                               ADT7462_REG_PIN_CFG(i));
+
+       for (i = 0; i < ADT7462_VOLT_COUNT; i++) {
+               int reg = ADT7462_REG_VOLT(data, i);
+               if (!reg)
+                       data->voltages[i] = 0;
+               else
+                       data->voltages[i] = i2c_smbus_read_byte_data(client,
+                                                                    reg);
+       }
+
+       data->alarms[0] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM1);
+       data->alarms[1] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM2);
+       data->alarms[2] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM3);
+       data->alarms[3] = i2c_smbus_read_byte_data(client, ADT7462_REG_ALARM4);
+
+       data->sensors_last_updated = local_jiffies;
+       data->sensors_valid = 1;
+
+no_sensor_update:
+       if (time_before(local_jiffies, data->limits_last_updated +
+               LIMIT_REFRESH_INTERVAL)
+               && data->limits_valid)
+               goto out;
+
+       for (i = 0; i < ADT7462_TEMP_COUNT; i++) {
+               data->temp_min[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_TEMP_MIN_REG(i));
+               data->temp_max[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_TEMP_MAX_REG(i));
+       }
+
+       for (i = 0; i < ADT7462_FAN_COUNT; i++)
+               data->fan_min[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_REG_FAN_MIN(i));
+
+       for (i = 0; i < ADT7462_VOLT_COUNT; i++) {
+               int reg = ADT7462_REG_VOLT_MAX(data, i);
+               data->volt_max[i] =
+                       (reg ? i2c_smbus_read_byte_data(client, reg) : 0);
+
+               reg = ADT7462_REG_VOLT_MIN(data, i);
+               data->volt_min[i] =
+                       (reg ? i2c_smbus_read_byte_data(client, reg) : 0);
+       }
+
+       for (i = 0; i < ADT7462_PWM_COUNT; i++) {
+               data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_REG_PWM_MIN(i));
+               data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_REG_PWM_TMIN(i));
+               data->pwm_trange[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_REG_PWM_TRANGE(i));
+               data->pwm_cfg[i] = i2c_smbus_read_byte_data(client,
+                                               ADT7462_REG_PWM_CFG(i));
+       }
+
+       data->pwm_max = i2c_smbus_read_byte_data(client, ADT7462_REG_PWM_MAX);
+
+       data->cfg2 = i2c_smbus_read_byte_data(client, ADT7462_REG_CFG2);
+
+       data->limits_last_updated = local_jiffies;
+       data->limits_valid = 1;
+
+out:
+       mutex_unlock(&data->lock);
+       return data;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+
+       if (!temp_enabled(data, attr->index))
+               return sprintf(buf, "0\n");
+
+       return sprintf(buf, "%d\n", 1000 * (data->temp_min[attr->index] - 64));
+}
+
+static ssize_t set_temp_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp) || !temp_enabled(data, attr->index))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000) + 64;
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->temp_min[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_TEMP_MIN_REG(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+
+       if (!temp_enabled(data, attr->index))
+               return sprintf(buf, "0\n");
+
+       return sprintf(buf, "%d\n", 1000 * (data->temp_max[attr->index] - 64));
+}
+
+static ssize_t set_temp_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp) || !temp_enabled(data, attr->index))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000) + 64;
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->temp_max[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_TEMP_MAX_REG(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       u8 frac = data->temp_frac[attr->index] >> TEMP_FRAC_OFFSET;
+
+       if (!temp_enabled(data, attr->index))
+               return sprintf(buf, "0\n");
+
+       return sprintf(buf, "%d\n", 1000 * (data->temp[attr->index] - 64) +
+                                    250 * frac);
+}
+
+static ssize_t show_temp_label(struct device *dev,
+                              struct device_attribute *devattr,
+                              char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+
+       return sprintf(buf, "%s\n", temp_label(data, attr->index));
+}
+
+static ssize_t show_volt_max(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       int x = voltage_multiplier(data, attr->index);
+
+       x *= data->volt_max[attr->index];
+       x /= 1000; /* convert from uV to mV */
+
+       return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t set_volt_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       int x = voltage_multiplier(data, attr->index);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp) || !x)
+               return -EINVAL;
+
+       temp *= 1000; /* convert mV to uV */
+       temp = ROUND_DIV(temp, x);
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->volt_max[attr->index] = temp;
+       i2c_smbus_write_byte_data(client,
+                                 ADT7462_REG_VOLT_MAX(data, attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_volt_min(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       int x = voltage_multiplier(data, attr->index);
+
+       x *= data->volt_min[attr->index];
+       x /= 1000; /* convert from uV to mV */
+
+       return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t set_volt_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       int x = voltage_multiplier(data, attr->index);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp) || !x)
+               return -EINVAL;
+
+       temp *= 1000; /* convert mV to uV */
+       temp = ROUND_DIV(temp, x);
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->volt_min[attr->index] = temp;
+       i2c_smbus_write_byte_data(client,
+                                 ADT7462_REG_VOLT_MIN(data, attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_voltage(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       int x = voltage_multiplier(data, attr->index);
+
+       x *= data->voltages[attr->index];
+       x /= 1000; /* convert from uV to mV */
+
+       return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t show_voltage_label(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+
+       return sprintf(buf, "%s\n", voltage_label(data, attr->index));
+}
+
+static ssize_t show_alarm(struct device *dev,
+                         struct device_attribute *devattr,
+                         char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       int reg = attr->index >> ADT7462_ALARM_REG_SHIFT;
+       int mask = attr->index & ADT7462_ALARM_FLAG_MASK;
+
+       if (data->alarms[reg] & mask)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static int fan_enabled(struct adt7462_data *data, int fan)
+{
+       return data->fan_enabled & (1 << fan);
+}
+
+static ssize_t show_fan_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       u16 temp;
+
+       /* Only the MSB of the min fan period is stored... */
+       temp = data->fan_min[attr->index];
+       temp <<= 8;
+
+       if (!fan_enabled(data, attr->index) ||
+           !FAN_DATA_VALID(temp))
+               return sprintf(buf, "0\n");
+
+       return sprintf(buf, "%d\n", FAN_PERIOD_TO_RPM(temp));
+}
+
+static ssize_t set_fan_min(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp) || !temp ||
+           !fan_enabled(data, attr->index))
+               return -EINVAL;
+
+       temp = FAN_RPM_TO_PERIOD(temp);
+       temp >>= 8;
+       temp = SENSORS_LIMIT(temp, 1, 255);
+
+       mutex_lock(&data->lock);
+       data->fan_min[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_FAN_MIN(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+                       char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+
+       if (!fan_enabled(data, attr->index) ||
+           !FAN_DATA_VALID(data->fan[attr->index]))
+               return sprintf(buf, "0\n");
+
+       return sprintf(buf, "%d\n",
+                      FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+}
+
+static ssize_t show_force_pwm_max(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct adt7462_data *data = adt7462_update_device(dev);
+       return sprintf(buf, "%d\n", (data->cfg2 & ADT7462_FSPD_MASK ? 1 : 0));
+}
+
+static ssize_t set_force_pwm_max(struct device *dev,
+                                struct device_attribute *devattr,
+                                const char *buf,
+                                size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+       u8 reg;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       mutex_lock(&data->lock);
+       reg = i2c_smbus_read_byte_data(client, ADT7462_REG_CFG2);
+       if (temp)
+               reg |= ADT7462_FSPD_MASK;
+       else
+               reg &= ~ADT7462_FSPD_MASK;
+       data->cfg2 = reg;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_CFG2, reg);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+                       char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->pwm[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM(attr->index), temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct adt7462_data *data = adt7462_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_max);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf,
+                          size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->pwm_max = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_MAX, temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+                          struct device_attribute *devattr,
+                          const char *buf,
+                          size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->pwm_min[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_MIN(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_hyst(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       return sprintf(buf, "%d\n", 1000 *
+                     (data->pwm_trange[attr->index] & ADT7462_PWM_HYST_MASK));
+}
+
+static ssize_t set_pwm_hyst(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 15);
+
+       /* package things up */
+       temp &= ADT7462_PWM_HYST_MASK;
+       temp |= data->pwm_trange[attr->index] & ADT7462_PWM_RANGE_MASK;
+
+       mutex_lock(&data->lock);
+       data->pwm_trange[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_TRANGE(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_tmax(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+
+       /* tmax = tmin + trange */
+       int trange = trange_values[data->pwm_trange[attr->index] >>
+                                  ADT7462_PWM_RANGE_SHIFT];
+       int tmin = (data->pwm_tmin[attr->index] - 64) * 1000;
+
+       return sprintf(buf, "%d\n", tmin + trange);
+}
+
+static ssize_t set_pwm_tmax(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       int temp;
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       int tmin, trange_value;
+       long trange;
+
+       if (strict_strtol(buf, 10, &trange))
+               return -EINVAL;
+
+       /* trange = tmax - tmin */
+       tmin = (data->pwm_tmin[attr->index] - 64) * 1000;
+       trange_value = find_trange_value(trange - tmin);
+
+       if (trange_value < 0)
+               return -EINVAL;
+
+       temp = trange_value << ADT7462_PWM_RANGE_SHIFT;
+       temp |= data->pwm_trange[attr->index] & ADT7462_PWM_HYST_MASK;
+
+       mutex_lock(&data->lock);
+       data->pwm_trange[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_TRANGE(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_tmin(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       return sprintf(buf, "%d\n", 1000 * (data->pwm_tmin[attr->index] - 64));
+}
+
+static ssize_t set_pwm_tmin(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000) + 64;
+       temp = SENSORS_LIMIT(temp, 0, 255);
+
+       mutex_lock(&data->lock);
+       data->pwm_tmin[attr->index] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_TMIN(attr->index),
+                                 temp);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_auto(struct device *dev,
+                            struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       int cfg = data->pwm_cfg[attr->index] >> ADT7462_PWM_CHANNEL_SHIFT;
+
+       switch (cfg) {
+       case 4: /* off */
+               return sprintf(buf, "0\n");
+       case 7: /* manual */
+               return sprintf(buf, "1\n");
+       default: /* automatic */
+               return sprintf(buf, "2\n");
+       }
+}
+
+static void set_pwm_channel(struct i2c_client *client,
+                           struct adt7462_data *data,
+                           int which,
+                           int value)
+{
+       int temp = data->pwm_cfg[which] & ~ADT7462_PWM_CHANNEL_MASK;
+       temp |= value << ADT7462_PWM_CHANNEL_SHIFT;
+
+       mutex_lock(&data->lock);
+       data->pwm_cfg[which] = temp;
+       i2c_smbus_write_byte_data(client, ADT7462_REG_PWM_CFG(which), temp);
+       mutex_unlock(&data->lock);
+}
+
+static ssize_t set_pwm_auto(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf,
+                           size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       switch (temp) {
+       case 0: /* off */
+               set_pwm_channel(client, data, attr->index, 4);
+               return count;
+       case 1: /* manual */
+               set_pwm_channel(client, data, attr->index, 7);
+               return count;
+       default:
+               return -EINVAL;
+       }
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adt7462_data *data = adt7462_update_device(dev);
+       int channel = data->pwm_cfg[attr->index] >> ADT7462_PWM_CHANNEL_SHIFT;
+
+       switch (channel) {
+       case 0: /* temp[1234] only */
+       case 1:
+       case 2:
+       case 3:
+               return sprintf(buf, "%d\n", (1 << channel));
+       case 5: /* temp1 & temp4  */
+               return sprintf(buf, "9\n");
+       case 6:
+               return sprintf(buf, "15\n");
+       default:
+               return sprintf(buf, "0\n");
+       }
+}
+
+static int cvt_auto_temp(int input)
+{
+       if (input == 0xF)
+               return 6;
+       if (input == 0x9)
+               return 5;
+       if (input < 1 || !is_power_of_2(input))
+               return -EINVAL;
+       return ilog2(input);
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+                                struct device_attribute *devattr,
+                                const char *buf,
+                                size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7462_data *data = i2c_get_clientdata(client);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = cvt_auto_temp(temp);
+       if (temp < 0)
+               return temp;
+
+       set_pwm_channel(client, data, attr->index, temp);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   set_temp_max, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   set_temp_min, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM1 | ADT7462_LT_ALARM);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM1 | ADT7462_R1T_ALARM);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM1 | ADT7462_R2T_ALARM);
+static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM1 | ADT7462_R3T_ALARM);
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO, show_volt_max,
+                   set_volt_max, 12);
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO, show_volt_min,
+                   set_volt_min, 12);
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_voltage, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_voltage, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_voltage, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_voltage, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_voltage, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_voltage, NULL, 12);
+
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_voltage_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_voltage_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_voltage_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_voltage_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_voltage_label, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_voltage_label, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_voltage_label, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_voltage_label, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_voltage_label, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_voltage_label, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_voltage_label, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_voltage_label, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_label, S_IRUGO, show_voltage_label, NULL, 12);
+
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V0_ALARM);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V7_ALARM);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V2_ALARM);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V6_ALARM);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V5_ALARM);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V4_ALARM);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V3_ALARM);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM2 | ADT7462_V1_ALARM);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM3 | ADT7462_V10_ALARM);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM3 | ADT7462_V9_ALARM);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM3 | ADT7462_V8_ALARM);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM3 | ADT7462_V11_ALARM);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM3 | ADT7462_V12_ALARM);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan8_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   set_fan_min, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F0_ALARM);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F1_ALARM);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F2_ALARM);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F3_ALARM);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F4_ALARM);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F5_ALARM);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F6_ALARM);
+static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_alarm, NULL,
+                         ADT7462_ALARM4 | ADT7462_F7_ALARM);
+
+static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
+                   show_force_pwm_max, set_force_pwm_max, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_min, set_pwm_min, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                   show_pwm_max, set_pwm_max, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point1_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point1_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point1_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point2_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point2_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point2_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point2_hyst, S_IWUSR | S_IRUGO,
+                   show_pwm_hyst, set_pwm_hyst, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point1_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmin, set_pwm_tmin, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmax, set_pwm_tmax, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmax, set_pwm_tmax, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point2_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmax, set_pwm_tmax, 2);
+static SENSOR_DEVICE_ATTR(temp4_auto_point2_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_tmax, set_pwm_tmax, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+                   set_pwm_auto, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
+                   show_pwm_auto_temp, set_pwm_auto_temp, 3);
+
+static struct attribute *adt7462_attr[] =
+{
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp4_min.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_label.dev_attr.attr,
+       &sensor_dev_attr_temp2_label.dev_attr.attr,
+       &sensor_dev_attr_temp3_label.dev_attr.attr,
+       &sensor_dev_attr_temp4_label.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp4_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
+       &sensor_dev_attr_in6_max.dev_attr.attr,
+       &sensor_dev_attr_in7_max.dev_attr.attr,
+       &sensor_dev_attr_in8_max.dev_attr.attr,
+       &sensor_dev_attr_in9_max.dev_attr.attr,
+       &sensor_dev_attr_in10_max.dev_attr.attr,
+       &sensor_dev_attr_in11_max.dev_attr.attr,
+       &sensor_dev_attr_in12_max.dev_attr.attr,
+       &sensor_dev_attr_in13_max.dev_attr.attr,
+
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in6_min.dev_attr.attr,
+       &sensor_dev_attr_in7_min.dev_attr.attr,
+       &sensor_dev_attr_in8_min.dev_attr.attr,
+       &sensor_dev_attr_in9_min.dev_attr.attr,
+       &sensor_dev_attr_in10_min.dev_attr.attr,
+       &sensor_dev_attr_in11_min.dev_attr.attr,
+       &sensor_dev_attr_in12_min.dev_attr.attr,
+       &sensor_dev_attr_in13_min.dev_attr.attr,
+
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       &sensor_dev_attr_in8_input.dev_attr.attr,
+       &sensor_dev_attr_in9_input.dev_attr.attr,
+       &sensor_dev_attr_in10_input.dev_attr.attr,
+       &sensor_dev_attr_in11_input.dev_attr.attr,
+       &sensor_dev_attr_in12_input.dev_attr.attr,
+       &sensor_dev_attr_in13_input.dev_attr.attr,
+
+       &sensor_dev_attr_in1_label.dev_attr.attr,
+       &sensor_dev_attr_in2_label.dev_attr.attr,
+       &sensor_dev_attr_in3_label.dev_attr.attr,
+       &sensor_dev_attr_in4_label.dev_attr.attr,
+       &sensor_dev_attr_in5_label.dev_attr.attr,
+       &sensor_dev_attr_in6_label.dev_attr.attr,
+       &sensor_dev_attr_in7_label.dev_attr.attr,
+       &sensor_dev_attr_in8_label.dev_attr.attr,
+       &sensor_dev_attr_in9_label.dev_attr.attr,
+       &sensor_dev_attr_in10_label.dev_attr.attr,
+       &sensor_dev_attr_in11_label.dev_attr.attr,
+       &sensor_dev_attr_in12_label.dev_attr.attr,
+       &sensor_dev_attr_in13_label.dev_attr.attr,
+
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
+       &sensor_dev_attr_in7_alarm.dev_attr.attr,
+       &sensor_dev_attr_in8_alarm.dev_attr.attr,
+       &sensor_dev_attr_in9_alarm.dev_attr.attr,
+       &sensor_dev_attr_in10_alarm.dev_attr.attr,
+       &sensor_dev_attr_in11_alarm.dev_attr.attr,
+       &sensor_dev_attr_in12_alarm.dev_attr.attr,
+       &sensor_dev_attr_in13_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan5_min.dev_attr.attr,
+       &sensor_dev_attr_fan6_min.dev_attr.attr,
+       &sensor_dev_attr_fan7_min.dev_attr.attr,
+       &sensor_dev_attr_fan8_min.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan5_input.dev_attr.attr,
+       &sensor_dev_attr_fan6_input.dev_attr.attr,
+       &sensor_dev_attr_fan7_input.dev_attr.attr,
+       &sensor_dev_attr_fan8_input.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan5_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan6_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan7_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan8_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_force_pwm_max.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+       &sensor_dev_attr_pwm4.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_auto_point1_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_point1_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_point1_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp4_auto_point1_hyst.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_auto_point2_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_point2_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_point2_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp4_auto_point2_hyst.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_temp4_auto_point1_temp.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_temp4_auto_point2_temp.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+
+       &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+       NULL
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adt7462_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (kind <= 0) {
+               int vendor, device, revision;
+
+               vendor = i2c_smbus_read_byte_data(client, ADT7462_REG_VENDOR);
+               if (vendor != ADT7462_VENDOR)
+                       return -ENODEV;
+
+               device = i2c_smbus_read_byte_data(client, ADT7462_REG_DEVICE);
+               if (device != ADT7462_DEVICE)
+                       return -ENODEV;
+
+               revision = i2c_smbus_read_byte_data(client,
+                                                   ADT7462_REG_REVISION);
+               if (revision != ADT7462_REVISION)
+                       return -ENODEV;
+       } else
+               dev_dbg(&adapter->dev, "detection forced\n");
+
+       strlcpy(info->type, "adt7462", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int adt7462_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct adt7462_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct adt7462_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->lock);
+
+       dev_info(&client->dev, "%s chip found\n", client->name);
+
+       /* Register sysfs hooks */
+       data->attrs.attrs = adt7462_attr;
+       err = sysfs_create_group(&client->dev.kobj, &data->attrs);
+       if (err)
+               goto exit_free;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int adt7462_remove(struct i2c_client *client)
+{
+       struct adt7462_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &data->attrs);
+       kfree(data);
+       return 0;
+}
+
+static int __init adt7462_init(void)
+{
+       return i2c_add_driver(&adt7462_driver);
+}
+
+static void __exit adt7462_exit(void)
+{
+       i2c_del_driver(&adt7462_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ADT7462 driver");
+MODULE_LICENSE("GPL");
+
+module_init(adt7462_init);
+module_exit(adt7462_exit);
index d368d8f845e1148d83a55da797d11a5758067b0b..1311a595147e17a136fbe5dbe1b81ebaa635acfe 100644 (file)
@@ -137,6 +137,8 @@ I2C_CLIENT_INSMOD_1(adt7470);
 #define FAN_PERIOD_INVALID     65535
 #define FAN_DATA_VALID(x)      ((x) && (x) != FAN_PERIOD_INVALID)
 
+#define ROUND_DIV(x, divisor)  (((x) + ((divisor) / 2)) / (divisor))
+
 struct adt7470_data {
        struct device           *hwmon_dev;
        struct attribute_group  attrs;
@@ -353,7 +355,13 @@ static ssize_t set_temp_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_min[attr->index] = temp;
@@ -381,7 +389,13 @@ static ssize_t set_temp_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_max[attr->index] = temp;
@@ -430,11 +444,13 @@ static ssize_t set_fan_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
 
-       if (!temp)
+       if (strict_strtol(buf, 10, &temp) || !temp)
                return -EINVAL;
+
        temp = FAN_RPM_TO_PERIOD(temp);
+       temp = SENSORS_LIMIT(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_max[attr->index] = temp;
@@ -465,11 +481,13 @@ static ssize_t set_fan_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
 
-       if (!temp)
+       if (strict_strtol(buf, 10, &temp) || !temp)
                return -EINVAL;
+
        temp = FAN_RPM_TO_PERIOD(temp);
+       temp = SENSORS_LIMIT(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_min[attr->index] = temp;
@@ -507,9 +525,12 @@ static ssize_t set_force_pwm_max(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
        u8 reg;
 
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
        mutex_lock(&data->lock);
        data->force_pwm_max = temp;
        reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
@@ -537,7 +558,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm[attr->index] = temp;
@@ -564,7 +590,12 @@ static ssize_t set_pwm_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_max[attr->index] = temp;
@@ -592,7 +623,12 @@ static ssize_t set_pwm_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_min[attr->index] = temp;
@@ -630,7 +666,13 @@ static ssize_t set_pwm_tmin(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_tmin[attr->index] = temp;
@@ -658,11 +700,14 @@ static ssize_t set_pwm_auto(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
        int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
        int pwm_auto_reg_mask;
+       long temp;
        u8 reg;
 
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
        if (attr->index % 2)
                pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
        else
@@ -716,10 +761,14 @@ static ssize_t set_pwm_auto_temp(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10));
        int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
+       long temp;
        u8 reg;
 
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = cvt_auto_temp(temp);
        if (temp < 0)
                return temp;
 
index b9a8ea30c99c822542682017fc40a4c83e99b4f7..18aa30866a6c53deccb0dc5eeda470dd9b5efd1d 100644 (file)
@@ -129,6 +129,8 @@ I2C_CLIENT_INSMOD_1(adt7473);
 #define FAN_PERIOD_INVALID     65535
 #define FAN_DATA_VALID(x)      ((x) && (x) != FAN_PERIOD_INVALID)
 
+#define ROUND_DIV(x, divisor)  (((x) + ((divisor) / 2)) / (divisor))
+
 struct adt7473_data {
        struct device           *hwmon_dev;
        struct attribute_group  attrs;
@@ -357,7 +359,12 @@ static ssize_t set_volt_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int volt = encode_volt(attr->index, simple_strtol(buf, NULL, 10));
+       long volt;
+
+       if (strict_strtol(buf, 10, &volt))
+               return -EINVAL;
+
+       volt = encode_volt(attr->index, volt);
 
        mutex_lock(&data->lock);
        data->volt_min[attr->index] = volt;
@@ -386,7 +393,12 @@ static ssize_t set_volt_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int volt = encode_volt(attr->index, simple_strtol(buf, NULL, 10));
+       long volt;
+
+       if (strict_strtol(buf, 10, &volt))
+               return -EINVAL;
+
+       volt = encode_volt(attr->index, volt);
 
        mutex_lock(&data->lock);
        data->volt_max[attr->index] = volt;
@@ -419,7 +431,8 @@ static int decode_temp(u8 twos_complement, u8 raw)
 
 static u8 encode_temp(u8 twos_complement, int cooked)
 {
-       return twos_complement ? cooked & 0xFF : cooked + 64;
+       u8 ret = twos_complement ? cooked & 0xFF : cooked + 64;
+       return SENSORS_LIMIT(ret, 0, 255);
 }
 
 static ssize_t show_temp_min(struct device *dev,
@@ -441,7 +454,12 @@ static ssize_t set_temp_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
        temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
@@ -472,7 +490,12 @@ static ssize_t set_temp_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
        temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
@@ -515,11 +538,13 @@ static ssize_t set_fan_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
 
-       if (!temp)
+       if (strict_strtol(buf, 10, &temp) || !temp)
                return -EINVAL;
+
        temp = FAN_RPM_TO_PERIOD(temp);
+       temp = SENSORS_LIMIT(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_min[attr->index] = temp;
@@ -558,7 +583,10 @@ static ssize_t set_max_duty_at_crit(struct device *dev,
        u8 reg;
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
 
        mutex_lock(&data->lock);
        data->max_duty_at_overheat = !!temp;
@@ -587,7 +615,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm[attr->index] = temp;
@@ -614,7 +647,12 @@ static ssize_t set_pwm_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_max[attr->index] = temp;
@@ -642,7 +680,12 @@ static ssize_t set_pwm_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_min[attr->index] = temp;
@@ -672,7 +715,12 @@ static ssize_t set_temp_tmax(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
        temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
@@ -703,7 +751,12 @@ static ssize_t set_temp_tmin(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = ROUND_DIV(temp, 1000);
        temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
@@ -741,7 +794,10 @@ static ssize_t set_pwm_enable(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
 
        switch (temp) {
        case 0:
@@ -805,7 +861,10 @@ static ssize_t set_pwm_auto_temp(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
 
        switch (temp) {
        case 1:
index be3285912cb76b65a7d69375215614f4fc898ee2..f7dce8b9f64b429f30b5eb5128ccca7c0df71bc1 100644 (file)
@@ -128,6 +128,9 @@ static const char* temperature_sensors_sets[][36] = {
 /* Set 13: iMac 8,1 */
        { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
          "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
+/* Set 14: iMac 6,1 */
+       { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
+         "TO0P", "Tp0P", NULL },
 };
 
 /* List of keys used to read/write fan speeds */
@@ -1280,7 +1283,7 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
        { .accelerometer = 0, .light = 0, .temperature_set = 4 },
 /* iMac: temperature set 5 */
        { .accelerometer = 0, .light = 0, .temperature_set = 5 },
-/* MacBook3: accelerometer and temperature set 6 */
+/* MacBook3, MacBook4: accelerometer and temperature set 6 */
        { .accelerometer = 1, .light = 0, .temperature_set = 6 },
 /* MacBook Air: accelerometer, backlight and temperature set 7 */
        { .accelerometer = 1, .light = 1, .temperature_set = 7 },
@@ -1296,6 +1299,8 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
        { .accelerometer = 1, .light = 1, .temperature_set = 12 },
 /* iMac 8: light sensor only, temperature set 13 */
        { .accelerometer = 0, .light = 0, .temperature_set = 13 },
+/* iMac 6: light sensor only, temperature set 14 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 14 },
 };
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
@@ -1329,6 +1334,10 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
          DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
                &applesmc_dmi_data[6]},
+       { applesmc_dmi_match, "Apple MacBook 4", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
+               &applesmc_dmi_data[6]},
        { applesmc_dmi_match, "Apple MacBook 5", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
@@ -1345,10 +1354,18 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
          DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
                &applesmc_dmi_data[4]},
+       { applesmc_dmi_match, "Apple MacPro", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
+               &applesmc_dmi_data[4]},
        { applesmc_dmi_match, "Apple iMac 8", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
                &applesmc_dmi_data[13]},
+       { applesmc_dmi_match, "Apple iMac 6", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
+               &applesmc_dmi_data[14]},
        { applesmc_dmi_match, "Apple iMac 5", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
index 7b0ed5dea399d9fe9a5e385385a216d559d9e326..fe74609a7feb5f706ab907c5d69be9881c5bc731 100644 (file)
 static DEFINE_IDR(aem_idr);
 static DEFINE_SPINLOCK(aem_idr_lock);
 
-static struct device_driver aem_driver = {
-       .name = DRVNAME,
-       .bus = &platform_bus_type,
+static struct platform_driver aem_driver = {
+       .driver = {
+               .name = DRVNAME,
+               .bus = &platform_bus_type,
+       }
 };
 
 struct aem_ipmi_data {
@@ -583,7 +585,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
        data->pdev = platform_device_alloc(DRVNAME, data->id);
        if (!data->pdev)
                goto dev_err;
-       data->pdev->dev.driver = &aem_driver;
+       data->pdev->dev.driver = &aem_driver.driver;
 
        res = platform_device_add(data->pdev);
        if (res)
@@ -716,7 +718,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
        data->pdev = platform_device_alloc(DRVNAME, data->id);
        if (!data->pdev)
                goto dev_err;
-       data->pdev->dev.driver = &aem_driver;
+       data->pdev->dev.driver = &aem_driver.driver;
 
        res = platform_device_add(data->pdev);
        if (res)
@@ -1085,7 +1087,7 @@ static int __init aem_init(void)
 {
        int res;
 
-       res = driver_register(&aem_driver);
+       res = driver_register(&aem_driver.driver);
        if (res) {
                printk(KERN_ERR "Can't register aem driver\n");
                return res;
@@ -1097,7 +1099,7 @@ static int __init aem_init(void)
        return 0;
 
 ipmi_reg_err:
-       driver_unregister(&aem_driver);
+       driver_unregister(&aem_driver.driver);
        return res;
 
 }
@@ -1107,7 +1109,7 @@ static void __exit aem_exit(void)
        struct aem_data *p1, *next1;
 
        ipmi_smi_watcher_unregister(&driver_data.bmc_events);
-       driver_unregister(&aem_driver);
+       driver_unregister(&aem_driver.driver);
        list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list)
                aem_delete(p1);
 }
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
new file mode 100644 (file)
index 0000000..c002144
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ *  lis3lv02d.c - ST LIS3LV02DL accelerometer driver
+ *
+ *  Copyright (C) 2007-2008 Yan Burman
+ *  Copyright (C) 2008 Eric Piel
+ *
+ *  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/init.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/kthread.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/freezer.h>
+#include <linux/uaccess.h>
+#include <acpi/acpi_drivers.h>
+#include <asm/atomic.h>
+#include "lis3lv02d.h"
+
+#define DRIVER_NAME     "lis3lv02d"
+#define ACPI_MDPS_CLASS "accelerometer"
+
+/* joystick device poll interval in milliseconds */
+#define MDPS_POLL_INTERVAL 50
+/*
+ * The sensor can also generate interrupts (DRDY) but it's pretty pointless
+ * because their are generated even if the data do not change. So it's better
+ * to keep the interrupt for the free-fall event. The values are updated at
+ * 40Hz (at the lowest frequency), but as it can be pretty time consuming on
+ * some low processor, we poll the sensor only at 20Hz... enough for the
+ * joystick.
+ */
+
+/* Maximum value our axis may get for the input device (signed 12 bits) */
+#define MDPS_MAX_VAL 2048
+
+struct axis_conversion {
+       s8      x;
+       s8      y;
+       s8      z;
+};
+
+struct acpi_lis3lv02d {
+       struct acpi_device      *device;   /* The ACPI device */
+       struct input_dev        *idev;     /* input device */
+       struct task_struct      *kthread;  /* kthread for input */
+       struct mutex            lock;
+       struct platform_device  *pdev;     /* platform device */
+       atomic_t                count;     /* interrupt count after last read */
+       int                     xcalib;    /* calibrated null value for x */
+       int                     ycalib;    /* calibrated null value for y */
+       int                     zcalib;    /* calibrated null value for z */
+       unsigned char           is_on;     /* whether the device is on or off */
+       unsigned char           usage;     /* usage counter */
+       struct axis_conversion  ac;        /* hw -> logical axis */
+};
+
+static struct acpi_lis3lv02d adev;
+
+static int lis3lv02d_remove_fs(void);
+static int lis3lv02d_add_fs(struct acpi_device *device);
+
+/* For automatic insertion of the module */
+static struct acpi_device_id lis3lv02d_device_ids[] = {
+       {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
+
+/**
+ * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
+ * @handle: the handle of the device
+ *
+ * Returns AE_OK on success.
+ */
+static inline acpi_status lis3lv02d_acpi_init(acpi_handle handle)
+{
+       return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL);
+}
+
+/**
+ * lis3lv02d_acpi_read - ACPI ALRD method: read a register
+ * @handle: the handle of the device
+ * @reg:    the register to read
+ * @ret:    result of the operation
+ *
+ * Returns AE_OK on success.
+ */
+static acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
+{
+       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+       struct acpi_object_list args = { 1, &arg0 };
+       unsigned long long lret;
+       acpi_status status;
+
+       arg0.integer.value = reg;
+
+       status = acpi_evaluate_integer(handle, "ALRD", &args, &lret);
+       *ret = lret;
+       return status;
+}
+
+/**
+ * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
+ * @handle: the handle of the device
+ * @reg:    the register to write to
+ * @val:    the value to write
+ *
+ * Returns AE_OK on success.
+ */
+static acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
+{
+       unsigned long long ret; /* Not used when writting */
+       union acpi_object in_obj[2];
+       struct acpi_object_list args = { 2, in_obj };
+
+       in_obj[0].type          = ACPI_TYPE_INTEGER;
+       in_obj[0].integer.value = reg;
+       in_obj[1].type          = ACPI_TYPE_INTEGER;
+       in_obj[1].integer.value = val;
+
+       return acpi_evaluate_integer(handle, "ALWR", &args, &ret);
+}
+
+static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
+{
+       u8 lo, hi;
+
+       lis3lv02d_acpi_read(handle, reg, &lo);
+       lis3lv02d_acpi_read(handle, reg + 1, &hi);
+       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
+       return (s16)((hi << 8) | lo);
+}
+
+/**
+ * lis3lv02d_get_axis - For the given axis, give the value converted
+ * @axis:      1,2,3 - can also be negative
+ * @hw_values: raw values returned by the hardware
+ *
+ * Returns the converted value.
+ */
+static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
+{
+       if (axis > 0)
+               return hw_values[axis - 1];
+       else
+               return -hw_values[-axis - 1];
+}
+
+/**
+ * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
+ * @handle: the handle to the device
+ * @x:      where to store the X axis value
+ * @y:      where to store the Y axis value
+ * @z:      where to store the Z axis value
+ *
+ * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
+ */
+static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
+{
+       int position[3];
+
+       position[0] = lis3lv02d_read_16(handle, OUTX_L);
+       position[1] = lis3lv02d_read_16(handle, OUTY_L);
+       position[2] = lis3lv02d_read_16(handle, OUTZ_L);
+
+       *x = lis3lv02d_get_axis(adev.ac.x, position);
+       *y = lis3lv02d_get_axis(adev.ac.y, position);
+       *z = lis3lv02d_get_axis(adev.ac.z, position);
+}
+
+static inline void lis3lv02d_poweroff(acpi_handle handle)
+{
+       adev.is_on = 0;
+       /* disable X,Y,Z axis and power down */
+       lis3lv02d_acpi_write(handle, CTRL_REG1, 0x00);
+}
+
+static void lis3lv02d_poweron(acpi_handle handle)
+{
+       u8 val;
+
+       adev.is_on = 1;
+       lis3lv02d_acpi_init(handle);
+       lis3lv02d_acpi_write(handle, FF_WU_CFG, 0);
+       /*
+        * BDU: LSB and MSB values are not updated until both have been read.
+        *      So the value read will always be correct.
+        * IEN: Interrupt for free-fall and DD, not for data-ready.
+        */
+       lis3lv02d_acpi_read(handle, CTRL_REG2, &val);
+       val |= CTRL2_BDU | CTRL2_IEN;
+       lis3lv02d_acpi_write(handle, CTRL_REG2, val);
+}
+
+#ifdef CONFIG_PM
+static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
+{
+       /* make sure the device is off when we suspend */
+       lis3lv02d_poweroff(device->handle);
+       return 0;
+}
+
+static int lis3lv02d_resume(struct acpi_device *device)
+{
+       /* put back the device in the right state (ACPI might turn it on) */
+       mutex_lock(&adev.lock);
+       if (adev.usage > 0)
+               lis3lv02d_poweron(device->handle);
+       else
+               lis3lv02d_poweroff(device->handle);
+       mutex_unlock(&adev.lock);
+       return 0;
+}
+#else
+#define lis3lv02d_suspend NULL
+#define lis3lv02d_resume NULL
+#endif
+
+
+/*
+ * To be called before starting to use the device. It makes sure that the
+ * device will always be on until a call to lis3lv02d_decrease_use(). Not to be
+ * used from interrupt context.
+ */
+static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev)
+{
+       mutex_lock(&dev->lock);
+       dev->usage++;
+       if (dev->usage == 1) {
+               if (!dev->is_on)
+                       lis3lv02d_poweron(dev->device->handle);
+       }
+       mutex_unlock(&dev->lock);
+}
+
+/*
+ * To be called whenever a usage of the device is stopped.
+ * It will make sure to turn off the device when there is not usage.
+ */
+static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev)
+{
+       mutex_lock(&dev->lock);
+       dev->usage--;
+       if (dev->usage == 0)
+               lis3lv02d_poweroff(dev->device->handle);
+       mutex_unlock(&dev->lock);
+}
+
+/**
+ * lis3lv02d_joystick_kthread - Kthread polling function
+ * @data: unused - here to conform to threadfn prototype
+ */
+static int lis3lv02d_joystick_kthread(void *data)
+{
+       int x, y, z;
+
+       while (!kthread_should_stop()) {
+               lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z);
+               input_report_abs(adev.idev, ABS_X, x - adev.xcalib);
+               input_report_abs(adev.idev, ABS_Y, y - adev.ycalib);
+               input_report_abs(adev.idev, ABS_Z, z - adev.zcalib);
+
+               input_sync(adev.idev);
+
+               try_to_freeze();
+               msleep_interruptible(MDPS_POLL_INTERVAL);
+       }
+
+       return 0;
+}
+
+static int lis3lv02d_joystick_open(struct input_dev *input)
+{
+       lis3lv02d_increase_use(&adev);
+       adev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
+       if (IS_ERR(adev.kthread)) {
+               lis3lv02d_decrease_use(&adev);
+               return PTR_ERR(adev.kthread);
+       }
+
+       return 0;
+}
+
+static void lis3lv02d_joystick_close(struct input_dev *input)
+{
+       kthread_stop(adev.kthread);
+       lis3lv02d_decrease_use(&adev);
+}
+
+
+static inline void lis3lv02d_calibrate_joystick(void)
+{
+       lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib);
+}
+
+static int lis3lv02d_joystick_enable(void)
+{
+       int err;
+
+       if (adev.idev)
+               return -EINVAL;
+
+       adev.idev = input_allocate_device();
+       if (!adev.idev)
+               return -ENOMEM;
+
+       lis3lv02d_calibrate_joystick();
+
+       adev.idev->name       = "ST LIS3LV02DL Accelerometer";
+       adev.idev->phys       = DRIVER_NAME "/input0";
+       adev.idev->id.bustype = BUS_HOST;
+       adev.idev->id.vendor  = 0;
+       adev.idev->dev.parent = &adev.pdev->dev;
+       adev.idev->open       = lis3lv02d_joystick_open;
+       adev.idev->close      = lis3lv02d_joystick_close;
+
+       set_bit(EV_ABS, adev.idev->evbit);
+       input_set_abs_params(adev.idev, ABS_X, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
+       input_set_abs_params(adev.idev, ABS_Y, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
+       input_set_abs_params(adev.idev, ABS_Z, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
+
+       err = input_register_device(adev.idev);
+       if (err) {
+               input_free_device(adev.idev);
+               adev.idev = NULL;
+       }
+
+       return err;
+}
+
+static void lis3lv02d_joystick_disable(void)
+{
+       if (!adev.idev)
+               return;
+
+       input_unregister_device(adev.idev);
+       adev.idev = NULL;
+}
+
+
+/*
+ * Initialise the accelerometer and the various subsystems.
+ * Should be rather independant of the bus system.
+ */
+static int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
+{
+       mutex_init(&dev->lock);
+       lis3lv02d_add_fs(dev->device);
+       lis3lv02d_increase_use(dev);
+
+       if (lis3lv02d_joystick_enable())
+               printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
+
+       lis3lv02d_decrease_use(dev);
+       return 0;
+}
+
+static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
+{
+       adev.ac = *((struct axis_conversion *)dmi->driver_data);
+       printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
+
+       return 1;
+}
+
+/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
+ * If the value is negative, the opposite of the hw value is used. */
+static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
+static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
+static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
+static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
+static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
+static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
+
+#define AXIS_DMI_MATCH(_ident, _name, _axis) {         \
+       .ident = _ident,                                \
+       .callback = lis3lv02d_dmi_matched,              \
+       .matches = {                                    \
+               DMI_MATCH(DMI_PRODUCT_NAME, _name)      \
+       },                                              \
+       .driver_data = &lis3lv02d_axis_##_axis          \
+}
+static struct dmi_system_id lis3lv02d_dmi_ids[] = {
+       /* product names are truncated to match all kinds of a same model */
+       AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
+       AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
+       AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
+       AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
+       AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
+       AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
+       AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
+       { NULL, }
+/* Laptop models without axis info (yet):
+ * "NC651xx" "HP Compaq 651"
+ * "NC671xx" "HP Compaq 671"
+ * "NC6910" "HP Compaq 6910"
+ * HP Compaq 8710x Notebook PC / Mobile Workstation
+ * "NC2400" "HP Compaq nc2400"
+ * "NX74x0" "HP Compaq nx74"
+ * "NX6325" "HP Compaq nx6325"
+ * "NC4400" "HP Compaq nc4400"
+ */
+};
+
+static int lis3lv02d_add(struct acpi_device *device)
+{
+       u8 val;
+
+       if (!device)
+               return -EINVAL;
+
+       adev.device = device;
+       strcpy(acpi_device_name(device), DRIVER_NAME);
+       strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
+       device->driver_data = &adev;
+
+       lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val);
+       if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) {
+               printk(KERN_ERR DRIVER_NAME
+                               ": Accelerometer chip not LIS3LV02D{L,Q}\n");
+       }
+
+       /* If possible use a "standard" axes order */
+       if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
+               printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
+                                "using default axes configuration\n");
+               adev.ac = lis3lv02d_axis_normal;
+       }
+
+       return lis3lv02d_init_device(&adev);
+}
+
+static int lis3lv02d_remove(struct acpi_device *device, int type)
+{
+       if (!device)
+               return -EINVAL;
+
+       lis3lv02d_joystick_disable();
+       lis3lv02d_poweroff(device->handle);
+
+       return lis3lv02d_remove_fs();
+}
+
+
+/* Sysfs stuff */
+static ssize_t lis3lv02d_position_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int x, y, z;
+
+       lis3lv02d_increase_use(&adev);
+       lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z);
+       lis3lv02d_decrease_use(&adev);
+       return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
+}
+
+static ssize_t lis3lv02d_calibrate_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "(%d,%d,%d)\n", adev.xcalib, adev.ycalib, adev.zcalib);
+}
+
+static ssize_t lis3lv02d_calibrate_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       lis3lv02d_increase_use(&adev);
+       lis3lv02d_calibrate_joystick();
+       lis3lv02d_decrease_use(&adev);
+       return count;
+}
+
+/* conversion btw sampling rate and the register values */
+static int lis3lv02dl_df_val[4] = {40, 160, 640, 2560};
+static ssize_t lis3lv02d_rate_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       u8 ctrl;
+       int val;
+
+       lis3lv02d_increase_use(&adev);
+       lis3lv02d_acpi_read(adev.device->handle, CTRL_REG1, &ctrl);
+       lis3lv02d_decrease_use(&adev);
+       val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
+       return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
+}
+
+static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
+static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, lis3lv02d_calibrate_show,
+       lis3lv02d_calibrate_store);
+static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL);
+
+static struct attribute *lis3lv02d_attributes[] = {
+       &dev_attr_position.attr,
+       &dev_attr_calibrate.attr,
+       &dev_attr_rate.attr,
+       NULL
+};
+
+static struct attribute_group lis3lv02d_attribute_group = {
+       .attrs = lis3lv02d_attributes
+};
+
+static int lis3lv02d_add_fs(struct acpi_device *device)
+{
+       adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(adev.pdev))
+               return PTR_ERR(adev.pdev);
+
+       return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+}
+
+static int lis3lv02d_remove_fs(void)
+{
+       sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+       platform_device_unregister(adev.pdev);
+       return 0;
+}
+
+/* For the HP MDPS aka 3D Driveguard */
+static struct acpi_driver lis3lv02d_driver = {
+       .name  = DRIVER_NAME,
+       .class = ACPI_MDPS_CLASS,
+       .ids   = lis3lv02d_device_ids,
+       .ops = {
+               .add     = lis3lv02d_add,
+               .remove  = lis3lv02d_remove,
+               .suspend = lis3lv02d_suspend,
+               .resume  = lis3lv02d_resume,
+       }
+};
+
+static int __init lis3lv02d_init_module(void)
+{
+       int ret;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       ret = acpi_bus_register_driver(&lis3lv02d_driver);
+       if (ret < 0)
+               return ret;
+
+       printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
+
+       return 0;
+}
+
+static void __exit lis3lv02d_exit_module(void)
+{
+       acpi_bus_unregister_driver(&lis3lv02d_driver);
+}
+
+MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
+MODULE_AUTHOR("Yan Burman and Eric Piel");
+MODULE_LICENSE("GPL");
+
+module_init(lis3lv02d_init_module);
+module_exit(lis3lv02d_exit_module);
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h
new file mode 100644 (file)
index 0000000..330cfc6
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  lis3lv02d.h - ST LIS3LV02DL accelerometer driver
+ *
+ *  Copyright (C) 2007-2008 Yan Burman
+ *  Copyright (C) 2008 Eric Piel
+ *
+ *  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
+ */
+
+/*
+ * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
+ * be connected via SPI. There exists also several similar chips (such as LIS302DL or
+ * LIS3L02DQ) but not in the HP laptops and they have slightly different registers.
+ * They can also be connected via I²C.
+ */
+
+#define LIS3LV02DL_ID  0x3A /* Also the LIS3LV02DQ */
+#define LIS302DL_ID    0x3B /* Also the LIS202DL! */
+
+enum lis3lv02d_reg {
+       WHO_AM_I        = 0x0F,
+       OFFSET_X        = 0x16,
+       OFFSET_Y        = 0x17,
+       OFFSET_Z        = 0x18,
+       GAIN_X          = 0x19,
+       GAIN_Y          = 0x1A,
+       GAIN_Z          = 0x1B,
+       CTRL_REG1       = 0x20,
+       CTRL_REG2       = 0x21,
+       CTRL_REG3       = 0x22,
+       HP_FILTER_RESET = 0x23,
+       STATUS_REG      = 0x27,
+       OUTX_L          = 0x28,
+       OUTX_H          = 0x29,
+       OUTY_L          = 0x2A,
+       OUTY_H          = 0x2B,
+       OUTZ_L          = 0x2C,
+       OUTZ_H          = 0x2D,
+       FF_WU_CFG       = 0x30,
+       FF_WU_SRC       = 0x31,
+       FF_WU_ACK       = 0x32,
+       FF_WU_THS_L     = 0x34,
+       FF_WU_THS_H     = 0x35,
+       FF_WU_DURATION  = 0x36,
+       DD_CFG          = 0x38,
+       DD_SRC          = 0x39,
+       DD_ACK          = 0x3A,
+       DD_THSI_L       = 0x3C,
+       DD_THSI_H       = 0x3D,
+       DD_THSE_L       = 0x3E,
+       DD_THSE_H       = 0x3F,
+};
+
+enum lis3lv02d_ctrl1 {
+       CTRL1_Xen       = 0x01,
+       CTRL1_Yen       = 0x02,
+       CTRL1_Zen       = 0x04,
+       CTRL1_ST        = 0x08,
+       CTRL1_DF0       = 0x10,
+       CTRL1_DF1       = 0x20,
+       CTRL1_PD0       = 0x40,
+       CTRL1_PD1       = 0x80,
+};
+enum lis3lv02d_ctrl2 {
+       CTRL2_DAS       = 0x01,
+       CTRL2_SIM       = 0x02,
+       CTRL2_DRDY      = 0x04,
+       CTRL2_IEN       = 0x08,
+       CTRL2_BOOT      = 0x10,
+       CTRL2_BLE       = 0x20,
+       CTRL2_BDU       = 0x40, /* Block Data Update */
+       CTRL2_FS        = 0x80, /* Full Scale selection */
+};
+
+
+enum lis3lv02d_ctrl3 {
+       CTRL3_CFS0      = 0x01,
+       CTRL3_CFS1      = 0x02,
+       CTRL3_FDS       = 0x10,
+       CTRL3_HPFF      = 0x20,
+       CTRL3_HPDD      = 0x40,
+       CTRL3_ECK       = 0x80,
+};
+
+enum lis3lv02d_status_reg {
+       STATUS_XDA      = 0x01,
+       STATUS_YDA      = 0x02,
+       STATUS_ZDA      = 0x04,
+       STATUS_XYZDA    = 0x08,
+       STATUS_XOR      = 0x10,
+       STATUS_YOR      = 0x20,
+       STATUS_ZOR      = 0x40,
+       STATUS_XYZOR    = 0x80,
+};
+
+enum lis3lv02d_ff_wu_cfg {
+       FF_WU_CFG_XLIE  = 0x01,
+       FF_WU_CFG_XHIE  = 0x02,
+       FF_WU_CFG_YLIE  = 0x04,
+       FF_WU_CFG_YHIE  = 0x08,
+       FF_WU_CFG_ZLIE  = 0x10,
+       FF_WU_CFG_ZHIE  = 0x20,
+       FF_WU_CFG_LIR   = 0x40,
+       FF_WU_CFG_AOI   = 0x80,
+};
+
+enum lis3lv02d_ff_wu_src {
+       FF_WU_SRC_XL    = 0x01,
+       FF_WU_SRC_XH    = 0x02,
+       FF_WU_SRC_YL    = 0x04,
+       FF_WU_SRC_YH    = 0x08,
+       FF_WU_SRC_ZL    = 0x10,
+       FF_WU_SRC_ZH    = 0x20,
+       FF_WU_SRC_IA    = 0x40,
+};
+
+enum lis3lv02d_dd_cfg {
+       DD_CFG_XLIE     = 0x01,
+       DD_CFG_XHIE     = 0x02,
+       DD_CFG_YLIE     = 0x04,
+       DD_CFG_YHIE     = 0x08,
+       DD_CFG_ZLIE     = 0x10,
+       DD_CFG_ZHIE     = 0x20,
+       DD_CFG_LIR      = 0x40,
+       DD_CFG_IEND     = 0x80,
+};
+
+enum lis3lv02d_dd_src {
+       DD_SRC_XL       = 0x01,
+       DD_SRC_XH       = 0x02,
+       DD_SRC_YL       = 0x04,
+       DD_SRC_YH       = 0x08,
+       DD_SRC_ZL       = 0x10,
+       DD_SRC_ZH       = 0x20,
+       DD_SRC_IA       = 0x40,
+};
+
index 3ff0285396fa1dd764a17e207ed6f266cfcb43e0..cfc1ee90f5a39d1934c686a5100a185457c2b8a6 100644 (file)
@@ -39,7 +39,8 @@
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
 /* Insmod parameters */
-I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
+I2C_CLIENT_INSMOD_7(lm85b, lm85c, adm1027, adt7463, adt7468, emc6d100,
+                   emc6d102);
 
 /* The LM85 registers */
 
@@ -59,6 +60,12 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 
 #define        LM85_REG_COMPANY                0x3e
 #define        LM85_REG_VERSTEP                0x3f
+
+#define        ADT7468_REG_CFG5                0x7c
+#define                ADT7468_OFF64           0x01
+#define        IS_ADT7468_OFF64(data)          \
+       ((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))
+
 /* These are the recognized values for the above regs */
 #define        LM85_COMPANY_NATIONAL           0x01
 #define        LM85_COMPANY_ANALOG_DEV         0x41
@@ -70,6 +77,8 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 #define        LM85_VERSTEP_ADM1027            0x60
 #define        LM85_VERSTEP_ADT7463            0x62
 #define        LM85_VERSTEP_ADT7463C           0x6A
+#define        LM85_VERSTEP_ADT7468_1          0x71
+#define        LM85_VERSTEP_ADT7468_2          0x72
 #define        LM85_VERSTEP_EMC6D100_A0        0x60
 #define        LM85_VERSTEP_EMC6D100_A1        0x61
 #define        LM85_VERSTEP_EMC6D102           0x65
@@ -306,6 +315,7 @@ struct lm85_data {
        u8 vid;                 /* Register value */
        u8 vrm;                 /* VRM version */
        u32 alarms;             /* Register encoding, combined */
+       u8 cfg5;                /* Config Register 5 on ADT7468 */
        struct lm85_autofan autofan[3];
        struct lm85_zone zone[3];
 };
@@ -685,6 +695,9 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
 
+       if (IS_ADT7468_OFF64(data))
+               val += 64;
+
        mutex_lock(&data->update_lock);
        data->temp_min[nr] = TEMP_TO_REG(val);
        lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]);
@@ -708,6 +721,9 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        struct lm85_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
 
+       if (IS_ADT7468_OFF64(data))
+               val += 64;
+
        mutex_lock(&data->update_lock);
        data->temp_max[nr] = TEMP_TO_REG(val);
        lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]);
@@ -1163,6 +1179,10 @@ static int lm85_detect(struct i2c_client *client, int kind,
                        case LM85_VERSTEP_ADT7463C:
                                kind = adt7463;
                                break;
+                       case LM85_VERSTEP_ADT7468_1:
+                       case LM85_VERSTEP_ADT7468_2:
+                               kind = adt7468;
+                               break;
                        }
                } else if (company == LM85_COMPANY_SMSC) {
                        switch (verstep) {
@@ -1195,6 +1215,9 @@ static int lm85_detect(struct i2c_client *client, int kind,
        case adt7463:
                type_name = "adt7463";
                break;
+       case adt7468:
+               type_name = "adt7468";
+               break;
        case emc6d100:
                type_name = "emc6d100";
                break;
@@ -1246,10 +1269,11 @@ static int lm85_probe(struct i2c_client *client,
        if (err)
                goto err_kfree;
 
-       /* The ADT7463 has an optional VRM 10 mode where pin 21 is used
+       /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
           as a sixth digital VID input rather than an analog input. */
        data->vid = lm85_read_value(client, LM85_REG_VID);
-       if (!(data->type == adt7463 && (data->vid & 0x80)))
+       if (!((data->type == adt7463 || data->type == adt7468) &&
+           (data->vid & 0x80)))
                if ((err = sysfs_create_group(&client->dev.kobj,
                                        &lm85_group_in4)))
                        goto err_remove_files;
@@ -1357,7 +1381,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                 * There are 2 additional resolution bits per channel and we
                 * have room for 4, so we shift them to the left.
                 */
-               if (data->type == adm1027 || data->type == adt7463) {
+               if (data->type == adm1027 || data->type == adt7463 ||
+                   data->type == adt7468) {
                        int ext1 = lm85_read_value(client,
                                                   ADM1027_REG_EXTEND_ADC1);
                        int ext2 =  lm85_read_value(client,
@@ -1382,16 +1407,23 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                            lm85_read_value(client, LM85_REG_FAN(i));
                }
 
-               if (!(data->type == adt7463 && (data->vid & 0x80))) {
+               if (!((data->type == adt7463 || data->type == adt7468) &&
+                   (data->vid & 0x80))) {
                        data->in[4] = lm85_read_value(client,
                                      LM85_REG_IN(4));
                }
 
+               if (data->type == adt7468)
+                       data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5);
+
                for (i = 0; i <= 2; ++i) {
                        data->temp[i] =
                            lm85_read_value(client, LM85_REG_TEMP(i));
                        data->pwm[i] =
                            lm85_read_value(client, LM85_REG_PWM(i));
+
+                       if (IS_ADT7468_OFF64(data))
+                               data->temp[i] -= 64;
                }
 
                data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
@@ -1446,7 +1478,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                            lm85_read_value(client, LM85_REG_FAN_MIN(i));
                }
 
-               if (!(data->type == adt7463 && (data->vid & 0x80))) {
+               if (!((data->type == adt7463 || data->type == adt7468) &&
+                   (data->vid & 0x80))) {
                        data->in_min[4] = lm85_read_value(client,
                                          LM85_REG_IN_MIN(4));
                        data->in_max[4] = lm85_read_value(client,
@@ -1481,6 +1514,13 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                            lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
                        data->zone[i].critical =
                            lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
+
+                       if (IS_ADT7468_OFF64(data)) {
+                               data->temp_min[i] -= 64;
+                               data->temp_max[i] -= 64;
+                               data->zone[i].limit -= 64;
+                               data->zone[i].critical -= 64;
+                       }
                }
 
                i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
index 640cbb237328196b1b3b22a91fea4b9ee42bf3b1..3384a717fec0d1d864eff63d8d0c798d7edd47cc 100644 (file)
@@ -318,7 +318,8 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
                } else
                        data = i2c_op(pd, OP_RX, 0);
 
-               pd->msg->buf[real_pos] = data;
+               if (real_pos >= 0)
+                       pd->msg->buf[real_pos] = data;
        } while (0);
 
        pd->pos++;
index cb199c815b534234bbd115c0ea19df7fea3a48e9..f50210fe558f1cd7ffff023385508be18029d4a1 100644 (file)
@@ -444,6 +444,7 @@ static struct pcmcia_device_id ide_ids[] = {
        PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
        PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
        PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
+       PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
        PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, ide_ids);
index bb904a0a98bdc353e14a512aaf45ed650769908d..1bfc55d7a26c745d226f840edcfd784dd6930985 100644 (file)
@@ -1641,8 +1641,10 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
        /* slarp reply, send own ip/netmask; if values are nonsense remote
         * should think we are unable to provide it with an address via SLARP */
        p += put_u32(p, CISCO_SLARP_REPLY);
-       p += put_u32(p, addr);  // address
-       p += put_u32(p, mask);  // netmask
+       *(__be32 *)p = addr;    // address
+       p += 4;
+       *(__be32 *)p = mask;    // netmask
+       p += 4;
        p += put_u16(p, 0);     // unused
 
        isdn_net_write_super(lp, skb);
index 4840733cd9032c48a1253a8fae8ebdea2d4c09cd..3d7f4923cd133a2216115bb18d6fb177eb93ffd1 100644 (file)
@@ -441,13 +441,13 @@ static void process_queued_ios(struct work_struct *work)
                __choose_pgpath(m);
 
        pgpath = m->current_pgpath;
-       m->pgpath_to_activate = m->current_pgpath;
 
        if ((pgpath && !m->queue_io) ||
            (!pgpath && !m->queue_if_no_path))
                must_queue = 0;
 
-       if (m->pg_init_required && !m->pg_init_in_progress) {
+       if (m->pg_init_required && !m->pg_init_in_progress && pgpath) {
+               m->pgpath_to_activate = pgpath;
                m->pg_init_count++;
                m->pg_init_required = 0;
                m->pg_init_in_progress = 1;
@@ -708,6 +708,10 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
                m->hw_handler_name = NULL;
                return -EINVAL;
        }
+
+       if (hw_argc > 1)
+               DMWARN("Ignoring user-specified arguments for "
+                      "hardware handler \"%s\"", m->hw_handler_name);
        consume(as, hw_argc - 1);
 
        return 0;
index 9d7b53ed75b228e05bc865571afdd424da92f483..ec43f9fa4b2acaffed0bf45f79edc5a115f36804 100644 (file)
@@ -1032,6 +1032,7 @@ static void mirror_dtr(struct dm_target *ti)
 
        del_timer_sync(&ms->timer);
        flush_workqueue(ms->kmirrord_wq);
+       flush_scheduled_work();
        dm_kcopyd_client_destroy(ms->kcopyd_client);
        destroy_workqueue(ms->kmirrord_wq);
        free_context(ms, ti, ms->nr_mirrors);
index a2d068dbe9e2669dc25290a09e8918b4b5c2f28f..9e4ef88d421e499dfb05e1697593bcbf82fefe38 100644 (file)
@@ -320,8 +320,10 @@ int __init dm_stripe_init(void)
        int r;
 
        r = dm_register_target(&stripe_target);
-       if (r < 0)
+       if (r < 0) {
                DMWARN("target registration failed");
+               return r;
+       }
 
        kstriped = create_singlethread_workqueue("kstriped");
        if (!kstriped) {
index 6963ad1484082bf5d0f8009c60aa1db18eb980c1..c99e4728ff4162ed16c4a7ec99fdc0c27c8cb35f 100644 (file)
@@ -375,7 +375,7 @@ static void start_io_acct(struct dm_io *io)
        dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
 }
 
-static int end_io_acct(struct dm_io *io)
+static void end_io_acct(struct dm_io *io)
 {
        struct mapped_device *md = io->md;
        struct bio *bio = io->bio;
@@ -391,7 +391,9 @@ static int end_io_acct(struct dm_io *io)
        dm_disk(md)->part0.in_flight = pending =
                atomic_dec_return(&md->pending);
 
-       return !pending;
+       /* nudge anyone waiting on suspend queue */
+       if (!pending)
+               wake_up(&md->wait);
 }
 
 /*
@@ -499,9 +501,7 @@ static void dec_pending(struct dm_io *io, int error)
                        spin_unlock_irqrestore(&io->md->pushback_lock, flags);
                }
 
-               if (end_io_acct(io))
-                       /* nudge anyone waiting on suspend queue */
-                       wake_up(&io->md->wait);
+               end_io_acct(io);
 
                if (io->error != DM_ENDIO_REQUEUE) {
                        blk_add_trace_bio(io->md->queue, io->bio,
@@ -937,16 +937,24 @@ static void dm_unplug_all(struct request_queue *q)
 
 static int dm_any_congested(void *congested_data, int bdi_bits)
 {
-       int r;
-       struct mapped_device *md = (struct mapped_device *) congested_data;
-       struct dm_table *map = dm_get_table(md);
+       int r = bdi_bits;
+       struct mapped_device *md = congested_data;
+       struct dm_table *map;
 
-       if (!map || test_bit(DMF_BLOCK_IO, &md->flags))
-               r = bdi_bits;
-       else
-               r = dm_table_any_congested(map, bdi_bits);
+       atomic_inc(&md->pending);
+
+       if (!test_bit(DMF_BLOCK_IO, &md->flags)) {
+               map = dm_get_table(md);
+               if (map) {
+                       r = dm_table_any_congested(map, bdi_bits);
+                       dm_table_put(map);
+               }
+       }
+
+       if (!atomic_dec_return(&md->pending))
+               /* nudge anyone waiting on suspend queue */
+               wake_up(&md->wait);
 
-       dm_table_put(map);
        return r;
 }
 
index b59e47272abfc292493e65bf66a0d2fbdda56f62..3720f0e03a16906efd339b0eefb89b5454499abf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * experimental driver for simple i2c audio chips.
+ * Driver for simple i2c audio chips.
  *
  * Copyright (c) 2000 Gerd Knorr
  * based on code by:
@@ -7,6 +7,10 @@
  *   Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  *   Greg Alexander (galexand@acm.org)
  *
+ * Copyright(c) 2005-2008 Mauro Carvalho Chehab
+ *     - Some cleanups, code fixes, etc
+ *     - Convert it to V4L2 API
+ *
  * This code is placed under the terms of the GNU General Public License
  *
  * OPTIONS:
@@ -30,6 +34,7 @@
 
 #include <media/tvaudio.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 
@@ -58,7 +63,6 @@ typedef int  (*checkit)(struct CHIPSTATE*);
 typedef int  (*initialize)(struct CHIPSTATE*);
 typedef int  (*getmode)(struct CHIPSTATE*);
 typedef void (*setmode)(struct CHIPSTATE*, int mode);
-typedef void (*checkmode)(struct CHIPSTATE*);
 
 /* i2c command */
 typedef struct AUDIOCMD {
@@ -79,6 +83,7 @@ struct CHIPDESC {
 #define CHIP_HAS_VOLUME      1
 #define CHIP_HAS_BASSTREBLE  2
 #define CHIP_HAS_INPUTSEL    4
+#define CHIP_NEED_CHECKMODE  8
 
        /* various i2c command sequences */
        audiocmd   init;
@@ -96,23 +101,20 @@ struct CHIPDESC {
        getmode  getmode;
        setmode  setmode;
 
-       /* check / autoswitch audio after channel switches */
-       checkmode  checkmode;
-
        /* input switch register + values for v4l inputs */
        int  inputreg;
        int  inputmap[4];
        int  inputmute;
        int  inputmask;
 };
-static struct CHIPDESC chiplist[];
 
 /* current state of the chip */
 struct CHIPSTATE {
        struct i2c_client *c;
 
-       /* index into CHIPDESC array */
-       int type;
+       /* chip-specific description - should point to
+          an entry at CHIPDESC table */
+       struct CHIPDESC *desc;
 
        /* shadow register set */
        audiocmd   shadow;
@@ -152,7 +154,7 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
 {
        unsigned char buffer[2];
 
-       if (-1 == subaddr) {
+       if (subaddr < 0) {
                v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
                        chip->c->name, val);
                chip->shadow.bytes[1] = val;
@@ -163,6 +165,13 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
                        return -1;
                }
        } else {
+               if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+                       v4l_info(chip->c,
+                               "Tried to access a non-existent register: %d\n",
+                               subaddr);
+                       return -EINVAL;
+               }
+
                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;
@@ -177,12 +186,20 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
        return 0;
 }
 
-static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
+static int chip_write_masked(struct CHIPSTATE *chip,
+                            int subaddr, int val, int mask)
 {
        if (mask != 0) {
-               if (-1 == subaddr) {
+               if (subaddr < 0) {
                        val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
                } else {
+                       if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+                               v4l_info(chip->c,
+                                       "Tried to access a non-existent register: %d\n",
+                                       subaddr);
+                               return -EINVAL;
+                       }
+
                        val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
                }
        }
@@ -228,6 +245,15 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
        if (0 == cmd->count)
                return 0;
 
+       if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+               v4l_info(chip->c,
+                        "Tried to access a non-existent register range: %d to %d\n",
+                        cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
+               return -EINVAL;
+       }
+
+       /* FIXME: it seems that the shadow bytes are wrong bellow !*/
+
        /* 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]);
@@ -263,7 +289,8 @@ static void chip_thread_wake(unsigned long data)
 static int chip_thread(void *data)
 {
        struct CHIPSTATE *chip = data;
-       struct CHIPDESC  *desc = chiplist + chip->type;
+       struct CHIPDESC  *desc = chip->desc;
+       int mode;
 
        v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
        set_freezable();
@@ -282,7 +309,26 @@ static int chip_thread(void *data)
                        continue;
 
                /* have a look what's going on */
-               desc->checkmode(chip);
+               mode = desc->getmode(chip);
+               if (mode == chip->prevmode)
+                       continue;
+
+               /* chip detected a new audio mode - set it */
+               v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n",
+                       chip->c->name);
+
+               chip->prevmode = mode;
+
+               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, V4L2_TUNER_MODE_MONO);
 
                /* schedule next check */
                mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
@@ -292,29 +338,6 @@ static int chip_thread(void *data)
        return 0;
 }
 
-static void generic_checkmode(struct CHIPSTATE *chip)
-{
-       struct CHIPDESC  *desc = chiplist + chip->type;
-       int mode = desc->getmode(chip);
-
-       if (mode == chip->prevmode)
-       return;
-
-       v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name);
-       chip->prevmode = mode;
-
-       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,V4L2_TUNER_MODE_MONO);
-}
-
 /* ---------------------------------------------------------------------- */
 /* audio chip descriptions - defines+functions for tda9840                */
 
@@ -777,7 +800,7 @@ static struct tda9874a_MODES {
        char *name;
        audiocmd cmd;
 } tda9874a_modelist[9] = {
-  {    "A2, B/G",
+  {    "A2, B/G", /* default */
        { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} },
   {    "A2, M (Korea)",
        { 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} },
@@ -791,7 +814,7 @@ static struct tda9874a_MODES {
        { 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} },
   {    "NICAM, B/G",
        { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} },
-  {    "NICAM, D/K", /* default */
+  {    "NICAM, D/K",
        { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} },
   {    "NICAM, L",
        { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} }
@@ -981,7 +1004,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
 {
        if (tda9874a_SIF > 2)
                tda9874a_SIF = 1;
-       if (tda9874a_STD > 8)
+       if (tda9874a_STD >= ARRAY_SIZE(tda9874a_modelist))
                tda9874a_STD = 0;
        if(tda9874a_AMSEL > 1)
                tda9874a_AMSEL = 0;
@@ -1089,7 +1112,7 @@ static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 
 static int tda8425_initialize(struct CHIPSTATE *chip)
 {
-       struct CHIPDESC *desc = chiplist + chip->type;
+       struct CHIPDESC *desc = chip->desc;
        int inputmap[4] = { /* tuner    */ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
                            /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
 
@@ -1259,27 +1282,28 @@ static struct CHIPDESC chiplist[] = {
                .addr_lo    = I2C_ADDR_TDA9840 >> 1,
                .addr_hi    = I2C_ADDR_TDA9840 >> 1,
                .registers  = 5,
+               .flags      = CHIP_NEED_CHECKMODE,
 
+               /* callbacks */
                .checkit    = tda9840_checkit,
                .getmode    = tda9840_getmode,
                .setmode    = tda9840_setmode,
-               .checkmode  = generic_checkmode,
 
                .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
                                /* ,TDA9840_SW, TDA9840_MONO */} }
        },
        {
                .name       = "tda9873h",
-               .checkit    = tda9873_checkit,
                .insmodopt  = &tda9873,
                .addr_lo    = I2C_ADDR_TDA985x_L >> 1,
                .addr_hi    = I2C_ADDR_TDA985x_H >> 1,
                .registers  = 3,
-               .flags      = CHIP_HAS_INPUTSEL,
+               .flags      = CHIP_HAS_INPUTSEL | CHIP_NEED_CHECKMODE,
 
+               /* callbacks */
+               .checkit    = tda9873_checkit,
                .getmode    = tda9873_getmode,
                .setmode    = tda9873_setmode,
-               .checkmode  = generic_checkmode,
 
                .init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
                .inputreg   = TDA9873_SW,
@@ -1290,15 +1314,16 @@ static struct CHIPDESC chiplist[] = {
        },
        {
                .name       = "tda9874h/a",
-               .checkit    = tda9874a_checkit,
-               .initialize = tda9874a_initialize,
                .insmodopt  = &tda9874a,
                .addr_lo    = I2C_ADDR_TDA9874 >> 1,
                .addr_hi    = I2C_ADDR_TDA9874 >> 1,
+               .flags      = CHIP_NEED_CHECKMODE,
 
+               /* callbacks */
+               .initialize = tda9874a_initialize,
+               .checkit    = tda9874a_checkit,
                .getmode    = tda9874a_getmode,
                .setmode    = tda9874a_setmode,
-               .checkmode  = generic_checkmode,
        },
        {
                .name       = "tda9850",
@@ -1324,10 +1349,11 @@ static struct CHIPDESC chiplist[] = {
                .rightreg   = TDA9855_VR,
                .bassreg    = TDA9855_BA,
                .treblereg  = TDA9855_TR,
+
+               /* callbacks */
                .volfunc    = tda9855_volume,
                .bassfunc   = tda9855_bass,
                .treblefunc = tda9855_treble,
-
                .getmode    = tda985x_getmode,
                .setmode    = tda985x_setmode,
 
@@ -1348,6 +1374,8 @@ static struct CHIPDESC chiplist[] = {
                .rightreg   = TEA6300_VL,
                .bassreg    = TEA6300_BA,
                .treblereg  = TEA6300_TR,
+
+               /* callbacks */
                .volfunc    = tea6300_shift10,
                .bassfunc   = tea6300_shift12,
                .treblefunc = tea6300_shift12,
@@ -1358,7 +1386,6 @@ static struct CHIPDESC chiplist[] = {
        },
        {
                .name       = "tea6320",
-               .initialize = tea6320_initialize,
                .insmodopt  = &tea6320,
                .addr_lo    = I2C_ADDR_TEA6300 >> 1,
                .addr_hi    = I2C_ADDR_TEA6300 >> 1,
@@ -1369,6 +1396,9 @@ static struct CHIPDESC chiplist[] = {
                .rightreg   = TEA6320_V,
                .bassreg    = TEA6320_BA,
                .treblereg  = TEA6320_TR,
+
+               /* callbacks */
+               .initialize = tea6320_initialize,
                .volfunc    = tea6320_volume,
                .bassfunc   = tea6320_shift11,
                .treblefunc = tea6320_shift11,
@@ -1401,16 +1431,18 @@ static struct CHIPDESC chiplist[] = {
                .rightreg   = TDA8425_VR,
                .bassreg    = TDA8425_BA,
                .treblereg  = TDA8425_TR,
+
+               /* callbacks */
+               .initialize = tda8425_initialize,
                .volfunc    = tda8425_shift10,
                .bassfunc   = tda8425_shift12,
                .treblefunc = tda8425_shift12,
+               .setmode    = tda8425_setmode,
 
                .inputreg   = TDA8425_S1,
                .inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
                .inputmute  = TDA8425_S1_OFF,
 
-               .setmode    = tda8425_setmode,
-               .initialize = tda8425_initialize,
        },
        {
                .name       = "pic16c54 (PV951)",
@@ -1434,10 +1466,11 @@ static struct CHIPDESC chiplist[] = {
                .addr_lo    = I2C_ADDR_TDA9840 >> 1,
                .addr_hi    = I2C_ADDR_TDA9840 >> 1,
                .registers  = 2,
+               .flags      = CHIP_NEED_CHECKMODE,
 
+               /* callbacks */
                .getmode    = ta8874z_getmode,
                .setmode    = ta8874z_setmode,
-               .checkmode  = generic_checkmode,
 
                .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
        },
@@ -1481,6 +1514,7 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
        }
        if (desc->name == NULL) {
                v4l_dbg(1, debug, client, "no matching chip description found\n");
+               kfree(chip);
                return -EIO;
        }
        v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
@@ -1494,7 +1528,7 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* fill required data structures */
        if (!id)
                strlcpy(client->name, desc->name, I2C_NAME_SIZE);
-       chip->type = desc-chiplist;
+       chip->desc = desc;
        chip->shadow.count = desc->registers+1;
        chip->prevmode = -1;
        chip->audmode = V4L2_TUNER_MODE_LANG1;
@@ -1506,20 +1540,49 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
                chip_cmd(chip,"init",&desc->init);
 
        if (desc->flags & CHIP_HAS_VOLUME) {
-               chip->left   = desc->leftinit   ? desc->leftinit   : 65535;
-               chip->right  = desc->rightinit  ? desc->rightinit  : 65535;
-               chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-               chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+               if (!desc->volfunc) {
+                       /* This shouldn't be happen. Warn user, but keep working
+                          without volume controls
+                        */
+                       v4l_info(chip->c, "volume callback undefined!\n");
+                       desc->flags &= ~CHIP_HAS_VOLUME;
+               } else {
+                       chip->left  = desc->leftinit  ? desc->leftinit  : 65535;
+                       chip->right = desc->rightinit ? desc->rightinit : 65535;
+                       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->treble = desc->trebleinit ? desc->trebleinit : 32768;
-               chip->bass   = desc->bassinit   ? desc->bassinit   : 32768;
-               chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
-               chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+               if (!desc->bassfunc || !desc->treblefunc) {
+                       /* This shouldn't be happen. Warn user, but keep working
+                          without bass/treble controls
+                        */
+                       v4l_info(chip->c, "bass/treble callbacks undefined!\n");
+                       desc->flags &= ~CHIP_HAS_BASSTREBLE;
+               } else {
+                       chip->treble = desc->trebleinit ?
+                                               desc->trebleinit : 32768;
+                       chip->bass   = desc->bassinit   ?
+                                               desc->bassinit   : 32768;
+                       chip_write(chip, desc->bassreg,
+                                  desc->bassfunc(chip->bass));
+                       chip_write(chip, desc->treblereg,
+                                  desc->treblefunc(chip->treble));
+               }
        }
 
        chip->thread = NULL;
-       if (desc->checkmode) {
+       if (desc->flags & CHIP_NEED_CHECKMODE) {
+               if (!desc->getmode || !desc->setmode) {
+                       /* This shouldn't be happen. Warn user, but keep working
+                          without kthread
+                        */
+                       v4l_info(chip->c, "set/get mode callbacks undefined!\n");
+                       return 0;
+               }
                /* start async thread */
                init_timer(&chip->wt);
                chip->wt.function = chip_thread_wake;
@@ -1552,7 +1615,7 @@ static int chip_remove(struct i2c_client *client)
 static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
                            struct v4l2_control *ctrl)
 {
-       struct CHIPDESC *desc = chiplist + chip->type;
+       struct CHIPDESC *desc = chip->desc;
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -1576,13 +1639,13 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
                return 0;
        }
        case V4L2_CID_AUDIO_BASS:
-               if (desc->flags & CHIP_HAS_BASSTREBLE)
+               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;
+               if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+                       break;
                ctrl->value = chip->treble;
                return 0;
        }
@@ -1592,7 +1655,7 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
 static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
                            struct v4l2_control *ctrl)
 {
-       struct CHIPDESC *desc = chiplist + chip->type;
+       struct CHIPDESC *desc = chip->desc;
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -1642,16 +1705,15 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
                return 0;
        }
        case V4L2_CID_AUDIO_BASS:
-               if (desc->flags & CHIP_HAS_BASSTREBLE)
+               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;
-
+               if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+                       break;
                chip->treble = ctrl->value;
                chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
 
@@ -1668,9 +1730,12 @@ static int chip_command(struct i2c_client *client,
                        unsigned int cmd, void *arg)
 {
        struct CHIPSTATE *chip = i2c_get_clientdata(client);
-       struct CHIPDESC  *desc = chiplist + chip->type;
+       struct CHIPDESC  *desc = chip->desc;
 
-       v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);
+       if (debug > 0) {
+               v4l_i2c_print_ioctl(chip->c, cmd);
+               printk("\n");
+       }
 
        switch (cmd) {
        case AUDC_SET_RADIO:
@@ -1695,7 +1760,7 @@ static int chip_command(struct i2c_client *client,
                                break;
                        case V4L2_CID_AUDIO_BASS:
                        case V4L2_CID_AUDIO_TREBLE:
-                               if (desc->flags & CHIP_HAS_BASSTREBLE)
+                               if (!(desc->flags & CHIP_HAS_BASSTREBLE))
                                        return -EINVAL;
                                break;
                        default:
@@ -1792,12 +1857,20 @@ static int chip_command(struct i2c_client *client,
                break;
        case VIDIOC_S_FREQUENCY:
                chip->mode = 0; /* automatic */
-               if (desc->checkmode && desc->setmode) {
+
+               /* For chips that provide getmode and setmode, and doesn't
+                  automatically follows the stereo carrier, a kthread is
+                  created to set the audio standard. In this case, when then
+                  the video channel is changed, tvaudio starts on MONO mode.
+                  After waiting for 2 seconds, the kernel thread is called,
+                  to follow whatever audio standard is pointed by the
+                  audio carrier.
+                */
+               if (chip->thread) {
                        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 */
                }
                break;
 
@@ -1836,9 +1909,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .legacy_probe = chip_legacy_probe,
        .id_table = chip_id,
 };
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index b57326ae464d4f91f83fce55e412d12f5712effa..0b5bd85dfcec5e4d4bdabfeae15a4a19f19f28ed 100644 (file)
@@ -267,7 +267,7 @@ static int da9030_mask_events(struct da903x_chip *chip, unsigned int events)
 {
        uint8_t v[3];
 
-       chip->events_mask &= ~events;
+       chip->events_mask |= events;
 
        v[0] = (chip->events_mask & 0xff);
        v[1] = (chip->events_mask >> 8) & 0xff;
index 8dfe21bb3bd128d213ae581bd604eea96f82e869..3e0ce0e50ea2263edcec7fcb3300ac20d693c866 100644 (file)
@@ -30,7 +30,12 @@ static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg,
        ret = i2c_master_send(wm8350->i2c_client, &reg, 1);
        if (ret < 0)
                return ret;
-       return i2c_master_recv(wm8350->i2c_client, dest, bytes);
+       ret = i2c_master_recv(wm8350->i2c_client, dest, bytes);
+       if (ret < 0)
+               return ret;
+       if (ret != bytes)
+               return -EIO;
+       return 0;
 }
 
 static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
@@ -38,13 +43,19 @@ static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
 {
        /* we add 1 byte for device register */
        u8 msg[(WM8350_MAX_REGISTER << 1) + 1];
+       int ret;
 
        if (bytes > ((WM8350_MAX_REGISTER << 1) + 1))
                return -EINVAL;
 
        msg[0] = reg;
        memcpy(&msg[1], src, bytes);
-       return i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
+       ret = i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
+       if (ret < 0)
+               return ret;
+       if (ret != bytes + 1)
+               return -EIO;
+       return 0;
 }
 
 static int wm8350_i2c_probe(struct i2c_client *i2c,
index 4494ad27cbf135b0156032d7224b989fe02b0723..fee7304102af8158ca3882bccb854f0f6fcb2bbe 100644 (file)
@@ -227,6 +227,16 @@ config HP_WMI
          To compile this driver as a module, choose M here: the module will
          be called hp-wmi.
 
+config ICS932S401
+       tristate "Integrated Circuits ICS932S401"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for the Integrated Circuits
+         ICS932S401 clock control chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called ics932s401.
+
 config MSI_LAPTOP
         tristate "MSI Laptop Extras"
         depends on X86
@@ -488,4 +498,6 @@ config SGI_GRU_DEBUG
        This option enables addition debugging code for the SGI GRU driver. If
        you are unsure, say N.
 
+source "drivers/misc/c2port/Kconfig"
+
 endif # MISC_DEVICES
index 909e2468cdc974be5e4ffc7c3e85affc6f6129c6..817f7f5ab3bd2c21476033c195dbba93bf58d05b 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_ATMEL_PWM)               += atmel_pwm.o
 obj-$(CONFIG_ATMEL_SSC)                += atmel-ssc.o
 obj-$(CONFIG_ATMEL_TCLIB)      += atmel_tclib.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
+obj-$(CONFIG_ICS932S401)       += ics932s401.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
 obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_KGDB_TESTS)      += kgdbts.o
 obj-$(CONFIG_SGI_XP)           += sgi-xp/
 obj-$(CONFIG_SGI_GRU)          += sgi-gru/
 obj-$(CONFIG_HP_ILO)           += hpilo.o
+obj-$(CONFIG_C2PORT)           += c2port/
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
new file mode 100644 (file)
index 0000000..e46af9a
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# C2 port devices
+#
+
+menuconfig C2PORT
+       tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       default no
+       help
+         This option enables support for Silicon Labs C2 port used to
+         program Silicon micro controller chips (and other 8051 compatible).
+
+         If your board have no such micro controllers you don't need this
+         interface at all.
+
+         To compile this driver as a module, choose M here: the module will
+         be called c2port_core. Note that you also need a client module
+         usually called c2port-*.
+
+         If you are not sure, say N here.
+
+if C2PORT
+
+config C2PORT_DURAMAR_2150
+       tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)"
+       depends on X86 && C2PORT
+       default no
+       help
+         This option enables C2 support for the Eurotech's Duramar 2150
+         on board micro controller.
+
+         To compile this driver as a module, choose M here: the module will
+         be called c2port-duramar2150.
+
+endif # C2PORT
diff --git a/drivers/misc/c2port/Makefile b/drivers/misc/c2port/Makefile
new file mode 100644 (file)
index 0000000..3b2cf43
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_C2PORT)           += core.o
+
+obj-$(CONFIG_C2PORT_DURAMAR_2150)      += c2port-duramar2150.o
diff --git a/drivers/misc/c2port/c2port-duramar2150.c b/drivers/misc/c2port/c2port-duramar2150.c
new file mode 100644 (file)
index 0000000..338dcc1
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *  Silicon Labs C2 port Linux support for Eurotech Duramar 2150
+ *
+ *  Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it>
+ *  Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * 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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/c2port.h>
+
+#define DATA_PORT      0x325
+#define DIR_PORT       0x326
+#define    C2D            (1 << 0)
+#define    C2CK                   (1 << 1)
+
+static DEFINE_MUTEX(update_lock);
+
+/*
+ * C2 port operations
+ */
+
+static void duramar2150_c2port_access(struct c2port_device *dev, int status)
+{
+       u8 v;
+
+       mutex_lock(&update_lock);
+
+       v = inb(DIR_PORT);
+
+       /* 0 = input, 1 = output */
+       if (status)
+               outb(v | (C2D | C2CK), DIR_PORT);
+       else
+               /* When access is "off" is important that both lines are set
+                * as inputs or hi-impedence */
+               outb(v & ~(C2D | C2CK), DIR_PORT);
+
+       mutex_unlock(&update_lock);
+}
+
+static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir)
+{
+       u8 v;
+
+       mutex_lock(&update_lock);
+
+       v = inb(DIR_PORT);
+
+       if (dir)
+               outb(v & ~C2D, DIR_PORT);
+       else
+               outb(v | C2D, DIR_PORT);
+
+       mutex_unlock(&update_lock);
+}
+
+static int duramar2150_c2port_c2d_get(struct c2port_device *dev)
+{
+       return inb(DATA_PORT) & C2D;
+}
+
+static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status)
+{
+       u8 v;
+
+       mutex_lock(&update_lock);
+
+       v = inb(DATA_PORT);
+
+       if (status)
+               outb(v | C2D, DATA_PORT);
+       else
+               outb(v & ~C2D, DATA_PORT);
+
+       mutex_unlock(&update_lock);
+}
+
+static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status)
+{
+       u8 v;
+
+       mutex_lock(&update_lock);
+
+       v = inb(DATA_PORT);
+
+       if (status)
+               outb(v | C2CK, DATA_PORT);
+       else
+               outb(v & ~C2CK, DATA_PORT);
+
+       mutex_unlock(&update_lock);
+}
+
+static struct c2port_ops duramar2150_c2port_ops = {
+       .block_size     = 512,  /* bytes */
+       .blocks_num     = 30,   /* total flash size: 15360 bytes */
+
+       .access         = duramar2150_c2port_access,
+       .c2d_dir        = duramar2150_c2port_c2d_dir,
+       .c2d_get        = duramar2150_c2port_c2d_get,
+       .c2d_set        = duramar2150_c2port_c2d_set,
+       .c2ck_set       = duramar2150_c2port_c2ck_set,
+};
+
+static struct c2port_device *duramar2150_c2port_dev;
+
+/*
+ * Module stuff
+ */
+
+static int __init duramar2150_c2port_init(void)
+{
+       struct resource *res;
+       int ret = 0;
+
+       res = request_region(0x325, 2, "c2port");
+       if (!res)
+               return -EBUSY;
+
+       duramar2150_c2port_dev = c2port_device_register("uc",
+                                       &duramar2150_c2port_ops, NULL);
+       if (!duramar2150_c2port_dev) {
+               ret = -ENODEV;
+               goto free_region;
+       }
+
+       return 0;
+
+free_region:
+       release_region(0x325, 2);
+       return ret;
+}
+
+static void __exit duramar2150_c2port_exit(void)
+{
+       /* Setup the GPIOs as input by default (access = 0) */
+       duramar2150_c2port_access(duramar2150_c2port_dev, 0);
+
+       c2port_device_unregister(duramar2150_c2port_dev);
+
+       release_region(0x325, 2);
+}
+
+module_init(duramar2150_c2port_init);
+module_exit(duramar2150_c2port_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
new file mode 100644 (file)
index 0000000..0207dd5
--- /dev/null
@@ -0,0 +1,1003 @@
+/*
+ *  Silicon Labs C2 port core Linux support
+ *
+ *  Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it>
+ *  Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/sched.h>
+
+#include <linux/c2port.h>
+
+#define DRIVER_NAME             "c2port"
+#define DRIVER_VERSION          "0.51.0"
+
+static DEFINE_SPINLOCK(c2port_idr_lock);
+static DEFINE_IDR(c2port_idr);
+
+/*
+ * Local variables
+ */
+
+static struct class *c2port_class;
+
+/*
+ * C2 registers & commands defines
+ */
+
+/* C2 registers */
+#define C2PORT_DEVICEID                0x00
+#define C2PORT_REVID           0x01
+#define C2PORT_FPCTL           0x02
+#define C2PORT_FPDAT           0xB4
+
+/* C2 interface commands */
+#define C2PORT_GET_VERSION     0x01
+#define C2PORT_DEVICE_ERASE    0x03
+#define C2PORT_BLOCK_READ      0x06
+#define C2PORT_BLOCK_WRITE     0x07
+#define C2PORT_PAGE_ERASE      0x08
+
+/* C2 status return codes */
+#define C2PORT_INVALID_COMMAND 0x00
+#define C2PORT_COMMAND_FAILED  0x02
+#define C2PORT_COMMAND_OK      0x0d
+
+/*
+ * C2 port low level signal managements
+ */
+
+static void c2port_reset(struct c2port_device *dev)
+{
+       struct c2port_ops *ops = dev->ops;
+
+       /* To reset the device we have to keep clock line low for at least
+        * 20us.
+        */
+       local_irq_disable();
+       ops->c2ck_set(dev, 0);
+       udelay(25);
+       ops->c2ck_set(dev, 1);
+       local_irq_enable();
+
+       udelay(1);
+}
+
+static void c2port_strobe_ck(struct c2port_device *dev)
+{
+       struct c2port_ops *ops = dev->ops;
+
+       /* During hi-low-hi transition we disable local IRQs to avoid
+        * interructions since C2 port specification says that it must be
+        * shorter than 5us, otherwise the microcontroller may consider
+        * it as a reset signal!
+        */
+       local_irq_disable();
+       ops->c2ck_set(dev, 0);
+       udelay(1);
+       ops->c2ck_set(dev, 1);
+       local_irq_enable();
+
+       udelay(1);
+}
+
+/*
+ * C2 port basic functions
+ */
+
+static void c2port_write_ar(struct c2port_device *dev, u8 addr)
+{
+       struct c2port_ops *ops = dev->ops;
+       int i;
+
+       /* START field */
+       c2port_strobe_ck(dev);
+
+       /* INS field (11b, LSB first) */
+       ops->c2d_dir(dev, 0);
+       ops->c2d_set(dev, 1);
+       c2port_strobe_ck(dev);
+       ops->c2d_set(dev, 1);
+       c2port_strobe_ck(dev);
+
+       /* ADDRESS field */
+       for (i = 0; i < 8; i++) {
+               ops->c2d_set(dev, addr & 0x01);
+               c2port_strobe_ck(dev);
+
+               addr >>= 1;
+       }
+
+       /* STOP field */
+       ops->c2d_dir(dev, 1);
+       c2port_strobe_ck(dev);
+}
+
+static int c2port_read_ar(struct c2port_device *dev, u8 *addr)
+{
+       struct c2port_ops *ops = dev->ops;
+       int i;
+
+       /* START field */
+       c2port_strobe_ck(dev);
+
+       /* INS field (10b, LSB first) */
+       ops->c2d_dir(dev, 0);
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+       ops->c2d_set(dev, 1);
+       c2port_strobe_ck(dev);
+
+       /* ADDRESS field */
+       ops->c2d_dir(dev, 1);
+       *addr = 0;
+       for (i = 0; i < 8; i++) {
+               *addr >>= 1;    /* shift in 8-bit ADDRESS field LSB first */
+
+               c2port_strobe_ck(dev);
+               if (ops->c2d_get(dev))
+                       *addr |= 0x80;
+       }
+
+       /* STOP field */
+       c2port_strobe_ck(dev);
+
+       return 0;
+}
+
+static int c2port_write_dr(struct c2port_device *dev, u8 data)
+{
+       struct c2port_ops *ops = dev->ops;
+       int timeout, i;
+
+       /* START field */
+       c2port_strobe_ck(dev);
+
+       /* INS field (01b, LSB first) */
+       ops->c2d_dir(dev, 0);
+       ops->c2d_set(dev, 1);
+       c2port_strobe_ck(dev);
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+
+       /* LENGTH field (00b, LSB first -> 1 byte) */
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+
+       /* DATA field */
+       for (i = 0; i < 8; i++) {
+               ops->c2d_set(dev, data & 0x01);
+               c2port_strobe_ck(dev);
+
+               data >>= 1;
+       }
+
+       /* WAIT field */
+       ops->c2d_dir(dev, 1);
+       timeout = 20;
+       do {
+               c2port_strobe_ck(dev);
+               if (ops->c2d_get(dev))
+                       break;
+
+               udelay(1);
+       } while (--timeout > 0);
+       if (timeout == 0)
+               return -EIO;
+
+       /* STOP field */
+       c2port_strobe_ck(dev);
+
+       return 0;
+}
+
+static int c2port_read_dr(struct c2port_device *dev, u8 *data)
+{
+       struct c2port_ops *ops = dev->ops;
+       int timeout, i;
+
+       /* START field */
+       c2port_strobe_ck(dev);
+
+       /* INS field (00b, LSB first) */
+       ops->c2d_dir(dev, 0);
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+
+       /* LENGTH field (00b, LSB first -> 1 byte) */
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+       ops->c2d_set(dev, 0);
+       c2port_strobe_ck(dev);
+
+       /* WAIT field */
+       ops->c2d_dir(dev, 1);
+       timeout = 20;
+       do {
+               c2port_strobe_ck(dev);
+               if (ops->c2d_get(dev))
+                       break;
+
+               udelay(1);
+       } while (--timeout > 0);
+       if (timeout == 0)
+               return -EIO;
+
+       /* DATA field */
+       *data = 0;
+       for (i = 0; i < 8; i++) {
+               *data >>= 1;    /* shift in 8-bit DATA field LSB first */
+
+               c2port_strobe_ck(dev);
+               if (ops->c2d_get(dev))
+                       *data |= 0x80;
+       }
+
+       /* STOP field */
+       c2port_strobe_ck(dev);
+
+       return 0;
+}
+
+static int c2port_poll_in_busy(struct c2port_device *dev)
+{
+       u8 addr;
+       int ret, timeout = 20;
+
+       do {
+               ret = (c2port_read_ar(dev, &addr));
+               if (ret < 0)
+                       return -EIO;
+
+               if (!(addr & 0x02))
+                       break;
+
+               udelay(1);
+       } while (--timeout > 0);
+       if (timeout == 0)
+               return -EIO;
+
+       return 0;
+}
+
+static int c2port_poll_out_ready(struct c2port_device *dev)
+{
+       u8 addr;
+       int ret, timeout = 10000; /* erase flash needs long time... */
+
+       do {
+               ret = (c2port_read_ar(dev, &addr));
+               if (ret < 0)
+                       return -EIO;
+
+               if (addr & 0x01)
+                       break;
+
+               udelay(1);
+       } while (--timeout > 0);
+       if (timeout == 0)
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * sysfs methods
+ */
+
+static ssize_t c2port_show_name(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", c2dev->name);
+}
+
+static ssize_t c2port_show_flash_blocks_num(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       struct c2port_ops *ops = c2dev->ops;
+
+       return sprintf(buf, "%d\n", ops->blocks_num);
+}
+
+static ssize_t c2port_show_flash_block_size(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       struct c2port_ops *ops = c2dev->ops;
+
+       return sprintf(buf, "%d\n", ops->block_size);
+}
+
+static ssize_t c2port_show_flash_size(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       struct c2port_ops *ops = c2dev->ops;
+
+       return sprintf(buf, "%d\n", ops->blocks_num * ops->block_size);
+}
+
+static ssize_t c2port_show_access(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", c2dev->access);
+}
+
+static ssize_t c2port_store_access(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       struct c2port_ops *ops = c2dev->ops;
+       int status, ret;
+
+       ret = sscanf(buf, "%d", &status);
+       if (ret != 1)
+               return -EINVAL;
+
+       mutex_lock(&c2dev->mutex);
+
+       c2dev->access = !!status;
+
+       /* If access is "on" clock should be HIGH _before_ setting the line
+        * as output and data line should be set as INPUT anyway */
+       if (c2dev->access)
+               ops->c2ck_set(c2dev, 1);
+       ops->access(c2dev, c2dev->access);
+       if (c2dev->access)
+               ops->c2d_dir(c2dev, 1);
+
+       mutex_unlock(&c2dev->mutex);
+
+       return count;
+}
+
+static ssize_t c2port_store_reset(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+
+       /* Check the device access status */
+       if (!c2dev->access)
+               return -EBUSY;
+
+       mutex_lock(&c2dev->mutex);
+
+       c2port_reset(c2dev);
+       c2dev->flash_access = 0;
+
+       mutex_unlock(&c2dev->mutex);
+
+       return count;
+}
+
+static ssize_t __c2port_show_dev_id(struct c2port_device *dev, char *buf)
+{
+       u8 data;
+       int ret;
+
+       /* Select DEVICEID register for C2 data register accesses */
+       c2port_write_ar(dev, C2PORT_DEVICEID);
+
+       /* Read and return the device ID register */
+       ret = c2port_read_dr(dev, &data);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t c2port_show_dev_id(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       ssize_t ret;
+
+       /* Check the device access status */
+       if (!c2dev->access)
+               return -EBUSY;
+
+       mutex_lock(&c2dev->mutex);
+       ret = __c2port_show_dev_id(c2dev, buf);
+       mutex_unlock(&c2dev->mutex);
+
+       if (ret < 0)
+               dev_err(dev, "cannot read from %s\n", c2dev->name);
+
+       return ret;
+}
+
+static ssize_t __c2port_show_rev_id(struct c2port_device *dev, char *buf)
+{
+       u8 data;
+       int ret;
+
+       /* Select REVID register for C2 data register accesses */
+       c2port_write_ar(dev, C2PORT_REVID);
+
+       /* Read and return the revision ID register */
+       ret = c2port_read_dr(dev, &data);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t c2port_show_rev_id(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       ssize_t ret;
+
+       /* Check the device access status */
+       if (!c2dev->access)
+               return -EBUSY;
+
+       mutex_lock(&c2dev->mutex);
+       ret = __c2port_show_rev_id(c2dev, buf);
+       mutex_unlock(&c2dev->mutex);
+
+       if (ret < 0)
+               dev_err(c2dev->dev, "cannot read from %s\n", c2dev->name);
+
+       return ret;
+}
+
+static ssize_t c2port_show_flash_access(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", c2dev->flash_access);
+}
+
+static ssize_t __c2port_store_flash_access(struct c2port_device *dev,
+                                               int status)
+{
+       int ret;
+
+       /* Check the device access status */
+       if (!dev->access)
+               return -EBUSY;
+
+       dev->flash_access = !!status;
+
+       /* If flash_access is off we have nothing to do... */
+       if (dev->flash_access == 0)
+               return 0;
+
+       /* Target the C2 flash programming control register for C2 data
+        * register access */
+       c2port_write_ar(dev, C2PORT_FPCTL);
+
+       /* Write the first keycode to enable C2 Flash programming */
+       ret = c2port_write_dr(dev, 0x02);
+       if (ret < 0)
+               return ret;
+
+       /* Write the second keycode to enable C2 Flash programming */
+       ret = c2port_write_dr(dev, 0x01);
+       if (ret < 0)
+               return ret;
+
+       /* Delay for at least 20ms to ensure the target is ready for
+        * C2 flash programming */
+       mdelay(25);
+
+       return 0;
+}
+
+static ssize_t c2port_store_flash_access(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       int status;
+       ssize_t ret;
+
+       ret = sscanf(buf, "%d", &status);
+       if (ret != 1)
+               return -EINVAL;
+
+       mutex_lock(&c2dev->mutex);
+       ret = __c2port_store_flash_access(c2dev, status);
+       mutex_unlock(&c2dev->mutex);
+
+       if (ret < 0) {
+               dev_err(c2dev->dev, "cannot enable %s flash programming\n",
+                       c2dev->name);
+               return ret;
+       }
+
+       return count;
+}
+
+static ssize_t __c2port_write_flash_erase(struct c2port_device *dev)
+{
+       u8 status;
+       int ret;
+
+       /* Target the C2 flash programming data register for C2 data register
+        * access.
+        */
+       c2port_write_ar(dev, C2PORT_FPDAT);
+
+       /* Send device erase command */
+       c2port_write_dr(dev, C2PORT_DEVICE_ERASE);
+
+       /* Wait for input acknowledge */
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Should check status before starting FLASH access sequence */
+
+       /* Wait for status information */
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Read flash programming interface status */
+       ret = c2port_read_dr(dev, &status);
+       if (ret < 0)
+               return ret;
+       if (status != C2PORT_COMMAND_OK)
+               return -EBUSY;
+
+       /* Send a three-byte arming sequence to enable the device erase.
+        * If the sequence is not received correctly, the command will be
+        * ignored.
+        * Sequence is: 0xde, 0xad, 0xa5.
+        */
+       c2port_write_dr(dev, 0xde);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+       c2port_write_dr(dev, 0xad);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+       c2port_write_dr(dev, 0xa5);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static ssize_t c2port_store_flash_erase(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct c2port_device *c2dev = dev_get_drvdata(dev);
+       int ret;
+
+       /* Check the device and flash access status */
+       if (!c2dev->access || !c2dev->flash_access)
+               return -EBUSY;
+
+       mutex_lock(&c2dev->mutex);
+       ret = __c2port_write_flash_erase(c2dev);
+       mutex_unlock(&c2dev->mutex);
+
+       if (ret < 0) {
+               dev_err(c2dev->dev, "cannot erase %s flash\n", c2dev->name);
+               return ret;
+       }
+
+       return count;
+}
+
+static ssize_t __c2port_read_flash_data(struct c2port_device *dev,
+                               char *buffer, loff_t offset, size_t count)
+{
+       struct c2port_ops *ops = dev->ops;
+       u8 status, nread = 128;
+       int i, ret;
+
+       /* Check for flash end */
+       if (offset >= ops->block_size * ops->blocks_num)
+               return 0;
+
+       if (ops->block_size * ops->blocks_num - offset < nread)
+               nread = ops->block_size * ops->blocks_num - offset;
+       if (count < nread)
+               nread = count;
+       if (nread == 0)
+               return nread;
+
+       /* Target the C2 flash programming data register for C2 data register
+        * access */
+       c2port_write_ar(dev, C2PORT_FPDAT);
+
+       /* Send flash block read command */
+       c2port_write_dr(dev, C2PORT_BLOCK_READ);
+
+       /* Wait for input acknowledge */
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Should check status before starting FLASH access sequence */
+
+       /* Wait for status information */
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Read flash programming interface status */
+       ret = c2port_read_dr(dev, &status);
+       if (ret < 0)
+               return ret;
+       if (status != C2PORT_COMMAND_OK)
+               return -EBUSY;
+
+       /* Send address high byte */
+       c2port_write_dr(dev, offset >> 8);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Send address low byte */
+       c2port_write_dr(dev, offset & 0x00ff);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Send address block size */
+       c2port_write_dr(dev, nread);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Should check status before reading FLASH block */
+
+       /* Wait for status information */
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Read flash programming interface status */
+       ret = c2port_read_dr(dev, &status);
+       if (ret < 0)
+               return ret;
+       if (status != C2PORT_COMMAND_OK)
+               return -EBUSY;
+
+       /* Read flash block */
+       for (i = 0; i < nread; i++) {
+               ret = c2port_poll_out_ready(dev);
+               if (ret < 0)
+                       return ret;
+
+               ret = c2port_read_dr(dev, buffer+i);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return nread;
+}
+
+static ssize_t c2port_read_flash_data(struct kobject *kobj,
+                               struct bin_attribute *attr,
+                               char *buffer, loff_t offset, size_t count)
+{
+       struct c2port_device *c2dev =
+                       dev_get_drvdata(container_of(kobj,
+                                               struct device, kobj));
+       ssize_t ret;
+
+       /* Check the device and flash access status */
+       if (!c2dev->access || !c2dev->flash_access)
+               return -EBUSY;
+
+       mutex_lock(&c2dev->mutex);
+       ret = __c2port_read_flash_data(c2dev, buffer, offset, count);
+       mutex_unlock(&c2dev->mutex);
+
+       if (ret < 0)
+               dev_err(c2dev->dev, "cannot read %s flash\n", c2dev->name);
+
+       return ret;
+}
+
+static ssize_t __c2port_write_flash_data(struct c2port_device *dev,
+                               char *buffer, loff_t offset, size_t count)
+{
+       struct c2port_ops *ops = dev->ops;
+       u8 status, nwrite = 128;
+       int i, ret;
+
+       if (nwrite > count)
+               nwrite = count;
+       if (ops->block_size * ops->blocks_num - offset < nwrite)
+               nwrite = ops->block_size * ops->blocks_num - offset;
+
+       /* Check for flash end */
+       if (offset >= ops->block_size * ops->blocks_num)
+               return -EINVAL;
+
+       /* Target the C2 flash programming data register for C2 data register
+        * access */
+       c2port_write_ar(dev, C2PORT_FPDAT);
+
+       /* Send flash block write command */
+       c2port_write_dr(dev, C2PORT_BLOCK_WRITE);
+
+       /* Wait for input acknowledge */
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Should check status before starting FLASH access sequence */
+
+       /* Wait for status information */
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Read flash programming interface status */
+       ret = c2port_read_dr(dev, &status);
+       if (ret < 0)
+               return ret;
+       if (status != C2PORT_COMMAND_OK)
+               return -EBUSY;
+
+       /* Send address high byte */
+       c2port_write_dr(dev, offset >> 8);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Send address low byte */
+       c2port_write_dr(dev, offset & 0x00ff);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Send address block size */
+       c2port_write_dr(dev, nwrite);
+       ret = c2port_poll_in_busy(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Should check status before writing FLASH block */
+
+       /* Wait for status information */
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       /* Read flash programming interface status */
+       ret = c2port_read_dr(dev, &status);
+       if (ret < 0)
+               return ret;
+       if (status != C2PORT_COMMAND_OK)
+               return -EBUSY;
+
+       /* Write flash block */
+       for (i = 0; i < nwrite; i++) {
+               ret = c2port_write_dr(dev, *(buffer+i));
+               if (ret < 0)
+                       return ret;
+
+               ret = c2port_poll_in_busy(dev);
+               if (ret < 0)
+                       return ret;
+
+       }
+
+       /* Wait for last flash write to complete */
+       ret = c2port_poll_out_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       return nwrite;
+}
+
+static ssize_t c2port_write_flash_data(struct kobject *kobj,
+                               struct bin_attribute *attr,
+                               char *buffer, loff_t offset, size_t count)
+{
+       struct c2port_device *c2dev =
+                       dev_get_drvdata(container_of(kobj,
+                                               struct device, kobj));
+       int ret;
+
+       /* Check the device access status */
+       if (!c2dev->access || !c2dev->flash_access)
+               return -EBUSY;
+
+       mutex_lock(&c2dev->mutex);
+       ret = __c2port_write_flash_data(c2dev, buffer, offset, count);
+       mutex_unlock(&c2dev->mutex);
+
+       if (ret < 0)
+               dev_err(c2dev->dev, "cannot write %s flash\n", c2dev->name);
+
+       return ret;
+}
+
+/*
+ * Class attributes
+ */
+
+static struct device_attribute c2port_attrs[] = {
+       __ATTR(name, 0444, c2port_show_name, NULL),
+       __ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL),
+       __ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL),
+       __ATTR(flash_size, 0444, c2port_show_flash_size, NULL),
+       __ATTR(access, 0644, c2port_show_access, c2port_store_access),
+       __ATTR(reset, 0200, NULL, c2port_store_reset),
+       __ATTR(dev_id, 0444, c2port_show_dev_id, NULL),
+       __ATTR(rev_id, 0444, c2port_show_rev_id, NULL),
+
+       __ATTR(flash_access, 0644, c2port_show_flash_access,
+                                       c2port_store_flash_access),
+       __ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase),
+       __ATTR_NULL,
+};
+
+static struct bin_attribute c2port_bin_attrs = {
+       .attr   = {
+               .name   = "flash_data",
+               .mode   = 0644
+       },
+       .read   = c2port_read_flash_data,
+       .write  = c2port_write_flash_data,
+       /* .size is computed at run-time */
+};
+
+/*
+ * Exported functions
+ */
+
+struct c2port_device *c2port_device_register(char *name,
+                                       struct c2port_ops *ops, void *devdata)
+{
+       struct c2port_device *c2dev;
+       int id, ret;
+
+       if (unlikely(!ops) || unlikely(!ops->access) || \
+               unlikely(!ops->c2d_dir) || unlikely(!ops->c2ck_set) || \
+               unlikely(!ops->c2d_get) || unlikely(!ops->c2d_set))
+               return ERR_PTR(-EINVAL);
+
+       c2dev = kmalloc(sizeof(struct c2port_device), GFP_KERNEL);
+       if (unlikely(!c2dev))
+               return ERR_PTR(-ENOMEM);
+
+       ret = idr_pre_get(&c2port_idr, GFP_KERNEL);
+       if (!ret) {
+               ret = -ENOMEM;
+               goto error_idr_get_new;
+       }
+
+       spin_lock_irq(&c2port_idr_lock);
+       ret = idr_get_new(&c2port_idr, c2dev, &id);
+       spin_unlock_irq(&c2port_idr_lock);
+
+       if (ret < 0)
+               goto error_idr_get_new;
+       c2dev->id = id;
+
+       c2dev->dev = device_create(c2port_class, NULL, 0, c2dev,
+                                       "c2port%d", id);
+       if (unlikely(!c2dev->dev)) {
+               ret = -ENOMEM;
+               goto error_device_create;
+       }
+       dev_set_drvdata(c2dev->dev, c2dev);
+
+       strncpy(c2dev->name, name, C2PORT_NAME_LEN);
+       c2dev->ops = ops;
+       mutex_init(&c2dev->mutex);
+
+       /* Create binary file */
+       c2port_bin_attrs.size = ops->blocks_num * ops->block_size;
+       ret = device_create_bin_file(c2dev->dev, &c2port_bin_attrs);
+       if (unlikely(ret))
+               goto error_device_create_bin_file;
+
+       /* By default C2 port access is off */
+       c2dev->access = c2dev->flash_access = 0;
+       ops->access(c2dev, 0);
+
+       dev_info(c2dev->dev, "C2 port %s added\n", name);
+       dev_info(c2dev->dev, "%s flash has %d blocks x %d bytes "
+                               "(%d bytes total)\n",
+                               name, ops->blocks_num, ops->block_size,
+                               ops->blocks_num * ops->block_size);
+
+       return c2dev;
+
+error_device_create_bin_file:
+       device_destroy(c2port_class, 0);
+
+error_device_create:
+       spin_lock_irq(&c2port_idr_lock);
+       idr_remove(&c2port_idr, id);
+       spin_unlock_irq(&c2port_idr_lock);
+
+error_idr_get_new:
+       kfree(c2dev);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(c2port_device_register);
+
+void c2port_device_unregister(struct c2port_device *c2dev)
+{
+       if (!c2dev)
+               return;
+
+       dev_info(c2dev->dev, "C2 port %s removed\n", c2dev->name);
+
+       device_remove_bin_file(c2dev->dev, &c2port_bin_attrs);
+       spin_lock_irq(&c2port_idr_lock);
+       idr_remove(&c2port_idr, c2dev->id);
+       spin_unlock_irq(&c2port_idr_lock);
+
+       device_destroy(c2port_class, c2dev->id);
+
+       kfree(c2dev);
+}
+EXPORT_SYMBOL(c2port_device_unregister);
+
+/*
+ * Module stuff
+ */
+
+static int __init c2port_init(void)
+{
+       printk(KERN_INFO "Silicon Labs C2 port support v. " DRIVER_VERSION
+               " - (C) 2007 Rodolfo Giometti\n");
+
+       c2port_class = class_create(THIS_MODULE, "c2port");
+       if (!c2port_class) {
+               printk(KERN_ERR "c2port: failed to allocate class\n");
+               return -ENOMEM;
+       }
+       c2port_class->dev_attrs = c2port_attrs;
+
+       return 0;
+}
+
+static void __exit c2port_exit(void)
+{
+       class_destroy(c2port_class);
+}
+
+module_init(c2port_init);
+module_exit(c2port_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("Silicon Labs C2 port support v. " DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c
new file mode 100644 (file)
index 0000000..6e43ab4
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * A driver for the Integrated Circuits ICS932S401
+ * Copyright (C) 2008 IBM
+ *
+ * Author: Darrick J. Wong <djwong@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.
+ *
+ * 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/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x69, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(ics932s401);
+
+/* ICS932S401 registers */
+#define ICS932S401_REG_CFG2                    0x01
+#define        ICS932S401_CFG1_SPREAD          0x01
+#define ICS932S401_REG_CFG7                    0x06
+#define                ICS932S401_FS_MASK              0x07
+#define        ICS932S401_REG_VENDOR_REV               0x07
+#define                ICS932S401_VENDOR               1
+#define                ICS932S401_VENDOR_MASK          0x0F
+#define                ICS932S401_REV                  4
+#define                ICS932S401_REV_SHIFT            4
+#define ICS932S401_REG_DEVICE                  0x09
+#define                ICS932S401_DEVICE               11
+#define        ICS932S401_REG_CTRL                     0x0A
+#define                ICS932S401_MN_ENABLED           0x80
+#define                ICS932S401_CPU_ALT              0x04
+#define                ICS932S401_SRC_ALT              0x08
+#define ICS932S401_REG_CPU_M_CTRL              0x0B
+#define                ICS932S401_M_MASK               0x3F
+#define        ICS932S401_REG_CPU_N_CTRL               0x0C
+#define        ICS932S401_REG_CPU_SPREAD1              0x0D
+#define ICS932S401_REG_CPU_SPREAD2             0x0E
+#define                ICS932S401_SPREAD_MASK          0x7FFF
+#define ICS932S401_REG_SRC_M_CTRL              0x0F
+#define ICS932S401_REG_SRC_N_CTRL              0x10
+#define        ICS932S401_REG_SRC_SPREAD1              0x11
+#define ICS932S401_REG_SRC_SPREAD2             0x12
+#define ICS932S401_REG_CPU_DIVISOR             0x13
+#define        ICS932S401_CPU_DIVISOR_SHIFT    4
+#define ICS932S401_REG_PCISRC_DIVISOR          0x14
+#define                ICS932S401_SRC_DIVISOR_MASK     0x0F
+#define                ICS932S401_PCI_DIVISOR_SHIFT    4
+
+/* Base clock is 14.318MHz */
+#define BASE_CLOCK                             14318
+
+#define NUM_REGS                               21
+#define NUM_MIRRORED_REGS                      15
+
+static int regs_to_copy[NUM_MIRRORED_REGS] = {
+       ICS932S401_REG_CFG2,
+       ICS932S401_REG_CFG7,
+       ICS932S401_REG_VENDOR_REV,
+       ICS932S401_REG_DEVICE,
+       ICS932S401_REG_CTRL,
+       ICS932S401_REG_CPU_M_CTRL,
+       ICS932S401_REG_CPU_N_CTRL,
+       ICS932S401_REG_CPU_SPREAD1,
+       ICS932S401_REG_CPU_SPREAD2,
+       ICS932S401_REG_SRC_M_CTRL,
+       ICS932S401_REG_SRC_N_CTRL,
+       ICS932S401_REG_SRC_SPREAD1,
+       ICS932S401_REG_SRC_SPREAD2,
+       ICS932S401_REG_CPU_DIVISOR,
+       ICS932S401_REG_PCISRC_DIVISOR,
+};
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL        (2 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL (60 * HZ)
+
+struct ics932s401_data {
+       struct attribute_group  attrs;
+       struct mutex            lock;
+       char                    sensors_valid;
+       unsigned long           sensors_last_updated;   /* In jiffies */
+
+       u8                      regs[NUM_REGS];
+};
+
+static int ics932s401_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id);
+static int ics932s401_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info);
+static int ics932s401_remove(struct i2c_client *client);
+
+static const struct i2c_device_id ics932s401_id[] = {
+       { "ics932s401", ics932s401 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ics932s401_id);
+
+static struct i2c_driver ics932s401_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "ics932s401",
+       },
+       .probe          = ics932s401_probe,
+       .remove         = ics932s401_remove,
+       .id_table       = ics932s401_id,
+       .detect         = ics932s401_detect,
+       .address_data   = &addr_data,
+};
+
+static struct ics932s401_data *ics932s401_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ics932s401_data *data = i2c_get_clientdata(client);
+       unsigned long local_jiffies = jiffies;
+       int i, temp;
+
+       mutex_lock(&data->lock);
+       if (time_before(local_jiffies, data->sensors_last_updated +
+               SENSOR_REFRESH_INTERVAL)
+               && data->sensors_valid)
+               goto out;
+
+       /*
+        * Each register must be read as a word and then right shifted 8 bits.
+        * Not really sure why this is; setting the "byte count programming"
+        * register to 1 does not fix this problem.
+        */
+       for (i = 0; i < NUM_MIRRORED_REGS; i++) {
+               temp = i2c_smbus_read_word_data(client, regs_to_copy[i]);
+               data->regs[regs_to_copy[i]] = temp >> 8;
+       }
+
+       data->sensors_last_updated = local_jiffies;
+       data->sensors_valid = 1;
+
+out:
+       mutex_unlock(&data->lock);
+       return data;
+}
+
+static ssize_t show_spread_enabled(struct device *dev,
+                                  struct device_attribute *devattr,
+                                  char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+
+       if (data->regs[ICS932S401_REG_CFG2] & ICS932S401_CFG1_SPREAD)
+               return sprintf(buf, "1\n");
+
+       return sprintf(buf, "0\n");
+}
+
+/* bit to cpu khz map */
+static const int fs_speeds[] = {
+       266666,
+       133333,
+       200000,
+       166666,
+       333333,
+       100000,
+       400000,
+       0,
+};
+
+/* clock divisor map */
+static const int divisors[] = {2, 3, 5, 15, 4, 6, 10, 30, 8, 12, 20, 60, 16,
+                              24, 40, 120};
+
+/* Calculate CPU frequency from the M/N registers. */
+static int calculate_cpu_freq(struct ics932s401_data *data)
+{
+       int m, n, freq;
+
+       m = data->regs[ICS932S401_REG_CPU_M_CTRL] & ICS932S401_M_MASK;
+       n = data->regs[ICS932S401_REG_CPU_N_CTRL];
+
+       /* Pull in bits 8 & 9 from the M register */
+       n |= ((int)data->regs[ICS932S401_REG_CPU_M_CTRL] & 0x80) << 1;
+       n |= ((int)data->regs[ICS932S401_REG_CPU_M_CTRL] & 0x40) << 3;
+
+       freq = BASE_CLOCK * (n + 8) / (m + 2);
+       freq /= divisors[data->regs[ICS932S401_REG_CPU_DIVISOR] >>
+                        ICS932S401_CPU_DIVISOR_SHIFT];
+
+       return freq;
+}
+
+static ssize_t show_cpu_clock(struct device *dev,
+                             struct device_attribute *devattr,
+                             char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+
+       return sprintf(buf, "%d\n", calculate_cpu_freq(data));
+}
+
+static ssize_t show_cpu_clock_sel(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+       int freq;
+
+       if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
+               freq = calculate_cpu_freq(data);
+       else {
+               /* Freq is neatly wrapped up for us */
+               int fid = data->regs[ICS932S401_REG_CFG7] & ICS932S401_FS_MASK;
+               freq = fs_speeds[fid];
+               if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_CPU_ALT) {
+                       switch (freq) {
+                       case 166666:
+                               freq = 160000;
+                               break;
+                       case 333333:
+                               freq = 320000;
+                               break;
+                       }
+               }
+       }
+
+       return sprintf(buf, "%d\n", freq);
+}
+
+/* Calculate SRC frequency from the M/N registers. */
+static int calculate_src_freq(struct ics932s401_data *data)
+{
+       int m, n, freq;
+
+       m = data->regs[ICS932S401_REG_SRC_M_CTRL] & ICS932S401_M_MASK;
+       n = data->regs[ICS932S401_REG_SRC_N_CTRL];
+
+       /* Pull in bits 8 & 9 from the M register */
+       n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x80) << 1;
+       n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x40) << 3;
+
+       freq = BASE_CLOCK * (n + 8) / (m + 2);
+       freq /= divisors[data->regs[ICS932S401_REG_PCISRC_DIVISOR] &
+                        ICS932S401_SRC_DIVISOR_MASK];
+
+       return freq;
+}
+
+static ssize_t show_src_clock(struct device *dev,
+                             struct device_attribute *devattr,
+                             char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+
+       return sprintf(buf, "%d\n", calculate_src_freq(data));
+}
+
+static ssize_t show_src_clock_sel(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+       int freq;
+
+       if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
+               freq = calculate_src_freq(data);
+       else
+               /* Freq is neatly wrapped up for us */
+               if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_CPU_ALT &&
+                   data->regs[ICS932S401_REG_CTRL] & ICS932S401_SRC_ALT)
+                       freq = 96000;
+               else
+                       freq = 100000;
+
+       return sprintf(buf, "%d\n", freq);
+}
+
+/* Calculate PCI frequency from the SRC M/N registers. */
+static int calculate_pci_freq(struct ics932s401_data *data)
+{
+       int m, n, freq;
+
+       m = data->regs[ICS932S401_REG_SRC_M_CTRL] & ICS932S401_M_MASK;
+       n = data->regs[ICS932S401_REG_SRC_N_CTRL];
+
+       /* Pull in bits 8 & 9 from the M register */
+       n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x80) << 1;
+       n |= ((int)data->regs[ICS932S401_REG_SRC_M_CTRL] & 0x40) << 3;
+
+       freq = BASE_CLOCK * (n + 8) / (m + 2);
+       freq /= divisors[data->regs[ICS932S401_REG_PCISRC_DIVISOR] >>
+                        ICS932S401_PCI_DIVISOR_SHIFT];
+
+       return freq;
+}
+
+static ssize_t show_pci_clock(struct device *dev,
+                             struct device_attribute *devattr,
+                             char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+
+       return sprintf(buf, "%d\n", calculate_pci_freq(data));
+}
+
+static ssize_t show_pci_clock_sel(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+       int freq;
+
+       if (data->regs[ICS932S401_REG_CTRL] & ICS932S401_MN_ENABLED)
+               freq = calculate_pci_freq(data);
+       else
+               freq = 33333;
+
+       return sprintf(buf, "%d\n", freq);
+}
+
+static ssize_t show_value(struct device *dev,
+                         struct device_attribute *devattr,
+                         char *buf);
+
+static ssize_t show_spread(struct device *dev,
+                          struct device_attribute *devattr,
+                          char *buf);
+
+static DEVICE_ATTR(spread_enabled, S_IRUGO, show_spread_enabled, NULL);
+static DEVICE_ATTR(cpu_clock_selection, S_IRUGO, show_cpu_clock_sel, NULL);
+static DEVICE_ATTR(cpu_clock, S_IRUGO, show_cpu_clock, NULL);
+static DEVICE_ATTR(src_clock_selection, S_IRUGO, show_src_clock_sel, NULL);
+static DEVICE_ATTR(src_clock, S_IRUGO, show_src_clock, NULL);
+static DEVICE_ATTR(pci_clock_selection, S_IRUGO, show_pci_clock_sel, NULL);
+static DEVICE_ATTR(pci_clock, S_IRUGO, show_pci_clock, NULL);
+static DEVICE_ATTR(usb_clock, S_IRUGO, show_value, NULL);
+static DEVICE_ATTR(ref_clock, S_IRUGO, show_value, NULL);
+static DEVICE_ATTR(cpu_spread, S_IRUGO, show_spread, NULL);
+static DEVICE_ATTR(src_spread, S_IRUGO, show_spread, NULL);
+
+static struct attribute *ics932s401_attr[] =
+{
+       &dev_attr_spread_enabled.attr,
+       &dev_attr_cpu_clock_selection.attr,
+       &dev_attr_cpu_clock.attr,
+       &dev_attr_src_clock_selection.attr,
+       &dev_attr_src_clock.attr,
+       &dev_attr_pci_clock_selection.attr,
+       &dev_attr_pci_clock.attr,
+       &dev_attr_usb_clock.attr,
+       &dev_attr_ref_clock.attr,
+       &dev_attr_cpu_spread.attr,
+       &dev_attr_src_spread.attr,
+       NULL
+};
+
+static ssize_t show_value(struct device *dev,
+                         struct device_attribute *devattr,
+                         char *buf)
+{
+       int x;
+
+       if (devattr == &dev_attr_usb_clock)
+               x = 48000;
+       else if (devattr == &dev_attr_ref_clock)
+               x = BASE_CLOCK;
+       else
+               BUG();
+
+       return sprintf(buf, "%d\n", x);
+}
+
+static ssize_t show_spread(struct device *dev,
+                          struct device_attribute *devattr,
+                          char *buf)
+{
+       struct ics932s401_data *data = ics932s401_update_device(dev);
+       int reg;
+       unsigned long val;
+
+       if (!(data->regs[ICS932S401_REG_CFG2] & ICS932S401_CFG1_SPREAD))
+               return sprintf(buf, "0%%\n");
+
+       if (devattr == &dev_attr_src_spread)
+               reg = ICS932S401_REG_SRC_SPREAD1;
+       else if (devattr == &dev_attr_cpu_spread)
+               reg = ICS932S401_REG_CPU_SPREAD1;
+       else
+               BUG();
+
+       val = data->regs[reg] | (data->regs[reg + 1] << 8);
+       val &= ICS932S401_SPREAD_MASK;
+
+       /* Scale 0..2^14 to -0.5. */
+       val = 500000 * val / 16384;
+       return sprintf(buf, "-0.%lu%%\n", val);
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int ics932s401_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (kind <= 0) {
+               int vendor, device, revision;
+
+               vendor = i2c_smbus_read_word_data(client,
+                                                 ICS932S401_REG_VENDOR_REV);
+               vendor >>= 8;
+               revision = vendor >> ICS932S401_REV_SHIFT;
+               vendor &= ICS932S401_VENDOR_MASK;
+               if (vendor != ICS932S401_VENDOR)
+                       return -ENODEV;
+
+               device = i2c_smbus_read_word_data(client,
+                                                 ICS932S401_REG_DEVICE);
+               device >>= 8;
+               if (device != ICS932S401_DEVICE)
+                       return -ENODEV;
+
+               if (revision != ICS932S401_REV)
+                       dev_info(&adapter->dev, "Unknown revision %d\n",
+                                revision);
+       } else
+               dev_dbg(&adapter->dev, "detection forced\n");
+
+       strlcpy(info->type, "ics932s401", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int ics932s401_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct ics932s401_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct ics932s401_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->lock);
+
+       dev_info(&client->dev, "%s chip found\n", client->name);
+
+       /* Register sysfs hooks */
+       data->attrs.attrs = ics932s401_attr;
+       err = sysfs_create_group(&client->dev.kobj, &data->attrs);
+       if (err)
+               goto exit_free;
+
+       return 0;
+
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int ics932s401_remove(struct i2c_client *client)
+{
+       struct ics932s401_data *data = i2c_get_clientdata(client);
+
+       sysfs_remove_group(&client->dev.kobj, &data->attrs);
+       kfree(data);
+       return 0;
+}
+
+static int __init ics932s401_init(void)
+{
+       return i2c_add_driver(&ics932s401_driver);
+}
+
+static void __exit ics932s401_exit(void)
+{
+       i2c_del_driver(&ics932s401_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ICS932S401 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ics932s401_init);
+module_exit(ics932s401_exit);
+
+/* IBM IntelliStation Z30 */
+MODULE_ALIAS("dmi:bvnIBM:*:rn9228:*");
+MODULE_ALIAS("dmi:bvnIBM:*:rn9232:*");
+
+/* IBM x3650/x3550 */
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3550*");
index d03597a521b00124bf6f6174da61c51185790c11..9e9170b3599a249e4576fbb8b8d4214dead20a2a 100644 (file)
@@ -1,3 +1,7 @@
+ifdef CONFIG_SGI_GRU_DEBUG
+  EXTRA_CFLAGS += -DDEBUG
+endif
+
 obj-$(CONFIG_SGI_GRU) := gru.o
 gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o
 
index e5059aa3c724b189613db3ab6a61255a91d2f3be..8d92d8db9a98c0a3c5625ce74fd27a4268070ba4 100644 (file)
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 
-
+/* dynamic ioremap() areas */
+#define FLASH_START      0x00000000
+#define FLASH_SIZE       0x800000
+#define FLASH_WIDTH      4
+
+#define SRAM_START       0x60000000
+#define SRAM_SIZE        0xc000
+#define SRAM_WIDTH       4
+
+#define BOOTROM_START    0x70000000
+#define BOOTROM_SIZE     0x80
+#define BOOTROM_WIDTH    4
 
 
 static struct mtd_info *flash_mtd;
index 35fef655ccc4c8e5cbfe55eae84f6aead0456b32..3b959fad1c4ec082bfd7310f789e673de214ac47 100644 (file)
@@ -24,8 +24,8 @@ static struct mtd_info *mymtd;
 static struct map_info h720x_map = {
        .name =         "H720X",
        .bankwidth =    4,
-       .size =         FLASH_SIZE,
-       .phys =         FLASH_PHYS,
+       .size =         H720X_FLASH_SIZE,
+       .phys =         H720X_FLASH_PHYS,
 };
 
 static struct mtd_partition h720x_partitions[] = {
@@ -70,7 +70,7 @@ int __init h720x_mtd_init(void)
 
        char    *part_type = NULL;
 
-       h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE);
+       h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size);
 
        if (!h720x_map.virt) {
                printk(KERN_ERR "H720x-MTD: ioremap failed\n");
index 8cbc1b59bd6287303c6fe179eb5af6084cad5de7..4a7700620119686c741b6ac454b4cfa1b346133e 100644 (file)
@@ -163,9 +163,6 @@ int atl1e_read_mac_addr(struct atl1e_hw *hw)
  * atl1e_hash_mc_addr
  *  purpose
  *      set hash value for a multicast address
- *      hash calcu processing :
- *          1. calcu 32bit CRC for multicast address
- *          2. reverse crc with MSB to LSB
  */
 u32 atl1e_hash_mc_addr(struct atl1e_hw *hw, u8 *mc_addr)
 {
@@ -174,7 +171,6 @@ u32 atl1e_hash_mc_addr(struct atl1e_hw *hw, u8 *mc_addr)
        int i;
 
        crc32 = ether_crc_le(6, mc_addr);
-       crc32 = ~crc32;
        for (i = 0; i < 32; i++)
                value |= (((crc32 >> i) & 1) << (31 - i));
 
index 246d92b426360b37865352d0d6133e71415770b4..aef403d299eef1a5b04a4218070c0e51594fa288 100644 (file)
@@ -3404,14 +3404,8 @@ static void atl1_get_wol(struct net_device *netdev,
 {
        struct atl1_adapter *adapter = netdev_priv(netdev);
 
-       wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+       wol->supported = WAKE_MAGIC;
        wol->wolopts = 0;
-       if (adapter->wol & ATLX_WUFC_EX)
-               wol->wolopts |= WAKE_UCAST;
-       if (adapter->wol & ATLX_WUFC_MC)
-               wol->wolopts |= WAKE_MCAST;
-       if (adapter->wol & ATLX_WUFC_BC)
-               wol->wolopts |= WAKE_BCAST;
        if (adapter->wol & ATLX_WUFC_MAG)
                wol->wolopts |= WAKE_MAGIC;
        return;
@@ -3422,15 +3416,10 @@ static int atl1_set_wol(struct net_device *netdev,
 {
        struct atl1_adapter *adapter = netdev_priv(netdev);
 
-       if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+       if (wol->wolopts & (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
+               WAKE_ARP | WAKE_MAGICSECURE))
                return -EOPNOTSUPP;
        adapter->wol = 0;
-       if (wol->wolopts & WAKE_UCAST)
-               adapter->wol |= ATLX_WUFC_EX;
-       if (wol->wolopts & WAKE_MCAST)
-               adapter->wol |= ATLX_WUFC_MC;
-       if (wol->wolopts & WAKE_BCAST)
-               adapter->wol |= ATLX_WUFC_BC;
        if (wol->wolopts & WAKE_MAGIC)
                adapter->wol |= ATLX_WUFC_MAG;
        return 0;
index 430d430bce29e8f3f6f03a37753579c140ff2e8e..d07e3f1489510642c0cde8b41b96875fdc115c92 100644 (file)
@@ -7204,10 +7204,13 @@ static void
 poll_bnx2(struct net_device *dev)
 {
        struct bnx2 *bp = netdev_priv(dev);
+       int i;
 
-       disable_irq(bp->pdev->irq);
-       bnx2_interrupt(bp->pdev->irq, dev);
-       enable_irq(bp->pdev->irq);
+       for (i = 0; i < bp->irq_nvecs; i++) {
+               disable_irq(bp->irq_tbl[i].vector);
+               bnx2_interrupt(bp->irq_tbl[i].vector, &bp->bnx2_napi[i]);
+               enable_irq(bp->irq_tbl[i].vector);
+       }
 }
 #endif
 
index 5e663ccda4d4473f675cdf887ab507131b1bfb90..2c341f83d3270e8d32a42d24e1a472fffd945599 100644 (file)
@@ -2701,7 +2701,7 @@ static void set_nqsets(struct adapter *adap)
        int hwports = adap->params.nports;
        int nqsets = SGE_QSETS;
 
-       if (adap->params.rev > 0) {
+       if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
                if (hwports == 2 &&
                    (hwports * nqsets > SGE_QSETS ||
                     num_cpus >= nqsets / hwports))
index 968f64be3743acb165dbe40013e5d2a4dd60ee42..9a0898b0dbcef2e8d214046c3ac9137de1ccfb23 100644 (file)
@@ -572,7 +572,7 @@ struct t3_vpd {
        u32 pad;                /* for multiple-of-4 sizing and alignment */
 };
 
-#define EEPROM_MAX_POLL   4
+#define EEPROM_MAX_POLL   40
 #define EEPROM_STAT_ADDR  0x4000
 #define VPD_BASE          0xc00
 
@@ -3690,6 +3690,12 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
                        ;
 
                pti = &port_types[adapter->params.vpd.port_type[j]];
+               if (!pti->phy_prep) {
+                       CH_ALERT(adapter, "Invalid port type index %d\n",
+                                adapter->params.vpd.port_type[j]);
+                       return -EINVAL;
+               }
+
                ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
                                    ai->mdio_ops);
                if (ret)
index 3d69fae781cf5461949b4d9fccf1e9ce7244249d..e8bfcce6b319da95be67ecc44e211b7f8ed7ac38 100644 (file)
 
 #define DRV_NAME               "e100"
 #define DRV_EXT                        "-NAPI"
-#define DRV_VERSION            "3.5.23-k4"DRV_EXT
+#define DRV_VERSION            "3.5.23-k6"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT          "Copyright(c) 1999-2006 Intel Corporation"
 #define PFX                    DRV_NAME ": "
@@ -1804,7 +1804,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
                struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
                put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
                pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
-                       sizeof(struct rfd), PCI_DMA_TODEVICE);
+                       sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
        }
 
        return 0;
@@ -1823,7 +1823,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 
        /* Need to sync before taking a peek at cb_complete bit */
        pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
-               sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+               sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
        rfd_status = le16_to_cpu(rfd->status);
 
        DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
@@ -1850,7 +1850,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 
        /* Get data */
        pci_unmap_single(nic->pdev, rx->dma_addr,
-               RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+               RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
 
        /* If this buffer has the el bit, but we think the receiver
         * is still running, check to see if it really stopped while
@@ -1943,7 +1943,7 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
                new_before_last_rfd->command |= cpu_to_le16(cb_el);
                pci_dma_sync_single_for_device(nic->pdev,
                        new_before_last_rx->dma_addr, sizeof(struct rfd),
-                       PCI_DMA_TODEVICE);
+                       PCI_DMA_BIDIRECTIONAL);
 
                /* Now that we have a new stopping point, we can clear the old
                 * stopping point.  We must sync twice to get the proper
@@ -1951,11 +1951,11 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
                old_before_last_rfd->command &= ~cpu_to_le16(cb_el);
                pci_dma_sync_single_for_device(nic->pdev,
                        old_before_last_rx->dma_addr, sizeof(struct rfd),
-                       PCI_DMA_TODEVICE);
+                       PCI_DMA_BIDIRECTIONAL);
                old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
                pci_dma_sync_single_for_device(nic->pdev,
                        old_before_last_rx->dma_addr, sizeof(struct rfd),
-                       PCI_DMA_TODEVICE);
+                       PCI_DMA_BIDIRECTIONAL);
        }
 
        if(restart_required) {
@@ -1978,7 +1978,7 @@ static void e100_rx_clean_list(struct nic *nic)
                for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
                        if(rx->skb) {
                                pci_unmap_single(nic->pdev, rx->dma_addr,
-                                       RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+                                       RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
                                dev_kfree_skb(rx->skb);
                        }
                }
@@ -2021,7 +2021,7 @@ static int e100_rx_alloc_list(struct nic *nic)
        before_last->command |= cpu_to_le16(cb_el);
        before_last->size = 0;
        pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
-               sizeof(struct rfd), PCI_DMA_TODEVICE);
+               sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
 
        nic->rx_to_use = nic->rx_to_clean = nic->rxs;
        nic->ru_running = RU_SUSPENDED;
@@ -2222,7 +2222,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
        msleep(10);
 
        pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr,
-                       RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+                       RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
 
        if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
           skb->data, ETH_DATA_LEN))
index 6a3893acfe04e3f963b231a373446fe8d8615863..c854c96f5ab326af0ca3bf0093c1ad464169ab5a 100644 (file)
@@ -1774,7 +1774,8 @@ static void e1000_get_wol(struct net_device *netdev,
 
        /* this function will set ->supported = 0 and return 1 if wol is not
         * supported by this hardware */
-       if (e1000_wol_exclusion(adapter, wol))
+       if (e1000_wol_exclusion(adapter, wol) ||
+           !device_can_wakeup(&adapter->pdev->dev))
                return;
 
        /* apply any specific unsupported masks here */
@@ -1811,7 +1812,8 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
                return -EOPNOTSUPP;
 
-       if (e1000_wol_exclusion(adapter, wol))
+       if (e1000_wol_exclusion(adapter, wol) ||
+           !device_can_wakeup(&adapter->pdev->dev))
                return wol->wolopts ? -EOPNOTSUPP : 0;
 
        switch (hw->device_id) {
@@ -1838,6 +1840,8 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & WAKE_MAGIC)
                adapter->wol |= E1000_WUFC_MAG;
 
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
        return 0;
 }
 
index fac82152e4c8795287fc5c2b7dc10481cc994093..872799b746f501a3af4264c13b4674dbb8802382 100644 (file)
@@ -1179,6 +1179,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        /* initialize the wol settings based on the eeprom settings */
        adapter->wol = adapter->eeprom_wol;
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
        /* print bus type/speed/width info */
        DPRINTK(PROBE, INFO, "(PCI%s:%s:%s) ",
index c55de1c027af9578687a553195bfb911c65a72f9..c55fd6fdb91c16bcf0fba6049b1ef0d6ea3064ff 100644 (file)
@@ -299,6 +299,7 @@ struct e1000_adapter {
        unsigned long led_status;
 
        unsigned int flags;
+       unsigned int flags2;
        struct work_struct downshift_task;
        struct work_struct update_phy_task;
 };
@@ -306,6 +307,7 @@ struct e1000_adapter {
 struct e1000_info {
        enum e1000_mac_type     mac;
        unsigned int            flags;
+       unsigned int            flags2;
        u32                     pba;
        s32                     (*get_variants)(struct e1000_adapter *);
        struct e1000_mac_operations *mac_ops;
@@ -347,6 +349,9 @@ struct e1000_info {
 #define FLAG_RX_RESTART_NOW               (1 << 30)
 #define FLAG_MSI_TEST_FAILED              (1 << 31)
 
+/* CRC Stripping defines */
+#define FLAG2_CRC_STRIPPING               (1 << 0)
+
 #define E1000_RX_DESC_PS(R, i)     \
        (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
 #define E1000_GET_DESC(R, i, type)     (&(((struct type *)((R).desc))[i]))
index 70c11c811a08e3534671ac6554e50767b1ae63be..62421ce9631191f3acfdc82d48030ded4655d551 100644 (file)
@@ -1713,7 +1713,8 @@ static void e1000_get_wol(struct net_device *netdev,
        wol->supported = 0;
        wol->wolopts = 0;
 
-       if (!(adapter->flags & FLAG_HAS_WOL))
+       if (!(adapter->flags & FLAG_HAS_WOL) ||
+           !device_can_wakeup(&adapter->pdev->dev))
                return;
 
        wol->supported = WAKE_UCAST | WAKE_MCAST |
@@ -1751,7 +1752,8 @@ static int e1000_set_wol(struct net_device *netdev,
        if (wol->wolopts & WAKE_MAGICSECURE)
                return -EOPNOTSUPP;
 
-       if (!(adapter->flags & FLAG_HAS_WOL))
+       if (!(adapter->flags & FLAG_HAS_WOL) ||
+           !device_can_wakeup(&adapter->pdev->dev))
                return wol->wolopts ? -EOPNOTSUPP : 0;
 
        /* these settings will always override what we currently have */
@@ -1770,6 +1772,8 @@ static int e1000_set_wol(struct net_device *netdev,
        if (wol->wolopts & WAKE_ARP)
                adapter->wol |= E1000_WUFC_ARP;
 
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
        return 0;
 }
 
index abd492b7336d30c0690e2c1d8247719dd8e5eacd..91795f78c3e4da0a067378cdc757d8ddb32c138b 100644 (file)
@@ -499,6 +499,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                        goto next_desc;
                }
 
+               /* adjust length to remove Ethernet CRC */
+               if (!(adapter->flags2 & FLAG2_CRC_STRIPPING))
+                       length -= 4;
+
                total_rx_bytes += length;
                total_rx_packets++;
 
@@ -804,6 +808,10 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                        pci_dma_sync_single_for_device(pdev, ps_page->dma,
                                PAGE_SIZE, PCI_DMA_FROMDEVICE);
 
+                       /* remove the CRC */
+                       if (!(adapter->flags2 & FLAG2_CRC_STRIPPING))
+                               l1 -= 4;
+
                        skb_put(skb, l1);
                        goto copydone;
                } /* if */
@@ -825,6 +833,12 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                        skb->truesize += length;
                }
 
+               /* strip the ethernet crc, problem is we're using pages now so
+                * this whole operation can get a little cpu intensive
+                */
+               if (!(adapter->flags2 & FLAG2_CRC_STRIPPING))
+                       pskb_trim(skb, skb->len - 4);
+
 copydone:
                total_rx_bytes += skb->len;
                total_rx_packets++;
@@ -2301,8 +2315,12 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
        else
                rctl |= E1000_RCTL_LPE;
 
-       /* Enable hardware CRC frame stripping */
-       rctl |= E1000_RCTL_SECRC;
+       /* Some systems expect that the CRC is included in SMBUS traffic. The
+        * hardware strips the CRC before sending to both SMBUS (BMC) and to
+        * host memory when this is enabled
+        */
+       if (adapter->flags2 & FLAG2_CRC_STRIPPING)
+               rctl |= E1000_RCTL_SECRC;
 
        /* Setup buffer sizes */
        rctl &= ~E1000_RCTL_SZ_4096;
@@ -4766,6 +4784,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        adapter->ei = ei;
        adapter->pba = ei->pba;
        adapter->flags = ei->flags;
+       adapter->flags2 = ei->flags2;
        adapter->hw.adapter = adapter;
        adapter->hw.mac.type = ei->mac;
        adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
@@ -4970,6 +4989,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        /* initialize the wol settings based on the eeprom settings */
        adapter->wol = adapter->eeprom_wol;
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
        /* reset the hardware with the new settings */
        e1000e_reset(adapter);
@@ -5008,6 +5028,7 @@ err_hw_init:
 err_sw_init:
        if (adapter->hw.flash_address)
                iounmap(adapter->hw.flash_address);
+       e1000e_reset_interrupt_capability(adapter);
 err_flashmap:
        iounmap(adapter->hw.hw_addr);
 err_ioremap:
index 77a3d7207a5f834db470731502e1197c973c5102..e909f96698e8cfb023105a765b00becd6d7e0ae6 100644 (file)
@@ -151,6 +151,16 @@ E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
  */
 E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
 
+/*
+ * Enable CRC Stripping
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+E1000_PARAM(CrcStripping, "Enable CRC Stripping, disable if your BMC needs " \
+                          "the CRC");
+
 struct e1000_option {
        enum { enable_option, range_option, list_option } type;
        const char *name;
@@ -404,6 +414,21 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                                adapter->flags |= FLAG_SMART_POWER_DOWN;
                }
        }
+       { /* CRC Stripping */
+               const struct e1000_option opt = {
+                       .type = enable_option,
+                       .name = "CRC Stripping",
+                       .err  = "defaulting to enabled",
+                       .def  = OPTION_ENABLED
+               };
+
+               if (num_CrcStripping > bd) {
+                       unsigned int crc_stripping = CrcStripping[bd];
+                       e1000_validate_option(&crc_stripping, &opt, adapter);
+                       if (crc_stripping == OPTION_ENABLED)
+                               adapter->flags2 |= FLAG2_CRC_STRIPPING;
+               }
+       }
        { /* Kumeran Lock Loss Workaround */
                const struct e1000_option opt = {
                        .type = enable_option,
index 83a5cb6aa23b1fc5c4426a9863303be6bb10dad3..c4af949bf860d81ffd69ce6ff6eceb9cf0c8a69a 100644 (file)
@@ -1407,6 +1407,10 @@ static int gfar_clean_tx_ring(struct net_device *dev)
                if (bdp->status & TXBD_DEF)
                        dev->stats.collisions++;
 
+               /* Unmap the DMA memory */
+               dma_unmap_single(&priv->dev->dev, bdp->bufPtr,
+                               bdp->length, DMA_TO_DEVICE);
+
                /* Free the sk buffer associated with this TxBD */
                dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
 
@@ -1666,6 +1670,9 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 
                skb = priv->rx_skbuff[priv->skb_currx];
 
+               dma_unmap_single(&priv->dev->dev, bdp->bufPtr,
+                               priv->rx_buffer_size, DMA_FROM_DEVICE);
+
                /* We drop the frame if we failed to allocate a new buffer */
                if (unlikely(!newskb || !(bdp->status & RXBD_LAST) ||
                                 bdp->status & RXBD_ERR)) {
@@ -1674,14 +1681,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
                        if (unlikely(!newskb))
                                newskb = skb;
 
-                       if (skb) {
-                               dma_unmap_single(&priv->dev->dev,
-                                               bdp->bufPtr,
-                                               priv->rx_buffer_size,
-                                               DMA_FROM_DEVICE);
-
+                       if (skb)
                                dev_kfree_skb_any(skb);
-                       }
                } else {
                        /* Increment the number of packets */
                        dev->stats.rx_packets++;
index 58906c984be9f641e8e87c1acac40a098387a022..89964fa739a031bb2a778298a96a11e1a30e8ad3 100644 (file)
@@ -1776,7 +1776,8 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 
        /* this function will set ->supported = 0 and return 1 if wol is not
         * supported by this hardware */
-       if (igb_wol_exclusion(adapter, wol))
+       if (igb_wol_exclusion(adapter, wol) ||
+           !device_can_wakeup(&adapter->pdev->dev))
                return;
 
        /* apply any specific unsupported masks here */
@@ -1805,7 +1806,8 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
                return -EOPNOTSUPP;
 
-       if (igb_wol_exclusion(adapter, wol))
+       if (igb_wol_exclusion(adapter, wol) ||
+           !device_can_wakeup(&adapter->pdev->dev))
                return wol->wolopts ? -EOPNOTSUPP : 0;
 
        switch (hw->device_id) {
@@ -1825,6 +1827,8 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & WAKE_MAGIC)
                adapter->wol |= E1000_WUFC_MAG;
 
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
        return 0;
 }
 
index 1f397cd99414dd51293b5d5dadfec1905c52fa19..1cbae85b142627facb0753ab2513b95587e9cfc2 100644 (file)
@@ -1019,10 +1019,9 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                        state &= ~PCIE_LINK_STATE_L0S;
                        pci_write_config_word(us_dev, pos + PCI_EXP_LNKCTL,
                                              state);
-                       printk(KERN_INFO "Disabling ASPM L0s upstream switch "
-                              "port %x:%x.%x\n", us_dev->bus->number,
-                              PCI_SLOT(us_dev->devfn),
-                              PCI_FUNC(us_dev->devfn));
+                       dev_info(&pdev->dev,
+                                "Disabling ASPM L0s upstream switch port %s\n",
+                                pci_name(us_dev));
                }
        default:
                break;
@@ -1244,6 +1243,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 
        /* initialize the wol settings based on the eeprom settings */
        adapter->wol = adapter->eeprom_wol;
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
        /* reset the hardware with the new settings */
        igb_reset(adapter);
index a3f732418c49dc68e4545bf404eb0a8fd36c42d7..96e709d6440a459866b7d5d461113408031d7c23 100644 (file)
@@ -656,10 +656,10 @@ static int mlx4_en_start_port(struct net_device *dev)
        /* Configure port */
        err = mlx4_SET_PORT_general(mdev->dev, priv->port,
                                    priv->rx_skb_size + ETH_FCS_LEN,
-                                   mdev->profile.tx_pause,
-                                   mdev->profile.tx_ppp,
-                                   mdev->profile.rx_pause,
-                                   mdev->profile.rx_ppp);
+                                   priv->prof->tx_pause,
+                                   priv->prof->tx_ppp,
+                                   priv->prof->rx_pause,
+                                   priv->prof->rx_ppp);
        if (err) {
                mlx4_err(mdev, "Failed setting port general configurations"
                               " for port %d, with error %d\n", priv->port, err);
index c2e69b1bcd0a4fc9da51250db1c3ca8a7478af09..95706ee1c01996898a255b210a7cf8efd14e5ab4 100644 (file)
@@ -90,6 +90,7 @@ MLX4_EN_PARM_INT(rx_ring_size2, MLX4_EN_AUTO_CONF, "Rx ring size for port 2");
 int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
        struct mlx4_en_profile *params = &mdev->profile;
+       int i;
 
        params->rx_moder_cnt = min_t(int, rx_moder_cnt, MLX4_EN_AUTO_CONF);
        params->rx_moder_time = min_t(int, rx_moder_time, MLX4_EN_AUTO_CONF);
@@ -97,11 +98,13 @@ int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
        params->rss_xor = (rss_xor != 0);
        params->rss_mask = rss_mask & 0x1f;
        params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
-       params->rx_pause = pprx;
-       params->rx_ppp = pfcrx;
-       params->tx_pause = pptx;
-       params->tx_ppp = pfctx;
-       if (params->rx_ppp || params->tx_ppp) {
+       for (i = 1; i <= MLX4_MAX_PORTS; i++) {
+               params->prof[i].rx_pause = pprx;
+               params->prof[i].rx_ppp = pfcrx;
+               params->prof[i].tx_pause = pptx;
+               params->prof[i].tx_ppp = pfctx;
+       }
+       if (pfcrx || pfctx) {
                params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM;
                params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM;
        } else {
@@ -407,14 +410,14 @@ static int mlx4_en_set_pauseparam(struct net_device *dev,
        struct mlx4_en_dev *mdev = priv->mdev;
        int err;
 
-       mdev->profile.tx_pause = pause->tx_pause != 0;
-       mdev->profile.rx_pause = pause->rx_pause != 0;
+       priv->prof->tx_pause = pause->tx_pause != 0;
+       priv->prof->rx_pause = pause->rx_pause != 0;
        err = mlx4_SET_PORT_general(mdev->dev, priv->port,
                                    priv->rx_skb_size + ETH_FCS_LEN,
-                                   mdev->profile.tx_pause,
-                                   mdev->profile.tx_ppp,
-                                   mdev->profile.rx_pause,
-                                   mdev->profile.rx_ppp);
+                                   priv->prof->tx_pause,
+                                   priv->prof->tx_ppp,
+                                   priv->prof->rx_pause,
+                                   priv->prof->rx_ppp);
        if (err)
                mlx4_err(mdev, "Failed setting pause params to\n");
 
@@ -425,10 +428,9 @@ static void mlx4_en_get_pauseparam(struct net_device *dev,
                                 struct ethtool_pauseparam *pause)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
 
-       pause->tx_pause = mdev->profile.tx_pause;
-       pause->rx_pause = mdev->profile.rx_pause;
+       pause->tx_pause = priv->prof->tx_pause;
+       pause->rx_pause = priv->prof->rx_pause;
 }
 
 static void mlx4_en_get_ringparam(struct net_device *dev,
index 11fb17c6e97bfd4b51d831104ff7f0121bd4e4e8..98ddc0811f93e78b13bd37303dd2a3c572610c67 100644 (file)
@@ -322,6 +322,10 @@ struct mlx4_en_port_profile {
        u32 rx_ring_num;
        u32 tx_ring_size;
        u32 rx_ring_size;
+       u8 rx_pause;
+       u8 rx_ppp;
+       u8 tx_pause;
+       u8 tx_ppp;
 };
 
 struct mlx4_en_profile {
@@ -333,10 +337,6 @@ struct mlx4_en_profile {
        int rx_moder_cnt;
        int rx_moder_time;
        int auto_moder;
-       u8 rx_pause;
-       u8 rx_ppp;
-       u8 tx_pause;
-       u8 tx_ppp;
        u8 no_reset;
        struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1];
 };
index a5f428bcc0ebb28011efb551534584e768c4a6e9..b3786709730811c2b6467cabda06c55d2203ddb1 100644 (file)
@@ -75,7 +75,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.4.3-1.375"
+#define MYRI10GE_VERSION_STR "1.4.3-1.378"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -1393,6 +1393,7 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index)
                if (tx->req == tx->done) {
                        tx->queue_active = 0;
                        put_be32(htonl(1), tx->send_stop);
+                       mb();
                        mmiowb();
                }
                __netif_tx_unlock(dev_queue);
@@ -2865,6 +2866,7 @@ again:
        if ((mgp->dev->real_num_tx_queues > 1) && tx->queue_active == 0) {
                tx->queue_active = 1;
                put_be32(htonl(1), tx->send_go);
+               mb();
                mmiowb();
        }
        tx->pkt_start++;
index 9acb5d70a3ae310c4ac179469a7d5f18ae721b32..1b6f548c4411203a7666e0f1703de8fcec4aabf5 100644 (file)
@@ -33,8 +33,8 @@
 
 #define DRV_MODULE_NAME                "niu"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "0.9"
-#define DRV_MODULE_RELDATE     "May 4, 2008"
+#define DRV_MODULE_VERSION     "1.0"
+#define DRV_MODULE_RELDATE     "Nov 14, 2008"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -51,8 +51,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
 #ifndef readq
 static u64 readq(void __iomem *reg)
 {
-       return (((u64)readl(reg + 0x4UL) << 32) |
-               (u64)readl(reg));
+       return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32);
 }
 
 static void writeq(u64 val, void __iomem *reg)
@@ -407,7 +406,7 @@ static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val)
 }
 
 /* Mode is always 10G fiber.  */
-static int serdes_init_niu(struct niu *np)
+static int serdes_init_niu_10g_fiber(struct niu *np)
 {
        struct niu_link_config *lp = &np->link_config;
        u32 tx_cfg, rx_cfg;
@@ -444,6 +443,223 @@ static int serdes_init_niu(struct niu *np)
        return 0;
 }
 
+static int serdes_init_niu_1g_serdes(struct niu *np)
+{
+       struct niu_link_config *lp = &np->link_config;
+       u16 pll_cfg, pll_sts;
+       int max_retry = 100;
+       u64 sig, mask, val;
+       u32 tx_cfg, rx_cfg;
+       unsigned long i;
+       int err;
+
+       tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV |
+                 PLL_TX_CFG_RATE_HALF);
+       rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
+                 PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
+                 PLL_RX_CFG_RATE_HALF);
+
+       if (np->port == 0)
+               rx_cfg |= PLL_RX_CFG_EQ_LP_ADAPTIVE;
+
+       if (lp->loopback_mode == LOOPBACK_PHY) {
+               u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
+
+               mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+                          ESR2_TI_PLL_TEST_CFG_L, test_cfg);
+
+               tx_cfg |= PLL_TX_CFG_ENTEST;
+               rx_cfg |= PLL_RX_CFG_ENTEST;
+       }
+
+       /* Initialize PLL for 1G */
+       pll_cfg = (PLL_CFG_ENPLL | PLL_CFG_MPY_8X);
+
+       err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+                        ESR2_TI_PLL_CFG_L, pll_cfg);
+       if (err) {
+               dev_err(np->device, PFX "NIU Port %d "
+                       "serdes_init_niu_1g_serdes: "
+                       "mdio write to ESR2_TI_PLL_CFG_L failed", np->port);
+               return err;
+       }
+
+       pll_sts = PLL_CFG_ENPLL;
+
+       err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+                        ESR2_TI_PLL_STS_L, pll_sts);
+       if (err) {
+               dev_err(np->device, PFX "NIU Port %d "
+                       "serdes_init_niu_1g_serdes: "
+                       "mdio write to ESR2_TI_PLL_STS_L failed", np->port);
+               return err;
+       }
+
+       udelay(200);
+
+       /* Initialize all 4 lanes of the SERDES.  */
+       for (i = 0; i < 4; i++) {
+               err = esr2_set_tx_cfg(np, i, tx_cfg);
+               if (err)
+                       return err;
+       }
+
+       for (i = 0; i < 4; i++) {
+               err = esr2_set_rx_cfg(np, i, rx_cfg);
+               if (err)
+                       return err;
+       }
+
+       switch (np->port) {
+       case 0:
+               val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0);
+               mask = val;
+               break;
+
+       case 1:
+               val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1);
+               mask = val;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       while (max_retry--) {
+               sig = nr64(ESR_INT_SIGNALS);
+               if ((sig & mask) == val)
+                       break;
+
+               mdelay(500);
+       }
+
+       if ((sig & mask) != val) {
+               dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
+                       "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int serdes_init_niu_10g_serdes(struct niu *np)
+{
+       struct niu_link_config *lp = &np->link_config;
+       u32 tx_cfg, rx_cfg, pll_cfg, pll_sts;
+       int max_retry = 100;
+       u64 sig, mask, val;
+       unsigned long i;
+       int err;
+
+       tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);
+       rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
+                 PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
+                 PLL_RX_CFG_EQ_LP_ADAPTIVE);
+
+       if (lp->loopback_mode == LOOPBACK_PHY) {
+               u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
+
+               mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+                          ESR2_TI_PLL_TEST_CFG_L, test_cfg);
+
+               tx_cfg |= PLL_TX_CFG_ENTEST;
+               rx_cfg |= PLL_RX_CFG_ENTEST;
+       }
+
+       /* Initialize PLL for 10G */
+       pll_cfg = (PLL_CFG_ENPLL | PLL_CFG_MPY_10X);
+
+       err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+                        ESR2_TI_PLL_CFG_L, pll_cfg & 0xffff);
+       if (err) {
+               dev_err(np->device, PFX "NIU Port %d "
+                       "serdes_init_niu_10g_serdes: "
+                       "mdio write to ESR2_TI_PLL_CFG_L failed", np->port);
+               return err;
+       }
+
+       pll_sts = PLL_CFG_ENPLL;
+
+       err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+                        ESR2_TI_PLL_STS_L, pll_sts & 0xffff);
+       if (err) {
+               dev_err(np->device, PFX "NIU Port %d "
+                       "serdes_init_niu_10g_serdes: "
+                       "mdio write to ESR2_TI_PLL_STS_L failed", np->port);
+               return err;
+       }
+
+       udelay(200);
+
+       /* Initialize all 4 lanes of the SERDES.  */
+       for (i = 0; i < 4; i++) {
+               err = esr2_set_tx_cfg(np, i, tx_cfg);
+               if (err)
+                       return err;
+       }
+
+       for (i = 0; i < 4; i++) {
+               err = esr2_set_rx_cfg(np, i, rx_cfg);
+               if (err)
+                       return err;
+       }
+
+       /* check if serdes is ready */
+
+       switch (np->port) {
+       case 0:
+               mask = ESR_INT_SIGNALS_P0_BITS;
+               val = (ESR_INT_SRDY0_P0 |
+                      ESR_INT_DET0_P0 |
+                      ESR_INT_XSRDY_P0 |
+                      ESR_INT_XDP_P0_CH3 |
+                      ESR_INT_XDP_P0_CH2 |
+                      ESR_INT_XDP_P0_CH1 |
+                      ESR_INT_XDP_P0_CH0);
+               break;
+
+       case 1:
+               mask = ESR_INT_SIGNALS_P1_BITS;
+               val = (ESR_INT_SRDY0_P1 |
+                      ESR_INT_DET0_P1 |
+                      ESR_INT_XSRDY_P1 |
+                      ESR_INT_XDP_P1_CH3 |
+                      ESR_INT_XDP_P1_CH2 |
+                      ESR_INT_XDP_P1_CH1 |
+                      ESR_INT_XDP_P1_CH0);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       while (max_retry--) {
+               sig = nr64(ESR_INT_SIGNALS);
+               if ((sig & mask) == val)
+                       break;
+
+               mdelay(500);
+       }
+
+       if ((sig & mask) != val) {
+               pr_info(PFX "NIU Port %u signal bits [%08x] are not "
+                       "[%08x] for 10G...trying 1G\n",
+                       np->port, (int) (sig & mask), (int) val);
+
+               /* 10G failed, try initializing at 1G */
+               err = serdes_init_niu_1g_serdes(np);
+               if (!err) {
+                       np->flags &= ~NIU_FLAGS_10G;
+                       np->mac_xcvr = MAC_XCVR_PCS;
+               }  else {
+                       dev_err(np->device, PFX "Port %u 10G/1G SERDES "
+                               "Link Failed \n", np->port);
+                       return -ENODEV;
+               }
+       }
+       return 0;
+}
+
 static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val)
 {
        int err;
@@ -1955,13 +2171,23 @@ static const struct niu_phy_ops phy_ops_10g_serdes = {
        .link_status            = link_status_10g_serdes,
 };
 
+static const struct niu_phy_ops phy_ops_10g_serdes_niu = {
+       .serdes_init            = serdes_init_niu_10g_serdes,
+       .link_status            = link_status_10g_serdes,
+};
+
+static const struct niu_phy_ops phy_ops_1g_serdes_niu = {
+       .serdes_init            = serdes_init_niu_1g_serdes,
+       .link_status            = link_status_1g_serdes,
+};
+
 static const struct niu_phy_ops phy_ops_1g_rgmii = {
        .xcvr_init              = xcvr_init_1g_rgmii,
        .link_status            = link_status_1g_rgmii,
 };
 
 static const struct niu_phy_ops phy_ops_10g_fiber_niu = {
-       .serdes_init            = serdes_init_niu,
+       .serdes_init            = serdes_init_niu_10g_fiber,
        .xcvr_init              = xcvr_init_10g,
        .link_status            = link_status_10g,
 };
@@ -1999,11 +2225,21 @@ struct niu_phy_template {
        u32                             phy_addr_base;
 };
 
-static const struct niu_phy_template phy_template_niu = {
+static const struct niu_phy_template phy_template_niu_10g_fiber = {
        .ops            = &phy_ops_10g_fiber_niu,
        .phy_addr_base  = 16,
 };
 
+static const struct niu_phy_template phy_template_niu_10g_serdes = {
+       .ops            = &phy_ops_10g_serdes_niu,
+       .phy_addr_base  = 0,
+};
+
+static const struct niu_phy_template phy_template_niu_1g_serdes = {
+       .ops            = &phy_ops_1g_serdes_niu,
+       .phy_addr_base  = 0,
+};
+
 static const struct niu_phy_template phy_template_10g_fiber = {
        .ops            = &phy_ops_10g_fiber,
        .phy_addr_base  = 8,
@@ -2183,8 +2419,25 @@ static int niu_determine_phy_disposition(struct niu *np)
        u32 phy_addr_off = 0;
 
        if (plat_type == PLAT_TYPE_NIU) {
-               tp = &phy_template_niu;
-               phy_addr_off += np->port;
+               switch (np->flags &
+                       (NIU_FLAGS_10G |
+                        NIU_FLAGS_FIBER |
+                        NIU_FLAGS_XCVR_SERDES)) {
+               case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
+                       /* 10G Serdes */
+                       tp = &phy_template_niu_10g_serdes;
+                       break;
+               case NIU_FLAGS_XCVR_SERDES:
+                       /* 1G Serdes */
+                       tp = &phy_template_niu_1g_serdes;
+                       break;
+               case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+                       /* 10G Fiber */
+               default:
+                       tp = &phy_template_niu_10g_fiber;
+                       phy_addr_off += np->port;
+                       break;
+               }
        } else {
                switch (np->flags &
                        (NIU_FLAGS_10G |
@@ -7214,6 +7467,12 @@ static int __devinit niu_phy_type_prop_decode(struct niu *np,
                np->flags |= NIU_FLAGS_10G;
                np->flags &= ~NIU_FLAGS_FIBER;
                np->mac_xcvr = MAC_XCVR_XPCS;
+       } else if (!strcmp(phy_prop, "xgsd") || !strcmp(phy_prop, "gsd")) {
+               /* 10G Serdes or 1G Serdes, default to 10G */
+               np->flags |= NIU_FLAGS_10G;
+               np->flags &= ~NIU_FLAGS_FIBER;
+               np->flags |= NIU_FLAGS_XCVR_SERDES;
+               np->mac_xcvr = MAC_XCVR_XPCS;
        } else {
                return -EINVAL;
        }
@@ -7742,6 +8001,8 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
        u32 val;
        int err;
 
+       num_10g = num_1g = 0;
+
        if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
            !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
                num_10g = 0;
@@ -7758,6 +8019,16 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
                parent->num_ports = 2;
                val = (phy_encode(PORT_TYPE_10G, 0) |
                       phy_encode(PORT_TYPE_10G, 1));
+       } else if ((np->flags & NIU_FLAGS_XCVR_SERDES) &&
+                  (parent->plat_type == PLAT_TYPE_NIU)) {
+               /* this is the Monza case */
+               if (np->flags & NIU_FLAGS_10G) {
+                       val = (phy_encode(PORT_TYPE_10G, 0) |
+                              phy_encode(PORT_TYPE_10G, 1));
+               } else {
+                       val = (phy_encode(PORT_TYPE_1G, 0) |
+                              phy_encode(PORT_TYPE_1G, 1));
+               }
        } else {
                err = fill_phy_probe_info(np, parent, info);
                if (err)
@@ -8657,7 +8928,9 @@ static void __devinit niu_device_announce(struct niu *np)
                                dev->name,
                                (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
                                (np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
-                               (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"),
+                               (np->flags & NIU_FLAGS_FIBER ? "FIBER" :
+                                (np->flags & NIU_FLAGS_XCVR_SERDES ? "SERDES" :
+                                 "COPPER")),
                                (np->mac_xcvr == MAC_XCVR_MII ? "MII" :
                                 (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
                                np->vpd.phy_type);
index c6fa883daa2217574a54675834c91b40df9ab0d0..180ca8ae93deabab7a6ddf201e4e2fb296487a2d 100644 (file)
 #define  PLL_CFG_LD_SHIFT              8
 #define  PLL_CFG_MPY                   0x0000001e
 #define  PLL_CFG_MPY_SHIFT             1
+#define  PLL_CFG_MPY_4X                0x0
+#define  PLL_CFG_MPY_5X                0x00000002
+#define  PLL_CFG_MPY_6X                0x00000004
+#define  PLL_CFG_MPY_8X                0x00000008
+#define  PLL_CFG_MPY_10X               0x0000000a
+#define  PLL_CFG_MPY_12X               0x0000000c
+#define  PLL_CFG_MPY_12P5X             0x0000000e
 #define  PLL_CFG_ENPLL                 0x00000001
 
 #define ESR2_TI_PLL_STS_L              (ESR2_BASE + 0x002)
 #define  PLL_TX_CFG_INVPAIR            0x00000080
 #define  PLL_TX_CFG_RATE               0x00000060
 #define  PLL_TX_CFG_RATE_SHIFT         5
+#define  PLL_TX_CFG_RATE_FULL          0x0
+#define  PLL_TX_CFG_RATE_HALF          0x20
+#define  PLL_TX_CFG_RATE_QUAD          0x40
 #define  PLL_TX_CFG_BUSWIDTH           0x0000001c
 #define  PLL_TX_CFG_BUSWIDTH_SHIFT     2
 #define  PLL_TX_CFG_ENTEST             0x00000002
 #define  PLL_RX_CFG_INVPAIR            0x00000080
 #define  PLL_RX_CFG_RATE               0x00000060
 #define  PLL_RX_CFG_RATE_SHIFT         5
+#define  PLL_RX_CFG_RATE_FULL          0x0
+#define  PLL_RX_CFG_RATE_HALF          0x20
+#define  PLL_RX_CFG_RATE_QUAD          0x40
 #define  PLL_RX_CFG_BUSWIDTH           0x0000001c
 #define  PLL_RX_CFG_BUSWIDTH_SHIFT     2
 #define  PLL_RX_CFG_ENTEST             0x00000002
index 4aa54794704045dfdec94bbaafea2d88970e163a..eb6411c4694ffbddc3deb28090a5d642c3ae143f 100644 (file)
@@ -227,6 +227,59 @@ static int m88e1111_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int m88e1118_config_aneg(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, MII_M1011_PHY_SCR,
+                       MII_M1011_PHY_SCR_AUTO_CROSS);
+       if (err < 0)
+               return err;
+
+       err = genphy_config_aneg(phydev);
+       return 0;
+}
+
+static int m88e1118_config_init(struct phy_device *phydev)
+{
+       int err;
+
+       /* Change address */
+       err = phy_write(phydev, 0x16, 0x0002);
+       if (err < 0)
+               return err;
+
+       /* Enable 1000 Mbit */
+       err = phy_write(phydev, 0x15, 0x1070);
+       if (err < 0)
+               return err;
+
+       /* Change address */
+       err = phy_write(phydev, 0x16, 0x0003);
+       if (err < 0)
+               return err;
+
+       /* Adjust LED Control */
+       err = phy_write(phydev, 0x10, 0x021e);
+       if (err < 0)
+               return err;
+
+       /* Reset address */
+       err = phy_write(phydev, 0x16, 0x0);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 static int m88e1145_config_init(struct phy_device *phydev)
 {
        int err;
@@ -415,6 +468,19 @@ static struct phy_driver marvell_drivers[] = {
                .config_intr = &marvell_config_intr,
                .driver = { .owner = THIS_MODULE },
        },
+       {
+               .phy_id = 0x01410e10,
+               .phy_id_mask = 0xfffffff0,
+               .name = "Marvell 88E1118",
+               .features = PHY_GBIT_FEATURES,
+               .flags = PHY_HAS_INTERRUPT,
+               .config_init = &m88e1118_config_init,
+               .config_aneg = &m88e1118_config_aneg,
+               .read_status = &genphy_read_status,
+               .ack_interrupt = &marvell_ack_interrupt,
+               .config_intr = &marvell_config_intr,
+               .driver = {.owner = THIS_MODULE,},
+       },
        {
                .phy_id = 0x01410cd0,
                .phy_id_mask = 0xfffffff0,
index d0ed1ef284a80404510e8f169537f40e4cb678a3..536bda1f428b6c09360be41448f7b0b7d4c16679 100644 (file)
@@ -136,7 +136,7 @@ void mdiobus_unregister(struct mii_bus *bus)
        BUG_ON(bus->state != MDIOBUS_REGISTERED);
        bus->state = MDIOBUS_UNREGISTERED;
 
-       device_unregister(&bus->dev);
+       device_del(&bus->dev);
        for (i = 0; i < PHY_MAX_ADDR; i++) {
                if (bus->phy_map[i])
                        device_unregister(&bus->phy_map[i]->dev);
index e11b03b2b25a776c2494951953feeb44777d2f84..8fb1faca883aef9126b547f09ecf830e4feb1562 100644 (file)
@@ -227,8 +227,8 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
        if (r)
                return ERR_PTR(r);
 
-       /* If the phy_id is all Fs, there is no device there */
-       if (0xffffffff == phy_id)
+       /* If the phy_id is all Fs or all 0s, there is no device there */
+       if ((0xffff == phy_id) || (0x00 == phy_id))
                return NULL;
 
        dev = phy_device_create(bus, addr, phy_id);
index 3cdd07c45b6dea4961a8a12422d90643a76d0c37..508452c0215144343a2aacbe37f44d20caedfbf3 100644 (file)
@@ -1515,9 +1515,6 @@ static u32 ql_get_link_state(struct ql3_adapter *qdev)
                linkState = LS_UP;
        } else {
                linkState = LS_DOWN;
-               if (netif_msg_link(qdev))
-                       printk(KERN_WARNING PFX
-                              "%s: Link is down.\n", qdev->ndev->name);
        }
        return linkState;
 }
@@ -1581,10 +1578,6 @@ static int ql_finish_auto_neg(struct ql3_adapter *qdev)
                        ql_mac_enable(qdev, 1);
                }
 
-               if (netif_msg_link(qdev))
-                       printk(KERN_DEBUG PFX
-                              "%s: Change port_link_state LS_DOWN to LS_UP.\n",
-                              qdev->ndev->name);
                qdev->port_link_state = LS_UP;
                netif_start_queue(qdev->ndev);
                netif_carrier_on(qdev->ndev);
@@ -1655,14 +1648,9 @@ static void ql_link_state_machine_work(struct work_struct *work)
                /* Fall Through */
 
        case LS_DOWN:
-               if (netif_msg_link(qdev))
-                       printk(KERN_DEBUG PFX
-                              "%s: port_link_state = LS_DOWN.\n",
-                              qdev->ndev->name);
                if (curr_link_state == LS_UP) {
                        if (netif_msg_link(qdev))
-                               printk(KERN_DEBUG PFX
-                                      "%s: curr_link_state = LS_UP.\n",
+                               printk(KERN_INFO PFX "%s: Link is up.\n",
                                       qdev->ndev->name);
                        if (ql_is_auto_neg_complete(qdev))
                                ql_finish_auto_neg(qdev);
@@ -1670,6 +1658,7 @@ static void ql_link_state_machine_work(struct work_struct *work)
                        if (qdev->port_link_state == LS_UP)
                                ql_link_down_detect_clear(qdev);
 
+                       qdev->port_link_state = LS_UP;
                }
                break;
 
@@ -1678,12 +1667,14 @@ static void ql_link_state_machine_work(struct work_struct *work)
                 * See if the link is currently down or went down and came
                 * back up
                 */
-               if ((curr_link_state == LS_DOWN) || ql_link_down_detect(qdev)) {
+               if (curr_link_state == LS_DOWN) {
                        if (netif_msg_link(qdev))
                                printk(KERN_INFO PFX "%s: Link is down.\n",
                                       qdev->ndev->name);
                        qdev->port_link_state = LS_DOWN;
                }
+               if (ql_link_down_detect(qdev))
+                       qdev->port_link_state = LS_DOWN;
                break;
        }
        spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
index 5051554ff05b06f6c90c0a7f2ed006b96e3fafc0..1f26ab0e7986533386a821870c30290222c387ba 100644 (file)
@@ -2050,7 +2050,9 @@ err_out:
  */
 static int smc911x_drv_probe(struct platform_device *pdev)
 {
+#ifdef SMC_DYNAMIC_BUS_CONFIG
        struct smc911x_platdata *pd = pdev->dev.platform_data;
+#endif
        struct net_device *ndev;
        struct resource *res;
        struct smc911x_local *lp;
@@ -2182,9 +2184,9 @@ static int smc911x_drv_resume(struct platform_device *dev)
 
                if (netif_running(ndev)) {
                        smc911x_reset(ndev);
-                       smc911x_enable(ndev);
                        if (lp->phy_type != 0)
                                smc911x_phy_configure(&lp->phy_configure);
+                       smc911x_enable(ndev);
                        netif_device_attach(ndev);
                }
        }
index 85f38a6b6a49f9d744a1c90785042d16845910db..68a7f5414133d230bcb36b54a9e9ac4d626b8a08 100644 (file)
@@ -323,17 +323,17 @@ static void uec_get_ethtool_stats(struct net_device *netdev,
        if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
                base = (u32 __iomem *)&ugeth->ug_regs->tx64;
                for (i = 0; i < UEC_HW_STATS_LEN; i++)
-                       data[j++] = (u64)in_be32(&base[i]);
+                       data[j++] = in_be32(&base[i]);
        }
        if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
                base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
                for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
-                       data[j++] = (u64)in_be32(&base[i]);
+                       data[j++] = base ? in_be32(&base[i]) : 0;
        }
        if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
                base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
                for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
-                       data[j++] = (u64)in_be32(&base[i]);
+                       data[j++] = base ? in_be32(&base[i]) : 0;
        }
 }
 
index 37ecf845edfe9b91c5a6aee4ef514ad713e541ea..e12cdb4543b406f543e6e363dd43dcef20918db7 100644 (file)
@@ -1444,6 +1444,10 @@ static const struct usb_device_id        products [] = {
        // Apple USB Ethernet Adapter
        USB_DEVICE(0x05ac, 0x1402),
        .driver_info = (unsigned long) &ax88772_info,
+}, {
+       // Cables-to-Go USB Ethernet Adapter
+       USB_DEVICE(0x0b95, 0x772a),
+       .driver_info = (unsigned long) &ax88772_info,
 },
        { },            // END
 };
index 3590ea5a902da1d6619cf62207fc071fa1e4e35b..11cb3e504e1cb43e16c4eb5b81dda369ab4c75c1 100644 (file)
@@ -2296,7 +2296,7 @@ static void velocity_set_multi(struct net_device *dev)
                }
 
                mac_set_cam_mask(regs, vptr->mCAMmask);
-               rx_mode = (RCR_AM | RCR_AB);
+               rx_mode = RCR_AM | RCR_AB | RCR_AP;
        }
        if (dev->mtu > 1500)
                rx_mode |= RCR_AL;
index ffdf4876121b60829dd9634f1fcc45f7d06fc24b..a68f97c3935947a59990d188f7d95d05b19c600c 100644 (file)
@@ -918,9 +918,12 @@ struct hostap_interface {
 
 /*
  * TX meta data - stored in skb->cb buffer, so this must not be increased over
- * the 40-byte limit
+ * the 48-byte limit.
+ * THE PADDING THIS STARTS WITH IS A HORRIBLE HACK THAT SHOULD NOT LIVE
+ * TO SEE THE DAY.
  */
 struct hostap_skb_tx_data {
+       unsigned int __padding_for_default_qdiscs;
        u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */
        u8 rate; /* transmit rate */
 #define HOSTAP_TX_FLAGS_WDS BIT(0)
index 431e3c78bf27668b00d87fc06120a7f909ae5090..69eb0132593b72cc2a5d995788a28d2744fcecce 100644 (file)
@@ -48,6 +48,9 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187},
        /* Sitecom */
        {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
+       {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B},
+       /* Abocom */
+       {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187},
        {}
 };
 
index 209b4a464bcfe24c129a9d703a43a728998fc0bf..855f389eea402710d4a97a2fa848384475a351bb 100644 (file)
@@ -36,7 +36,7 @@ if PARPORT
 config PARPORT_PC
        tristate "PC-style hardware"
        depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \
-               (!M68K || ISA) && !MN10300 && !AVR32
+               (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN
        ---help---
          You should say Y here if you have a PC-style parallel port. All
          IBM PC compatible computers and some Alphas have PC-style
index b3a63edb69012bd443f4caebffdaddf12103b86a..ae5ec76dca77a636bf5b1f1a6cf4c52b03b8d9c8 100644 (file)
@@ -63,7 +63,7 @@ static acpi_status acpi_run_osc(acpi_handle handle,
        union acpi_object in_params[4];
        struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *out_obj;
-       u32 osc_dw0, flags = osc_args->capbuf[OSC_QUERY_TYPE];
+       u32 errors, flags = osc_args->capbuf[OSC_QUERY_TYPE];
 
        /* Setting up input parameters */
        input.count = 4;
@@ -92,15 +92,16 @@ static acpi_status acpi_run_osc(acpi_handle handle,
                status = AE_TYPE;
                goto out_kfree;
        }
-       osc_dw0 = *((u32 *)out_obj->buffer.pointer);
-       if (osc_dw0) {
-               if (osc_dw0 & OSC_REQUEST_ERROR)
+       /* Need to ignore the bit0 in result code */
+       errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
+       if (errors) {
+               if (errors & OSC_REQUEST_ERROR)
                        printk(KERN_DEBUG "_OSC request fails\n"); 
-               if (osc_dw0 & OSC_INVALID_UUID_ERROR)
+               if (errors & OSC_INVALID_UUID_ERROR)
                        printk(KERN_DEBUG "_OSC invalid UUID\n"); 
-               if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
+               if (errors & OSC_INVALID_REVISION_ERROR)
                        printk(KERN_DEBUG "_OSC invalid revision\n"); 
-               if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
+               if (errors & OSC_CAPABILITIES_MASK_ERROR) {
                        if (flags & OSC_QUERY_ENABLE)
                                goto out_success;
                        printk(KERN_DEBUG "_OSC FW not grant req. control\n");
index dcce9f5d84654a0612f99ed9bbe85813d53966f5..4a110b7b2673911885741209b3891c5eab891fab 100644 (file)
@@ -351,10 +351,11 @@ int verify_cis_cache(struct pcmcia_socket *s)
        char *buf;
 
        buf = kmalloc(256, GFP_KERNEL);
-       if (buf == NULL)
+       if (buf == NULL) {
                dev_printk(KERN_WARNING, &s->dev,
                           "no memory for verifying CIS\n");
                return -ENOMEM;
+       }
        list_for_each_entry(cis, &s->cis_cache, node) {
                int len = cis->len;
 
index c68c5d3382859eb4af84f8d9e0278ee3ce00b8ea..0660ad18258953af06dfa7cc72afda3b9259f716 100644 (file)
@@ -186,12 +186,6 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
 
        spin_lock_init(&socket->lock);
 
-       if (socket->resource_ops->init) {
-               ret = socket->resource_ops->init(socket);
-               if (ret)
-                       return (ret);
-       }
-
        /* try to obtain a socket number [yes, it gets ugly if we
         * register more than 2^sizeof(unsigned int) pcmcia
         * sockets... but the socket number is deprecated
@@ -226,7 +220,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
        /* set proper values in socket->dev */
        dev_set_drvdata(&socket->dev, socket);
        socket->dev.class = &pcmcia_socket_class;
-       snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+       dev_set_name(&socket->dev, "pcmcia_socket%u", socket->sock);
 
        /* base address = 0, map = 0 */
        socket->cis_mem.flags = 0;
@@ -239,6 +233,12 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
        mutex_init(&socket->skt_mutex);
        spin_lock_init(&socket->thread_lock);
 
+       if (socket->resource_ops->init) {
+               ret = socket->resource_ops->init(socket);
+               if (ret)
+                       goto err;
+       }
+
        tsk = kthread_run(pccardd, socket, "pccardd");
        if (IS_ERR(tsk)) {
                ret = PTR_ERR(tsk);
index 7956602554901297f86055cea142707f7eead769..47cab31ff6e49c0780692ead159cf81fb4113c58 100644 (file)
@@ -622,7 +622,6 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
 {
        struct pcmcia_device *p_dev, *tmp_dev;
        unsigned long flags;
-       int bus_id_len;
 
        s = pcmcia_get_socket(s);
        if (!s)
@@ -650,12 +649,12 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
        /* by default don't allow DMA */
        p_dev->dma_mask = DMA_MASK_NONE;
        p_dev->dev.dma_mask = &p_dev->dma_mask;
-       bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
-
-       p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL);
+       dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no);
+       if (!dev_name(&p_dev->dev))
+               goto err_free;
+       p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev));
        if (!p_dev->devname)
                goto err_free;
-       sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
        ds_dev_dbg(3, &p_dev->dev, "devname is %s\n", p_dev->devname);
 
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
@@ -668,6 +667,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
         list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
                 if (p_dev->func == tmp_dev->func) {
                        p_dev->function_config = tmp_dev->function_config;
+                       p_dev->io = tmp_dev->io;
+                       p_dev->irq = tmp_dev->irq;
                        kref_get(&p_dev->function_config->ref);
                }
 
index 76d4a98f09559b9a78d3f4335a1961b9de11eb6e..f5d0ba8e22d5473fb46e00bfbe5e3bfe2e7719a9 100644 (file)
@@ -302,9 +302,10 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
        /* We only allow changing Vpp1 and Vpp2 to the same value */
        if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
            (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-               if (mod->Vpp1 != mod->Vpp2)
+               if (mod->Vpp1 != mod->Vpp2) {
                        ds_dbg(s, 0, "Vpp1 and Vpp2 must be the same\n");
                        return -EINVAL;
+               }
                s->socket.Vpp = mod->Vpp1;
                if (s->ops->set_socket(s, &s->socket)) {
                        dev_printk(KERN_WARNING, &s->dev,
index 17f4ecf1c0c5b214af03b7188ecedca3e516d8b5..9ca22c7aafb29f5959bbcb3ddb2ed0296408b6c4 100644 (file)
@@ -71,7 +71,7 @@ static DEFINE_MUTEX(rsrc_mutex);
 ======================================================================*/
 
 static struct resource *
-make_resource(resource_size_t b, resource_size_t n, int flags, char *name)
+make_resource(resource_size_t b, resource_size_t n, int flags, const char *name)
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
@@ -624,7 +624,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
 static struct resource *nonstatic_find_io_region(unsigned long base, int num,
                   unsigned long align, struct pcmcia_socket *s)
 {
-       struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id);
+       struct resource *res = make_resource(0, num, IORESOURCE_IO, dev_name(&s->dev));
        struct socket_data *s_data = s->resource_data;
        struct pcmcia_align_data data;
        unsigned long min = base;
@@ -658,7 +658,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
 static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
                u_long align, int low, struct pcmcia_socket *s)
 {
-       struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id);
+       struct resource *res = make_resource(0, num, IORESOURCE_MEM, dev_name(&s->dev));
        struct socket_data *s_data = s->resource_data;
        struct pcmcia_align_data data;
        unsigned long min, max;
index 8abbb2020af9c0d6b238d16cf81c4277de31dc3d..123092d8a98484aebde61d7c60cc77639e95c351 100644 (file)
@@ -277,6 +277,14 @@ config RTC_DRV_FM3130
          This driver can also be built as a module. If so the module
          will be called rtc-fm3130.
 
+config RTC_DRV_RX8581
+       tristate "Epson RX-8581"
+       help
+         If you say yes here you will get support for the Epson RX-8581.
+
+         This driver can also be built as a module. If so the module
+         will be called rtc-rx8581.
+
 endif # I2C
 
 comment "SPI RTC drivers"
@@ -302,6 +310,17 @@ config RTC_DRV_DS1305
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1305.
 
+config RTC_DRV_DS1390
+       tristate "Dallas/Maxim DS1390/93/94"
+       help
+         If you say yes here you get support for the DS1390/93/94 chips.
+
+         This driver only supports the RTC feature, and not other chip
+         features such as alarms and trickle charging.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds1390.
+
 config RTC_DRV_MAX6902
        tristate "Maxim MAX6902"
        help
@@ -468,6 +487,16 @@ config RTC_DRV_V3020
          This driver can also be built as a module. If so, the module
          will be called rtc-v3020.
 
+config RTC_DRV_WM8350
+       tristate "Wolfson Microelectronics WM8350 RTC"
+       depends on MFD_WM8350
+       help
+         If you say yes here you will get support for the RTC subsystem
+         of the Wolfson Microelectronics WM8350.
+
+         This driver can also be built as a module. If so, the module
+         will be called "rtc-wm8350".
+
 comment "on-CPU RTC drivers"
 
 config RTC_DRV_OMAP
index e9e8474cc8fea8fb11ff77f31df46e30d8c7dbba..6e79c912bf9ee1b44d30baafabe2ef424fb14f3b 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_DS1302)  += rtc-ds1302.o
 obj-$(CONFIG_RTC_DRV_DS1305)   += rtc-ds1305.o
 obj-$(CONFIG_RTC_DRV_DS1307)   += rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1374)   += rtc-ds1374.o
+obj-$(CONFIG_RTC_DRV_DS1390)   += rtc-ds1390.o
 obj-$(CONFIG_RTC_DRV_DS1511)   += rtc-ds1511.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
@@ -57,6 +58,7 @@ obj-$(CONFIG_RTC_DRV_R9701)   += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_RX8581)   += rtc-rx8581.o
 obj-$(CONFIG_RTC_DRV_S35390A)  += rtc-s35390a.o
 obj-$(CONFIG_RTC_DRV_S3C)      += rtc-s3c.o
 obj-$(CONFIG_RTC_DRV_SA1100)   += rtc-sa1100.o
@@ -66,4 +68,5 @@ obj-$(CONFIG_RTC_DRV_TEST)    += rtc-test.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl4030.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
new file mode 100644 (file)
index 0000000..599e976
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * rtc-ds1390.c -- driver for DS1390/93/94
+ *
+ * Copyright (C) 2008 Mercury IMC Ltd
+ * Written by Mark Jackson <mpfj@mimc.co.uk>
+ *
+ * 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.
+ *
+ * NOTE : Currently this driver only supports the bare minimum for read
+ * and write the RTC.  The extra features provided by the chip family
+ * (alarms, trickle charger, different control registers) are unavailable.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#define DS1390_REG_100THS              0x00
+#define DS1390_REG_SECONDS             0x01
+#define DS1390_REG_MINUTES             0x02
+#define DS1390_REG_HOURS               0x03
+#define DS1390_REG_DAY                 0x04
+#define DS1390_REG_DATE                        0x05
+#define DS1390_REG_MONTH_CENT          0x06
+#define DS1390_REG_YEAR                        0x07
+
+#define DS1390_REG_ALARM_100THS                0x08
+#define DS1390_REG_ALARM_SECONDS       0x09
+#define DS1390_REG_ALARM_MINUTES       0x0A
+#define DS1390_REG_ALARM_HOURS         0x0B
+#define DS1390_REG_ALARM_DAY_DATE      0x0C
+
+#define DS1390_REG_CONTROL             0x0D
+#define DS1390_REG_STATUS              0x0E
+#define DS1390_REG_TRICKLE             0x0F
+
+struct ds1390 {
+       struct rtc_device *rtc;
+       u8 txrx_buf[9]; /* cmd + 8 registers */
+};
+
+static void ds1390_set_reg(struct device *dev, unsigned char address,
+                               unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ds1390 *chip = dev_get_drvdata(dev);
+
+       /* Set MSB to indicate write */
+       chip->txrx_buf[0] = address | 0x80;
+       chip->txrx_buf[1] = data;
+
+       /* do the i/o */
+       spi_write_then_read(spi, chip->txrx_buf, 2, NULL, 0);
+}
+
+static int ds1390_get_reg(struct device *dev, unsigned char address,
+                               unsigned char *data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ds1390 *chip = dev_get_drvdata(dev);
+       int status;
+
+       if (!data)
+               return -EINVAL;
+
+       /* Clear MSB to indicate read */
+       chip->txrx_buf[0] = address & 0x7f;
+       /* do the i/o */
+       status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 1);
+       if (status != 0)
+               return status;
+
+       *data = chip->txrx_buf[1];
+
+       return 0;
+}
+
+static int ds1390_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ds1390 *chip = dev_get_drvdata(dev);
+       int status;
+
+       /* build the message */
+       chip->txrx_buf[0] = DS1390_REG_SECONDS;
+
+       /* do the i/o */
+       status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 8);
+       if (status != 0)
+               return status;
+
+       /* The chip sends data in this order:
+        * Seconds, Minutes, Hours, Day, Date, Month / Century, Year */
+       dt->tm_sec      = bcd2bin(chip->txrx_buf[0]);
+       dt->tm_min      = bcd2bin(chip->txrx_buf[1]);
+       dt->tm_hour     = bcd2bin(chip->txrx_buf[2]);
+       dt->tm_wday     = bcd2bin(chip->txrx_buf[3]);
+       dt->tm_mday     = bcd2bin(chip->txrx_buf[4]);
+       /* mask off century bit */
+       dt->tm_mon      = bcd2bin(chip->txrx_buf[5] & 0x7f) - 1;
+       /* adjust for century bit */
+       dt->tm_year = bcd2bin(chip->txrx_buf[6]) + ((chip->txrx_buf[5] & 0x80) ? 100 : 0);
+
+       return rtc_valid_tm(dt);
+}
+
+static int ds1390_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ds1390 *chip = dev_get_drvdata(dev);
+
+       /* build the message */
+       chip->txrx_buf[0] = DS1390_REG_SECONDS | 0x80;
+       chip->txrx_buf[1] = bin2bcd(dt->tm_sec);
+       chip->txrx_buf[2] = bin2bcd(dt->tm_min);
+       chip->txrx_buf[3] = bin2bcd(dt->tm_hour);
+       chip->txrx_buf[4] = bin2bcd(dt->tm_wday);
+       chip->txrx_buf[5] = bin2bcd(dt->tm_mday);
+       chip->txrx_buf[6] = bin2bcd(dt->tm_mon + 1) |
+                               ((dt->tm_year > 99) ? 0x80 : 0x00);
+       chip->txrx_buf[7] = bin2bcd(dt->tm_year % 100);
+
+       /* do the i/o */
+       return spi_write_then_read(spi, chip->txrx_buf, 8, NULL, 0);
+}
+
+static int ds1390_read_time(struct device *dev, struct rtc_time *tm)
+{
+       return ds1390_get_datetime(dev, tm);
+}
+
+static int ds1390_set_time(struct device *dev, struct rtc_time *tm)
+{
+       return ds1390_set_datetime(dev, tm);
+}
+
+static const struct rtc_class_ops ds1390_rtc_ops = {
+       .read_time      = ds1390_read_time,
+       .set_time       = ds1390_set_time,
+};
+
+static int __devinit ds1390_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char tmp;
+       struct ds1390 *chip;
+       int res;
+
+       printk(KERN_DEBUG "DS1390 SPI RTC driver\n");
+
+       rtc = rtc_device_register("ds1390",
+                               &spi->dev, &ds1390_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               printk(KERN_ALERT "RTC : unable to register device\n");
+               return PTR_ERR(rtc);
+       }
+
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       chip = kzalloc(sizeof *chip, GFP_KERNEL);
+       if (!chip) {
+               printk(KERN_ALERT "RTC : unable to allocate device memory\n");
+               rtc_device_unregister(rtc);
+               return -ENOMEM;
+       }
+       chip->rtc = rtc;
+       dev_set_drvdata(&spi->dev, chip);
+
+       res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp);
+       if (res) {
+               printk(KERN_ALERT "RTC : unable to read device\n");
+               rtc_device_unregister(rtc);
+               return res;
+       }
+
+       return 0;
+}
+
+static int __devexit ds1390_remove(struct spi_device *spi)
+{
+       struct ds1390 *chip = platform_get_drvdata(spi);
+       struct rtc_device *rtc = chip->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       kfree(chip);
+
+       return 0;
+}
+
+static struct spi_driver ds1390_driver = {
+       .driver = {
+               .name   = "rtc-ds1390",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = ds1390_probe,
+       .remove = __devexit_p(ds1390_remove),
+};
+
+static __init int ds1390_init(void)
+{
+       return spi_register_driver(&ds1390_driver);
+}
+module_init(ds1390_init);
+
+static __exit void ds1390_exit(void)
+{
+       spi_unregister_driver(&ds1390_driver);
+}
+module_exit(ds1390_exit);
+
+MODULE_DESCRIPTION("DS1390/93/94 SPI RTC driver");
+MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
new file mode 100644 (file)
index 0000000..c9522f3
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * An I2C driver for the Epson RX8581 RTC
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC)
+ * Copyright 2005-06 Tower Technologies
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/log2.h>
+
+#define DRV_VERSION "0.1"
+
+#define RX8581_REG_SC          0x00 /* Second in BCD */
+#define RX8581_REG_MN          0x01 /* Minute in BCD */
+#define RX8581_REG_HR          0x02 /* Hour in BCD */
+#define RX8581_REG_DW          0x03 /* Day of Week */
+#define RX8581_REG_DM          0x04 /* Day of Month in BCD */
+#define RX8581_REG_MO          0x05 /* Month in BCD */
+#define RX8581_REG_YR          0x06 /* Year in BCD */
+#define RX8581_REG_RAM         0x07 /* RAM */
+#define RX8581_REG_AMN         0x08 /* Alarm Min in BCD*/
+#define RX8581_REG_AHR         0x09 /* Alarm Hour in BCD */
+#define RX8581_REG_ADM         0x0A
+#define RX8581_REG_ADW         0x0A
+#define RX8581_REG_TMR0                0x0B
+#define RX8581_REG_TMR1                0x0C
+#define RX8581_REG_EXT         0x0D /* Extension Register */
+#define RX8581_REG_FLAG                0x0E /* Flag Register */
+#define RX8581_REG_CTRL                0x0F /* Control Register */
+
+
+/* Flag Register bit definitions */
+#define RX8581_FLAG_UF         0x20 /* Update */
+#define RX8581_FLAG_TF         0x10 /* Timer */
+#define RX8581_FLAG_AF         0x08 /* Alarm */
+#define RX8581_FLAG_VLF                0x02 /* Voltage Low */
+
+/* Control Register bit definitions */
+#define RX8581_CTRL_UIE                0x20 /* Update Interrupt Enable */
+#define RX8581_CTRL_TIE                0x10 /* Timer Interrupt Enable */
+#define RX8581_CTRL_AIE                0x08 /* Alarm Interrupt Enable */
+#define RX8581_CTRL_STOP       0x02 /* STOP bit */
+#define RX8581_CTRL_RESET      0x01 /* RESET bit */
+
+static struct i2c_driver rx8581_driver;
+
+/*
+ * In the routines that deal directly with the rx8581 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+       unsigned char date[7];
+       int data, err;
+
+       /* First we ensure that the "update flag" is not set, we read the
+        * time and date then re-read the "update flag". If the update flag
+        * has been set, we know that the time has changed during the read so
+        * we repeat the whole process again.
+        */
+       data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
+       if (data < 0) {
+               dev_err(&client->dev, "Unable to read device flags\n");
+               return -EIO;
+       }
+
+       do {
+               /* If update flag set, clear it */
+               if (data & RX8581_FLAG_UF) {
+                       err = i2c_smbus_write_byte_data(client,
+                               RX8581_REG_FLAG, (data & ~RX8581_FLAG_UF));
+                       if (err != 0) {
+                               dev_err(&client->dev, "Unable to write device "
+                                       "flags\n");
+                               return -EIO;
+                       }
+               }
+
+               /* Now read time and date */
+               err = i2c_smbus_read_i2c_block_data(client, RX8581_REG_SC,
+                       7, date);
+               if (err < 0) {
+                       dev_err(&client->dev, "Unable to read date\n");
+                       return -EIO;
+               }
+
+               /* Check flag register */
+               data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
+               if (data < 0) {
+                       dev_err(&client->dev, "Unable to read device flags\n");
+                       return -EIO;
+               }
+       } while (data & RX8581_FLAG_UF);
+
+       if (data & RX8581_FLAG_VLF)
+               dev_info(&client->dev,
+                       "low voltage detected, date/time is not reliable.\n");
+
+       dev_dbg(&client->dev,
+               "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
+               "wday=%02x, mday=%02x, mon=%02x, year=%02x\n",
+               __func__,
+               date[0], date[1], date[2], date[3], date[4], date[5], date[6]);
+
+       tm->tm_sec = bcd2bin(date[RX8581_REG_SC] & 0x7F);
+       tm->tm_min = bcd2bin(date[RX8581_REG_MN] & 0x7F);
+       tm->tm_hour = bcd2bin(date[RX8581_REG_HR] & 0x3F); /* rtc hr 0-23 */
+       tm->tm_wday = ilog2(date[RX8581_REG_DW] & 0x7F);
+       tm->tm_mday = bcd2bin(date[RX8581_REG_DM] & 0x3F);
+       tm->tm_mon = bcd2bin(date[RX8581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+       tm->tm_year = bcd2bin(date[RX8581_REG_YR]);
+       if (tm->tm_year < 70)
+               tm->tm_year += 100;     /* assume we are in 1970...2069 */
+
+
+       dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __func__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       err = rtc_valid_tm(tm);
+       if (err < 0)
+               dev_err(&client->dev, "retrieved date/time is not valid.\n");
+
+       return err;
+}
+
+static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+       int data, err;
+       unsigned char buf[7];
+
+       dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __func__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       /* hours, minutes and seconds */
+       buf[RX8581_REG_SC] = bin2bcd(tm->tm_sec);
+       buf[RX8581_REG_MN] = bin2bcd(tm->tm_min);
+       buf[RX8581_REG_HR] = bin2bcd(tm->tm_hour);
+
+       buf[RX8581_REG_DM] = bin2bcd(tm->tm_mday);
+
+       /* month, 1 - 12 */
+       buf[RX8581_REG_MO] = bin2bcd(tm->tm_mon + 1);
+
+       /* year and century */
+       buf[RX8581_REG_YR] = bin2bcd(tm->tm_year % 100);
+       buf[RX8581_REG_DW] = (0x1 << tm->tm_wday);
+
+       /* Stop the clock */
+       data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL);
+       if (data < 0) {
+               dev_err(&client->dev, "Unable to read control register\n");
+               return -EIO;
+       }
+
+       err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
+               (data | RX8581_CTRL_STOP));
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write control register\n");
+               return -EIO;
+       }
+
+       /* write register's data */
+       err = i2c_smbus_write_i2c_block_data(client, RX8581_REG_SC, 7, buf);
+       if (err < 0) {
+               dev_err(&client->dev, "Unable to write to date registers\n");
+               return -EIO;
+       }
+
+       /* Restart the clock */
+       data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL);
+       if (data < 0) {
+               dev_err(&client->dev, "Unable to read control register\n");
+               return -EIO;
+       }
+
+       err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
+               (data | ~(RX8581_CTRL_STOP)));
+       if (err != 0) {
+               dev_err(&client->dev, "Unable to write control register\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       return rx8581_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       return rx8581_set_datetime(to_i2c_client(dev), tm);
+}
+
+static const struct rtc_class_ops rx8581_rtc_ops = {
+       .read_time      = rx8581_rtc_read_time,
+       .set_time       = rx8581_rtc_set_time,
+};
+
+static int __devinit rx8581_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct rtc_device *rtc;
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+       rtc = rtc_device_register(rx8581_driver.driver.name,
+                               &client->dev, &rx8581_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       i2c_set_clientdata(client, rtc);
+
+       return 0;
+}
+
+static int __devexit rx8581_remove(struct i2c_client *client)
+{
+       struct rtc_device *rtc = i2c_get_clientdata(client);
+
+       rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static const struct i2c_device_id rx8581_id[] = {
+       { "rx8581", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rx8581_id);
+
+static struct i2c_driver rx8581_driver = {
+       .driver         = {
+               .name   = "rtc-rx8581",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = rx8581_probe,
+       .remove         = __devexit_p(rx8581_remove),
+       .id_table       = rx8581_id,
+};
+
+static int __init rx8581_init(void)
+{
+       return i2c_add_driver(&rx8581_driver);
+}
+
+static void __exit rx8581_exit(void)
+{
+       i2c_del_driver(&rx8581_driver);
+}
+
+MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com>");
+MODULE_DESCRIPTION("Epson RX-8581 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(rx8581_init);
+module_exit(rx8581_exit);
index 2012ccbb4a539dbfaab57ac83558f4a8f712f021..5b2261052a6550c7501c2eb02d2935a8578dfa4d 100644 (file)
@@ -1,4 +1,4 @@
-/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
+/* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
  *
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
@@ -7,21 +7,11 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/time.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 
 #include <asm/hypervisor.h>
 
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("SUN4V RTC driver");
-MODULE_LICENSE("GPL");
-
-struct sun4v_rtc {
-       struct rtc_device       *rtc;
-       spinlock_t              lock;
-};
-
 static unsigned long hypervisor_get_time(void)
 {
        unsigned long ret, time;
@@ -45,15 +35,7 @@ retry:
 
 static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
 {
-       struct sun4v_rtc *p = dev_get_drvdata(dev);
-       unsigned long flags, secs;
-
-       spin_lock_irqsave(&p->lock, flags);
-       secs = hypervisor_get_time();
-       spin_unlock_irqrestore(&p->lock, flags);
-
-       rtc_time_to_tm(secs, tm);
-
+       rtc_time_to_tm(hypervisor_get_time(), tm);
        return 0;
 }
 
@@ -80,19 +62,14 @@ retry:
 
 static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
 {
-       struct sun4v_rtc *p = dev_get_drvdata(dev);
-       unsigned long flags, secs;
+       unsigned long secs;
        int err;
 
        err = rtc_tm_to_time(tm, &secs);
        if (err)
                return err;
 
-       spin_lock_irqsave(&p->lock, flags);
-       err = hypervisor_set_time(secs);
-       spin_unlock_irqrestore(&p->lock, flags);
-
-       return err;
+       return hypervisor_set_time(secs);
 }
 
 static const struct rtc_class_ops sun4v_rtc_ops = {
@@ -100,33 +77,22 @@ static const struct rtc_class_ops sun4v_rtc_ops = {
        .set_time       = sun4v_set_time,
 };
 
-static int __devinit sun4v_rtc_probe(struct platform_device *pdev)
+static int __init sun4v_rtc_probe(struct platform_device *pdev)
 {
-       struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
-
-       if (!p)
-               return -ENOMEM;
-
-       spin_lock_init(&p->lock);
-
-       p->rtc = rtc_device_register("sun4v", &pdev->dev,
+       struct rtc_device *rtc = rtc_device_register("sun4v", &pdev->dev,
                                     &sun4v_rtc_ops, THIS_MODULE);
-       if (IS_ERR(p->rtc)) {
-               int err = PTR_ERR(p->rtc);
-               kfree(p);
-               return err;
-       }
-       platform_set_drvdata(pdev, p);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(pdev, rtc);
        return 0;
 }
 
-static int __devexit sun4v_rtc_remove(struct platform_device *pdev)
+static int __exit sun4v_rtc_remove(struct platform_device *pdev)
 {
-       struct sun4v_rtc *p = platform_get_drvdata(pdev);
-
-       rtc_device_unregister(p->rtc);
-       kfree(p);
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
 
+       rtc_device_unregister(rtc);
        return 0;
 }
 
@@ -135,13 +101,12 @@ static struct platform_driver sun4v_rtc_driver = {
                .name   = "rtc-sun4v",
                .owner  = THIS_MODULE,
        },
-       .probe          = sun4v_rtc_probe,
-       .remove         = __devexit_p(sun4v_rtc_remove),
+       .remove         = __exit_p(sun4v_rtc_remove),
 };
 
 static int __init sun4v_rtc_init(void)
 {
-       return platform_driver_register(&sun4v_rtc_driver);
+       return platform_driver_probe(&sun4v_rtc_driver, sun4v_rtc_probe);
 }
 
 static void __exit sun4v_rtc_exit(void)
@@ -151,3 +116,7 @@ static void __exit sun4v_rtc_exit(void)
 
 module_init(sun4v_rtc_init);
 module_exit(sun4v_rtc_exit);
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("SUN4V RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
new file mode 100644 (file)
index 0000000..5c5e3aa
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ *     Real Time Clock driver for Wolfson Microelectronics WM8350
+ *
+ *     Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ *  Author: Liam Girdwood
+ *          linux@wolfsonmicro.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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#define WM8350_SET_ALM_RETRIES 5
+#define WM8350_SET_TIME_RETRIES        5
+#define WM8350_GET_TIME_RETRIES        5
+
+#define to_wm8350_from_rtc_dev(d) container_of(d, struct wm8350, rtc.pdev.dev)
+
+/*
+ * Read current time and date in RTC
+ */
+static int wm8350_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+       u16 time1[4], time2[4];
+       int retries = WM8350_GET_TIME_RETRIES, ret;
+
+       /*
+        * Read the time twice and compare.
+        * If time1 == time2, then time is valid else retry.
+        */
+       do {
+               ret = wm8350_block_read(wm8350, WM8350_RTC_SECONDS_MINUTES,
+                                       4, time1);
+               if (ret < 0)
+                       return ret;
+               ret = wm8350_block_read(wm8350, WM8350_RTC_SECONDS_MINUTES,
+                                       4, time2);
+               if (ret < 0)
+                       return ret;
+
+               if (memcmp(time1, time2, sizeof(time1)) == 0) {
+                       tm->tm_sec = time1[0] & WM8350_RTC_SECS_MASK;
+
+                       tm->tm_min = (time1[0] & WM8350_RTC_MINS_MASK)
+                           >> WM8350_RTC_MINS_SHIFT;
+
+                       tm->tm_hour = time1[1] & WM8350_RTC_HRS_MASK;
+
+                       tm->tm_wday = ((time1[1] >> WM8350_RTC_DAY_SHIFT)
+                                      & 0x7) - 1;
+
+                       tm->tm_mon = ((time1[2] & WM8350_RTC_MTH_MASK)
+                                     >> WM8350_RTC_MTH_SHIFT) - 1;
+
+                       tm->tm_mday = (time1[2] & WM8350_RTC_DATE_MASK);
+
+                       tm->tm_year = ((time1[3] & WM8350_RTC_YHUNDREDS_MASK)
+                                      >> WM8350_RTC_YHUNDREDS_SHIFT) * 100;
+                       tm->tm_year += time1[3] & WM8350_RTC_YUNITS_MASK;
+
+                       tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon,
+                                                   tm->tm_year);
+                       tm->tm_year -= 1900;
+
+                       dev_dbg(dev, "Read (%d left): %04x %04x %04x %04x\n",
+                               retries,
+                               time1[0], time1[1], time1[2], time1[3]);
+
+                       return 0;
+               }
+       } while (retries--);
+
+       dev_err(dev, "timed out reading RTC time\n");
+       return -EIO;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+       u16 time[4];
+       u16 rtc_ctrl;
+       int ret, retries = WM8350_SET_TIME_RETRIES;
+
+       time[0] = tm->tm_sec;
+       time[0] |= tm->tm_min << WM8350_RTC_MINS_SHIFT;
+       time[1] = tm->tm_hour;
+       time[1] |= (tm->tm_wday + 1) << WM8350_RTC_DAY_SHIFT;
+       time[2] = tm->tm_mday;
+       time[2] |= (tm->tm_mon + 1) << WM8350_RTC_MTH_SHIFT;
+       time[3] = ((tm->tm_year + 1900) / 100) << WM8350_RTC_YHUNDREDS_SHIFT;
+       time[3] |= (tm->tm_year + 1900) % 100;
+
+       dev_dbg(dev, "Setting: %04x %04x %04x %04x\n",
+               time[0], time[1], time[2], time[3]);
+
+       /* Set RTC_SET to stop the clock */
+       ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET);
+       if (ret < 0)
+               return ret;
+
+       /* Wait until confirmation of stopping */
+       do {
+               rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+       } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS));
+
+       if (!retries) {
+               dev_err(dev, "timed out on set confirmation\n");
+               return -EIO;
+       }
+
+       /* Write time to RTC */
+       ret = wm8350_block_write(wm8350, WM8350_RTC_SECONDS_MINUTES, 4, time);
+       if (ret < 0)
+               return ret;
+
+       /* Clear RTC_SET to start the clock */
+       ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
+                               WM8350_RTC_SET);
+       return ret;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int wm8350_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       u16 time[4];
+       int ret;
+
+       ret = wm8350_block_read(wm8350, WM8350_ALARM_SECONDS_MINUTES, 4, time);
+       if (ret < 0)
+               return ret;
+
+       tm->tm_sec = time[0] & WM8350_RTC_ALMSECS_MASK;
+       if (tm->tm_sec == WM8350_RTC_ALMSECS_MASK)
+               tm->tm_sec = -1;
+
+       tm->tm_min = time[0] & WM8350_RTC_ALMMINS_MASK;
+       if (tm->tm_min == WM8350_RTC_ALMMINS_MASK)
+               tm->tm_min = -1;
+       else
+               tm->tm_min >>= WM8350_RTC_ALMMINS_SHIFT;
+
+       tm->tm_hour = time[1] & WM8350_RTC_ALMHRS_MASK;
+       if (tm->tm_hour == WM8350_RTC_ALMHRS_MASK)
+               tm->tm_hour = -1;
+
+       tm->tm_wday = ((time[1] >> WM8350_RTC_ALMDAY_SHIFT) & 0x7) - 1;
+       if (tm->tm_wday > 7)
+               tm->tm_wday = -1;
+
+       tm->tm_mon = time[2] & WM8350_RTC_ALMMTH_MASK;
+       if (tm->tm_mon == WM8350_RTC_ALMMTH_MASK)
+               tm->tm_mon = -1;
+       else
+               tm->tm_mon = (tm->tm_mon >> WM8350_RTC_ALMMTH_SHIFT) - 1;
+
+       tm->tm_mday = (time[2] & WM8350_RTC_ALMDATE_MASK);
+       if (tm->tm_mday == WM8350_RTC_ALMDATE_MASK)
+               tm->tm_mday = -1;
+
+       tm->tm_year = -1;
+
+       alrm->enabled = !(time[3] & WM8350_RTC_ALMSTS);
+
+       return 0;
+}
+
+static int wm8350_rtc_stop_alarm(struct wm8350 *wm8350)
+{
+       int retries = WM8350_SET_ALM_RETRIES;
+       u16 rtc_ctrl;
+       int ret;
+
+       /* Set RTC_SET to stop the clock */
+       ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL,
+                             WM8350_RTC_ALMSET);
+       if (ret < 0)
+               return ret;
+
+       /* Wait until confirmation of stopping */
+       do {
+               rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+       } while (retries-- && !(rtc_ctrl & WM8350_RTC_ALMSTS));
+
+       if (!(rtc_ctrl & WM8350_RTC_ALMSTS))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int wm8350_rtc_start_alarm(struct wm8350 *wm8350)
+{
+       int ret;
+       int retries = WM8350_SET_ALM_RETRIES;
+       u16 rtc_ctrl;
+
+       ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
+                               WM8350_RTC_ALMSET);
+       if (ret < 0)
+               return ret;
+
+       /* Wait until confirmation */
+       do {
+               rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+       } while (retries-- && rtc_ctrl & WM8350_RTC_ALMSTS);
+
+       if (rtc_ctrl & WM8350_RTC_ALMSTS)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       u16 time[3];
+       int ret;
+
+       memset(time, 0, sizeof(time));
+
+       if (tm->tm_sec != -1)
+               time[0] |= tm->tm_sec;
+       else
+               time[0] |= WM8350_RTC_ALMSECS_MASK;
+
+       if (tm->tm_min != -1)
+               time[0] |= tm->tm_min << WM8350_RTC_ALMMINS_SHIFT;
+       else
+               time[0] |= WM8350_RTC_ALMMINS_MASK;
+
+       if (tm->tm_hour != -1)
+               time[1] |= tm->tm_hour;
+       else
+               time[1] |= WM8350_RTC_ALMHRS_MASK;
+
+       if (tm->tm_wday != -1)
+               time[1] |= (tm->tm_wday + 1) << WM8350_RTC_ALMDAY_SHIFT;
+       else
+               time[1] |= WM8350_RTC_ALMDAY_MASK;
+
+       if (tm->tm_mday != -1)
+               time[2] |= tm->tm_mday;
+       else
+               time[2] |= WM8350_RTC_ALMDATE_MASK;
+
+       if (tm->tm_mon != -1)
+               time[2] |= (tm->tm_mon + 1) << WM8350_RTC_ALMMTH_SHIFT;
+       else
+               time[2] |= WM8350_RTC_ALMMTH_MASK;
+
+       ret = wm8350_rtc_stop_alarm(wm8350);
+       if (ret < 0)
+               return ret;
+
+       /* Write time to RTC */
+       ret = wm8350_block_write(wm8350, WM8350_ALARM_SECONDS_MINUTES,
+                                3, time);
+       if (ret < 0)
+               return ret;
+
+       if (alrm->enabled)
+               ret = wm8350_rtc_start_alarm(wm8350);
+
+       return ret;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int wm8350_rtc_ioctl(struct device *dev, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               return wm8350_rtc_stop_alarm(wm8350);
+       case RTC_AIE_ON:
+               return wm8350_rtc_start_alarm(wm8350);
+
+       case RTC_UIE_OFF:
+               wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
+               break;
+       case RTC_UIE_ON:
+               wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq,
+                                    void *data)
+{
+       struct rtc_device *rtc = wm8350->rtc.rtc;
+       int ret;
+
+       rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+       /* Make it one shot */
+       ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL,
+                             WM8350_RTC_ALMSET);
+       if (ret != 0) {
+               dev_err(&(wm8350->rtc.pdev->dev),
+                       "Failed to disable alarm: %d\n", ret);
+       }
+}
+
+static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq,
+                                     void *data)
+{
+       struct rtc_device *rtc = wm8350->rtc.rtc;
+
+       rtc_update_irq(rtc, 1, RTC_IRQF | RTC_UF);
+}
+
+static const struct rtc_class_ops wm8350_rtc_ops = {
+       .ioctl = wm8350_rtc_ioctl,
+       .read_time = wm8350_rtc_readtime,
+       .set_time = wm8350_rtc_settime,
+       .read_alarm = wm8350_rtc_readalarm,
+       .set_alarm = wm8350_rtc_setalarm,
+};
+
+#ifdef CONFIG_PM
+static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+       int ret = 0;
+       u16 reg;
+
+       reg = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
+
+       if (device_may_wakeup(&wm8350->rtc.pdev->dev) &&
+           reg & WM8350_RTC_ALMSTS) {
+               ret = wm8350_rtc_stop_alarm(wm8350);
+               if (ret != 0)
+                       dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n",
+                               ret);
+       }
+
+       return ret;
+}
+
+static int wm8350_rtc_resume(struct platform_device *pdev)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+       int ret;
+
+       if (wm8350->rtc.alarm_enabled) {
+               ret = wm8350_rtc_start_alarm(wm8350);
+               if (ret != 0)
+                       dev_err(&pdev->dev,
+                               "Failed to restart RTC alarm: %d\n", ret);
+       }
+
+       return 0;
+}
+
+#else
+#define wm8350_rtc_suspend NULL
+#define wm8350_rtc_resume NULL
+#endif
+
+static int wm8350_rtc_probe(struct platform_device *pdev)
+{
+       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+       struct wm8350_rtc *wm_rtc = &wm8350->rtc;
+       int ret = 0;
+       u16 timectl, power5;
+
+       timectl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
+       if (timectl & WM8350_RTC_BCD) {
+               dev_err(&pdev->dev, "RTC BCD mode not supported\n");
+               return -EINVAL;
+       }
+       if (timectl & WM8350_RTC_12HR) {
+               dev_err(&pdev->dev, "RTC 12 hour mode not supported\n");
+               return -EINVAL;
+       }
+
+       /* enable the RTC if it's not already enabled */
+       power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+       if (!(power5 &  WM8350_RTC_TICK_ENA)) {
+               dev_info(wm8350->dev, "Starting RTC\n");
+
+               wm8350_reg_unlock(wm8350);
+
+               ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5,
+                                     WM8350_RTC_TICK_ENA);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to enable RTC: %d\n", ret);
+                       return ret;
+               }
+
+               wm8350_reg_lock(wm8350);
+       }
+
+       if (timectl & WM8350_RTC_STS) {
+               int retries;
+
+               ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
+                                       WM8350_RTC_SET);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to start: %d\n", ret);
+                       return ret;
+               }
+
+               retries = WM8350_SET_TIME_RETRIES;
+               do {
+                       timectl = wm8350_reg_read(wm8350,
+                                                 WM8350_RTC_TIME_CONTROL);
+               } while (timectl & WM8350_RTC_STS && retries--);
+
+               if (retries == 0) {
+                       dev_err(&pdev->dev, "failed to start: timeout\n");
+                       return -ENODEV;
+               }
+       }
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       wm_rtc->rtc = rtc_device_register("wm8350", &pdev->dev,
+                                         &wm8350_rtc_ops, THIS_MODULE);
+       if (IS_ERR(wm_rtc->rtc)) {
+               ret = PTR_ERR(wm_rtc->rtc);
+               dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
+               return ret;
+       }
+
+       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_PER);
+
+       wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC,
+                           wm8350_rtc_update_handler, NULL);
+
+       wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM,
+                           wm8350_rtc_alarm_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_ALM);
+
+       return 0;
+}
+
+static int __devexit wm8350_rtc_remove(struct platform_device *pdev)
+{
+       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+       struct wm8350_rtc *wm_rtc = &wm8350->rtc;
+
+       wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
+
+       wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);
+       wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM);
+
+       rtc_device_unregister(wm_rtc->rtc);
+
+       return 0;
+}
+
+static struct platform_driver wm8350_rtc_driver = {
+       .probe = wm8350_rtc_probe,
+       .remove = __devexit_p(wm8350_rtc_remove),
+       .suspend = wm8350_rtc_suspend,
+       .resume = wm8350_rtc_resume,
+       .driver = {
+               .name = "wm8350-rtc",
+       },
+};
+
+static int __init wm8350_rtc_init(void)
+{
+       return platform_driver_register(&wm8350_rtc_driver);
+}
+module_init(wm8350_rtc_init);
+
+static void __exit wm8350_rtc_exit(void)
+{
+       platform_driver_unregister(&wm8350_rtc_driver);
+}
+module_exit(wm8350_rtc_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("RTC driver for the WM8350");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-rtc");
index 4b76fca64a6f1bf5538c8babc8595b15a234aa8e..363bd1303d217aa4904ea088549e8f0bb9f23618 100644 (file)
@@ -1746,6 +1746,11 @@ restart:
                        goto restart;
                }
 
+               /* log sense for fatal error */
+               if (cqr->status == DASD_CQR_FAILED) {
+                       dasd_log_sense(cqr, &cqr->irb);
+               }
+
                /* First of all call extended error reporting. */
                if (dasd_eer_enabled(base) &&
                    cqr->status == DASD_CQR_FAILED) {
index eb5f1b8bc57fd0546c94067a5b57364f3db1addf..ec9c0bcf66eeefd8ee9029675cc193d0af328b0f 100644 (file)
@@ -324,6 +324,9 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn)
        case 0x0120:
                break;
        default:
+               pr_warning("assign storage failed (cmd=0x%08x, "
+                          "response=0x%04x, rn=0x%04x)\n", cmd,
+                          sccb->header.response_code, rn);
                rc = -EIO;
                break;
        }
index 4e78c82194b47520c271be8617ac5202644d395c..4e4008325e281edc58f11b3a211506b3f8bac35a 100644 (file)
@@ -874,11 +874,15 @@ void ccw_device_move_to_orphanage(struct work_struct *work)
        replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
        if (replacing_cdev) {
                sch_attach_disconnected_device(sch, replacing_cdev);
+               /* Release reference from get_disc_ccwdev_by_dev_id() */
+               put_device(&cdev->dev);
                return;
        }
        replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
        if (replacing_cdev) {
                sch_attach_orphaned_device(sch, replacing_cdev);
+               /* Release reference from get_orphaned_ccwdev_by_dev_id() */
+               put_device(&cdev->dev);
                return;
        }
        sch_create_and_recog_new_device(sch);
index ff4a6931bb8e680b4f429577fc81e481df4cd786..3d442444c618ccb431d7e4d6b6e1b5bc4f16924b 100644 (file)
@@ -322,13 +322,13 @@ static int __init kvm_devices_init(void)
                return rc;
        }
 
-       rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE);
+       rc = vmem_add_mapping(real_memory_size, PAGE_SIZE);
        if (rc) {
                s390_root_dev_unregister(kvm_root);
                return rc;
        }
 
-       kvm_devices = (void *) PFN_PHYS(max_pfn);
+       kvm_devices = (void *) real_memory_size;
 
        ctl_set_bit(0, 9);
        register_external_interrupt(0x2603, kvm_extint_handler);
index 3b56220fb900291df60b56284191b6e66119a02d..3d4e3e3f3fc07c873846d75b56d6e338c54475ce 100644 (file)
@@ -610,7 +610,8 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
        atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
        atomic_set(&port->refcount, 0);
 
-       dev_set_name(&port->sysfs_device, "0x%016llx", wwpn);
+       dev_set_name(&port->sysfs_device, "0x%016llx",
+                    (unsigned long long)wwpn);
        port->sysfs_device.parent = &adapter->ccw_device->dev;
 
        port->sysfs_device.release = zfcp_sysfs_port_release;
index b04038c74786b32456ded58505b96efd7f4c1756..951a8d409d1d5faa787a058d3f3542f13c9852c6 100644 (file)
@@ -116,7 +116,9 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
        zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 85,
                                NULL);
        zfcp_erp_wait(adapter);
-       goto out;
+       up(&zfcp_data.config_sema);
+       flush_work(&adapter->scan_work);
+       return 0;
 
  out_scsi_register:
        zfcp_erp_thread_kill(adapter);
index 060f5f2352ecb590b74e8667bb703fb1c0e62bc1..31012d58cfb760fb457862bfd596da12f8532310 100644 (file)
@@ -30,7 +30,7 @@ static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len,
                dump->offset = offset;
                dump->size = min(from_len - offset, room);
                memcpy(dump->data, from + offset, dump->size);
-               debug_event(dbf, level, dump, dump->size);
+               debug_event(dbf, level, dump, dump->size + sizeof(*dump));
        }
 }
 
@@ -108,7 +108,7 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view,
                             t.tv_sec, t.tv_nsec);
                zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid);
        } else  {
-               zfcp_dbf_outd(&p, NULL, dump->data, dump->size, dump->offset,
+               zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset,
                              dump->total_size);
                if ((dump->offset + dump->size) == dump->total_size)
                        p += sprintf(p, "\n");
@@ -366,6 +366,7 @@ static void zfcp_hba_dbf_view_response(char **p,
                        break;
                zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
                zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
+               p += sprintf(*p, "\n");
                break;
 
        case FSF_QTCB_OPEN_PORT_WITH_DID:
@@ -465,7 +466,8 @@ static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view,
        else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0)
                zfcp_hba_dbf_view_berr(&p, &r->u.berr);
 
-       p += sprintf(p, "\n");
+       if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0)
+               p += sprintf(p, "\n");
        return p - out_buf;
 }
 
@@ -880,6 +882,7 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
        struct ct_hdr *hdr = sg_virt(ct->req);
        struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf;
        struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req;
+       int level = 3;
        unsigned long flags;
 
        spin_lock_irqsave(&adapter->san_dbf_lock, flags);
@@ -896,9 +899,10 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
        oct->options = hdr->options;
        oct->max_res_size = hdr->max_res_size;
        oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr),
-                      ZFCP_DBF_CT_PAYLOAD);
-       memcpy(oct->payload, (void *)hdr + sizeof(struct ct_hdr), oct->len);
-       debug_event(adapter->san_dbf, 3, r, sizeof(*r));
+                      ZFCP_DBF_SAN_MAX_PAYLOAD);
+       debug_event(adapter->san_dbf, level, r, sizeof(*r));
+       zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level,
+                        (void *)hdr + sizeof(struct ct_hdr), oct->len);
        spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
@@ -914,6 +918,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
        struct ct_hdr *hdr = sg_virt(ct->resp);
        struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf;
        struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp;
+       int level = 3;
        unsigned long flags;
 
        spin_lock_irqsave(&adapter->san_dbf_lock, flags);
@@ -929,9 +934,10 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
        rct->expl = hdr->reason_code_expl;
        rct->vendor_unique = hdr->vendor_unique;
        rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr),
-                      ZFCP_DBF_CT_PAYLOAD);
-       memcpy(rct->payload, (void *)hdr + sizeof(struct ct_hdr), rct->len);
-       debug_event(adapter->san_dbf, 3, r, sizeof(*r));
+                      ZFCP_DBF_SAN_MAX_PAYLOAD);
+       debug_event(adapter->san_dbf, level, r, sizeof(*r));
+       zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level,
+                        (void *)hdr + sizeof(struct ct_hdr), rct->len);
        spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
@@ -954,7 +960,7 @@ static void zfcp_san_dbf_event_els(const char *tag, int level,
        rec->u.els.ls_code = ls_code;
        debug_event(adapter->san_dbf, level, rec, sizeof(*rec));
        zfcp_dbf_hexdump(adapter->san_dbf, rec, sizeof(*rec), level,
-                        buffer, min(buflen, ZFCP_DBF_ELS_MAX_PAYLOAD));
+                        buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD));
        spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
@@ -1008,8 +1014,6 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view,
                                    char *out_buf, const char *in_buf)
 {
        struct zfcp_san_dbf_record *r = (struct zfcp_san_dbf_record *)in_buf;
-       char *buffer = NULL;
-       int buflen = 0, total = 0;
        char *p = out_buf;
 
        if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
@@ -1029,9 +1033,6 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view,
                zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype);
                zfcp_dbf_out(&p, "options", "0x%02x", ct->options);
                zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size);
-               total = ct->len;
-               buffer = ct->payload;
-               buflen = min(total, ZFCP_DBF_CT_PAYLOAD);
        } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
                struct zfcp_san_dbf_record_ct_response *ct = &r->u.ct_resp;
                zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code);
@@ -1039,23 +1040,12 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view,
                zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code);
                zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl);
                zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique);
-               total = ct->len;
-               buffer = ct->payload;
-               buflen = min(total, ZFCP_DBF_CT_PAYLOAD);
        } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 ||
                   strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
                   strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
                struct zfcp_san_dbf_record_els *els = &r->u.els;
                zfcp_dbf_out(&p, "ls_code", "0x%02x", els->ls_code);
-               total = els->len;
-               buffer = els->payload;
-               buflen = min(total, ZFCP_DBF_ELS_PAYLOAD);
        }
-
-       zfcp_dbf_outd(&p, "payload", buffer, buflen, 0, total);
-       if (buflen == total)
-               p += sprintf(p, "\n");
-
        return p - out_buf;
 }
 
index e8f450801fea7f1cd351b7dad1049d02f82ab238..5d6b2dff855bb44e46d7fa6c65f93791b0bf1dfa 100644 (file)
@@ -163,8 +163,6 @@ struct zfcp_san_dbf_record_ct_request {
        u8 options;
        u16 max_res_size;
        u32 len;
-#define ZFCP_DBF_CT_PAYLOAD    24
-       u8 payload[ZFCP_DBF_CT_PAYLOAD];
 } __attribute__ ((packed));
 
 struct zfcp_san_dbf_record_ct_response {
@@ -174,15 +172,11 @@ struct zfcp_san_dbf_record_ct_response {
        u8 expl;
        u8 vendor_unique;
        u32 len;
-       u8 payload[ZFCP_DBF_CT_PAYLOAD];
 } __attribute__ ((packed));
 
 struct zfcp_san_dbf_record_els {
        u8 ls_code;
        u32 len;
-#define ZFCP_DBF_ELS_PAYLOAD   32
-#define ZFCP_DBF_ELS_MAX_PAYLOAD 1024
-       u8 payload[ZFCP_DBF_ELS_PAYLOAD];
 } __attribute__ ((packed));
 
 struct zfcp_san_dbf_record {
@@ -196,6 +190,8 @@ struct zfcp_san_dbf_record {
                struct zfcp_san_dbf_record_ct_response ct_resp;
                struct zfcp_san_dbf_record_els els;
        } u;
+#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024
+       u8 payload[32];
 } __attribute__ ((packed));
 
 struct zfcp_scsi_dbf_record {
index 9040f738ff333f47fd243486c311380f0ea00ebe..35364f64da7ff27ce7c740f3bde2a121df3d8556 100644 (file)
@@ -472,6 +472,7 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
                                   ZFCP_STATUS_ERP_TIMEDOUT)) {
                        act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
                        zfcp_rec_dbf_event_action(142, act);
+                       act->fsf_req->erp_action = NULL;
                }
                if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
                        zfcp_rec_dbf_event_action(143, act);
index 5ae1d497e5ed21f9061d36331a5a75ee63934b76..d024442ee128d9ee04ec44c5fe6b43e9ec099959 100644 (file)
@@ -683,6 +683,7 @@ static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool)
        if (!req)
                return NULL;
        memset(req, 0, sizeof(*req));
+       req->pool = pool;
        return req;
 }
 
@@ -769,28 +770,24 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
 static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
 {
        struct zfcp_adapter *adapter = req->adapter;
-       struct zfcp_qdio_queue *req_q = &adapter->req_q;
+       unsigned long flags;
        int idx;
 
        /* put allocated FSF request into hash table */
-       spin_lock(&adapter->req_list_lock);
+       spin_lock_irqsave(&adapter->req_list_lock, flags);
        idx = zfcp_reqlist_hash(req->req_id);
        list_add_tail(&req->list, &adapter->req_list[idx]);
-       spin_unlock(&adapter->req_list_lock);
+       spin_unlock_irqrestore(&adapter->req_list_lock, flags);
 
-       req->qdio_outb_usage = atomic_read(&req_q->count);
+       req->qdio_outb_usage = atomic_read(&adapter->req_q.count);
        req->issued = get_clock();
        if (zfcp_qdio_send(req)) {
-               /* Queues are down..... */
                del_timer(&req->timer);
-               spin_lock(&adapter->req_list_lock);
-               zfcp_reqlist_remove(adapter, req);
-               spin_unlock(&adapter->req_list_lock);
-               /* undo changes in request queue made for this request */
-               atomic_add(req->sbal_number, &req_q->count);
-               req_q->first -= req->sbal_number;
-               req_q->first += QDIO_MAX_BUFFERS_PER_Q;
-               req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
+               spin_lock_irqsave(&adapter->req_list_lock, flags);
+               /* lookup request again, list might have changed */
+               if (zfcp_reqlist_find_safe(adapter, req))
+                       zfcp_reqlist_remove(adapter, req);
+               spin_unlock_irqrestore(&adapter->req_list_lock, flags);
                zfcp_erp_adapter_reopen(adapter, 0, 116, req);
                return -EIO;
        }
index ca8f85f3dad439f515e25b8e5b049a0edd3701ee..e46fd3e9f68fb85ff3dc9899e454772b5bb33a39 100644 (file)
@@ -24,14 +24,10 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 {
        struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
-       WARN_ON(!unit);
-       if (unit) {
-               atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
-               sdpnt->hostdata = NULL;
-               unit->device = NULL;
-               zfcp_erp_unit_failed(unit, 12, NULL);
-               zfcp_unit_put(unit);
-       }
+       atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
+       unit->device = NULL;
+       zfcp_erp_unit_failed(unit, 12, NULL);
+       zfcp_unit_put(unit);
 }
 
 static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
index 8aba4fdfb5222b40d93a8e231fd1b69858ddecdc..6194ed5d02c4e694bc2bfbe3faf9a56860a2ade5 100644 (file)
@@ -2445,7 +2445,7 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
        hba_status = detailed_status >> 8;
 
        // calculate resid for sg 
-       scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+5));
+       scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+20));
 
        pHba = (adpt_hba*) cmd->device->host->hostdata[0];
 
@@ -2456,7 +2456,7 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
                case I2O_SCSI_DSC_SUCCESS:
                        cmd->result = (DID_OK << 16);
                        // handle underflow
-                       if(readl(reply+5) < cmd->underflow ) {
+                       if (readl(reply+20) < cmd->underflow) {
                                cmd->result = (DID_ERROR <<16);
                                printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name);
                        }
index 28c9da7d4a5c5f0aad97c0a41f964c8994c4d228..7dc62deb4087cead7dfeed562cc3e9bc4a5c9011 100644 (file)
@@ -4402,6 +4402,10 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
        scb_t   *scb;
        int     rval;
 
+       scmd = scsi_allocate_command(GFP_KERNEL);
+       if (!scmd)
+               return -ENOMEM;
+
        /*
         * The internal commands share one command id and hence are
         * serialized. This is so because we want to reserve maximum number of
@@ -4412,12 +4416,11 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
        scb = &adapter->int_scb;
        memset(scb, 0, sizeof(scb_t));
 
-       scmd = &adapter->int_scmd;
-       memset(scmd, 0, sizeof(Scsi_Cmnd));
-
        sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
        scmd->device = sdev;
 
+       memset(adapter->int_cdb, 0, sizeof(adapter->int_cdb));
+       scmd->cmnd = adapter->int_cdb;
        scmd->device->host = adapter->host;
        scmd->host_scribble = (void *)scb;
        scmd->cmnd[0] = MEGA_INTERNAL_CMD;
@@ -4456,6 +4459,8 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
 
        mutex_unlock(&adapter->int_mtx);
 
+       scsi_free_command(GFP_KERNEL, scmd);
+
        return rval;
 }
 
index ee70bd4ae4badc0f2f7a82eb0a523d5702c796f4..795201fa0b487d1a23113f38534666d90d23ec49 100644 (file)
@@ -888,8 +888,8 @@ typedef struct {
 
        u8      sglen;  /* f/w supported scatter-gather list length */
 
+       unsigned char int_cdb[MAX_COMMAND_SIZE];
        scb_t                   int_scb;
-       Scsi_Cmnd               int_scmd;
        struct mutex            int_mtx;        /* To synchronize the internal
                                                commands */
        struct completion       int_waitq;      /* wait queue for internal
index f25f41a499e5ed7be7ebd3dc109d4d4b14c9494a..b97194096d8e6a285f55389360bf92691c6cf471 100644 (file)
@@ -2547,7 +2547,6 @@ typedef struct scsi_qla_host {
        uint8_t         fcode_revision[16];
        uint32_t        fw_revision[4];
 
-       uint16_t        fdt_odd_index;
        uint32_t        fdt_wrt_disable;
        uint32_t        fdt_erase_cmd;
        uint32_t        fdt_block_size;
index a470f2d3270d205ad35ee26519a25e9d37f90252..4218f20f5ed5256b35a61862a73424e7c581d712 100644 (file)
@@ -140,7 +140,6 @@ int
 qla2100_pci_config(scsi_qla_host_t *ha)
 {
        uint16_t w;
-       uint32_t d;
        unsigned long flags;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
@@ -151,10 +150,7 @@ qla2100_pci_config(scsi_qla_host_t *ha)
        w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
        pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
-       /* Reset expansion ROM address decode enable */
-       pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
-       d &= ~PCI_ROM_ADDRESS_ENABLE;
-       pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+       pci_disable_rom(ha->pdev);
 
        /* Get PCI bus information. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -174,7 +170,6 @@ int
 qla2300_pci_config(scsi_qla_host_t *ha)
 {
        uint16_t        w;
-       uint32_t        d;
        unsigned long   flags = 0;
        uint32_t        cnt;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
@@ -236,10 +231,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
 
        pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
-       /* Reset expansion ROM address decode enable */
-       pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
-       d &= ~PCI_ROM_ADDRESS_ENABLE;
-       pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+       pci_disable_rom(ha->pdev);
 
        /* Get PCI bus information. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -259,7 +251,6 @@ int
 qla24xx_pci_config(scsi_qla_host_t *ha)
 {
        uint16_t w;
-       uint32_t d;
        unsigned long flags = 0;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
@@ -281,10 +272,7 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
        if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
                pcie_set_readrq(ha->pdev, 2048);
 
-       /* Reset expansion ROM address decode enable */
-       pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
-       d &= ~PCI_ROM_ADDRESS_ENABLE;
-       pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+       pci_disable_rom(ha->pdev);
 
        ha->chip_revision = ha->pdev->revision;
 
@@ -306,7 +294,6 @@ int
 qla25xx_pci_config(scsi_qla_host_t *ha)
 {
        uint16_t w;
-       uint32_t d;
 
        pci_set_master(ha->pdev);
        pci_try_set_mwi(ha->pdev);
@@ -320,10 +307,7 @@ qla25xx_pci_config(scsi_qla_host_t *ha)
        if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
                pcie_set_readrq(ha->pdev, 2048);
 
-       /* Reset expansion ROM address decode enable */
-       pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
-       d &= ~PCI_ROM_ADDRESS_ENABLE;
-       pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+       pci_disable_rom(ha->pdev);
 
        ha->chip_revision = ha->pdev->revision;
 
@@ -980,7 +964,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
                                    &ha->fw_minor_version,
                                    &ha->fw_subminor_version,
                                    &ha->fw_attributes, &ha->fw_memory_size);
-                               qla2x00_resize_request_q(ha);
                                ha->flags.npiv_supported = 0;
                                if ((IS_QLA24XX(ha) || IS_QLA25XX(ha) ||
                                     IS_QLA84XX(ha)) &&
@@ -992,6 +975,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
                                                ha->max_npiv_vports =
                                                    MIN_MULTI_ID_FABRIC - 1;
                                }
+                               qla2x00_resize_request_q(ha);
 
                                if (ql2xallocfwdump)
                                        qla2x00_alloc_fw_dump(ha);
index 36bc6851e23dd2b13cfbbe98a6a14eac5faf0c07..3402746ec128a54115ac1880acbba27b7da6541f 100644 (file)
@@ -1964,7 +1964,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
                        *cur_iocb_cnt = mcp->mb[7];
                if (orig_iocb_cnt)
                        *orig_iocb_cnt = mcp->mb[10];
-               if (max_npiv_vports)
+               if (ha->flags.npiv_supported && max_npiv_vports)
                        *max_npiv_vports = mcp->mb[11];
        }
 
index 21dd182ad512214c7646299a1af4ad4f2e9d9e88..35567203ef611bc730df2fde134c036b6e124107 100644 (file)
@@ -728,6 +728,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                if (ha->isp_ops->abort_command(ha, sp)) {
                        DEBUG2(printk("%s(%ld): abort_command "
                            "mbx failed.\n", __func__, ha->host_no));
+                       ret = FAILED;
                } else {
                        DEBUG3(printk("%s(%ld): abort_command "
                            "mbx success.\n", __func__, ha->host_no));
index 90a13211717f7d367a89c3b7f0b74fc5dd0f113c..e4af678eb2d62ca071f6d04a2461074d611d089a 100644 (file)
@@ -722,6 +722,7 @@ done:
 static void
 qla2xxx_get_fdt_info(scsi_qla_host_t *ha)
 {
+#define FLASH_BLK_SIZE_4K      0x1000
 #define FLASH_BLK_SIZE_32K     0x8000
 #define FLASH_BLK_SIZE_64K     0x10000
        const char *loc, *locations[] = { "MID", "FDT" };
@@ -755,7 +756,6 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *ha)
        loc = locations[1];
        mid = le16_to_cpu(fdt->man_id);
        fid = le16_to_cpu(fdt->id);
-       ha->fdt_odd_index = mid == 0x1f;
        ha->fdt_wrt_disable = fdt->wrt_disable_bits;
        ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd);
        ha->fdt_block_size = le32_to_cpu(fdt->block_size);
@@ -788,8 +788,7 @@ no_flash_data:
                ha->fdt_block_size = FLASH_BLK_SIZE_64K;
                break;
        case 0x1f: /* Atmel 26DF081A. */
-               ha->fdt_odd_index = 1;
-               ha->fdt_block_size = FLASH_BLK_SIZE_64K;
+               ha->fdt_block_size = FLASH_BLK_SIZE_4K;
                ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320);
                ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339);
                ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336);
@@ -801,9 +800,9 @@ no_flash_data:
        }
 done:
        DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
-           "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
+           "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
            ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
-           ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable,
+           ha->fdt_unprotect_sec_cmd, ha->fdt_wrt_disable,
            ha->fdt_block_size));
 }
 
@@ -987,13 +986,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
        qla24xx_unprotect_flash(ha);
 
        for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
-               if (ha->fdt_odd_index) {
-                       findex = faddr << 2;
-                       fdata = findex & sec_mask;
-               } else {
-                       findex = faddr;
-                       fdata = (findex & sec_mask) << 2;
-               }
+
+               findex = faddr;
+               fdata = (findex & sec_mask) << 2;
 
                /* Are we at the beginning of a sector? */
                if ((findex & rest_addr) == 0) {
index be5e299df528e22eed62f8ac25d03c01a11630d7..eea6720adf1693c8521851f57e8b15bb1b87880b 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.02.01-k8"
+#define QLA2XXX_VERSION      "8.02.01-k9"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   2
index 94ed262bdf0c7731040c0112d955ded856fe96e4..386361778ebb32d859c6770971329f46d55ae23e 100644 (file)
@@ -1340,9 +1340,10 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                 * LLD/transport was disrupted during processing of the IO.
                 * The transport class is now blocked/blocking,
                 * and the transport will decide what to do with the IO
-                * based on its timers and recovery capablilities.
+                * based on its timers and recovery capablilities if
+                * there are enough retries.
                 */
-               return ADD_TO_MLQUEUE;
+               goto maybe_retry;
        case DID_TRANSPORT_FAILFAST:
                /*
                 * The transport decided to failfast the IO (most likely
index 5c0f32c7fbf6b20c8e20fba1ec32f7e08af29909..165fc010978c2624a7a45730f403b505ed48e726 100644 (file)
@@ -144,9 +144,9 @@ static void put_char(struct uart_port *port, char c)
                status = sci_in(port, SCxSR);
        } while (!(status & SCxSR_TDxE(port)));
 
-       sci_out(port, SCxTDR, c);
        sci_in(port, SCxSR);            /* Dummy read */
        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+       sci_out(port, SCxTDR, c);
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -478,10 +478,10 @@ static void sci_transmit_chars(struct uart_port *port)
                return;
        }
 
-       if (port->type == PORT_SCIF)
-               count = scif_txroom(port);
-       else
+       if (port->type == PORT_SCI)
                count = sci_txroom(port);
+       else
+               count = scif_txroom(port);
 
        do {
                unsigned char c;
@@ -510,7 +510,7 @@ static void sci_transmit_chars(struct uart_port *port)
        } else {
                ctrl = sci_in(port, SCSCR);
 
-               if (port->type == PORT_SCIF) {
+               if (port->type != PORT_SCI) {
                        sci_in(port, SCxSR); /* Dummy read */
                        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
                }
@@ -536,10 +536,10 @@ static inline void sci_receive_chars(struct uart_port *port)
                return;
 
        while (1) {
-               if (port->type == PORT_SCIF)
-                       count = scif_rxroom(port);
-               else
+               if (port->type == PORT_SCI)
                        count = sci_rxroom(port);
+               else
+                       count = scif_rxroom(port);
 
                /* Don't copy more bytes than there is room for in the buffer */
                count = tty_buffer_request_room(tty, count);
@@ -714,7 +714,7 @@ static inline int sci_handle_breaks(struct uart_port *port)
 
 #if defined(SCIF_ORER)
        /* XXX: Handle SCIF overrun error */
-       if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+       if (port->type != PORT_SCI && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
                sci_out(port, SCLSR, 0);
                if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
                        copied++;
@@ -1042,7 +1042,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 
        sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
 
-       if (port->type == PORT_SCIF)
+       if (port->type != PORT_SCI)
                sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
 
        smr_val = sci_in(port, SCSMR) & 3;
@@ -1085,6 +1085,7 @@ static const char *sci_type(struct uart_port *port)
                case PORT_SCI:  return "sci";
                case PORT_SCIF: return "scif";
                case PORT_IRDA: return "irda";
+               case PORT_SCIFA:        return "scifa";
        }
 
        return NULL;
@@ -1112,6 +1113,7 @@ static void sci_config_port(struct uart_port *port, int flags)
                s->init_pins = sci_init_pins_sci;
                break;
        case PORT_SCIF:
+       case PORT_SCIFA:
                s->init_pins = sci_init_pins_scif;
                break;
        case PORT_IRDA:
index 6163a45f968f4b9aef1b79056f02e2329232e231..9f33b064172e86607e607ae69afbfaf595c21da9 100644 (file)
 #define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
   static inline unsigned int sci_##name##_in(struct uart_port *port)   \
   {                                                                    \
-    if (port->type == PORT_SCI) {                                      \
-      SCI_IN(sci_size, sci_offset)                                     \
-    } else {                                                           \
-      SCI_IN(scif_size, scif_offset);                                  \
+    if (port->type == PORT_SCIF) {                                     \
+      SCI_IN(scif_size, scif_offset)                                   \
+    } else {   /* PORT_SCI or PORT_SCIFA */                            \
+      SCI_IN(sci_size, sci_offset);                                    \
     }                                                                  \
   }                                                                    \
   static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
   {                                                                    \
-    if (port->type == PORT_SCI) {                                      \
-      SCI_OUT(sci_size, sci_offset, value)                             \
-    } else {                                                           \
-      SCI_OUT(scif_size, scif_offset, value);                          \
+    if (port->type == PORT_SCIF) {                                     \
+      SCI_OUT(scif_size, scif_offset, value)                           \
+    } else {   /* PORT_SCI or PORT_SCIFA */                            \
+      SCI_OUT(sci_size, sci_offset, value);                            \
     }                                                                  \
   }
 
index 02f9320f3efcf25000393284e7823f9089d0b7f3..8abae4ad0fa528565427ec050555142924dc7b99 100644 (file)
@@ -766,6 +766,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
        /* Initialize the hardware */
        clk_enable(clk);
        spi_writel(as, CR, SPI_BIT(SWRST));
+       spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
        spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
        spi_writel(as, CR, SPI_BIT(SPIEN));
@@ -782,6 +783,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
 
 out_reset_hw:
        spi_writel(as, CR, SPI_BIT(SWRST));
+       spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        clk_disable(clk);
        free_irq(irq, master);
 out_unmap_regs:
@@ -805,6 +807,7 @@ static int __exit atmel_spi_remove(struct platform_device *pdev)
        spin_lock_irq(&as->lock);
        as->stopping = 1;
        spi_writel(as, CR, SPI_BIT(SWRST));
+       spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        spi_readl(as, SR);
        spin_unlock_irq(&as->lock);
 
index dae87b1a4c6effa5c18cff538c3a634a846a2957..cf12f2d84be2c2547fdbe88caf81ea25d733f867 100644 (file)
@@ -352,21 +352,21 @@ static int map_dma_buffers(struct driver_data *drv_data)
        } else
                drv_data->tx_map_len = drv_data->len;
 
-       /* Stream map the rx buffer */
-       drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
-                                               drv_data->rx_map_len,
-                                               DMA_FROM_DEVICE);
-       if (dma_mapping_error(dev, drv_data->rx_dma))
-               return 0;
-
-       /* Stream map the tx buffer */
+       /* Stream map the tx buffer. Always do DMA_TO_DEVICE first
+        * so we flush the cache *before* invalidating it, in case
+        * the tx and rx buffers overlap.
+        */
        drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
-                                               drv_data->tx_map_len,
-                                               DMA_TO_DEVICE);
+                                       drv_data->tx_map_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, drv_data->tx_dma))
+               return 0;
 
-       if (dma_mapping_error(dev, drv_data->tx_dma)) {
-               dma_unmap_single(dev, drv_data->rx_dma,
+       /* Stream map the rx buffer */
+       drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
                                        drv_data->rx_map_len, DMA_FROM_DEVICE);
+       if (dma_mapping_error(dev, drv_data->rx_dma)) {
+               dma_unmap_single(dev, drv_data->tx_dma,
+                                       drv_data->tx_map_len, DMA_TO_DEVICE);
                return 0;
        }
 
index 61ba147e384d5ddfb350115bfecf3fb239e190e0..0b4db0ce78d6d08e7d86237461f44339811e0194 100644 (file)
@@ -506,20 +506,6 @@ static int map_dma_buffers(struct driver_data *drv_data)
        if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
                return -1;
 
-       /* NULL rx means write-only transfer and no map needed
-          since rx DMA will not be used */
-       if (drv_data->rx) {
-               buf = drv_data->rx;
-               drv_data->rx_dma = dma_map_single(
-                                       dev,
-                                       buf,
-                                       drv_data->len,
-                                       DMA_FROM_DEVICE);
-               if (dma_mapping_error(dev, drv_data->rx_dma))
-                       return -1;
-               drv_data->rx_dma_needs_unmap = 1;
-       }
-
        if (drv_data->tx == NULL) {
                /* Read only message --> use drv_data->dummy_dma_buf for dummy
                   writes to achive reads */
@@ -533,18 +519,31 @@ static int map_dma_buffers(struct driver_data *drv_data)
                                        buf,
                                        drv_data->tx_map_len,
                                        DMA_TO_DEVICE);
-       if (dma_mapping_error(dev, drv_data->tx_dma)) {
-               if (drv_data->rx_dma) {
-                       dma_unmap_single(dev,
-                                       drv_data->rx_dma,
-                                       drv_data->len,
-                                       DMA_FROM_DEVICE);
-                       drv_data->rx_dma_needs_unmap = 0;
-               }
+       if (dma_mapping_error(dev, drv_data->tx_dma))
                return -1;
-       }
        drv_data->tx_dma_needs_unmap = 1;
 
+       /* NULL rx means write-only transfer and no map needed
+        * since rx DMA will not be used */
+       if (drv_data->rx) {
+               buf = drv_data->rx;
+               drv_data->rx_dma = dma_map_single(dev,
+                                               buf,
+                                               drv_data->len,
+                                               DMA_FROM_DEVICE);
+               if (dma_mapping_error(dev, drv_data->rx_dma)) {
+                       if (drv_data->tx_dma) {
+                               dma_unmap_single(dev,
+                                               drv_data->tx_dma,
+                                               drv_data->tx_map_len,
+                                               DMA_TO_DEVICE);
+                               drv_data->tx_dma_needs_unmap = 0;
+                       }
+                       return -1;
+               }
+               drv_data->rx_dma_needs_unmap = 1;
+       }
+
        return 0;
 }
 
index 20104443081ad1fc260d4ba74f17a0c9828eca69..d50a99f70aee8d33941e5445f62bef41778093d3 100644 (file)
@@ -158,16 +158,12 @@ static int acm_wb_is_avail(struct acm *acm)
 }
 
 /*
- * Finish write.
+ * Finish write. Caller must hold acm->write_lock
  */
 static void acm_write_done(struct acm *acm, struct acm_wb *wb)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&acm->write_lock, flags);
        wb->use = 0;
        acm->transmitting--;
-       spin_unlock_irqrestore(&acm->write_lock, flags);
 }
 
 /*
@@ -482,6 +478,7 @@ static void acm_write_bulk(struct urb *urb)
 {
        struct acm_wb *wb = urb->context;
        struct acm *acm = wb->instance;
+       unsigned long flags;
 
        if (verbose || urb->status
                        || (urb->actual_length != urb->transfer_buffer_length))
@@ -490,7 +487,9 @@ static void acm_write_bulk(struct urb *urb)
                        urb->transfer_buffer_length,
                        urb->status);
 
+       spin_lock_irqsave(&acm->write_lock, flags);
        acm_write_done(acm, wb);
+       spin_unlock_irqrestore(&acm->write_lock, flags);
        if (ACM_READY(acm))
                schedule_work(&acm->work);
        else
index 887738577b2838df3e02f93c05a9fe32a48b0606..6d1048faf08e1679597af0fadd6a5849d3afd299 100644 (file)
@@ -1091,6 +1091,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
                                continue;
                        dev_dbg(&dev->dev, "unregistering interface %s\n",
                                dev_name(&interface->dev));
+                       interface->unregistering = 1;
                        usb_remove_sysfs_intf_files(interface);
                        device_del(&interface->dev);
                }
index f66fba11fbd53f2eeaf5a5ebc17a9d8251c526db..4fb65fdc9dc36bb51eb25059789886fbd1dfe857 100644 (file)
@@ -840,7 +840,7 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
        struct usb_host_interface *alt = intf->cur_altsetting;
        int retval;
 
-       if (intf->sysfs_files_created)
+       if (intf->sysfs_files_created || intf->unregistering)
                return 0;
 
        /* The interface string may be present in some altsettings
index 4342bd9c3bb610d9582217aae0bc524378a28a7f..1f68af9db3f7d6bed13bcab914eb238b638b5bee 100644 (file)
@@ -85,8 +85,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_urb);
  * Must be called when a user of a urb is finished with it.  When the last user
  * of the urb calls this function, the memory of the urb is freed.
  *
- * Note: The transfer buffer associated with the urb is not freed, that must be
- * done elsewhere.
+ * Note: The transfer buffer associated with the urb is not freed unless the
+ * URB_FREE_BUFFER transfer flag is set.
  */
 void usb_free_urb(struct urb *urb)
 {
index 5ee1590b8e9cf2739e629804193aa8fa053954cf..c1d34df0b157c45f533b03b794bd14a929055f70 100644 (file)
@@ -463,7 +463,11 @@ static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
        notify->wLength = cpu_to_le16(length);
        memcpy(buf, data, length);
 
+       /* ep_queue() can complete immediately if it fills the fifo... */
+       spin_unlock(&acm->lock);
        status = usb_ep_queue(ep, req, GFP_ATOMIC);
+       spin_lock(&acm->lock);
+
        if (status < 0) {
                ERROR(acm->port.func.config->cdev,
                                "acm ttyGS%d can't notify serial state, %d\n",
index 56f592dc0b3626139f4e9b34dd191af967f30bf0..f3a75a929e0aa26dcdbaee0c75c0cfa10403f8bf 100644 (file)
@@ -110,29 +110,18 @@ config USB_ISP116X_HCD
 
 config USB_ISP1760_HCD
        tristate "ISP 1760 HCD support"
-       depends on USB && EXPERIMENTAL
+       depends on USB && EXPERIMENTAL && (PCI || PPC_OF)
        ---help---
          The ISP1760 chip is a USB 2.0 host controller.
 
          This driver does not support isochronous transfers or OTG.
+         This USB controller is usually attached to a non-DMA-Master
+         capable bus. NXP's eval kit brings this chip on PCI card
+         where the chip itself is behind a PLB to simulate such
+         a bus.
 
          To compile this driver as a module, choose M here: the
-         module will be called isp1760-hcd.
-
-config USB_ISP1760_PCI
-       bool "Support for the PCI bus"
-       depends on USB_ISP1760_HCD && PCI
-       ---help---
-         Enables support for the device present on the PCI bus.
-         This should only be required if you happen to have the eval kit from
-         NXP and you are going to test it.
-
-config USB_ISP1760_OF
-       bool "Support for the OF platform bus"
-       depends on USB_ISP1760_HCD && PPC_OF
-       ---help---
-         Enables support for the device present on the PowerPC
-         OpenFirmware platform bus.
+         module will be called isp1760.
 
 config USB_OHCI_HCD
        tristate "OHCI HCD support"
index 15a803b206b8ea72c4774ba6edb504a0fd5e964c..4725d15d096f559fc833d0e0f6323bcff4aa7631 100644 (file)
@@ -643,7 +643,7 @@ static int ehci_run (struct usb_hcd *hcd)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       u32                     status, pcd_status = 0, cmd;
+       u32                     status, masked_status, pcd_status = 0, cmd;
        int                     bh;
 
        spin_lock (&ehci->lock);
@@ -656,14 +656,14 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                goto dead;
        }
 
-       status &= INTR_MASK;
-       if (!status) {                  /* irq sharing? */
+       masked_status = status & INTR_MASK;
+       if (!masked_status) {           /* irq sharing? */
                spin_unlock(&ehci->lock);
                return IRQ_NONE;
        }
 
        /* clear (just) interrupts */
-       ehci_writel(ehci, status, &ehci->regs->status);
+       ehci_writel(ehci, masked_status, &ehci->regs->status);
        cmd = ehci_readl(ehci, &ehci->regs->command);
        bh = 0;
 
@@ -734,18 +734,17 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
+               ehci_err(ehci, "fatal error\n");
                dbg_cmd(ehci, "fatal", cmd);
                dbg_status(ehci, "fatal", status);
-               if (status & STS_HALT) {
-                       ehci_err (ehci, "fatal error\n");
+               ehci_halt(ehci);
 dead:
-                       ehci_reset (ehci);
-                       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
-                       /* generic layer kills/unlinks all urbs, then
-                        * uses ehci_stop to clean up the rest
-                        */
-                       bh = 1;
-               }
+               ehci_reset(ehci);
+               ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+               /* generic layer kills/unlinks all urbs, then
+                * uses ehci_stop to clean up the rest
+                */
+               bh = 1;
        }
 
        if (bh)
index 0eba894bcb017aa0706f5e60224149e76338d99a..9c9da35abc6c010c6929a1e515fc4179ef898111 100644 (file)
@@ -205,6 +205,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
 
        tmp = hcd->irq;
 
+       ehci_shutdown(hcd);
        usb_remove_hcd(hcd);
 
        ps3_system_bus_set_driver_data(dev, NULL);
index 4a0c5a78b2ed74358055e800d5181b1a1e2cb1c7..a081ee65bde6d933f3f2000c67028d461ece27c7 100644 (file)
@@ -918,7 +918,7 @@ iso_stream_init (
                 */
                stream->usecs = HS_USECS_ISO (maxp);
                bandwidth = stream->usecs * 8;
-               bandwidth /= 1 << (interval - 1);
+               bandwidth /= interval;
 
        } else {
                u32             addr;
@@ -951,7 +951,7 @@ iso_stream_init (
                } else
                        stream->raw_mask = smask_out [hs_transfers - 1];
                bandwidth = stream->usecs + stream->c_usecs;
-               bandwidth /= 1 << (interval + 2);
+               bandwidth /= interval << 3;
 
                /* stream->splits gets created from raw_mask later */
                stream->address = cpu_to_hc32(ehci, addr);
index af849f596135324bf727ac667f7f2d4cbc7d9920..b87ca7cf4b378f4ee0c6ee7ed403e629d79a38ea 100644 (file)
 #include "../core/hcd.h"
 #include "isp1760-hcd.h"
 
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #endif
 
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
 
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
 static int of_isp1760_probe(struct of_device *dev,
                const struct of_device_id *match)
 {
@@ -128,7 +128,7 @@ static struct of_platform_driver isp1760_of_driver = {
 };
 #endif
 
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
 static u32 nxp_pci_io_base;
 static u32 iolength;
 static u32 pci_mem_phy0;
@@ -288,28 +288,28 @@ static struct pci_driver isp1761_pci_driver = {
 
 static int __init isp1760_init(void)
 {
-       int ret = -ENODEV;
+       int ret;
 
        init_kmem_once();
 
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
        ret = of_register_platform_driver(&isp1760_of_driver);
        if (ret) {
                deinit_kmem_cache();
                return ret;
        }
 #endif
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
        ret = pci_register_driver(&isp1761_pci_driver);
        if (ret)
                goto unreg_of;
 #endif
        return ret;
 
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
 unreg_of:
 #endif
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
        of_unregister_platform_driver(&isp1760_of_driver);
 #endif
        deinit_kmem_cache();
@@ -319,10 +319,10 @@ module_init(isp1760_init);
 
 static void __exit isp1760_exit(void)
 {
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
        of_unregister_platform_driver(&isp1760_of_driver);
 #endif
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
        pci_unregister_driver(&isp1761_pci_driver);
 #endif
        deinit_kmem_cache();
index 2089d8a46c4bbedb0cd140dc5db4d0cee4cab908..3c1a3b5f89f19fb19dde0962b8b4e6a2e704b9e4 100644 (file)
@@ -192,7 +192,7 @@ fail_start:
        return result;
 }
 
-static int ps3_ohci_remove (struct ps3_system_bus_device *dev)
+static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
 {
        unsigned int tmp;
        struct usb_hcd *hcd =
@@ -205,6 +205,7 @@ static int ps3_ohci_remove (struct ps3_system_bus_device *dev)
 
        tmp = hcd->irq;
 
+       ohci_shutdown(hcd);
        usb_remove_hcd(hcd);
 
        ps3_system_bus_set_driver_data(dev, NULL);
index c18d8790c4107c032eb0e34b94be345683828d8d..2376f24f3c83dc964f03286a66a88ab195434179 100644 (file)
@@ -1763,11 +1763,12 @@ static void r8a66597_timer(unsigned long _r8a66597)
 {
        struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
        unsigned long flags;
+       int port;
 
        spin_lock_irqsave(&r8a66597->lock, flags);
 
-       r8a66597_root_hub_control(r8a66597, 0);
-       r8a66597_root_hub_control(r8a66597, 1);
+       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+               r8a66597_root_hub_control(r8a66597, port);
 
        spin_unlock_irqrestore(&r8a66597->lock, flags);
 }
index 69c34a58e2054a7c49d225164a3f1a7ead20cf5a..b4ec716de7dadc12b766e445822edbc4f35f537a 100644 (file)
@@ -3270,6 +3270,7 @@ static struct usb_device_id sisusb_table [] = {
        { USB_DEVICE(0x0711, 0x0900) },
        { USB_DEVICE(0x0711, 0x0901) },
        { USB_DEVICE(0x0711, 0x0902) },
+       { USB_DEVICE(0x0711, 0x0903) },
        { USB_DEVICE(0x0711, 0x0918) },
        { USB_DEVICE(0x182d, 0x021c) },
        { USB_DEVICE(0x182d, 0x0269) },
index 8648470c81caa3a4e516445255a00b9101373c25..63dff9ba73c5d074bcd87ba13fcd4188dce81960 100644 (file)
@@ -620,7 +620,7 @@ static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                __func__);
                        retval = -EFAULT;
                } else {
-                       dev_dbg(&dev->dev, "%s: recv %d bytes from pipe %d\n",
+                       dev_dbg(&dev->dev, "%s: recv %zd bytes from pipe %d\n",
                                __func__, usb_data.count, usb_data.pipe);
                }
 
index 4a35745b30be6992ff775cfd118c02750a2eef52..5280dba9b1fb7e0a94f6dc1b379b28fc5c7d831b 100644 (file)
 
 
 
-unsigned debug;
-module_param(debug, uint, S_IRUGO | S_IWUSR);
+unsigned musb_debug;
+module_param(musb_debug, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
 
 #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
@@ -2248,7 +2248,7 @@ static int __init musb_init(void)
                "host"
 #endif
                ", debug=%d\n",
-               musb_driver_name, debug);
+               musb_driver_name, musb_debug);
        return platform_driver_probe(&musb_driver, musb_probe);
 }
 
index 4d2794441b153ac6c2f745b99f06c245cb56bbe5..9fc1db44c72c13844e73148112bbe8055c65ef3f 100644 (file)
                                __func__, __LINE__ , ## args); \
        } } while (0)
 
-extern unsigned debug;
+extern unsigned musb_debug;
 
 static inline int _dbg_level(unsigned l)
 {
-       return debug >= l;
+       return musb_debug >= l;
 }
 
 #define DBG(level, fmt, args...) xprintk(level, KERN_DEBUG, fmt, ## args)
index 3133990f04ec868fcb0809cd233535f3fc562ff2..e45e70bcc5e2ea1c79610ad7f754a8029e922ccd 100644 (file)
@@ -378,6 +378,19 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
 
                switch (qh->type) {
 
+               case USB_ENDPOINT_XFER_CONTROL:
+               case USB_ENDPOINT_XFER_BULK:
+                       /* fifo policy for these lists, except that NAKing
+                        * should rotate a qh to the end (for fairness).
+                        */
+                       if (qh->mux == 1) {
+                               head = qh->ring.prev;
+                               list_del(&qh->ring);
+                               kfree(qh);
+                               qh = first_qh(head);
+                               break;
+                       }
+
                case USB_ENDPOINT_XFER_ISOC:
                case USB_ENDPOINT_XFER_INT:
                        /* this is where periodic bandwidth should be
@@ -388,17 +401,6 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
                        kfree(qh);
                        qh = NULL;
                        break;
-
-               case USB_ENDPOINT_XFER_CONTROL:
-               case USB_ENDPOINT_XFER_BULK:
-                       /* fifo policy for these lists, except that NAKing
-                        * should rotate a qh to the end (for fairness).
-                        */
-                       head = qh->ring.prev;
-                       list_del(&qh->ring);
-                       kfree(qh);
-                       qh = first_qh(head);
-                       break;
                }
        }
        return qh;
@@ -1507,10 +1509,29 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                musb_writew(hw_ep->regs, MUSB_RXCSR, val);
 
 #ifdef CONFIG_USB_INVENTRA_DMA
+               if (usb_pipeisoc(pipe)) {
+                       struct usb_iso_packet_descriptor *d;
+
+                       d = urb->iso_frame_desc + qh->iso_idx;
+                       d->actual_length = xfer_len;
+
+                       /* even if there was an error, we did the dma
+                        * for iso_frame_desc->length
+                        */
+                       if (d->status != EILSEQ && d->status != -EOVERFLOW)
+                               d->status = 0;
+
+                       if (++qh->iso_idx >= urb->number_of_packets)
+                               done = true;
+                       else
+                               done = false;
+
+               } else  {
                /* done if urb buffer is full or short packet is recd */
                done = (urb->actual_length + xfer_len >=
                                urb->transfer_buffer_length
                        || dma->actual_len < qh->maxpacket);
+               }
 
                /* send IN token for next packet, without AUTOREQ */
                if (!done) {
@@ -1547,7 +1568,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                if (dma) {
                        struct dma_controller   *c;
                        u16                     rx_count;
-                       int                     ret;
+                       int                     ret, length;
+                       dma_addr_t              buf;
 
                        rx_count = musb_readw(epio, MUSB_RXCOUNT);
 
@@ -1560,6 +1582,35 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 
                        c = musb->dma_controller;
 
+                       if (usb_pipeisoc(pipe)) {
+                               int status = 0;
+                               struct usb_iso_packet_descriptor *d;
+
+                               d = urb->iso_frame_desc + qh->iso_idx;
+
+                               if (iso_err) {
+                                       status = -EILSEQ;
+                                       urb->error_count++;
+                               }
+                               if (rx_count > d->length) {
+                                       if (status == 0) {
+                                               status = -EOVERFLOW;
+                                               urb->error_count++;
+                                       }
+                                       DBG(2, "** OVERFLOW %d into %d\n",\
+                                           rx_count, d->length);
+
+                                       length = d->length;
+                               } else
+                                       length = rx_count;
+                               d->status = status;
+                               buf = urb->transfer_dma + d->offset;
+                       } else {
+                               length = rx_count;
+                               buf = urb->transfer_dma +
+                                               urb->actual_length;
+                       }
+
                        dma->desired_mode = 0;
 #ifdef USE_MODE1
                        /* because of the issue below, mode 1 will
@@ -1571,6 +1622,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                                                urb->actual_length)
                                        > qh->maxpacket)
                                dma->desired_mode = 1;
+                       if (rx_count < hw_ep->max_packet_sz_rx) {
+                               length = rx_count;
+                               dma->bDesiredMode = 0;
+                       } else {
+                               length = urb->transfer_buffer_length;
+                       }
 #endif
 
 /* Disadvantage of using mode 1:
@@ -1608,12 +1665,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                         */
                        ret = c->channel_program(
                                dma, qh->maxpacket,
-                               dma->desired_mode,
-                               urb->transfer_dma
-                                       + urb->actual_length,
-                               (dma->desired_mode == 0)
-                                       ? rx_count
-                                       : urb->transfer_buffer_length);
+                               dma->desired_mode, buf, length);
 
                        if (!ret) {
                                c->channel_release(dma);
@@ -1631,19 +1683,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                }
        }
 
-       if (dma && usb_pipeisoc(pipe)) {
-               struct usb_iso_packet_descriptor        *d;
-               int                                     iso_stat = status;
-
-               d = urb->iso_frame_desc + qh->iso_idx;
-               d->actual_length += xfer_len;
-               if (iso_err) {
-                       iso_stat = -EILSEQ;
-                       urb->error_count++;
-               }
-               d->status = iso_stat;
-       }
-
 finish:
        urb->actual_length += xfer_len;
        qh->offset += xfer_len;
@@ -1671,22 +1710,9 @@ static int musb_schedule(
        struct list_head        *head = NULL;
 
        /* use fixed hardware for control and bulk */
-       switch (qh->type) {
-       case USB_ENDPOINT_XFER_CONTROL:
+       if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
                head = &musb->control;
                hw_ep = musb->control_ep;
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               hw_ep = musb->bulk_ep;
-               if (is_in)
-                       head = &musb->in_bulk;
-               else
-                       head = &musb->out_bulk;
-               break;
-       }
-       if (head) {
-               idle = list_empty(head);
-               list_add_tail(&qh->ring, head);
                goto success;
        }
 
@@ -1725,19 +1751,34 @@ static int musb_schedule(
                else
                        diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
 
-               if (diff > 0 && best_diff > diff) {
+               if (diff >= 0 && best_diff > diff) {
                        best_diff = diff;
                        best_end = epnum;
                }
        }
-       if (best_end < 0)
+       /* use bulk reserved ep1 if no other ep is free */
+       if (best_end > 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
+               hw_ep = musb->bulk_ep;
+               if (is_in)
+                       head = &musb->in_bulk;
+               else
+                       head = &musb->out_bulk;
+               goto success;
+       } else if (best_end < 0) {
                return -ENOSPC;
+       }
 
        idle = 1;
+       qh->mux = 0;
        hw_ep = musb->endpoints + best_end;
        musb->periodic[best_end] = qh;
        DBG(4, "qh %p periodic slot %d\n", qh, best_end);
 success:
+       if (head) {
+               idle = list_empty(head);
+               list_add_tail(&qh->ring, head);
+               qh->mux = 1;
+       }
        qh->hw_ep = hw_ep;
        qh->hep->hcpriv = qh;
        if (idle)
@@ -2015,11 +2056,13 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                        sched = &musb->control;
                        break;
                case USB_ENDPOINT_XFER_BULK:
-                       if (usb_pipein(urb->pipe))
-                               sched = &musb->in_bulk;
-                       else
-                               sched = &musb->out_bulk;
-                       break;
+                       if (qh->mux == 1) {
+                               if (usb_pipein(urb->pipe))
+                                       sched = &musb->in_bulk;
+                               else
+                                       sched = &musb->out_bulk;
+                               break;
+                       }
                default:
                        /* REVISIT when we get a schedule tree, periodic
                         * transfers won't always be at the head of a
@@ -2067,11 +2110,13 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
                sched = &musb->control;
                break;
        case USB_ENDPOINT_XFER_BULK:
-               if (is_in)
-                       sched = &musb->in_bulk;
-               else
-                       sched = &musb->out_bulk;
-               break;
+               if (qh->mux == 1) {
+                       if (is_in)
+                               sched = &musb->in_bulk;
+                       else
+                               sched = &musb->out_bulk;
+                       break;
+               }
        default:
                /* REVISIT when we get a schedule tree, periodic transfers
                 * won't always be at the head of a singleton queue...
index 77bcdb9d5b32d93c1fd77433bce4821d9ab9c4bd..0b7fbcd21963ebcc23435d168a061bed741ff612 100644 (file)
@@ -53,6 +53,7 @@ struct musb_qh {
 
        struct list_head        ring;           /* of musb_qh */
        /* struct musb_qh               *next; */       /* for periodic tree */
+       u8                      mux;            /* qh multiplexed to hw_ep */
 
        unsigned                offset;         /* in urb->transfer_buffer */
        unsigned                segsize;        /* current xfer fragment */
index 9d2dcb121c5e95cc7e6ba81a5cdfa59ae07637ae..ce6c162920f7bfcb5bef980b2438aeba4661d12b 100644 (file)
@@ -53,7 +53,9 @@ static void musb_do_idle(unsigned long _musb)
 {
        struct musb     *musb = (void *)_musb;
        unsigned long   flags;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
        u8      power;
+#endif
        u8      devctl;
 
        devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
index b73b036f3d7770c01822e0885635a5fa3879aeae..ee8fca92a4ac4cd0ec58b157941bf8017ecff331 100644 (file)
@@ -605,7 +605,7 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
 
        if (musb->board_mode != MUSB_OTG) {
                ERR("Changing mode currently only supported in OTG mode\n");
-               return;
+               return -EINVAL;
        }
 
        otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
index 8008d0bc80ad3732a05b4fa82b04b06f3fb334fc..9035d7256b03570a63203994d0fc031ea59e0a22 100644 (file)
@@ -67,6 +67,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
        { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
+       { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
        { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
        { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
        { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
@@ -85,6 +86,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
        { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
+       { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
index bd07eaa300b967f792ffd2923af3385b8784cf3b..6fa1ec441b618d12575adf9bec5ee67a327fde6f 100644 (file)
@@ -160,6 +160,11 @@ static int  option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
 
 #define NOVATELWIRELESS_VENDOR_ID              0x1410
 
+/* YISO PRODUCTS */
+
+#define YISO_VENDOR_ID                         0x0EAB
+#define YISO_PRODUCT_U893                      0xC893
+
 /* MERLIN EVDO PRODUCTS */
 #define NOVATELWIRELESS_PRODUCT_V640           0x1100
 #define NOVATELWIRELESS_PRODUCT_V620           0x1110
@@ -408,6 +413,7 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
        { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) },
        { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
+       { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1004) },
index 3d9249632ae12e7051174817241ef37ea6f2cd4c..c68b738900bdbb9b6c8f6c95d536a69d7cada937 100644 (file)
@@ -2,8 +2,8 @@
 # USB Storage driver configuration
 #
 
-comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'"
-comment "may also be needed; see USB_STORAGE Help for more information"
+comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;"
+comment "see USB_STORAGE Help for more information"
        depends on USB
 
 config USB_STORAGE
index fb9e20e624c1477f909c6ec4825dc7e6d22ebe50..d4e5fc86e43c679eee20ee64e5334cfd2eceda66 100644 (file)
@@ -253,6 +253,14 @@ UNUSUAL_DEV(  0x0421, 0x006a, 0x0000, 0x0591,
        US_SC_DEVICE, US_PR_DEVICE, NULL,
        US_FL_FIX_CAPACITY ),
 
+/* Submitted by Ricky Wong Yung Fei <evilbladewarrior@gmail.com> */
+/* Nokia 7610 Supernova - Too many sectors reported in usb storage mode */
+UNUSUAL_DEV(  0x0421, 0x00f5, 0x0000, 0x0470,
+       "Nokia",
+       "7610 Supernova",
+       US_SC_DEVICE, US_PR_DEVICE, NULL,
+       US_FL_FIX_CAPACITY ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
                "SMSC",
@@ -418,6 +426,13 @@ UNUSUAL_DEV(  0x04b0, 0x0417, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY),
 
+/* Reported by paul ready <lxtwin@homecall.co.uk> */
+UNUSUAL_DEV(  0x04b0, 0x0419, 0x0100, 0x0200,
+               "NIKON",
+               "NIKON DSC D300",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
 /* Reported by Doug Maxey (dwm@austin.ibm.com) */
 UNUSUAL_DEV(  0x04b3, 0x4001, 0x0110, 0x0110,
                "IBM",
@@ -1258,6 +1273,13 @@ UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_INQUIRY),
 
+/* Reported by Luciano Rocha <luciano@eurotux.com> */
+UNUSUAL_DEV( 0x0840, 0x0082, 0x0001, 0x0001,
+               "Argosy",
+               "Storage",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
 /* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
  * Flag will support Bulk devices which use a standards-violating 32-byte
  * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with
index f8d0a57a07cbe3852d4128b0b6d46c8eddefebd5..9a577a800db5a05b0d0fc87ef5d775c26e55fcb2 100644 (file)
@@ -132,7 +132,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
 
        bl = backlight_device_register("backlight", &sinfo->pdev->dev,
                        sinfo, &atmel_lcdc_bl_ops);
-       if (IS_ERR(sinfo->backlight)) {
+       if (IS_ERR(bl)) {
                dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
                                PTR_ERR(bl));
                return;
index 242c38250166d7edac8f3a600599191d8322ae40..93bb4340cc64e66470841868c1d52535ef595d2e 100644 (file)
@@ -119,6 +119,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
        default:
                dev_err(&pdev->dev, "invalid backlight device ID(%d)\n",
                                pdev->id);
+               kfree(data);
                return -EINVAL;
        }
 
@@ -130,6 +131,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
                        data, &da903x_backlight_ops);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
                return PTR_ERR(bl);
        }
 
index 8e1731d3b2283e311bcad1d6f10475901467cda2..680e57b616cdeb3f0f11748aff79f9483f41c247 100644 (file)
@@ -42,10 +42,13 @@ static int fb_notifier_callback(struct notifier_block *self,
 
        mutex_lock(&ld->ops_lock);
        if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
-               if (event == FB_EVENT_BLANK)
-                       ld->ops->set_power(ld, *(int *)evdata->data);
-               else
-                       ld->ops->set_mode(ld, evdata->data);
+               if (event == FB_EVENT_BLANK) {
+                       if (ld->ops->set_power)
+                               ld->ops->set_power(ld, *(int *)evdata->data);
+               } else {
+                       if (ld->ops->set_mode)
+                               ld->ops->set_mode(ld, evdata->data);
+               }
        }
        mutex_unlock(&ld->ops_lock);
        return 0;
index 8a8760230bc78561b2f3a25c7095c9db21d68c54..a2aa6ddffbe25d6e764a0dc6bdc7dd298e9f1849 100644 (file)
@@ -2462,8 +2462,7 @@ static int __init cirrusfb_init(void)
 
 #ifndef MODULE
 static int __init cirrusfb_setup(char *options) {
-       char *this_opt, s[32];
-       int i;
+       char *this_opt;
 
        DPRINTK("ENTER\n");
 
index 1d5ae39cb271ecb3219f9089ef9366f532f93efe..3c65b0d676174f6ee683a0516700324a0cb4cc17 100644 (file)
@@ -230,7 +230,7 @@ static void fb_set_logo_directpalette(struct fb_info *info,
        greenshift = info->var.green.offset;
        blueshift = info->var.blue.offset;
 
-       for (i = 32; i < logo->clutsize; i++)
+       for (i = 32; i < 32 + logo->clutsize; i++)
                palette[i] = i << redshift | i << greenshift | i << blueshift;
 }
 
index 2a380011e9baf07f37593dadc730ac51562e57cf..7baf2dd12d5024f33b5e7af20f6288085e573b9c 100644 (file)
@@ -222,6 +222,9 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
        unsigned int bbisc = tmio_ioread16(par->lcr + LCR_BBISC);
 
 
+       tmio_iowrite16(bbisc, par->lcr + LCR_BBISC);
+
+#ifdef CONFIG_FB_TMIO_ACCELL
        /*
         * We were in polling mode and now we got correct irq.
         * Switch back to IRQ-based sync of command FIFO
@@ -231,9 +234,6 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
                par->use_polling = false;
        }
 
-       tmio_iowrite16(bbisc, par->lcr + LCR_BBISC);
-
-#ifdef CONFIG_FB_TMIO_ACCELL
        if (bbisc & 1)
                wake_up(&par->wait_acc);
 #endif
@@ -938,7 +938,9 @@ static void tmiofb_dump_regs(struct platform_device *dev)
 static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct fb_info *info = platform_get_drvdata(dev);
+#ifdef CONFIG_FB_TMIO_ACCELL
        struct tmiofb_par *par = info->par;
+#endif
        struct mfd_cell *cell = dev->dev.platform_data;
        int retval = 0;
 
@@ -950,12 +952,14 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
                info->fbops->fb_sync(info);
 
 
+#ifdef CONFIG_FB_TMIO_ACCELL
        /*
         * The fb should be usable even if interrupts are disabled (and they are
         * during suspend/resume). Switch temporary to forced polling.
         */
        printk(KERN_INFO "tmiofb: switching to polling\n");
        par->use_polling = true;
+#endif
        tmiofb_hw_stop(dev);
 
        if (cell->suspend)
index 0132eae06f5586960f0abfa3f76df314b30492d3..73ac754ad801952bebb8741639df05a98ace7c4a 100644 (file)
@@ -2036,30 +2036,30 @@ static int viafb_vt1636_proc_write(struct file *file,
        return count;
 }
 
-static void viafb_init_proc(struct proc_dir_entry *viafb_entry)
+static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
 {
        struct proc_dir_entry *entry;
-       viafb_entry = proc_mkdir("viafb", NULL);
+       *viafb_entry = proc_mkdir("viafb", NULL);
        if (viafb_entry) {
-               entry = create_proc_entry("dvp0", 0, viafb_entry);
+               entry = create_proc_entry("dvp0", 0, *viafb_entry);
                if (entry) {
                        entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dvp0_proc_read;
                        entry->write_proc = viafb_dvp0_proc_write;
                }
-               entry = create_proc_entry("dvp1", 0, viafb_entry);
+               entry = create_proc_entry("dvp1", 0, *viafb_entry);
                if (entry) {
                        entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dvp1_proc_read;
                        entry->write_proc = viafb_dvp1_proc_write;
                }
-               entry = create_proc_entry("dfph", 0, viafb_entry);
+               entry = create_proc_entry("dfph", 0, *viafb_entry);
                if (entry) {
                        entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dfph_proc_read;
                        entry->write_proc = viafb_dfph_proc_write;
                }
-               entry = create_proc_entry("dfpl", 0, viafb_entry);
+               entry = create_proc_entry("dfpl", 0, *viafb_entry);
                if (entry) {
                        entry->owner = THIS_MODULE;
                        entry->read_proc = viafb_dfpl_proc_read;
@@ -2068,7 +2068,7 @@ static void viafb_init_proc(struct proc_dir_entry *viafb_entry)
                if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info.
                        lvds_chip_name || VT1636_LVDS ==
                    viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
-                       entry = create_proc_entry("vt1636", 0, viafb_entry);
+                       entry = create_proc_entry("vt1636", 0, *viafb_entry);
                        if (entry) {
                                entry->owner = THIS_MODULE;
                                entry->read_proc = viafb_vt1636_proc_read;
@@ -2087,6 +2087,7 @@ static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
        remove_proc_entry("dfpl", viafb_entry);
        remove_proc_entry("vt1636", viafb_entry);
        remove_proc_entry("vt1625", viafb_entry);
+       remove_proc_entry("viafb", NULL);
 }
 
 static int __devinit via_pci_probe(void)
@@ -2348,7 +2349,7 @@ static int __devinit via_pci_probe(void)
                  viafbinfo->node, viafbinfo->fix.id, default_var.xres,
                  default_var.yres, default_var.bits_per_pixel);
 
-       viafb_init_proc(viaparinfo->proc_entry);
+       viafb_init_proc(&viaparinfo->proc_entry);
        viafb_init_dac(IGA2);
        return 0;
 }
index c4493091c655d109dd008983183048b02c2a304e..a14d5b6e4c7c280b831f9f87ea33ace10f8fc571 100644 (file)
@@ -52,5 +52,12 @@ config W1_MASTER_GPIO
          This support is also available as a module.  If so, the module
          will be called w1-gpio.ko.
 
+config HDQ_MASTER_OMAP
+       tristate "OMAP HDQ driver"
+       depends on ARCH_OMAP2430 || ARCH_OMAP34XX
+       help
+         Say Y here if you want support for the 1-wire or HDQ Interface
+         on an OMAP processor.
+
 endmenu
 
index 1420b5bbdda81f930379dfac9e776af216af7557..bc4714a75f3a0358ebcc7c51a78025dab7e1d594 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_W1_MASTER_DS2490)          += ds2490.o
 obj-$(CONFIG_W1_MASTER_DS2482)         += ds2482.o
 obj-$(CONFIG_W1_MASTER_DS1WM)          += ds1wm.o
 obj-$(CONFIG_W1_MASTER_GPIO)           += w1-gpio.o
+obj-$(CONFIG_HDQ_MASTER_OMAP)          += omap_hdq.o
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
new file mode 100644 (file)
index 0000000..c973889
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * drivers/w1/masters/omap_hdq.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#define        MOD_NAME        "OMAP_HDQ:"
+
+#define OMAP_HDQ_REVISION                      0x00
+#define OMAP_HDQ_TX_DATA                       0x04
+#define OMAP_HDQ_RX_DATA                       0x08
+#define OMAP_HDQ_CTRL_STATUS                   0x0c
+#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK     (1<<6)
+#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE       (1<<5)
+#define OMAP_HDQ_CTRL_STATUS_GO                        (1<<4)
+#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION    (1<<2)
+#define OMAP_HDQ_CTRL_STATUS_DIR               (1<<1)
+#define OMAP_HDQ_CTRL_STATUS_MODE              (1<<0)
+#define OMAP_HDQ_INT_STATUS                    0x10
+#define OMAP_HDQ_INT_STATUS_TXCOMPLETE         (1<<2)
+#define OMAP_HDQ_INT_STATUS_RXCOMPLETE         (1<<1)
+#define OMAP_HDQ_INT_STATUS_TIMEOUT            (1<<0)
+#define OMAP_HDQ_SYSCONFIG                     0x14
+#define OMAP_HDQ_SYSCONFIG_SOFTRESET           (1<<1)
+#define OMAP_HDQ_SYSCONFIG_AUTOIDLE            (1<<0)
+#define OMAP_HDQ_SYSSTATUS                     0x18
+#define OMAP_HDQ_SYSSTATUS_RESETDONE           (1<<0)
+
+#define OMAP_HDQ_FLAG_CLEAR                    0
+#define OMAP_HDQ_FLAG_SET                      1
+#define OMAP_HDQ_TIMEOUT                       (HZ/5)
+
+#define OMAP_HDQ_MAX_USER                      4
+
+static DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue);
+static int w1_id;
+
+struct hdq_data {
+       struct device           *dev;
+       void __iomem            *hdq_base;
+       /* lock status update */
+       struct  mutex           hdq_mutex;
+       int                     hdq_usecount;
+       struct  clk             *hdq_ick;
+       struct  clk             *hdq_fck;
+       u8                      hdq_irqstatus;
+       /* device lock */
+       spinlock_t              hdq_spinlock;
+       /*
+        * Used to control the call to omap_hdq_get and omap_hdq_put.
+        * HDQ Protocol: Write the CMD|REG_address first, followed by
+        * the data wrire or read.
+        */
+       int                     init_trans;
+};
+
+static int __init omap_hdq_probe(struct platform_device *pdev);
+static int omap_hdq_remove(struct platform_device *pdev);
+
+static struct platform_driver omap_hdq_driver = {
+       .probe =        omap_hdq_probe,
+       .remove =       omap_hdq_remove,
+       .driver =       {
+               .name = "omap_hdq",
+       },
+};
+
+static u8 omap_w1_read_byte(void *_hdq);
+static void omap_w1_write_byte(void *_hdq, u8 byte);
+static u8 omap_w1_reset_bus(void *_hdq);
+static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
+               u8 search_type, w1_slave_found_callback slave_found);
+
+
+static struct w1_bus_master omap_w1_master = {
+       .read_byte      = omap_w1_read_byte,
+       .write_byte     = omap_w1_write_byte,
+       .reset_bus      = omap_w1_reset_bus,
+       .search         = omap_w1_search_bus,
+};
+
+/* HDQ register I/O routines */
+static inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset)
+{
+       return __raw_readb(hdq_data->hdq_base + offset);
+}
+
+static inline void hdq_reg_out(struct hdq_data *hdq_data, u32 offset, u8 val)
+{
+       __raw_writeb(val, hdq_data->hdq_base + offset);
+}
+
+static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
+                       u8 val, u8 mask)
+{
+       u8 new_val = (__raw_readb(hdq_data->hdq_base + offset) & ~mask)
+                       | (val & mask);
+       __raw_writeb(new_val, hdq_data->hdq_base + offset);
+
+       return new_val;
+}
+
+/*
+ * Wait for one or more bits in flag change.
+ * HDQ_FLAG_SET: wait until any bit in the flag is set.
+ * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared.
+ * return 0 on success and -ETIMEDOUT in the case of timeout.
+ */
+static int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
+               u8 flag, u8 flag_set, u8 *status)
+{
+       int ret = 0;
+       unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+       if (flag_set == OMAP_HDQ_FLAG_CLEAR) {
+               /* wait for the flag clear */
+               while (((*status = hdq_reg_in(hdq_data, offset)) & flag)
+                       && time_before(jiffies, timeout)) {
+                       schedule_timeout_uninterruptible(1);
+               }
+               if (*status & flag)
+                       ret = -ETIMEDOUT;
+       } else if (flag_set == OMAP_HDQ_FLAG_SET) {
+               /* wait for the flag set */
+               while (!((*status = hdq_reg_in(hdq_data, offset)) & flag)
+                       && time_before(jiffies, timeout)) {
+                       schedule_timeout_uninterruptible(1);
+               }
+               if (!(*status & flag))
+                       ret = -ETIMEDOUT;
+       } else
+               return -EINVAL;
+
+       return ret;
+}
+
+/* write out a byte and fill *status with HDQ_INT_STATUS */
+static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
+{
+       int ret;
+       u8 tmp_status;
+       unsigned long irqflags;
+
+       *status = 0;
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       /* clear interrupt flags via a dummy read */
+       hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+       /* ISR loads it with new INT_STATUS */
+       hdq_data->hdq_irqstatus = 0;
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+       hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
+
+       /* set the GO bit */
+       hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
+               OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+       /* wait for the TXCOMPLETE bit */
+       ret = wait_event_timeout(hdq_wait_queue,
+               hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+       if (ret == 0) {
+               dev_dbg(hdq_data->dev, "TX wait elapsed\n");
+               goto out;
+       }
+
+       *status = hdq_data->hdq_irqstatus;
+       /* check irqstatus */
+       if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
+               dev_dbg(hdq_data->dev, "timeout waiting for"
+                       "TXCOMPLETE/RXCOMPLETE, %x", *status);
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       /* wait for the GO bit return to zero */
+       ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_GO,
+                       OMAP_HDQ_FLAG_CLEAR, &tmp_status);
+       if (ret) {
+               dev_dbg(hdq_data->dev, "timeout waiting GO bit"
+                       "return to zero, %x", tmp_status);
+       }
+
+out:
+       return ret;
+}
+
+/* HDQ Interrupt service routine */
+static irqreturn_t hdq_isr(int irq, void *_hdq)
+{
+       struct hdq_data *hdq_data = _hdq;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+       dev_dbg(hdq_data->dev, "hdq_isr: %x", hdq_data->hdq_irqstatus);
+
+       if (hdq_data->hdq_irqstatus &
+               (OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
+               | OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+               /* wake up sleeping process */
+               wake_up(&hdq_wait_queue);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* HDQ Mode: always return success */
+static u8 omap_w1_reset_bus(void *_hdq)
+{
+       return 0;
+}
+
+/* W1 search callback function */
+static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
+               u8 search_type, w1_slave_found_callback slave_found)
+{
+       u64 module_id, rn_le, cs, id;
+
+       if (w1_id)
+               module_id = w1_id;
+       else
+               module_id = 0x1;
+
+       rn_le = cpu_to_le64(module_id);
+       /*
+        * HDQ might not obey truly the 1-wire spec.
+        * So calculate CRC based on module parameter.
+        */
+       cs = w1_calc_crc8((u8 *)&rn_le, 7);
+       id = (cs << 56) | module_id;
+
+       slave_found(master_dev, id);
+}
+
+static int _omap_hdq_reset(struct hdq_data *hdq_data)
+{
+       int ret;
+       u8 tmp_status;
+
+       hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_SOFTRESET);
+       /*
+        * Select HDQ mode & enable clocks.
+        * It is observed that INT flags can't be cleared via a read and GO/INIT
+        * won't return to zero if interrupt is disabled. So we always enable
+        * interrupt.
+        */
+       hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+               OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+               OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+
+       /* wait for reset to complete */
+       ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
+               OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
+       if (ret)
+               dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x",
+                               tmp_status);
+       else {
+               hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+                       OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+               hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+                       OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+       }
+
+       return ret;
+}
+
+/* Issue break pulse to the device */
+static int omap_hdq_break(struct hdq_data *hdq_data)
+{
+       int ret = 0;
+       u8 tmp_status;
+       unsigned long irqflags;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0) {
+               dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+               ret = -EINTR;
+               goto rtn;
+       }
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       /* clear interrupt flags via a dummy read */
+       hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+       /* ISR loads it with new INT_STATUS */
+       hdq_data->hdq_irqstatus = 0;
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+       /* set the INIT and GO bit */
+       hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+               OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
+               OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+               OMAP_HDQ_CTRL_STATUS_GO);
+
+       /* wait for the TIMEOUT bit */
+       ret = wait_event_timeout(hdq_wait_queue,
+               hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+       if (ret == 0) {
+               dev_dbg(hdq_data->dev, "break wait elapsed\n");
+               ret = -EINTR;
+               goto out;
+       }
+
+       tmp_status = hdq_data->hdq_irqstatus;
+       /* check irqstatus */
+       if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+               dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x",
+                               tmp_status);
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+       /*
+        * wait for both INIT and GO bits rerurn to zero.
+        * zero wait time expected for interrupt mode.
+        */
+       ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+                       OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
+                       &tmp_status);
+       if (ret)
+               dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
+                       "return to zero, %x", tmp_status);
+
+out:
+       mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+       return ret;
+}
+
+static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
+{
+       int ret = 0;
+       u8 status;
+       unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0) {
+               ret = -EINTR;
+               goto rtn;
+       }
+
+       if (!hdq_data->hdq_usecount) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+               hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
+                       OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+               /*
+                * The RX comes immediately after TX. It
+                * triggers another interrupt before we
+                * sleep. So we have to wait for RXCOMPLETE bit.
+                */
+               while (!(hdq_data->hdq_irqstatus
+                       & OMAP_HDQ_INT_STATUS_RXCOMPLETE)
+                       && time_before(jiffies, timeout)) {
+                       schedule_timeout_uninterruptible(1);
+               }
+               hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0,
+                       OMAP_HDQ_CTRL_STATUS_DIR);
+               status = hdq_data->hdq_irqstatus;
+               /* check irqstatus */
+               if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+                       dev_dbg(hdq_data->dev, "timeout waiting for"
+                               "RXCOMPLETE, %x", status);
+                       ret = -ETIMEDOUT;
+                       goto out;
+               }
+       }
+       /* the data is ready. Read it in! */
+       *val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
+out:
+       mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+       return 0;
+
+}
+
+/* Enable clocks and set the controller to HDQ mode */
+static int omap_hdq_get(struct hdq_data *hdq_data)
+{
+       int ret = 0;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0) {
+               ret = -EINTR;
+               goto rtn;
+       }
+
+       if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
+               dev_dbg(hdq_data->dev, "attempt to exceed the max use count");
+               ret = -EINVAL;
+               goto out;
+       } else {
+               hdq_data->hdq_usecount++;
+               try_module_get(THIS_MODULE);
+               if (1 == hdq_data->hdq_usecount) {
+                       if (clk_enable(hdq_data->hdq_ick)) {
+                               dev_dbg(hdq_data->dev, "Can not enable ick\n");
+                               ret = -ENODEV;
+                               goto clk_err;
+                       }
+                       if (clk_enable(hdq_data->hdq_fck)) {
+                               dev_dbg(hdq_data->dev, "Can not enable fck\n");
+                               clk_disable(hdq_data->hdq_ick);
+                               ret = -ENODEV;
+                               goto clk_err;
+                       }
+
+                       /* make sure HDQ is out of reset */
+                       if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
+                               OMAP_HDQ_SYSSTATUS_RESETDONE)) {
+                               ret = _omap_hdq_reset(hdq_data);
+                               if (ret)
+                                       /* back up the count */
+                                       hdq_data->hdq_usecount--;
+                       } else {
+                               /* select HDQ mode & enable clocks */
+                               hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                                       OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+                                       OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+                               hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+                                       OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+                               hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+                       }
+               }
+       }
+
+clk_err:
+       clk_put(hdq_data->hdq_ick);
+       clk_put(hdq_data->hdq_fck);
+out:
+       mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+       return ret;
+}
+
+/* Disable clocks to the module */
+static int omap_hdq_put(struct hdq_data *hdq_data)
+{
+       int ret = 0;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0)
+               return -EINTR;
+
+       if (0 == hdq_data->hdq_usecount) {
+               dev_dbg(hdq_data->dev, "attempt to decrement use count"
+                       "when it is zero");
+               ret = -EINVAL;
+       } else {
+               hdq_data->hdq_usecount--;
+               module_put(THIS_MODULE);
+               if (0 == hdq_data->hdq_usecount) {
+                       clk_disable(hdq_data->hdq_ick);
+                       clk_disable(hdq_data->hdq_fck);
+               }
+       }
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       return ret;
+}
+
+/* Read a byte of data from the device */
+static u8 omap_w1_read_byte(void *_hdq)
+{
+       struct hdq_data *hdq_data = _hdq;
+       u8 val = 0;
+       int ret;
+
+       ret = hdq_read_byte(hdq_data, &val);
+       if (ret) {
+               ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+               if (ret < 0) {
+                       dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+                       return -EINTR;
+               }
+               hdq_data->init_trans = 0;
+               mutex_unlock(&hdq_data->hdq_mutex);
+               omap_hdq_put(hdq_data);
+               return -1;
+       }
+
+       /* Write followed by a read, release the module */
+       if (hdq_data->init_trans) {
+               ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+               if (ret < 0) {
+                       dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+                       return -EINTR;
+               }
+               hdq_data->init_trans = 0;
+               mutex_unlock(&hdq_data->hdq_mutex);
+               omap_hdq_put(hdq_data);
+       }
+
+       return val;
+}
+
+/* Write a byte of data to the device */
+static void omap_w1_write_byte(void *_hdq, u8 byte)
+{
+       struct hdq_data *hdq_data = _hdq;
+       int ret;
+       u8 status;
+
+       /* First write to initialize the transfer */
+       if (hdq_data->init_trans == 0)
+               omap_hdq_get(hdq_data);
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0) {
+               dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+               return;
+       }
+       hdq_data->init_trans++;
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       ret = hdq_write_byte(hdq_data, byte, &status);
+       if (ret == 0) {
+               dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
+               return;
+       }
+
+       /* Second write, data transfered. Release the module */
+       if (hdq_data->init_trans > 1) {
+               omap_hdq_put(hdq_data);
+               ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+               if (ret < 0) {
+                       dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+                       return;
+               }
+               hdq_data->init_trans = 0;
+               mutex_unlock(&hdq_data->hdq_mutex);
+       }
+
+       return;
+}
+
+static int __init omap_hdq_probe(struct platform_device *pdev)
+{
+       struct hdq_data *hdq_data;
+       struct resource *res;
+       int ret, irq;
+       u8 rev;
+
+       hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
+       if (!hdq_data) {
+               dev_dbg(&pdev->dev, "unable to allocate memory\n");
+               ret = -ENOMEM;
+               goto err_kmalloc;
+       }
+
+       hdq_data->dev = &pdev->dev;
+       platform_set_drvdata(pdev, hdq_data);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_dbg(&pdev->dev, "unable to get resource\n");
+               ret = -ENXIO;
+               goto err_resource;
+       }
+
+       hdq_data->hdq_base = ioremap(res->start, SZ_4K);
+       if (!hdq_data->hdq_base) {
+               dev_dbg(&pdev->dev, "ioremap failed\n");
+               ret = -EINVAL;
+               goto err_ioremap;
+       }
+
+       /* get interface & functional clock objects */
+       hdq_data->hdq_ick = clk_get(&pdev->dev, "hdq_ick");
+       hdq_data->hdq_fck = clk_get(&pdev->dev, "hdq_fck");
+
+       if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) {
+               dev_dbg(&pdev->dev, "Can't get HDQ clock objects\n");
+               if (IS_ERR(hdq_data->hdq_ick)) {
+                       ret = PTR_ERR(hdq_data->hdq_ick);
+                       goto err_clk;
+               }
+               if (IS_ERR(hdq_data->hdq_fck)) {
+                       ret = PTR_ERR(hdq_data->hdq_fck);
+                       clk_put(hdq_data->hdq_ick);
+                       goto err_clk;
+               }
+       }
+
+       hdq_data->hdq_usecount = 0;
+       mutex_init(&hdq_data->hdq_mutex);
+
+       if (clk_enable(hdq_data->hdq_ick)) {
+               dev_dbg(&pdev->dev, "Can not enable ick\n");
+               ret = -ENODEV;
+               goto err_intfclk;
+       }
+
+       if (clk_enable(hdq_data->hdq_fck)) {
+               dev_dbg(&pdev->dev, "Can not enable fck\n");
+               ret = -ENODEV;
+               goto err_fnclk;
+       }
+
+       rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
+       dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
+               (rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
+
+       spin_lock_init(&hdq_data->hdq_spinlock);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = -ENXIO;
+               goto err_irq;
+       }
+
+       ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data);
+       if (ret < 0) {
+               dev_dbg(&pdev->dev, "could not request irq\n");
+               goto err_irq;
+       }
+
+       omap_hdq_break(hdq_data);
+
+       /* don't clock the HDQ until it is needed */
+       clk_disable(hdq_data->hdq_ick);
+       clk_disable(hdq_data->hdq_fck);
+
+       omap_w1_master.data = hdq_data;
+
+       ret = w1_add_master_device(&omap_w1_master);
+       if (ret) {
+               dev_dbg(&pdev->dev, "Failure in registering w1 master\n");
+               goto err_w1;
+       }
+
+       return 0;
+
+err_w1:
+err_irq:
+       clk_disable(hdq_data->hdq_fck);
+
+err_fnclk:
+       clk_disable(hdq_data->hdq_ick);
+
+err_intfclk:
+       clk_put(hdq_data->hdq_ick);
+       clk_put(hdq_data->hdq_fck);
+
+err_clk:
+       iounmap(hdq_data->hdq_base);
+
+err_ioremap:
+err_resource:
+       platform_set_drvdata(pdev, NULL);
+       kfree(hdq_data);
+
+err_kmalloc:
+       return ret;
+
+}
+
+static int omap_hdq_remove(struct platform_device *pdev)
+{
+       struct hdq_data *hdq_data = platform_get_drvdata(pdev);
+
+       mutex_lock(&hdq_data->hdq_mutex);
+
+       if (hdq_data->hdq_usecount) {
+               dev_dbg(&pdev->dev, "removed when use count is not zero\n");
+               return -EBUSY;
+       }
+
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       /* remove module dependency */
+       clk_put(hdq_data->hdq_ick);
+       clk_put(hdq_data->hdq_fck);
+       free_irq(INT_24XX_HDQ_IRQ, hdq_data);
+       platform_set_drvdata(pdev, NULL);
+       iounmap(hdq_data->hdq_base);
+       kfree(hdq_data);
+
+       return 0;
+}
+
+static int __init
+omap_hdq_init(void)
+{
+       return platform_driver_register(&omap_hdq_driver);
+}
+module_init(omap_hdq_init);
+
+static void __exit
+omap_hdq_exit(void)
+{
+       platform_driver_unregister(&omap_hdq_driver);
+}
+module_exit(omap_hdq_exit);
+
+module_param(w1_id, int, S_IRUSR);
+MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("HDQ driver Library");
+MODULE_LICENSE("GPL");
index 3df29a122f84c559d6ca1dcc104725028f18a9a7..8d0b1fb1e52edb6eeb57f98887e399d8a4c4b7af 100644 (file)
@@ -44,4 +44,11 @@ config W1_SLAVE_DS2760
 
          If you are unsure, say N.
 
+config W1_SLAVE_BQ27000
+       tristate "BQ27000 slave support"
+       depends on W1
+       help
+         Say Y here if you want to use a hdq
+         bq27000 slave support.
+
 endmenu
index a8eb7524df1db2c0c4db0dbe8a4097d9f65fcff6..990f400b6d22dc82563a382f6c0b7defd09820a6 100644 (file)
@@ -6,4 +6,4 @@ obj-$(CONFIG_W1_SLAVE_THERM)    += w1_therm.o
 obj-$(CONFIG_W1_SLAVE_SMEM)    += w1_smem.o
 obj-$(CONFIG_W1_SLAVE_DS2433)  += w1_ds2433.o
 obj-$(CONFIG_W1_SLAVE_DS2760)  += w1_ds2760.o
-
+obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
diff --git a/drivers/w1/slaves/w1_bq27000.c b/drivers/w1/slaves/w1_bq27000.c
new file mode 100644 (file)
index 0000000..8f4c91f
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * drivers/w1/slaves/w1_bq27000.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define HDQ_CMD_READ   (0)
+#define HDQ_CMD_WRITE  (1<<7)
+
+static int F_ID;
+
+void w1_bq27000_write(struct device *dev, u8 buf, u8 reg)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       if (!dev) {
+               pr_info("Could not obtain slave dev ptr\n");
+               return;
+       }
+
+       w1_write_8(sl->master, HDQ_CMD_WRITE | reg);
+       w1_write_8(sl->master, buf);
+}
+EXPORT_SYMBOL(w1_bq27000_write);
+
+int w1_bq27000_read(struct device *dev, u8 reg)
+{
+       u8 val;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       if (!dev)
+               return 0;
+
+       w1_write_8(sl->master, HDQ_CMD_READ | reg);
+       val = w1_read_8(sl->master);
+
+       return val;
+}
+EXPORT_SYMBOL(w1_bq27000_read);
+
+static int w1_bq27000_add_slave(struct w1_slave *sl)
+{
+       int ret;
+       int id = 1;
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc("bq27000-battery", id);
+       if (!pdev) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       pdev->dev.parent = &sl->dev;
+
+       ret = platform_device_add(pdev);
+       if (ret)
+               goto pdev_add_failed;
+
+       dev_set_drvdata(&sl->dev, pdev);
+
+       goto success;
+
+pdev_add_failed:
+       platform_device_unregister(pdev);
+success:
+       return ret;
+}
+
+static void w1_bq27000_remove_slave(struct w1_slave *sl)
+{
+       struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+
+       platform_device_unregister(pdev);
+}
+
+static struct w1_family_ops w1_bq27000_fops = {
+       .add_slave      = w1_bq27000_add_slave,
+       .remove_slave   = w1_bq27000_remove_slave,
+};
+
+static struct w1_family w1_bq27000_family = {
+       .fid = 1,
+       .fops = &w1_bq27000_fops,
+};
+
+static int __init w1_bq27000_init(void)
+{
+       if (F_ID)
+               w1_bq27000_family.fid = F_ID;
+
+       return w1_register_family(&w1_bq27000_family);
+}
+
+static void __exit w1_bq27000_exit(void)
+{
+       w1_unregister_family(&w1_bq27000_family);
+}
+
+
+module_init(w1_bq27000_init);
+module_exit(w1_bq27000_exit);
+
+module_param(F_ID, int, S_IRUSR);
+MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ device");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Ltd");
+MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip");
index cdaa6fffbfc73c2c6bd6be3eefdd2a600ca3f82e..97304bd83ec9674105bc837a4e9ecea6ba373cfd 100644 (file)
@@ -206,6 +206,7 @@ void w1_slave_detach(struct w1_slave *sl);
 
 u8 w1_triplet(struct w1_master *dev, int bdir);
 void w1_write_8(struct w1_master *, u8);
+u8 w1_read_8(struct w1_master *);
 int w1_reset_bus(struct w1_master *);
 u8 w1_calc_crc8(u8 *, int);
 void w1_write_block(struct w1_master *, const u8 *, int);
index f4f82f1f486ebdd2c70c9ff80c5fdb4e99f03fe2..0d15b0eaf79a7b5a56eb50bb00efc1a9571280e6 100644 (file)
@@ -217,7 +217,7 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
  * @param dev     the master device
  * @return        the byte read
  */
-static u8 w1_read_8(struct w1_master * dev)
+u8 w1_read_8(struct w1_master *dev)
 {
        int i;
        u8 res = 0;
@@ -230,6 +230,7 @@ static u8 w1_read_8(struct w1_master * dev)
 
        return res;
 }
+EXPORT_SYMBOL_GPL(w1_read_8);
 
 /**
  * Writes a series of bytes.
index a0fb5eac407c78b07f54f281db70664b78f761a6..526c191e84ea9cfd32d0a6252e27046a90cfc6f4 100644 (file)
@@ -122,14 +122,7 @@ static struct timer_list balloon_timer;
 static void scrub_page(struct page *page)
 {
 #ifdef CONFIG_XEN_SCRUB_PAGES
-       if (PageHighMem(page)) {
-               void *v = kmap(page);
-               clear_page(v);
-               kunmap(v);
-       } else {
-               void *v = page_address(page);
-               clear_page(v);
-       }
+       clear_highpage(page);
 #endif
 }
 
index 69a12aae91d313e832ae3e2002d3bdfc7732ecc6..490e34bbf27a66641c0bad3327e5bb22156a88af 100644 (file)
@@ -107,12 +107,13 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
 #ifdef CONFIG_PROC_FS
 static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 {
-       struct list_head *tmp;
-       struct list_head *tmp1;
+       struct list_head *tmp1, *tmp2, *tmp3;
        struct mid_q_entry *mid_entry;
+       struct TCP_Server_Info *server;
        struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
-       int i;
+       int i, j;
+       __u32 dev_type;
 
        seq_puts(m,
                    "Display Internal CIFS Data Structures for Debugging\n"
@@ -122,46 +123,78 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
        seq_printf(m, "Servers:");
 
        i = 0;
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalSMBSessionList) {
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp1, &cifs_tcp_ses_list) {
+               server = list_entry(tmp1, struct TCP_Server_Info,
+                                   tcp_ses_list);
                i++;
-               ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-               if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
-                  (ses->serverNOS == NULL)) {
-                       seq_printf(m, "\nentry for %s not fully "
-                                       "displayed\n\t", ses->serverName);
-               } else {
-                       seq_printf(m,
-                                   "\n%d) Name: %s  Domain: %s Mounts: %d OS:"
-                                   " %s  \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
+               list_for_each(tmp2, &server->smb_ses_list) {
+                       ses = list_entry(tmp2, struct cifsSesInfo,
+                                        smb_ses_list);
+                       if ((ses->serverDomain == NULL) ||
+                               (ses->serverOS == NULL) ||
+                               (ses->serverNOS == NULL)) {
+                               seq_printf(m, "\n%d) entry for %s not fully "
+                                          "displayed\n\t", i, ses->serverName);
+                       } else {
+                               seq_printf(m,
+                                   "\n%d) Name: %s  Domain: %s Uses: %d OS:"
+                                   " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
                                    " session status: %d\t",
                                i, ses->serverName, ses->serverDomain,
-                               atomic_read(&ses->inUse),
-                               ses->serverOS, ses->serverNOS,
+                               ses->ses_count, ses->serverOS, ses->serverNOS,
                                ses->capabilities, ses->status);
-               }
-               if (ses->server) {
+                       }
                        seq_printf(m, "TCP status: %d\n\tLocal Users To "
-                                   "Server: %d SecMode: 0x%x Req On Wire: %d",
-                               ses->server->tcpStatus,
-                               atomic_read(&ses->server->socketUseCount),
-                               ses->server->secMode,
-                               atomic_read(&ses->server->inFlight));
+                                  "Server: %d SecMode: 0x%x Req On Wire: %d",
+                                  server->tcpStatus, server->srv_count,
+                                  server->secMode,
+                                  atomic_read(&server->inFlight));
 
 #ifdef CONFIG_CIFS_STATS2
                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
-                               atomic_read(&ses->server->inSend),
-                               atomic_read(&ses->server->num_waiters));
+                               atomic_read(&server->inSend),
+                               atomic_read(&server->num_waiters));
 #endif
 
-                       seq_puts(m, "\nMIDs:\n");
+                       seq_puts(m, "\n\tShares:");
+                       j = 0;
+                       list_for_each(tmp3, &ses->tcon_list) {
+                               tcon = list_entry(tmp3, struct cifsTconInfo,
+                                                 tcon_list);
+                               ++j;
+                               dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
+                               seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
+                                          tcon->treeName, tcon->tc_count);
+                               if (tcon->nativeFileSystem) {
+                                       seq_printf(m, "Type: %s ",
+                                                  tcon->nativeFileSystem);
+                               }
+                               seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
+                                       "\nPathComponentMax: %d Status: 0x%d",
+                                       le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
+                                       le32_to_cpu(tcon->fsAttrInfo.Attributes),
+                                       le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
+                                       tcon->tidStatus);
+                               if (dev_type == FILE_DEVICE_DISK)
+                                       seq_puts(m, " type: DISK ");
+                               else if (dev_type == FILE_DEVICE_CD_ROM)
+                                       seq_puts(m, " type: CDROM ");
+                               else
+                                       seq_printf(m, " type: %d ", dev_type);
+
+                               if (tcon->need_reconnect)
+                                       seq_puts(m, "\tDISCONNECTED ");
+                               seq_putc(m, '\n');
+                       }
+
+                       seq_puts(m, "\n\tMIDs:\n");
 
                        spin_lock(&GlobalMid_Lock);
-                       list_for_each(tmp1, &ses->server->pending_mid_q) {
-                               mid_entry = list_entry(tmp1, struct
-                                       mid_q_entry,
+                       list_for_each(tmp3, &server->pending_mid_q) {
+                               mid_entry = list_entry(tmp3, struct mid_q_entry,
                                        qhead);
-                               seq_printf(m, "State: %d com: %d pid:"
+                               seq_printf(m, "\tState: %d com: %d pid:"
                                                " %d tsk: %p mid %d\n",
                                                mid_entry->midState,
                                                (int)mid_entry->command,
@@ -171,44 +204,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        }
                        spin_unlock(&GlobalMid_Lock);
                }
-
-       }
-       read_unlock(&GlobalSMBSeslock);
-       seq_putc(m, '\n');
-
-       seq_puts(m, "Shares:");
-
-       i = 0;
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalTreeConnectionList) {
-               __u32 dev_type;
-               i++;
-               tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
-               seq_printf(m, "\n%d) %s Uses: %d ", i,
-                                tcon->treeName, atomic_read(&tcon->useCount));
-               if (tcon->nativeFileSystem) {
-                       seq_printf(m, "Type: %s ",
-                                        tcon->nativeFileSystem);
-               }
-               seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
-                                "\nPathComponentMax: %d Status: %d",
-                           le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
-                           le32_to_cpu(tcon->fsAttrInfo.Attributes),
-                           le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
-                           tcon->tidStatus);
-               if (dev_type == FILE_DEVICE_DISK)
-                       seq_puts(m, " type: DISK ");
-               else if (dev_type == FILE_DEVICE_CD_ROM)
-                       seq_puts(m, " type: CDROM ");
-               else
-                       seq_printf(m, " type: %d ", dev_type);
-
-               if (tcon->tidStatus == CifsNeedReconnect)
-                       seq_puts(m, "\tDISCONNECTED ");
        }
-       read_unlock(&GlobalSMBSeslock);
-
+       read_unlock(&cifs_tcp_ses_lock);
        seq_putc(m, '\n');
 
        /* BB add code to dump additional info such as TCP session info now */
@@ -234,7 +231,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
 {
        char c;
        int rc;
-       struct list_head *tmp;
+       struct list_head *tmp1, *tmp2, *tmp3;
+       struct TCP_Server_Info *server;
+       struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
 
        rc = get_user(c, buffer);
@@ -242,33 +241,42 @@ static ssize_t cifs_stats_proc_write(struct file *file,
                return rc;
 
        if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
-               read_lock(&GlobalSMBSeslock);
 #ifdef CONFIG_CIFS_STATS2
                atomic_set(&totBufAllocCount, 0);
                atomic_set(&totSmBufAllocCount, 0);
 #endif /* CONFIG_CIFS_STATS2 */
-               list_for_each(tmp, &GlobalTreeConnectionList) {
-                       tcon = list_entry(tmp, struct cifsTconInfo,
-                                       cifsConnectionList);
-                       atomic_set(&tcon->num_smbs_sent, 0);
-                       atomic_set(&tcon->num_writes, 0);
-                       atomic_set(&tcon->num_reads, 0);
-                       atomic_set(&tcon->num_oplock_brks, 0);
-                       atomic_set(&tcon->num_opens, 0);
-                       atomic_set(&tcon->num_closes, 0);
-                       atomic_set(&tcon->num_deletes, 0);
-                       atomic_set(&tcon->num_mkdirs, 0);
-                       atomic_set(&tcon->num_rmdirs, 0);
-                       atomic_set(&tcon->num_renames, 0);
-                       atomic_set(&tcon->num_t2renames, 0);
-                       atomic_set(&tcon->num_ffirst, 0);
-                       atomic_set(&tcon->num_fnext, 0);
-                       atomic_set(&tcon->num_fclose, 0);
-                       atomic_set(&tcon->num_hardlinks, 0);
-                       atomic_set(&tcon->num_symlinks, 0);
-                       atomic_set(&tcon->num_locks, 0);
+               read_lock(&cifs_tcp_ses_lock);
+               list_for_each(tmp1, &cifs_tcp_ses_list) {
+                       server = list_entry(tmp1, struct TCP_Server_Info,
+                                           tcp_ses_list);
+                       list_for_each(tmp2, &server->smb_ses_list) {
+                               ses = list_entry(tmp2, struct cifsSesInfo,
+                                                smb_ses_list);
+                               list_for_each(tmp3, &ses->tcon_list) {
+                                       tcon = list_entry(tmp3,
+                                                         struct cifsTconInfo,
+                                                         tcon_list);
+                                       atomic_set(&tcon->num_smbs_sent, 0);
+                                       atomic_set(&tcon->num_writes, 0);
+                                       atomic_set(&tcon->num_reads, 0);
+                                       atomic_set(&tcon->num_oplock_brks, 0);
+                                       atomic_set(&tcon->num_opens, 0);
+                                       atomic_set(&tcon->num_closes, 0);
+                                       atomic_set(&tcon->num_deletes, 0);
+                                       atomic_set(&tcon->num_mkdirs, 0);
+                                       atomic_set(&tcon->num_rmdirs, 0);
+                                       atomic_set(&tcon->num_renames, 0);
+                                       atomic_set(&tcon->num_t2renames, 0);
+                                       atomic_set(&tcon->num_ffirst, 0);
+                                       atomic_set(&tcon->num_fnext, 0);
+                                       atomic_set(&tcon->num_fclose, 0);
+                                       atomic_set(&tcon->num_hardlinks, 0);
+                                       atomic_set(&tcon->num_symlinks, 0);
+                                       atomic_set(&tcon->num_locks, 0);
+                               }
+                       }
                }
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
        }
 
        return count;
@@ -277,7 +285,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
 static int cifs_stats_proc_show(struct seq_file *m, void *v)
 {
        int i;
-       struct list_head *tmp;
+       struct list_head *tmp1, *tmp2, *tmp3;
+       struct TCP_Server_Info *server;
+       struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
 
        seq_printf(m,
@@ -306,44 +316,55 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
                GlobalCurrentXid, GlobalMaxActiveXid);
 
        i = 0;
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalTreeConnectionList) {
-               i++;
-               tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               seq_printf(m, "\n%d) %s", i, tcon->treeName);
-               if (tcon->tidStatus == CifsNeedReconnect)
-                       seq_puts(m, "\tDISCONNECTED ");
-               seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
-                       atomic_read(&tcon->num_smbs_sent),
-                       atomic_read(&tcon->num_oplock_brks));
-               seq_printf(m, "\nReads:  %d Bytes: %lld",
-                       atomic_read(&tcon->num_reads),
-                       (long long)(tcon->bytes_read));
-               seq_printf(m, "\nWrites: %d Bytes: %lld",
-                       atomic_read(&tcon->num_writes),
-                       (long long)(tcon->bytes_written));
-               seq_printf(m,
-                       "\nLocks: %d HardLinks: %d Symlinks: %d",
-                       atomic_read(&tcon->num_locks),
-                       atomic_read(&tcon->num_hardlinks),
-                       atomic_read(&tcon->num_symlinks));
-
-               seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
-                       atomic_read(&tcon->num_opens),
-                       atomic_read(&tcon->num_closes),
-                       atomic_read(&tcon->num_deletes));
-               seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
-                       atomic_read(&tcon->num_mkdirs),
-                       atomic_read(&tcon->num_rmdirs));
-               seq_printf(m, "\nRenames: %d T2 Renames %d",
-                       atomic_read(&tcon->num_renames),
-                       atomic_read(&tcon->num_t2renames));
-               seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
-                       atomic_read(&tcon->num_ffirst),
-                       atomic_read(&tcon->num_fnext),
-                       atomic_read(&tcon->num_fclose));
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp1, &cifs_tcp_ses_list) {
+               server = list_entry(tmp1, struct TCP_Server_Info,
+                                   tcp_ses_list);
+               list_for_each(tmp2, &server->smb_ses_list) {
+                       ses = list_entry(tmp2, struct cifsSesInfo,
+                                        smb_ses_list);
+                       list_for_each(tmp3, &ses->tcon_list) {
+                               tcon = list_entry(tmp3,
+                                                 struct cifsTconInfo,
+                                                 tcon_list);
+                               i++;
+                               seq_printf(m, "\n%d) %s", i, tcon->treeName);
+                               if (tcon->need_reconnect)
+                                       seq_puts(m, "\tDISCONNECTED ");
+                               seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
+                                       atomic_read(&tcon->num_smbs_sent),
+                                       atomic_read(&tcon->num_oplock_brks));
+                               seq_printf(m, "\nReads:  %d Bytes: %lld",
+                                       atomic_read(&tcon->num_reads),
+                                       (long long)(tcon->bytes_read));
+                               seq_printf(m, "\nWrites: %d Bytes: %lld",
+                                       atomic_read(&tcon->num_writes),
+                                       (long long)(tcon->bytes_written));
+                               seq_printf(m, "\nLocks: %d HardLinks: %d "
+                                             "Symlinks: %d",
+                                       atomic_read(&tcon->num_locks),
+                                       atomic_read(&tcon->num_hardlinks),
+                                       atomic_read(&tcon->num_symlinks));
+                               seq_printf(m, "\nOpens: %d Closes: %d"
+                                             "Deletes: %d",
+                                       atomic_read(&tcon->num_opens),
+                                       atomic_read(&tcon->num_closes),
+                                       atomic_read(&tcon->num_deletes));
+                               seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
+                                       atomic_read(&tcon->num_mkdirs),
+                                       atomic_read(&tcon->num_rmdirs));
+                               seq_printf(m, "\nRenames: %d T2 Renames %d",
+                                       atomic_read(&tcon->num_renames),
+                                       atomic_read(&tcon->num_t2renames));
+                               seq_printf(m, "\nFindFirst: %d FNext %d "
+                                             "FClose %d",
+                                       atomic_read(&tcon->num_ffirst),
+                                       atomic_read(&tcon->num_fnext),
+                                       atomic_read(&tcon->num_fclose));
+                       }
+               }
        }
-       read_unlock(&GlobalSMBSeslock);
+       read_unlock(&cifs_tcp_ses_lock);
 
        seq_putc(m, '\n');
        return 0;
index d2c8eef84f3c7c805d8a484115ae090bc56e8920..e1c18362ba466c973999e0076887edc51f7c515b 100644 (file)
@@ -106,7 +106,8 @@ static char *cifs_get_share_name(const char *node_name)
 /**
  * compose_mount_options       -       creates mount options for refferral
  * @sb_mountdata:      parent/root DFS mount options (template)
- * @ref_unc:           refferral server UNC
+ * @dentry:            point where we are going to mount
+ * @ref:               server's referral
  * @devname:           pointer for saving device name
  *
  * creates mount options for submount based on template options sb_mountdata
@@ -116,7 +117,8 @@ static char *cifs_get_share_name(const char *node_name)
  * Caller is responcible for freeing retunrned value if it is not error.
  */
 static char *compose_mount_options(const char *sb_mountdata,
-                                  const char *ref_unc,
+                                  struct dentry *dentry,
+                                  const struct dfs_info3_param *ref,
                                   char **devname)
 {
        int rc;
@@ -126,11 +128,12 @@ static char *compose_mount_options(const char *sb_mountdata,
        char *srvIP = NULL;
        char sep = ',';
        int off, noff;
+       char *fullpath;
 
        if (sb_mountdata == NULL)
                return ERR_PTR(-EINVAL);
 
-       *devname = cifs_get_share_name(ref_unc);
+       *devname = cifs_get_share_name(ref->node_name);
        rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
        if (rc != 0) {
                cERROR(1, ("%s: Failed to resolve server part of %s to IP",
@@ -138,7 +141,12 @@ static char *compose_mount_options(const char *sb_mountdata,
                mountdata = ERR_PTR(rc);
                goto compose_mount_options_out;
        }
-       md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
+       /* md_len = strlen(...) + 12 for 'sep+prefixpath='
+        * assuming that we have 'unc=' and 'ip=' in
+        * the original sb_mountdata
+        */
+       md_len = strlen(sb_mountdata) + strlen(srvIP) +
+               strlen(ref->node_name) + 12;
        mountdata = kzalloc(md_len+1, GFP_KERNEL);
        if (mountdata == NULL) {
                mountdata = ERR_PTR(-ENOMEM);
@@ -152,41 +160,56 @@ static char *compose_mount_options(const char *sb_mountdata,
                        strncpy(mountdata, sb_mountdata, 5);
                        off += 5;
        }
-       while ((tkn_e = strchr(sb_mountdata+off, sep))) {
-               noff = (tkn_e - (sb_mountdata+off)) + 1;
-               if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
+
+       do {
+               tkn_e = strchr(sb_mountdata + off, sep);
+               if (tkn_e == NULL)
+                       noff = strlen(sb_mountdata + off);
+               else
+                       noff = tkn_e - (sb_mountdata + off) + 1;
+
+               if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
                        off += noff;
                        continue;
                }
-               if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
+               if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
                        off += noff;
                        continue;
                }
-               if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
+               if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
                        off += noff;
                        continue;
                }
-               strncat(mountdata, sb_mountdata+off, noff);
+               strncat(mountdata, sb_mountdata + off, noff);
                off += noff;
-       }
-       strcat(mountdata, sb_mountdata+off);
+       } while (tkn_e);
+       strcat(mountdata, sb_mountdata + off);
        mountdata[md_len] = '\0';
 
        /* copy new IP and ref share name */
-       strcat(mountdata, ",ip=");
+       if (mountdata[strlen(mountdata) - 1] != sep)
+               strncat(mountdata, &sep, 1);
+       strcat(mountdata, "ip=");
        strcat(mountdata, srvIP);
-       strcat(mountdata, ",unc=");
+       strncat(mountdata, &sep, 1);
+       strcat(mountdata, "unc=");
        strcat(mountdata, *devname);
 
        /* find & copy prefixpath */
-       tkn_e = strchr(ref_unc+2, '\\');
-       if (tkn_e) {
-               tkn_e = strchr(tkn_e+1, '\\');
-               if (tkn_e) {
-                       strcat(mountdata, ",prefixpath=");
-                       strcat(mountdata, tkn_e+1);
-               }
+       tkn_e = strchr(ref->node_name + 2, '\\');
+       if (tkn_e == NULL) /* invalid unc, missing share name*/
+               goto compose_mount_options_out;
+
+       fullpath = build_path_from_dentry(dentry);
+       tkn_e = strchr(tkn_e + 1, '\\');
+       if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
+               strncat(mountdata, &sep, 1);
+               strcat(mountdata, "prefixpath=");
+               if (tkn_e)
+                       strcat(mountdata, tkn_e + 1);
+               strcat(mountdata, fullpath + (ref->path_consumed));
        }
+       kfree(fullpath);
 
        /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
        /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
@@ -198,7 +221,7 @@ compose_mount_options_out:
 
 
 static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
-               struct dentry *dentry, char *ref_unc)
+               struct dentry *dentry, const struct dfs_info3_param *ref)
 {
        struct cifs_sb_info *cifs_sb;
        struct vfsmount *mnt;
@@ -207,7 +230,7 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
 
        cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
        mountdata = compose_mount_options(cifs_sb->mountdata,
-                                               ref_unc, &devname);
+                                               dentry, ref, &devname);
 
        if (IS_ERR(mountdata))
                return (struct vfsmount *)mountdata;
@@ -310,7 +333,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
                        }
                        mnt = cifs_dfs_do_refmount(nd->path.mnt,
                                                nd->path.dentry,
-                                               referrals[i].node_name);
+                                               referrals + i);
                        cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
                                         __func__,
                                        referrals[i].node_name, mnt));
index fcee9298b6206ab9db2e597c47139db8dd7c8661..0ab2fb5afef12a78a9ae2fdd0e79af761133468b 100644 (file)
@@ -73,8 +73,8 @@ struct key_type cifs_spnego_key_type = {
  * strlen(";sec=ntlmsspi") */
 #define MAX_MECH_STR_LEN       13
 
-/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
-#define MAX_IPV6_ADDR_LEN      42
+/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */
+#define MAX_IPV6_ADDR_LEN      43
 
 /* strlen of "host=" */
 #define HOST_KEY_LEN           5
index ac5915d61dca768d4f71d689c5948712e2bf012f..d9cf467309e8cdc1449a7ca287c80452093de23c 100644 (file)
@@ -514,10 +514,11 @@ static void cifs_umount_begin(struct super_block *sb)
        tcon = cifs_sb->tcon;
        if (tcon == NULL)
                return;
-       down(&tcon->tconSem);
-       if (atomic_read(&tcon->useCount) == 1)
+
+       read_lock(&cifs_tcp_ses_lock);
+       if (tcon->tc_count == 1)
                tcon->tidStatus = CifsExiting;
-       up(&tcon->tconSem);
+       read_unlock(&cifs_tcp_ses_lock);
 
        /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
        /* cancel_notify_requests(tcon); */
@@ -1013,7 +1014,7 @@ static int cifs_oplock_thread(void *dummyarg)
                                not bother sending an oplock release if session
                                to server still is disconnected since oplock
                                already released by the server in that case */
-                       if (pTcon->tidStatus != CifsNeedReconnect) {
+                       if (!pTcon->need_reconnect) {
                                rc = CIFSSMBLock(0, pTcon, netfid,
                                                0 /* len */ , 0 /* offset */, 0,
                                                0, LOCKING_ANDX_OPLOCK_RELEASE,
@@ -1031,24 +1032,24 @@ static int cifs_oplock_thread(void *dummyarg)
 static int cifs_dnotify_thread(void *dummyarg)
 {
        struct list_head *tmp;
-       struct cifsSesInfo *ses;
+       struct TCP_Server_Info *server;
 
        do {
                if (try_to_freeze())
                        continue;
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(15*HZ);
-               read_lock(&GlobalSMBSeslock);
                /* check if any stuck requests that need
                   to be woken up and wakeq so the
                   thread can wake up and error out */
-               list_for_each(tmp, &GlobalSMBSessionList) {
-                       ses = list_entry(tmp, struct cifsSesInfo,
-                               cifsSessionList);
-                       if (ses->server && atomic_read(&ses->server->inFlight))
-                               wake_up_all(&ses->server->response_q);
+               read_lock(&cifs_tcp_ses_lock);
+               list_for_each(tmp, &cifs_tcp_ses_list) {
+                       server = list_entry(tmp, struct TCP_Server_Info,
+                                        tcp_ses_list);
+                       if (atomic_read(&server->inFlight))
+                               wake_up_all(&server->response_q);
                }
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
        } while (!kthread_should_stop());
 
        return 0;
@@ -1059,9 +1060,7 @@ init_cifs(void)
 {
        int rc = 0;
        cifs_proc_init();
-/*     INIT_LIST_HEAD(&GlobalServerList);*/    /* BB not implemented yet */
-       INIT_LIST_HEAD(&GlobalSMBSessionList);
-       INIT_LIST_HEAD(&GlobalTreeConnectionList);
+       INIT_LIST_HEAD(&cifs_tcp_ses_list);
        INIT_LIST_HEAD(&GlobalOplock_Q);
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        INIT_LIST_HEAD(&GlobalDnotifyReqList);
@@ -1089,6 +1088,7 @@ init_cifs(void)
        GlobalMaxActiveXid = 0;
        memset(Local_System_Name, 0, 15);
        rwlock_init(&GlobalSMBSeslock);
+       rwlock_init(&cifs_tcp_ses_lock);
        spin_lock_init(&GlobalMid_Lock);
 
        if (cifs_max_pending < 2) {
index 1cb1189f24e0e3417751d91838bf29e0968e5dea..f1ae1f57c30dcbfd86de17dcbb46bcc9c3991e71 100644 (file)
@@ -85,8 +85,7 @@ enum securityEnum {
 };
 
 enum protocolEnum {
-       IPV4 = 0,
-       IPV6,
+       TCP = 0,
        SCTP
        /* Netbios frames protocol not supported at this time */
 };
@@ -122,6 +121,9 @@ struct cifs_cred {
  */
 
 struct TCP_Server_Info {
+       struct list_head tcp_ses_list;
+       struct list_head smb_ses_list;
+       int srv_count; /* reference counter */
        /* 15 character server name + 0x20 16th byte indicating type = srv */
        char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
        char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
@@ -143,7 +145,6 @@ struct TCP_Server_Info {
        bool svlocal:1;                 /* local server or remote */
        bool noblocksnd;                /* use blocking sendmsg */
        bool noautotune;                /* do not autotune send buf sizes */
-       atomic_t socketUseCount; /* number of open cifs sessions on socket */
        atomic_t inFlight;  /* number of requests on the wire to server */
 #ifdef CONFIG_CIFS_STATS2
        atomic_t inSend; /* requests trying to send */
@@ -194,13 +195,14 @@ struct cifsUidInfo {
  * Session structure.  One of these for each uid session with a particular host
  */
 struct cifsSesInfo {
-       struct list_head cifsSessionList;
+       struct list_head smb_ses_list;
+       struct list_head tcon_list;
        struct semaphore sesSem;
 #if 0
        struct cifsUidInfo *uidInfo;    /* pointer to user info */
 #endif
        struct TCP_Server_Info *server; /* pointer to server info */
-       atomic_t inUse; /* # of mounts (tree connections) on this ses */
+       int ses_count;          /* reference counter */
        enum statusEnum status;
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
@@ -216,6 +218,7 @@ struct cifsSesInfo {
        char userName[MAX_USERNAME_SIZE + 1];
        char *domainName;
        char *password;
+       bool need_reconnect:1; /* connection reset, uid now invalid */
 };
 /* no more than one of the following three session flags may be set */
 #define CIFS_SES_NT4 1
@@ -230,16 +233,15 @@ struct cifsSesInfo {
  * session
  */
 struct cifsTconInfo {
-       struct list_head cifsConnectionList;
+       struct list_head tcon_list;
+       int tc_count;
        struct list_head openFileList;
-       struct semaphore tconSem;
        struct cifsSesInfo *ses;        /* pointer to session associated with */
        char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
        char *nativeFileSystem;
        __u16 tid;              /* The 2 byte tree id */
        __u16 Flags;            /* optional support bits */
        enum statusEnum tidStatus;
-       atomic_t useCount;      /* how many explicit/implicit mounts to share */
 #ifdef CONFIG_CIFS_STATS
        atomic_t num_smbs_sent;
        atomic_t num_writes;
@@ -288,6 +290,7 @@ struct cifsTconInfo {
        bool unix_ext:1;  /* if false disable Linux extensions to CIFS protocol
                                for this mount even if server would support */
        bool local_lease:1; /* check leases (only) on local system not remote */
+       bool need_reconnect:1; /* connection reset, tid now invalid */
        /* BB add field for back pointer to sb struct(s)? */
 };
 
@@ -588,21 +591,21 @@ require use of the stronger protocol */
 #endif
 
 /*
- * The list of servers that did not respond with NT LM 0.12.
- * This list helps improve performance and eliminate the messages indicating
- * that we had a communications error talking to the server in this list.
+ * the list of TCP_Server_Info structures, ie each of the sockets
+ * connecting our client to a distinct server (ip address), is
+ * chained together by cifs_tcp_ses_list. The list of all our SMB
+ * sessions (and from that the tree connections) can be found
+ * by iterating over cifs_tcp_ses_list
  */
-/* Feature not supported */
-/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
+GLOBAL_EXTERN struct list_head         cifs_tcp_ses_list;
 
 /*
- * The following is a hash table of all the users we know about.
+ * This lock protects the cifs_tcp_ses_list, the list of smb sessions per
+ * tcp session, and the list of tcon's per smb session. It also protects
+ * the reference counters for the server, smb session, and tcon. Finally,
+ * changes to the tcon->tidStatus should be done while holding this lock.
  */
-GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
-
-/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */
-GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
-GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
+GLOBAL_EXTERN rwlock_t         cifs_tcp_ses_lock;
 GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
 
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
index d5eac48fc41525494d017afd84d14d3d550b1cd8..bdda46dd435a0d9fd8c6d0d692e7b98be4390cc6 100644 (file)
@@ -190,10 +190,10 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if (tcon->ses->status == CifsNeedReconnect)
+                       if (tcon->ses->need_reconnect)
                                rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->need_reconnect)) {
                                mark_open_files_invalid(tcon);
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
@@ -295,7 +295,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
           check for tcp and smb session status done differently
           for those three - in the calling routine */
        if (tcon) {
-               if (tcon->tidStatus == CifsExiting) {
+               if (tcon->need_reconnect) {
                        /* only tree disconnect, open, and write,
                          (and ulogoff which does not have tcon)
                          are allowed as we start force umount */
@@ -337,10 +337,10 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if (tcon->ses->status == CifsNeedReconnect)
+                       if (tcon->ses->need_reconnect)
                                rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->need_reconnect)) {
                                mark_open_files_invalid(tcon);
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
@@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        rc = -EIO;
                        goto neg_err_exit;
                }
-
-               if (server->socketUseCount.counter > 1) {
+               read_lock(&cifs_tcp_ses_lock);
+               if (server->srv_count > 1) {
+                       read_unlock(&cifs_tcp_ses_lock);
                        if (memcmp(server->server_GUID,
                                   pSMBr->u.extended_response.
                                   GUID, 16) != 0) {
@@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                        pSMBr->u.extended_response.GUID,
                                        16);
                        }
-               } else
+               } else {
+                       read_unlock(&cifs_tcp_ses_lock);
                        memcpy(server->server_GUID,
                               pSMBr->u.extended_response.GUID, 16);
+               }
 
                if (count == 16) {
                        server->secType = RawNTLMSSP;
@@ -739,50 +742,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
        int rc = 0;
 
        cFYI(1, ("In tree disconnect"));
-       /*
-        *  If last user of the connection and
-        *  connection alive - disconnect it
-        *  If this is the last connection on the server session disconnect it
-        *  (and inside session disconnect we should check if tcp socket needs
-        *  to be freed and kernel thread woken up).
-        */
-       if (tcon)
-               down(&tcon->tconSem);
-       else
-               return -EIO;
 
-       atomic_dec(&tcon->useCount);
-       if (atomic_read(&tcon->useCount) > 0) {
-               up(&tcon->tconSem);
-               return -EBUSY;
-       }
+       /* BB: do we need to check this? These should never be NULL. */
+       if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+               return -EIO;
 
-       /* No need to return error on this operation if tid invalidated and
-       closed on server already e.g. due to tcp session crashing */
-       if (tcon->tidStatus == CifsNeedReconnect) {
-               up(&tcon->tconSem);
+       /*
+        * No need to return error on this operation if tid invalidated and
+        * closed on server already e.g. due to tcp session crashing. Also,
+        * the tcon is no longer on the list, so no need to take lock before
+        * checking this.
+        */
+       if (tcon->need_reconnect)
                return 0;
-       }
 
-       if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
-               up(&tcon->tconSem);
-               return -EIO;
-       }
        rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
                            (void **)&smb_buffer);
-       if (rc) {
-               up(&tcon->tconSem);
+       if (rc)
                return rc;
-       }
 
        rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
        if (rc)
                cFYI(1, ("Tree disconnect failed %d", rc));
 
-       up(&tcon->tconSem);
-
        /* No need to return error on this operation if tid invalidated and
-       closed on server already e.g. due to tcp session crashing */
+          closed on server already e.g. due to tcp session crashing */
        if (rc == -EAGAIN)
                rc = 0;
 
@@ -796,43 +780,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        int rc = 0;
 
        cFYI(1, ("In SMBLogoff for session disconnect"));
-       if (ses)
-               down(&ses->sesSem);
-       else
+
+       /*
+        * BB: do we need to check validity of ses and server? They should
+        * always be valid since we have an active reference. If not, that
+        * should probably be a BUG()
+        */
+       if (!ses || !ses->server)
                return -EIO;
 
-       atomic_dec(&ses->inUse);
-       if (atomic_read(&ses->inUse) > 0) {
-               up(&ses->sesSem);
-               return -EBUSY;
-       }
+       down(&ses->sesSem);
+       if (ses->need_reconnect)
+               goto session_already_dead; /* no need to send SMBlogoff if uid
+                                             already closed due to reconnect */
        rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
        if (rc) {
                up(&ses->sesSem);
                return rc;
        }
 
-       if (ses->server) {
-               pSMB->hdr.Mid = GetNextMid(ses->server);
+       pSMB->hdr.Mid = GetNextMid(ses->server);
 
-               if (ses->server->secMode &
+       if (ses->server->secMode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-       }
 
        pSMB->hdr.Uid = ses->Suid;
 
        pSMB->AndXCommand = 0xFF;
        rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
-       if (ses->server) {
-               atomic_dec(&ses->server->socketUseCount);
-               if (atomic_read(&ses->server->socketUseCount) == 0) {
-                       spin_lock(&GlobalMid_Lock);
-                       ses->server->tcpStatus = CifsExiting;
-                       spin_unlock(&GlobalMid_Lock);
-                       rc = -ESHUTDOWN;
-               }
-       }
+session_already_dead:
        up(&ses->sesSem);
 
        /* if session dead then we do not need to do ulogoff,
@@ -3922,6 +3899,27 @@ GetInodeNumOut:
        return rc;
 }
 
+/* computes length of UCS string converted to host codepage
+ * @src:       UCS string
+ * @maxlen:    length of the input string in UCS characters
+ *             (not in bytes)
+ *
+ * return:     size of input string in host codepage
+ */
+static int hostlen_fromUCS(const __le16 *src, const int maxlen,
+               const struct nls_table *nls_codepage) {
+       int i;
+       int hostlen = 0;
+       char to[4];
+       int charlen;
+       for (i = 0; (i < maxlen) && src[i]; ++i) {
+               charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
+                               to, NLS_MAX_CHARSET_SIZE);
+               hostlen += charlen > 0 ? charlen : 1;
+       }
+       return hostlen;
+}
+
 /* parses DFS refferal V3 structure
  * caller is responsible for freeing target_nodes
  * returns:
@@ -3932,7 +3930,8 @@ static int
 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
                unsigned int *num_of_nodes,
                struct dfs_info3_param **target_nodes,
-               const struct nls_table *nls_codepage)
+               const struct nls_table *nls_codepage, int remap,
+               const char *searchName)
 {
        int i, rc = 0;
        char *data_end;
@@ -3983,7 +3982,17 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
                struct dfs_info3_param *node = (*target_nodes)+i;
 
                node->flags = le16_to_cpu(pSMBr->DFSFlags);
-               node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
+               if (is_unicode) {
+                       __le16 *tmp = kmalloc(strlen(searchName)*2, GFP_KERNEL);
+                       cifsConvertToUCS((__le16 *) tmp, searchName,
+                                       PATH_MAX, nls_codepage, remap);
+                       node->path_consumed = hostlen_fromUCS(tmp,
+                                       le16_to_cpu(pSMBr->PathConsumed)/2,
+                                       nls_codepage);
+                       kfree(tmp);
+               } else
+                       node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
+
                node->server_type = le16_to_cpu(ref->ServerType);
                node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
 
@@ -4116,7 +4125,8 @@ getDFSRetry:
 
        /* parse returned result into more usable form */
        rc = parse_DFS_referrals(pSMBr, num_of_nodes,
-                                target_nodes, nls_codepage);
+                                target_nodes, nls_codepage, remap,
+                                searchName);
 
 GetDFSRefExit:
        cifs_buf_release(pSMB);
index e9f9248cb3feff13deeeb4d5eeae1d2a65f79ebe..c7d341714586fdfc9086c381dc310fe81a371237 100644 (file)
@@ -124,7 +124,7 @@ static int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
        int rc = 0;
-       struct list_head *tmp;
+       struct list_head *tmp, *tmp2;
        struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
        struct mid_q_entry *mid_entry;
@@ -144,23 +144,17 @@ cifs_reconnect(struct TCP_Server_Info *server)
 
        /* before reconnecting the tcp session, mark the smb session (uid)
                and the tid bad so they are not used until reconnected */
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalSMBSessionList) {
-               ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-               if (ses->server) {
-                       if (ses->server == server) {
-                               ses->status = CifsNeedReconnect;
-                               ses->ipc_tid = 0;
-                       }
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               ses->need_reconnect = true;
+               ses->ipc_tid = 0;
+               list_for_each(tmp2, &ses->tcon_list) {
+                       tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
+                       tcon->need_reconnect = true;
                }
-               /* else tcp and smb sessions need reconnection */
-       }
-       list_for_each(tmp, &GlobalTreeConnectionList) {
-               tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if ((tcon->ses) && (tcon->ses->server == server))
-                       tcon->tidStatus = CifsNeedReconnect;
        }
-       read_unlock(&GlobalSMBSeslock);
+       read_unlock(&cifs_tcp_ses_lock);
        /* do not want to be sending data on a socket we are freeing */
        down(&server->tcpSem);
        if (server->ssocket) {
@@ -193,7 +187,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
        while ((server->tcpStatus != CifsExiting) &&
               (server->tcpStatus != CifsGood)) {
                try_to_freeze();
-               if (server->protocolType == IPV6) {
+               if (server->addr.sockAddr6.sin6_family == AF_INET6) {
                        rc = ipv6_connect(&server->addr.sockAddr6,
                                          &server->ssocket, server->noautotune);
                } else {
@@ -417,9 +411,14 @@ incomplete_rcv:
                        msleep(1); /* minimum sleep to prevent looping
                                allowing socket to clear and app threads to set
                                tcpStatus CifsNeedReconnect if server hung */
-                       if (pdu_length < 4)
+                       if (pdu_length < 4) {
+                               iov.iov_base = (4 - pdu_length) +
+                                                       (char *)smb_buffer;
+                               iov.iov_len = pdu_length;
+                               smb_msg.msg_control = NULL;
+                               smb_msg.msg_controllen = 0;
                                goto incomplete_rcv;
-                       else
+                       else
                                continue;
                } else if (length <= 0) {
                        if (server->tcpStatus == CifsNew) {
@@ -654,6 +653,11 @@ multi_t2_fnd:
                }
        } /* end while !EXITING */
 
+       /* take it off the list, if it's not already */
+       write_lock(&cifs_tcp_ses_lock);
+       list_del_init(&server->tcp_ses_list);
+       write_unlock(&cifs_tcp_ses_lock);
+
        spin_lock(&GlobalMid_Lock);
        server->tcpStatus = CifsExiting;
        spin_unlock(&GlobalMid_Lock);
@@ -686,29 +690,29 @@ multi_t2_fnd:
        if (smallbuf) /* no sense logging a debug message if NULL */
                cifs_small_buf_release(smallbuf);
 
-       read_lock(&GlobalSMBSeslock);
+       /*
+        * BB: we shouldn't have to do any of this. It shouldn't be
+        * possible to exit from the thread with active SMB sessions
+        */
+       read_lock(&cifs_tcp_ses_lock);
        if (list_empty(&server->pending_mid_q)) {
                /* loop through server session structures attached to this and
                    mark them dead */
-               list_for_each(tmp, &GlobalSMBSessionList) {
-                       ses =
-                           list_entry(tmp, struct cifsSesInfo,
-                                      cifsSessionList);
-                       if (ses->server == server) {
-                               ses->status = CifsExiting;
-                               ses->server = NULL;
-                       }
+               list_for_each(tmp, &server->smb_ses_list) {
+                       ses = list_entry(tmp, struct cifsSesInfo,
+                                        smb_ses_list);
+                       ses->status = CifsExiting;
+                       ses->server = NULL;
                }
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
        } else {
                /* although we can not zero the server struct pointer yet,
                since there are active requests which may depnd on them,
                mark the corresponding SMB sessions as exiting too */
-               list_for_each(tmp, &GlobalSMBSessionList) {
+               list_for_each(tmp, &server->smb_ses_list) {
                        ses = list_entry(tmp, struct cifsSesInfo,
-                                        cifsSessionList);
-                       if (ses->server == server)
-                               ses->status = CifsExiting;
+                                        smb_ses_list);
+                       ses->status = CifsExiting;
                }
 
                spin_lock(&GlobalMid_Lock);
@@ -723,7 +727,7 @@ multi_t2_fnd:
                        }
                }
                spin_unlock(&GlobalMid_Lock);
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
                /* 1/8th of sec is more than enough time for them to exit */
                msleep(125);
        }
@@ -745,14 +749,13 @@ multi_t2_fnd:
        if there are any pointing to this (e.g
        if a crazy root user tried to kill cifsd
        kernel thread explicitly this might happen) */
-       write_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalSMBSessionList) {
-               ses = list_entry(tmp, struct cifsSesInfo,
-                               cifsSessionList);
-               if (ses->server == server)
-                       ses->server = NULL;
+       /* BB: This shouldn't be necessary, see above */
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               ses->server = NULL;
        }
-       write_unlock(&GlobalSMBSeslock);
+       read_unlock(&cifs_tcp_ses_lock);
 
        kfree(server->hostname);
        task_to_wake = xchg(&server->tsk, NULL);
@@ -1352,94 +1355,158 @@ cifs_parse_mount_options(char *options, const char *devname,
        return 0;
 }
 
-static struct cifsSesInfo *
-cifs_find_tcp_session(struct in_addr *target_ip_addr,
-                     struct in6_addr *target_ip6_addr,
-                     char *userName, struct TCP_Server_Info **psrvTcp)
+static struct TCP_Server_Info *
+cifs_find_tcp_session(struct sockaddr *addr)
 {
        struct list_head *tmp;
-       struct cifsSesInfo *ses;
-
-       *psrvTcp = NULL;
+       struct TCP_Server_Info *server;
+       struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
+
+       write_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &cifs_tcp_ses_list) {
+               server = list_entry(tmp, struct TCP_Server_Info,
+                                   tcp_ses_list);
+               /*
+                * the demux thread can exit on its own while still in CifsNew
+                * so don't accept any sockets in that state. Since the
+                * tcpStatus never changes back to CifsNew it's safe to check
+                * for this without a lock.
+                */
+               if (server->tcpStatus == CifsNew)
+                       continue;
 
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalSMBSessionList) {
-               ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-               if (!ses->server)
+               if (addr->sa_family == AF_INET &&
+                   (addr4->sin_addr.s_addr !=
+                    server->addr.sockAddr.sin_addr.s_addr))
+                       continue;
+               else if (addr->sa_family == AF_INET6 &&
+                        memcmp(&server->addr.sockAddr6.sin6_addr,
+                               &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
                        continue;
 
-               if (target_ip_addr &&
-                   ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
-                               continue;
-               else if (target_ip6_addr &&
-                        memcmp(&ses->server->addr.sockAddr6.sin6_addr,
-                               target_ip6_addr, sizeof(*target_ip6_addr)))
-                               continue;
-               /* BB lock server and tcp session; increment use count here?? */
+               ++server->srv_count;
+               write_unlock(&cifs_tcp_ses_lock);
+               cFYI(1, ("Existing tcp session with server found"));
+               return server;
+       }
+       write_unlock(&cifs_tcp_ses_lock);
+       return NULL;
+}
 
-               /* found a match on the TCP session */
-               *psrvTcp = ses->server;
+static void
+cifs_put_tcp_session(struct TCP_Server_Info *server)
+{
+       struct task_struct *task;
 
-               /* BB check if reconnection needed */
-               if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
-                       read_unlock(&GlobalSMBSeslock);
-                       /* Found exact match on both TCP and
-                          SMB sessions */
-                       return ses;
-               }
-               /* else tcp and smb sessions need reconnection */
+       write_lock(&cifs_tcp_ses_lock);
+       if (--server->srv_count > 0) {
+               write_unlock(&cifs_tcp_ses_lock);
+               return;
        }
-       read_unlock(&GlobalSMBSeslock);
 
-       return NULL;
+       list_del_init(&server->tcp_ses_list);
+       write_unlock(&cifs_tcp_ses_lock);
+
+       spin_lock(&GlobalMid_Lock);
+       server->tcpStatus = CifsExiting;
+       spin_unlock(&GlobalMid_Lock);
+
+       task = xchg(&server->tsk, NULL);
+       if (task)
+               force_sig(SIGKILL, task);
 }
 
-static struct cifsTconInfo *
-find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
+static struct cifsSesInfo *
+cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
 {
        struct list_head *tmp;
-       struct cifsTconInfo *tcon;
-       __be32 old_ip;
-
-       read_lock(&GlobalSMBSeslock);
+       struct cifsSesInfo *ses;
 
-       list_for_each(tmp, &GlobalTreeConnectionList) {
-               cFYI(1, ("Next tcon"));
-               tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if (!tcon->ses || !tcon->ses->server)
+       write_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
                        continue;
 
-               old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
-               cFYI(1, ("old ip addr: %x == new ip %x ?",
-                       old_ip, new_target_ip_addr));
+               ++ses->ses_count;
+               write_unlock(&cifs_tcp_ses_lock);
+               return ses;
+       }
+       write_unlock(&cifs_tcp_ses_lock);
+       return NULL;
+}
 
-               if (old_ip != new_target_ip_addr)
-                       continue;
+static void
+cifs_put_smb_ses(struct cifsSesInfo *ses)
+{
+       int xid;
+       struct TCP_Server_Info *server = ses->server;
 
-               /* BB lock tcon, server, tcp session and increment use count? */
-               /* found a match on the TCP session */
-               /* BB check if reconnection needed */
-               cFYI(1, ("IP match, old UNC: %s new: %s",
-                       tcon->treeName, uncName));
+       write_lock(&cifs_tcp_ses_lock);
+       if (--ses->ses_count > 0) {
+               write_unlock(&cifs_tcp_ses_lock);
+               return;
+       }
 
-               if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
-                       continue;
+       list_del_init(&ses->smb_ses_list);
+       write_unlock(&cifs_tcp_ses_lock);
 
-               cFYI(1, ("and old usr: %s new: %s",
-                       tcon->treeName, uncName));
+       if (ses->status == CifsGood) {
+               xid = GetXid();
+               CIFSSMBLogoff(xid, ses);
+               _FreeXid(xid);
+       }
+       sesInfoFree(ses);
+       cifs_put_tcp_session(server);
+}
 
-               if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
+static struct cifsTconInfo *
+cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
+{
+       struct list_head *tmp;
+       struct cifsTconInfo *tcon;
+
+       write_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &ses->tcon_list) {
+               tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
+               if (tcon->tidStatus == CifsExiting)
+                       continue;
+               if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
                        continue;
 
-               /* matched smb session (user name) */
-               read_unlock(&GlobalSMBSeslock);
+               ++tcon->tc_count;
+               write_unlock(&cifs_tcp_ses_lock);
                return tcon;
        }
-
-       read_unlock(&GlobalSMBSeslock);
+       write_unlock(&cifs_tcp_ses_lock);
        return NULL;
 }
 
+static void
+cifs_put_tcon(struct cifsTconInfo *tcon)
+{
+       int xid;
+       struct cifsSesInfo *ses = tcon->ses;
+
+       write_lock(&cifs_tcp_ses_lock);
+       if (--tcon->tc_count > 0) {
+               write_unlock(&cifs_tcp_ses_lock);
+               return;
+       }
+
+       list_del_init(&tcon->tcon_list);
+       write_unlock(&cifs_tcp_ses_lock);
+
+       xid = GetXid();
+       CIFSSMBTDis(xid, tcon);
+       _FreeXid(xid);
+
+       DeleteTconOplockQEntries(tcon);
+       tconInfoFree(tcon);
+       cifs_put_smb_ses(ses);
+}
+
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
             const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -1876,14 +1943,90 @@ convert_delimiter(char *path, char delim)
        }
 }
 
-static void
-kill_cifsd(struct TCP_Server_Info *server)
+static void setup_cifs_sb(struct smb_vol *pvolume_info,
+                         struct cifs_sb_info *cifs_sb)
 {
-       struct task_struct *task;
-
-       task = xchg(&server->tsk, NULL);
-       if (task)
-               force_sig(SIGKILL, task);
+       if (pvolume_info->rsize > CIFSMaxBufSize) {
+               cERROR(1, ("rsize %d too large, using MaxBufSize",
+                       pvolume_info->rsize));
+               cifs_sb->rsize = CIFSMaxBufSize;
+       } else if ((pvolume_info->rsize) &&
+                       (pvolume_info->rsize <= CIFSMaxBufSize))
+               cifs_sb->rsize = pvolume_info->rsize;
+       else /* default */
+               cifs_sb->rsize = CIFSMaxBufSize;
+
+       if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+               cERROR(1, ("wsize %d too large, using 4096 instead",
+                         pvolume_info->wsize));
+               cifs_sb->wsize = 4096;
+       } else if (pvolume_info->wsize)
+               cifs_sb->wsize = pvolume_info->wsize;
+       else
+               cifs_sb->wsize = min_t(const int,
+                                       PAGEVEC_SIZE * PAGE_CACHE_SIZE,
+                                       127*1024);
+               /* old default of CIFSMaxBufSize was too small now
+                  that SMB Write2 can send multiple pages in kvec.
+                  RFC1001 does not describe what happens when frame
+                  bigger than 128K is sent so use that as max in
+                  conjunction with 52K kvec constraint on arch with 4K
+                  page size  */
+
+       if (cifs_sb->rsize < 2048) {
+               cifs_sb->rsize = 2048;
+               /* Windows ME may prefer this */
+               cFYI(1, ("readsize set to minimum: 2048"));
+       }
+       /* calculate prepath */
+       cifs_sb->prepath = pvolume_info->prepath;
+       if (cifs_sb->prepath) {
+               cifs_sb->prepathlen = strlen(cifs_sb->prepath);
+               /* we can not convert the / to \ in the path
+               separators in the prefixpath yet because we do not
+               know (until reset_cifs_unix_caps is called later)
+               whether POSIX PATH CAP is available. We normalize
+               the / to \ after reset_cifs_unix_caps is called */
+               pvolume_info->prepath = NULL;
+       } else
+               cifs_sb->prepathlen = 0;
+       cifs_sb->mnt_uid = pvolume_info->linux_uid;
+       cifs_sb->mnt_gid = pvolume_info->linux_gid;
+       cifs_sb->mnt_file_mode = pvolume_info->file_mode;
+       cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
+       cFYI(1, ("file mode: 0x%x  dir mode: 0x%x",
+               cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
+
+       if (pvolume_info->noperm)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
+       if (pvolume_info->setuids)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
+       if (pvolume_info->server_ino)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+       if (pvolume_info->remap)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+       if (pvolume_info->no_xattr)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+       if (pvolume_info->sfu_emul)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+       if (pvolume_info->nobrl)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+       if (pvolume_info->cifs_acl)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
+       if (pvolume_info->override_uid)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+       if (pvolume_info->override_gid)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+       if (pvolume_info->dynperm)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+       if (pvolume_info->direct_io) {
+               cFYI(1, ("mounting share using direct i/o"));
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
+       }
+
+       if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
+               cERROR(1, ("mount option dynperm ignored if cifsacl "
+                          "mount option supported"));
 }
 
 int
@@ -1892,13 +2035,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 {
        int rc = 0;
        int xid;
-       int address_type = AF_INET;
        struct socket *csocket = NULL;
-       struct sockaddr_in sin_server;
-       struct sockaddr_in6 sin_server6;
+       struct sockaddr addr;
+       struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
+       struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
        struct smb_vol volume_info;
        struct cifsSesInfo *pSesInfo = NULL;
-       struct cifsSesInfo *existingCifsSes = NULL;
        struct cifsTconInfo *tcon = NULL;
        struct TCP_Server_Info *srvTcp = NULL;
 
@@ -1906,6 +2048,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
 
+       memset(&addr, 0, sizeof(struct sockaddr));
        memset(&volume_info, 0, sizeof(struct smb_vol));
        if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
                rc = -EINVAL;
@@ -1928,16 +2071,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
        if (volume_info.UNCip && volume_info.UNC) {
                rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
-                                   &sin_server.sin_addr.s_addr);
+                                   &sin_server->sin_addr.s_addr);
 
                if (rc <= 0) {
                        /* not ipv4 address, try ipv6 */
                        rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
-                                           &sin_server6.sin6_addr.in6_u);
+                                           &sin_server6->sin6_addr.in6_u);
                        if (rc > 0)
-                               address_type = AF_INET6;
+                               addr.sa_family = AF_INET6;
                } else {
-                       address_type = AF_INET;
+                       addr.sa_family = AF_INET;
                }
 
                if (rc <= 0) {
@@ -1977,41 +2120,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                }
        }
 
-       if (address_type == AF_INET)
-               existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
-                       NULL /* no ipv6 addr */,
-                       volume_info.username, &srvTcp);
-       else if (address_type == AF_INET6) {
-               cFYI(1, ("looking for ipv6 address"));
-               existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
-                       &sin_server6.sin6_addr,
-                       volume_info.username, &srvTcp);
-       } else {
-               rc = -EINVAL;
-               goto out;
-       }
-
-       if (srvTcp) {
-               cFYI(1, ("Existing tcp session with server found"));
-       } else {        /* create socket */
-               if (volume_info.port)
-                       sin_server.sin_port = htons(volume_info.port);
-               else
-                       sin_server.sin_port = 0;
-               if (address_type == AF_INET6) {
+       srvTcp = cifs_find_tcp_session(&addr);
+       if (!srvTcp) { /* create socket */
+               if (addr.sa_family == AF_INET6) {
                        cFYI(1, ("attempting ipv6 connect"));
                        /* BB should we allow ipv6 on port 139? */
                        /* other OS never observed in Wild doing 139 with v6 */
-                       rc = ipv6_connect(&sin_server6, &csocket,
+                       sin_server6->sin6_port = htons(volume_info.port);
+                       rc = ipv6_connect(sin_server6, &csocket,
                                        volume_info.noblocksnd);
-               } else
-                       rc = ipv4_connect(&sin_server, &csocket,
+               } else {
+                       sin_server->sin_port = htons(volume_info.port);
+                       rc = ipv4_connect(sin_server, &csocket,
                                  volume_info.source_rfc1001_name,
                                  volume_info.target_rfc1001_name,
                                  volume_info.noblocksnd,
                                  volume_info.noautotune);
+               }
                if (rc < 0) {
-                       cERROR(1, ("Error connecting to IPv4 socket. "
+                       cERROR(1, ("Error connecting to socket. "
                                   "Aborting operation"));
                        if (csocket != NULL)
                                sock_release(csocket);
@@ -2026,12 +2153,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                } else {
                        srvTcp->noblocksnd = volume_info.noblocksnd;
                        srvTcp->noautotune = volume_info.noautotune;
-                       memcpy(&srvTcp->addr.sockAddr, &sin_server,
-                               sizeof(struct sockaddr_in));
+                       if (addr.sa_family == AF_INET6)
+                               memcpy(&srvTcp->addr.sockAddr6, sin_server6,
+                                       sizeof(struct sockaddr_in6));
+                       else
+                               memcpy(&srvTcp->addr.sockAddr, sin_server,
+                                       sizeof(struct sockaddr_in));
                        atomic_set(&srvTcp->inFlight, 0);
                        /* BB Add code for ipv6 case too */
                        srvTcp->ssocket = csocket;
-                       srvTcp->protocolType = IPV4;
                        srvTcp->hostname = extract_hostname(volume_info.UNC);
                        if (IS_ERR(srvTcp->hostname)) {
                                rc = PTR_ERR(srvTcp->hostname);
@@ -2061,15 +2191,28 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        memcpy(srvTcp->server_RFC1001_name,
                                volume_info.target_rfc1001_name, 16);
                        srvTcp->sequence_number = 0;
+                       INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
+                       INIT_LIST_HEAD(&srvTcp->smb_ses_list);
+                       ++srvTcp->srv_count;
+                       write_lock(&cifs_tcp_ses_lock);
+                       list_add(&srvTcp->tcp_ses_list,
+                                &cifs_tcp_ses_list);
+                       write_unlock(&cifs_tcp_ses_lock);
                }
        }
 
-       if (existingCifsSes) {
-               pSesInfo = existingCifsSes;
+       pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
+       if (pSesInfo) {
                cFYI(1, ("Existing smb sess found (status=%d)",
                        pSesInfo->status));
+               /*
+                * The existing SMB session already has a reference to srvTcp,
+                * so we can put back the extra one we got before
+                */
+               cifs_put_tcp_session(srvTcp);
+
                down(&pSesInfo->sesSem);
-               if (pSesInfo->status == CifsNeedReconnect) {
+               if (pSesInfo->need_reconnect) {
                        cFYI(1, ("Session needs reconnect"));
                        rc = cifs_setup_session(xid, pSesInfo,
                                                cifs_sb->local_nls);
@@ -2078,187 +2221,101 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        } else if (!rc) {
                cFYI(1, ("Existing smb sess not found"));
                pSesInfo = sesInfoAlloc();
-               if (pSesInfo == NULL)
+               if (pSesInfo == NULL) {
                        rc = -ENOMEM;
-               else {
-                       pSesInfo->server = srvTcp;
-                       sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
-                               NIPQUAD(sin_server.sin_addr.s_addr));
-               }
+                       goto mount_fail_check;
+               }
+
+               /* new SMB session uses our srvTcp ref */
+               pSesInfo->server = srvTcp;
+               sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
+                       NIPQUAD(sin_server->sin_addr.s_addr));
+
+               write_lock(&cifs_tcp_ses_lock);
+               list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
+               write_unlock(&cifs_tcp_ses_lock);
+
+               /* volume_info.password freed at unmount */
+               if (volume_info.password) {
+                       pSesInfo->password = volume_info.password;
+                       /* set to NULL to prevent freeing on exit */
+                       volume_info.password = NULL;
+               }
+               if (volume_info.username)
+                       strncpy(pSesInfo->userName, volume_info.username,
+                               MAX_USERNAME_SIZE);
+               if (volume_info.domainname) {
+                       int len = strlen(volume_info.domainname);
+                       pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
+                       if (pSesInfo->domainName)
+                               strcpy(pSesInfo->domainName,
+                                       volume_info.domainname);
+               }
+               pSesInfo->linux_uid = volume_info.linux_uid;
+               pSesInfo->overrideSecFlg = volume_info.secFlg;
+               down(&pSesInfo->sesSem);
 
-               if (!rc) {
-                       /* volume_info.password freed at unmount */
-                       if (volume_info.password) {
-                               pSesInfo->password = volume_info.password;
-                               /* set to NULL to prevent freeing on exit */
-                               volume_info.password = NULL;
-                       }
-                       if (volume_info.username)
-                               strncpy(pSesInfo->userName,
-                                       volume_info.username,
-                                       MAX_USERNAME_SIZE);
-                       if (volume_info.domainname) {
-                               int len = strlen(volume_info.domainname);
-                               pSesInfo->domainName =
-                                       kmalloc(len + 1, GFP_KERNEL);
-                               if (pSesInfo->domainName)
-                                       strcpy(pSesInfo->domainName,
-                                               volume_info.domainname);
-                       }
-                       pSesInfo->linux_uid = volume_info.linux_uid;
-                       pSesInfo->overrideSecFlg = volume_info.secFlg;
-                       down(&pSesInfo->sesSem);
-                       /* BB FIXME need to pass vol->secFlgs BB */
-                       rc = cifs_setup_session(xid, pSesInfo,
-                                               cifs_sb->local_nls);
-                       up(&pSesInfo->sesSem);
-                       if (!rc)
-                               atomic_inc(&srvTcp->socketUseCount);
-               }
+               /* BB FIXME need to pass vol->secFlgs BB */
+               rc = cifs_setup_session(xid, pSesInfo,
+                                       cifs_sb->local_nls);
+               up(&pSesInfo->sesSem);
        }
 
        /* search for existing tcon to this server share */
        if (!rc) {
-               if (volume_info.rsize > CIFSMaxBufSize) {
-                       cERROR(1, ("rsize %d too large, using MaxBufSize",
-                               volume_info.rsize));
-                       cifs_sb->rsize = CIFSMaxBufSize;
-               } else if ((volume_info.rsize) &&
-                               (volume_info.rsize <= CIFSMaxBufSize))
-                       cifs_sb->rsize = volume_info.rsize;
-               else /* default */
-                       cifs_sb->rsize = CIFSMaxBufSize;
-
-               if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
-                       cERROR(1, ("wsize %d too large, using 4096 instead",
-                                 volume_info.wsize));
-                       cifs_sb->wsize = 4096;
-               } else if (volume_info.wsize)
-                       cifs_sb->wsize = volume_info.wsize;
-               else
-                       cifs_sb->wsize =
-                               min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
-                                       127*1024);
-                       /* old default of CIFSMaxBufSize was too small now
-                          that SMB Write2 can send multiple pages in kvec.
-                          RFC1001 does not describe what happens when frame
-                          bigger than 128K is sent so use that as max in
-                          conjunction with 52K kvec constraint on arch with 4K
-                          page size  */
-
-               if (cifs_sb->rsize < 2048) {
-                       cifs_sb->rsize = 2048;
-                       /* Windows ME may prefer this */
-                       cFYI(1, ("readsize set to minimum: 2048"));
-               }
-               /* calculate prepath */
-               cifs_sb->prepath = volume_info.prepath;
-               if (cifs_sb->prepath) {
-                       cifs_sb->prepathlen = strlen(cifs_sb->prepath);
-                       /* we can not convert the / to \ in the path
-                       separators in the prefixpath yet because we do not
-                       know (until reset_cifs_unix_caps is called later)
-                       whether POSIX PATH CAP is available. We normalize
-                       the / to \ after reset_cifs_unix_caps is called */
-                       volume_info.prepath = NULL;
-               } else
-                       cifs_sb->prepathlen = 0;
-               cifs_sb->mnt_uid = volume_info.linux_uid;
-               cifs_sb->mnt_gid = volume_info.linux_gid;
-               cifs_sb->mnt_file_mode = volume_info.file_mode;
-               cifs_sb->mnt_dir_mode = volume_info.dir_mode;
-               cFYI(1, ("file mode: 0x%x  dir mode: 0x%x",
-                       cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
-
-               if (volume_info.noperm)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
-               if (volume_info.setuids)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
-               if (volume_info.server_ino)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
-               if (volume_info.remap)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
-               if (volume_info.no_xattr)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
-               if (volume_info.sfu_emul)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
-               if (volume_info.nobrl)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
-               if (volume_info.cifs_acl)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
-               if (volume_info.override_uid)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
-               if (volume_info.override_gid)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
-               if (volume_info.dynperm)
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
-               if (volume_info.direct_io) {
-                       cFYI(1, ("mounting share using direct i/o"));
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
-               }
+               setup_cifs_sb(&volume_info, cifs_sb);
 
-               if ((volume_info.cifs_acl) && (volume_info.dynperm))
-                       cERROR(1, ("mount option dynperm ignored if cifsacl "
-                                  "mount option supported"));
-
-               tcon =
-                   find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
-                            volume_info.username);
+               tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
                if (tcon) {
                        cFYI(1, ("Found match on UNC path"));
-                       /* we can have only one retry value for a connection
-                          to a share so for resources mounted more than once
-                          to the same server share the last value passed in
-                          for the retry flag is used */
-                       tcon->retry = volume_info.retry;
-                       tcon->nocase = volume_info.nocase;
-                       tcon->local_lease = volume_info.local_lease;
+                       /* existing tcon already has a reference */
+                       cifs_put_smb_ses(pSesInfo);
                        if (tcon->seal != volume_info.seal)
                                cERROR(1, ("transport encryption setting "
                                           "conflicts with existing tid"));
                } else {
                        tcon = tconInfoAlloc();
-                       if (tcon == NULL)
+                       if (tcon == NULL) {
                                rc = -ENOMEM;
-                       else {
-                               /* check for null share name ie connecting to
-                                * dfs root */
-
-                               /* BB check if this works for exactly length
-                                * three strings */
-                               if ((strchr(volume_info.UNC + 3, '\\') == NULL)
-                                   && (strchr(volume_info.UNC + 3, '/') ==
-                                       NULL)) {
-/*                                     rc = connect_to_dfs_path(xid, pSesInfo,
-                                               "", cifs_sb->local_nls,
-                                               cifs_sb->mnt_cifs_flags &
-                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
-                                       cFYI(1, ("DFS root not supported"));
-                                       rc = -ENODEV;
-                                       goto out;
-                               } else {
-                                       /* BB Do we need to wrap sesSem around
-                                        * this TCon call and Unix SetFS as
-                                        * we do on SessSetup and reconnect? */
-                                       rc = CIFSTCon(xid, pSesInfo,
-                                               volume_info.UNC,
-                                               tcon, cifs_sb->local_nls);
-                                       cFYI(1, ("CIFS Tcon rc = %d", rc));
-                                       if (volume_info.nodfs) {
-                                               tcon->Flags &=
-                                                       ~SMB_SHARE_IS_IN_DFS;
-                                               cFYI(1, ("DFS disabled (%d)",
-                                                       tcon->Flags));
-                                       }
-                               }
-                               if (!rc) {
-                                       atomic_inc(&pSesInfo->inUse);
-                                       tcon->retry = volume_info.retry;
-                                       tcon->nocase = volume_info.nocase;
-                                       tcon->seal = volume_info.seal;
+                               goto mount_fail_check;
+                       }
+                       tcon->ses = pSesInfo;
+
+                       /* check for null share name ie connect to dfs root */
+                       if ((strchr(volume_info.UNC + 3, '\\') == NULL)
+                           && (strchr(volume_info.UNC + 3, '/') == NULL)) {
+                               /* rc = connect_to_dfs_path(...) */
+                               cFYI(1, ("DFS root not supported"));
+                               rc = -ENODEV;
+                               goto mount_fail_check;
+                       } else {
+                               /* BB Do we need to wrap sesSem around
+                                * this TCon call and Unix SetFS as
+                                * we do on SessSetup and reconnect? */
+                               rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
+                                             tcon, cifs_sb->local_nls);
+                               cFYI(1, ("CIFS Tcon rc = %d", rc));
+                               if (volume_info.nodfs) {
+                                       tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
+                                       cFYI(1, ("DFS disabled (%d)",
+                                               tcon->Flags));
                                }
                        }
-               }
+                       if (rc)
+                               goto mount_fail_check;
+                       tcon->seal = volume_info.seal;
+                       write_lock(&cifs_tcp_ses_lock);
+                       list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
+                       write_unlock(&cifs_tcp_ses_lock);
+               }
+
+               /* we can have only one retry value for a connection
+                  to a share so for resources mounted more than once
+                  to the same server share the last value passed in
+                  for the retry flag is used */
+               tcon->retry = volume_info.retry;
+               tcon->nocase = volume_info.nocase;
+               tcon->local_lease = volume_info.local_lease;
        }
        if (pSesInfo) {
                if (pSesInfo->capabilities & CAP_LARGE_FILES) {
@@ -2270,80 +2327,49 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        /* BB FIXME fix time_gran to be larger for LANMAN sessions */
        sb->s_time_gran = 100;
 
-/* on error free sesinfo and tcon struct if needed */
+mount_fail_check:
+       /* on error free sesinfo and tcon struct if needed */
        if (rc) {
-               /* if session setup failed, use count is zero but
-               we still need to free cifsd thread */
-               if (atomic_read(&srvTcp->socketUseCount) == 0) {
-                       spin_lock(&GlobalMid_Lock);
-                       srvTcp->tcpStatus = CifsExiting;
-                       spin_unlock(&GlobalMid_Lock);
-                       kill_cifsd(srvTcp);
-               }
-                /* If find_unc succeeded then rc == 0 so we can not end */
-               if (tcon)  /* up accidently freeing someone elses tcon struct */
-                       tconInfoFree(tcon);
-               if (existingCifsSes == NULL) {
-                       if (pSesInfo) {
-                               if ((pSesInfo->server) &&
-                                   (pSesInfo->status == CifsGood)) {
-                                       int temp_rc;
-                                       temp_rc = CIFSSMBLogoff(xid, pSesInfo);
-                                       /* if the socketUseCount is now zero */
-                                       if ((temp_rc == -ESHUTDOWN) &&
-                                           (pSesInfo->server))
-                                               kill_cifsd(pSesInfo->server);
-                               } else {
-                                       cFYI(1, ("No session or bad tcon"));
-                                       if (pSesInfo->server) {
-                                               spin_lock(&GlobalMid_Lock);
-                                               srvTcp->tcpStatus = CifsExiting;
-                                               spin_unlock(&GlobalMid_Lock);
-                                               kill_cifsd(pSesInfo->server);
-                                       }
-                               }
-                               sesInfoFree(pSesInfo);
-                               /* pSesInfo = NULL; */
-                       }
-               }
-       } else {
-               atomic_inc(&tcon->useCount);
-               cifs_sb->tcon = tcon;
-               tcon->ses = pSesInfo;
-
-               /* do not care if following two calls succeed - informational */
-               if (!tcon->ipc) {
-                       CIFSSMBQFSDeviceInfo(xid, tcon);
-                       CIFSSMBQFSAttributeInfo(xid, tcon);
-               }
-
-               /* tell server which Unix caps we support */
-               if (tcon->ses->capabilities & CAP_UNIX)
-                       /* reset of caps checks mount to see if unix extensions
-                          disabled for just this mount */
-                       reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
+               /* If find_unc succeeded then rc == 0 so we can not end */
+               /* up accidently freeing someone elses tcon struct */
+               if (tcon)
+                       cifs_put_tcon(tcon);
+               else if (pSesInfo)
+                       cifs_put_smb_ses(pSesInfo);
                else
-                       tcon->unix_ext = 0; /* server does not support them */
+                       cifs_put_tcp_session(srvTcp);
+               goto out;
+       }
+       cifs_sb->tcon = tcon;
 
-               /* convert forward to back slashes in prepath here if needed */
-               if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
-                       convert_delimiter(cifs_sb->prepath,
-                                         CIFS_DIR_SEP(cifs_sb));
+       /* do not care if following two calls succeed - informational */
+       if (!tcon->ipc) {
+               CIFSSMBQFSDeviceInfo(xid, tcon);
+               CIFSSMBQFSAttributeInfo(xid, tcon);
+       }
 
-               if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
-                       cifs_sb->rsize = 1024 * 127;
-                       cFYI(DBG2,
-                               ("no very large read support, rsize now 127K"));
-               }
-               if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
-                       cifs_sb->wsize = min(cifs_sb->wsize,
-                                            (tcon->ses->server->maxBuf -
-                                             MAX_CIFS_HDR_SIZE));
-               if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
-                       cifs_sb->rsize = min(cifs_sb->rsize,
-                                            (tcon->ses->server->maxBuf -
-                                             MAX_CIFS_HDR_SIZE));
+       /* tell server which Unix caps we support */
+       if (tcon->ses->capabilities & CAP_UNIX)
+               /* reset of caps checks mount to see if unix extensions
+                  disabled for just this mount */
+               reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
+       else
+               tcon->unix_ext = 0; /* server does not support them */
+
+       /* convert forward to back slashes in prepath here if needed */
+       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
+               convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
+
+       if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
+               cifs_sb->rsize = 1024 * 127;
+               cFYI(DBG2, ("no very large read support, rsize now 127K"));
        }
+       if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+               cifs_sb->wsize = min(cifs_sb->wsize,
+                              (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
+       if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+               cifs_sb->rsize = min(cifs_sb->rsize,
+                              (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
 
        /* volume_info.password is freed above when existing session found
        (in which case it is not needed anymore) but when new sesion is created
@@ -3513,6 +3539,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        /* above now done in SendReceive */
        if ((rc == 0) && (tcon != NULL)) {
                tcon->tidStatus = CifsGood;
+               tcon->need_reconnect = false;
                tcon->tid = smb_buffer_response->Tid;
                bcc_ptr = pByteArea(smb_buffer_response);
                length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
@@ -3584,48 +3611,17 @@ int
 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 {
        int rc = 0;
-       int xid;
-       struct cifsSesInfo *ses = NULL;
        char *tmp;
 
-       xid = GetXid();
-
-       if (cifs_sb->tcon) {
-               ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
-               rc = CIFSSMBTDis(xid, cifs_sb->tcon);
-               if (rc == -EBUSY) {
-                       FreeXid(xid);
-                       return 0;
-               }
-               DeleteTconOplockQEntries(cifs_sb->tcon);
-               tconInfoFree(cifs_sb->tcon);
-               if ((ses) && (ses->server)) {
-                       /* save off task so we do not refer to ses later */
-                       cFYI(1, ("About to do SMBLogoff "));
-                       rc = CIFSSMBLogoff(xid, ses);
-                       if (rc == -EBUSY) {
-                               FreeXid(xid);
-                               return 0;
-                       } else if (rc == -ESHUTDOWN) {
-                               cFYI(1, ("Waking up socket by sending signal"));
-                               if (ses->server)
-                                       kill_cifsd(ses->server);
-                               rc = 0;
-                       } /* else - we have an smb session
-                               left on this socket do not kill cifsd */
-               } else
-                       cFYI(1, ("No session or bad tcon"));
-       }
+       if (cifs_sb->tcon)
+               cifs_put_tcon(cifs_sb->tcon);
 
        cifs_sb->tcon = NULL;
        tmp = cifs_sb->prepath;
        cifs_sb->prepathlen = 0;
        cifs_sb->prepath = NULL;
        kfree(tmp);
-       if (ses)
-               sesInfoFree(ses);
 
-       FreeXid(xid);
        return rc;
 }
 
@@ -3741,6 +3737,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                cFYI(1, ("CIFS Session Established successfully"));
                        spin_lock(&GlobalMid_Lock);
                        pSesInfo->status = CifsGood;
+                       pSesInfo->need_reconnect = false;
                        spin_unlock(&GlobalMid_Lock);
        }
 
index ead1a3bb02564722f98e3f93aa068ade04022503..6449e1aae621aa2721a1f5a5bd12338ac2890b6c 100644 (file)
@@ -493,7 +493,7 @@ int cifs_close(struct inode *inode, struct file *file)
                if (pTcon) {
                        /* no sense reconnecting to close a file that is
                           already closed */
-                       if (pTcon->tidStatus != CifsNeedReconnect) {
+                       if (!pTcon->need_reconnect) {
                                timeout = 2;
                                while ((atomic_read(&pSMBFile->wrtPending) != 0)
                                        && (timeout <= 2048)) {
@@ -1404,7 +1404,10 @@ retry:
                        if ((wbc->nr_to_write -= n_iov) <= 0)
                                done = 1;
                        index = next;
-               }
+               } else
+                       /* Need to re-find the pages we skipped */
+                       index = pvec.pages[0]->index + 1;
+
                pagevec_release(&pvec);
        }
        if (!scanned && !done) {
index 88786ba02d277fac25923893c29bb96206e42827..addd1dcc2d79513ab6404e6a530d6927cbe71eee 100644 (file)
@@ -75,12 +75,12 @@ sesInfoAlloc(void)
 
        ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
        if (ret_buf) {
-               write_lock(&GlobalSMBSeslock);
                atomic_inc(&sesInfoAllocCount);
                ret_buf->status = CifsNew;
-               list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
+               ++ret_buf->ses_count;
+               INIT_LIST_HEAD(&ret_buf->smb_ses_list);
+               INIT_LIST_HEAD(&ret_buf->tcon_list);
                init_MUTEX(&ret_buf->sesSem);
-               write_unlock(&GlobalSMBSeslock);
        }
        return ret_buf;
 }
@@ -93,10 +93,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
                return;
        }
 
-       write_lock(&GlobalSMBSeslock);
        atomic_dec(&sesInfoAllocCount);
-       list_del(&buf_to_free->cifsSessionList);
-       write_unlock(&GlobalSMBSeslock);
        kfree(buf_to_free->serverOS);
        kfree(buf_to_free->serverDomain);
        kfree(buf_to_free->serverNOS);
@@ -111,17 +108,14 @@ tconInfoAlloc(void)
        struct cifsTconInfo *ret_buf;
        ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
        if (ret_buf) {
-               write_lock(&GlobalSMBSeslock);
                atomic_inc(&tconInfoAllocCount);
-               list_add(&ret_buf->cifsConnectionList,
-                        &GlobalTreeConnectionList);
                ret_buf->tidStatus = CifsNew;
+               ++ret_buf->tc_count;
                INIT_LIST_HEAD(&ret_buf->openFileList);
-               init_MUTEX(&ret_buf->tconSem);
+               INIT_LIST_HEAD(&ret_buf->tcon_list);
 #ifdef CONFIG_CIFS_STATS
                spin_lock_init(&ret_buf->stat_lock);
 #endif
-               write_unlock(&GlobalSMBSeslock);
        }
        return ret_buf;
 }
@@ -133,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
                cFYI(1, ("Null buffer passed to tconInfoFree"));
                return;
        }
-       write_lock(&GlobalSMBSeslock);
        atomic_dec(&tconInfoAllocCount);
-       list_del(&buf_to_free->cifsConnectionList);
-       write_unlock(&GlobalSMBSeslock);
        kfree(buf_to_free->nativeFileSystem);
        kfree(buf_to_free);
 }
@@ -350,9 +341,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                                if (current->fsuid != treeCon->ses->linux_uid) {
                                        cFYI(1, ("Multiuser mode and UID "
                                                 "did not match tcon uid"));
-                                       read_lock(&GlobalSMBSeslock);
-                                       list_for_each(temp_item, &GlobalSMBSessionList) {
-                                               ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
+                                       read_lock(&cifs_tcp_ses_lock);
+                                       list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
+                                               ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
                                                if (ses->linux_uid == current->fsuid) {
                                                        if (ses->server == treeCon->ses->server) {
                                                                cFYI(1, ("found matching uid substitute right smb_uid"));
@@ -364,7 +355,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                                                        }
                                                }
                                        }
-                                       read_unlock(&GlobalSMBSeslock);
+                                       read_unlock(&cifs_tcp_ses_lock);
                                }
                        }
                }
@@ -497,9 +488,10 @@ bool
 is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 {
        struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
-       struct list_head *tmp;
-       struct list_head *tmp1;
+       struct list_head *tmp, *tmp1, *tmp2;
+       struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
+       struct cifsInodeInfo *pCifsInode;
        struct cifsFileInfo *netfile;
 
        cFYI(1, ("Checking for oplock break or dnotify response"));
@@ -554,42 +546,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                return false;
 
        /* look up tcon based on tid & uid */
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalTreeConnectionList) {
-               tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &srv->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               list_for_each(tmp1, &ses->tcon_list) {
+                       tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
+                       if (tcon->tid != buf->Tid)
+                               continue;
+
                        cifs_stats_inc(&tcon->num_oplock_brks);
-                       list_for_each(tmp1, &tcon->openFileList) {
-                               netfile = list_entry(tmp1, struct cifsFileInfo,
+                       list_for_each(tmp2, &tcon->openFileList) {
+                               netfile = list_entry(tmp2, struct cifsFileInfo,
                                                     tlist);
-                               if (pSMB->Fid == netfile->netfid) {
-                                       struct cifsInodeInfo *pCifsInode;
-                                       read_unlock(&GlobalSMBSeslock);
-                                       cFYI(1,
-                                           ("file id match, oplock break"));
-                                       pCifsInode =
-                                               CIFS_I(netfile->pInode);
-                                       pCifsInode->clientCanCacheAll = false;
-                                       if (pSMB->OplockLevel == 0)
-                                               pCifsInode->clientCanCacheRead
-                                                       = false;
-                                       pCifsInode->oplockPending = true;
-                                       AllocOplockQEntry(netfile->pInode,
-                                                         netfile->netfid,
-                                                         tcon);
-                                       cFYI(1,
-                                           ("about to wake up oplock thread"));
-                                       if (oplockThread)
-                                           wake_up_process(oplockThread);
-                                       return true;
-                               }
+                               if (pSMB->Fid != netfile->netfid)
+                                       continue;
+
+                               read_unlock(&cifs_tcp_ses_lock);
+                               cFYI(1, ("file id match, oplock break"));
+                               pCifsInode = CIFS_I(netfile->pInode);
+                               pCifsInode->clientCanCacheAll = false;
+                               if (pSMB->OplockLevel == 0)
+                                       pCifsInode->clientCanCacheRead = false;
+                               pCifsInode->oplockPending = true;
+                               AllocOplockQEntry(netfile->pInode,
+                                                 netfile->netfid, tcon);
+                               cFYI(1, ("about to wake up oplock thread"));
+                               if (oplockThread)
+                                       wake_up_process(oplockThread);
+
+                               return true;
                        }
-                       read_unlock(&GlobalSMBSeslock);
+                       read_unlock(&cifs_tcp_ses_lock);
                        cFYI(1, ("No matching file for oplock break"));
                        return true;
                }
        }
-       read_unlock(&GlobalSMBSeslock);
+       read_unlock(&cifs_tcp_ses_lock);
        cFYI(1, ("Can not process oplock break for non-existent connection"));
        return true;
 }
index d910501de6d2ca9d4fc8ed1a1cda8d9a1aca1519..8d86b7960f0df7527fed5494230676b137b4f63b 100644 (file)
@@ -812,7 +812,7 @@ int dlm_release_lockspace(void *lockspace, int force)
        error = release_lockspace(ls, force);
        if (!error)
                ls_count--;
-       else if (!ls_count)
+       if (!ls_count)
                threads_stop();
        mutex_unlock(&ls_lock);
 
index e22bc39613458e98fe35169b4de06412d9a4ec3f..0d713b6919411375b4831c4e8c0f89419dfbd767 100644 (file)
@@ -1037,17 +1037,14 @@ static int
 decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                                         struct ecryptfs_crypt_stat *crypt_stat)
 {
-       struct scatterlist dst_sg;
-       struct scatterlist src_sg;
+       struct scatterlist dst_sg[2];
+       struct scatterlist src_sg[2];
        struct mutex *tfm_mutex;
        struct blkcipher_desc desc = {
                .flags = CRYPTO_TFM_REQ_MAY_SLEEP
        };
        int rc = 0;
 
-       sg_init_table(&dst_sg, 1);
-       sg_init_table(&src_sg, 1);
-
        if (unlikely(ecryptfs_verbosity > 0)) {
                ecryptfs_printk(
                        KERN_DEBUG, "Session key encryption key (size [%d]):\n",
@@ -1066,8 +1063,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        }
        rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
                                 auth_tok->session_key.encrypted_key_size,
-                                &src_sg, 1);
-       if (rc != 1) {
+                                src_sg, 2);
+       if (rc < 1 || rc > 2) {
                printk(KERN_ERR "Internal error whilst attempting to convert "
                        "auth_tok->session_key.encrypted_key to scatterlist; "
                        "expected rc = 1; got rc = [%d]. "
@@ -1079,8 +1076,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                auth_tok->session_key.encrypted_key_size;
        rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
                                 auth_tok->session_key.decrypted_key_size,
-                                &dst_sg, 1);
-       if (rc != 1) {
+                                dst_sg, 2);
+       if (rc < 1 || rc > 2) {
                printk(KERN_ERR "Internal error whilst attempting to convert "
                        "auth_tok->session_key.decrypted_key to scatterlist; "
                        "expected rc = 1; got rc = [%d]\n", rc);
@@ -1096,7 +1093,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                rc = -EINVAL;
                goto out;
        }
-       rc = crypto_blkcipher_decrypt(&desc, &dst_sg, &src_sg,
+       rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg,
                                      auth_tok->session_key.encrypted_key_size);
        mutex_unlock(tfm_mutex);
        if (unlikely(rc)) {
@@ -1539,8 +1536,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
        size_t i;
        size_t encrypted_session_key_valid = 0;
        char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
-       struct scatterlist dst_sg;
-       struct scatterlist src_sg;
+       struct scatterlist dst_sg[2];
+       struct scatterlist src_sg[2];
        struct mutex *tfm_mutex = NULL;
        u8 cipher_code;
        size_t packet_size_length;
@@ -1619,8 +1616,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
                ecryptfs_dump_hex(session_key_encryption_key, 16);
        }
        rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,
-                                &src_sg, 1);
-       if (rc != 1) {
+                                src_sg, 2);
+       if (rc < 1 || rc > 2) {
                ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
                                "for crypt_stat session key; expected rc = 1; "
                                "got rc = [%d]. key_rec->enc_key_size = [%d]\n",
@@ -1629,8 +1626,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
                goto out;
        }
        rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,
-                                &dst_sg, 1);
-       if (rc != 1) {
+                                dst_sg, 2);
+       if (rc < 1 || rc > 2) {
                ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
                                "for crypt_stat encrypted session key; "
                                "expected rc = 1; got rc = [%d]. "
@@ -1651,7 +1648,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
        rc = 0;
        ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
                        crypt_stat->key_size);
-       rc = crypto_blkcipher_encrypt(&desc, &dst_sg, &src_sg,
+       rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
                                      (*key_rec).enc_key_size);
        mutex_unlock(tfm_mutex);
        if (rc) {
index 5dec6d1356c4b07477bb40f68305c0d9de89258b..f6c94f232ec1e8fee05e47dfcc54b234c82e7cf0 100644 (file)
@@ -2375,12 +2375,9 @@ int ext3_force_commit(struct super_block *sb)
 /*
  * Ext3 always journals updates to the superblock itself, so we don't
  * have to propagate any other updates to the superblock on disk at this
- * point.  Just start an async writeback to get the buffers on their way
- * to the disk.
- *
- * This implicitly triggers the writebehind on sync().
+ * point.  (We can probably nuke this function altogether, and remove
+ * any mention to sb->s_dirt in all of fs/ext3; eventual cleanup...)
  */
-
 static void ext3_write_super (struct super_block * sb)
 {
        if (mutex_trylock(&sb->s_lock) != 0)
index 6ae9011b95eb4bbf2ea46f823497686bd1820e5a..2f34f8f2134b31b3082dab1087abd67de0594465 100644 (file)
@@ -81,7 +81,7 @@ extern int do_rmdir(const char *file);
 extern int do_mknod(const char *file, int mode, unsigned int major,
                    unsigned int minor);
 extern int link_file(const char *from, const char *to);
-extern int do_readlink(char *file, char *buf, int size);
+extern int hostfs_do_readlink(char *file, char *buf, int size);
 extern int rename_file(char *from, char *to);
 extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
                     long long *bfree_out, long long *bavail_out,
index 7f34f4385de00dbcca17d9d3bf7c45bd0aedc1d7..3a31451ac1704a86ef3d3b7ae9e9a73240ff29ad 100644 (file)
@@ -168,7 +168,7 @@ static char *follow_link(char *link)
                if (name == NULL)
                        goto out;
 
-               n = do_readlink(link, name, len);
+               n = hostfs_do_readlink(link, name, len);
                if (n < len)
                        break;
                len *= 2;
@@ -943,7 +943,7 @@ int hostfs_link_readpage(struct file *file, struct page *page)
        name = inode_name(page->mapping->host, 0);
        if (name == NULL)
                return -ENOMEM;
-       err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
+       err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
        kfree(name);
        if (err == PAGE_CACHE_SIZE)
                err = -E2BIG;
index 53fd0a67c11abf148a76cea7820a1a3c782adc26..b79424f9328298e60bdae763ffd85669d1d96214 100644 (file)
@@ -377,7 +377,7 @@ int link_file(const char *to, const char *from)
        return 0;
 }
 
-int do_readlink(char *file, char *buf, int size)
+int hostfs_do_readlink(char *file, char *buf, int size)
 {
        int n;
 
index 690e72595e6e6048addba645cf179cb418208f50..7bbed1b89825f8b37f4fa753201290d0002bf618 100644 (file)
@@ -106,6 +106,20 @@ void get_inotify_watch(struct inotify_watch *watch)
 }
 EXPORT_SYMBOL_GPL(get_inotify_watch);
 
+int pin_inotify_watch(struct inotify_watch *watch)
+{
+       struct super_block *sb = watch->inode->i_sb;
+       spin_lock(&sb_lock);
+       if (sb->s_count >= S_BIAS) {
+               atomic_inc(&sb->s_active);
+               spin_unlock(&sb_lock);
+               atomic_inc(&watch->count);
+               return 1;
+       }
+       spin_unlock(&sb_lock);
+       return 0;
+}
+
 /**
  * put_inotify_watch - decrements the ref count on a given watch.  cleans up
  * watch references if the count reaches zero.  inotify_watch is freed by
@@ -124,6 +138,13 @@ void put_inotify_watch(struct inotify_watch *watch)
 }
 EXPORT_SYMBOL_GPL(put_inotify_watch);
 
+void unpin_inotify_watch(struct inotify_watch *watch)
+{
+       struct super_block *sb = watch->inode->i_sb;
+       put_inotify_watch(watch);
+       deactivate_super(sb);
+}
+
 /*
  * inotify_handle_get_wd - returns the next WD for use by the given handle
  *
@@ -479,6 +500,112 @@ void inotify_init_watch(struct inotify_watch *watch)
 }
 EXPORT_SYMBOL_GPL(inotify_init_watch);
 
+/*
+ * Watch removals suck violently.  To kick the watch out we need (in this
+ * order) inode->inotify_mutex and ih->mutex.  That's fine if we have
+ * a hold on inode; however, for all other cases we need to make damn sure
+ * we don't race with umount.  We can *NOT* just grab a reference to a
+ * watch - inotify_unmount_inodes() will happily sail past it and we'll end
+ * with reference to inode potentially outliving its superblock.  Ideally
+ * we just want to grab an active reference to superblock if we can; that
+ * will make sure we won't go into inotify_umount_inodes() until we are
+ * done.  Cleanup is just deactivate_super().  However, that leaves a messy
+ * case - what if we *are* racing with umount() and active references to
+ * superblock can't be acquired anymore?  We can bump ->s_count, grab
+ * ->s_umount, which will almost certainly wait until the superblock is shut
+ * down and the watch in question is pining for fjords.  That's fine, but
+ * there is a problem - we might have hit the window between ->s_active
+ * getting to 0 / ->s_count - below S_BIAS (i.e. the moment when superblock
+ * is past the point of no return and is heading for shutdown) and the
+ * moment when deactivate_super() acquires ->s_umount.  We could just do
+ * drop_super() yield() and retry, but that's rather antisocial and this
+ * stuff is luser-triggerable.  OTOH, having grabbed ->s_umount and having
+ * found that we'd got there first (i.e. that ->s_root is non-NULL) we know
+ * that we won't race with inotify_umount_inodes().  So we could grab a
+ * reference to watch and do the rest as above, just with drop_super() instead
+ * of deactivate_super(), right?  Wrong.  We had to drop ih->mutex before we
+ * could grab ->s_umount.  So the watch could've been gone already.
+ *
+ * That still can be dealt with - we need to save watch->wd, do idr_find()
+ * and compare its result with our pointer.  If they match, we either have
+ * the damn thing still alive or we'd lost not one but two races at once,
+ * the watch had been killed and a new one got created with the same ->wd
+ * at the same address.  That couldn't have happened in inotify_destroy(),
+ * but inotify_rm_wd() could run into that.  Still, "new one got created"
+ * is not a problem - we have every right to kill it or leave it alone,
+ * whatever's more convenient.
+ *
+ * So we can use idr_find(...) == watch && watch->inode->i_sb == sb as
+ * "grab it and kill it" check.  If it's been our original watch, we are
+ * fine, if it's a newcomer - nevermind, just pretend that we'd won the
+ * race and kill the fscker anyway; we are safe since we know that its
+ * superblock won't be going away.
+ *
+ * And yes, this is far beyond mere "not very pretty"; so's the entire
+ * concept of inotify to start with.
+ */
+
+/**
+ * pin_to_kill - pin the watch down for removal
+ * @ih: inotify handle
+ * @watch: watch to kill
+ *
+ * Called with ih->mutex held, drops it.  Possible return values:
+ * 0 - nothing to do, it has died
+ * 1 - remove it, drop the reference and deactivate_super()
+ * 2 - remove it, drop the reference and drop_super(); we tried hard to avoid
+ * that variant, since it involved a lot of PITA, but that's the best that
+ * could've been done.
+ */
+static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch)
+{
+       struct super_block *sb = watch->inode->i_sb;
+       s32 wd = watch->wd;
+
+       spin_lock(&sb_lock);
+       if (sb->s_count >= S_BIAS) {
+               atomic_inc(&sb->s_active);
+               spin_unlock(&sb_lock);
+               get_inotify_watch(watch);
+               mutex_unlock(&ih->mutex);
+               return 1;       /* the best outcome */
+       }
+       sb->s_count++;
+       spin_unlock(&sb_lock);
+       mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */
+       down_read(&sb->s_umount);
+       if (likely(!sb->s_root)) {
+               /* fs is already shut down; the watch is dead */
+               drop_super(sb);
+               return 0;
+       }
+       /* raced with the final deactivate_super() */
+       mutex_lock(&ih->mutex);
+       if (idr_find(&ih->idr, wd) != watch || watch->inode->i_sb != sb) {
+               /* the watch is dead */
+               mutex_unlock(&ih->mutex);
+               drop_super(sb);
+               return 0;
+       }
+       /* still alive or freed and reused with the same sb and wd; kill */
+       get_inotify_watch(watch);
+       mutex_unlock(&ih->mutex);
+       return 2;
+}
+
+static void unpin_and_kill(struct inotify_watch *watch, int how)
+{
+       struct super_block *sb = watch->inode->i_sb;
+       put_inotify_watch(watch);
+       switch (how) {
+       case 1:
+               deactivate_super(sb);
+               break;
+       case 2:
+               drop_super(sb);
+       }
+}
+
 /**
  * inotify_destroy - clean up and destroy an inotify instance
  * @ih: inotify handle
@@ -490,11 +617,15 @@ void inotify_destroy(struct inotify_handle *ih)
         * pretty.  We cannot do a simple iteration over the list, because we
         * do not know the inode until we iterate to the watch.  But we need to
         * hold inode->inotify_mutex before ih->mutex.  The following works.
+        *
+        * AV: it had to become even uglier to start working ;-/
         */
        while (1) {
                struct inotify_watch *watch;
                struct list_head *watches;
+               struct super_block *sb;
                struct inode *inode;
+               int how;
 
                mutex_lock(&ih->mutex);
                watches = &ih->watches;
@@ -503,8 +634,10 @@ void inotify_destroy(struct inotify_handle *ih)
                        break;
                }
                watch = list_first_entry(watches, struct inotify_watch, h_list);
-               get_inotify_watch(watch);
-               mutex_unlock(&ih->mutex);
+               sb = watch->inode->i_sb;
+               how = pin_to_kill(ih, watch);
+               if (!how)
+                       continue;
 
                inode = watch->inode;
                mutex_lock(&inode->inotify_mutex);
@@ -518,7 +651,7 @@ void inotify_destroy(struct inotify_handle *ih)
 
                mutex_unlock(&ih->mutex);
                mutex_unlock(&inode->inotify_mutex);
-               put_inotify_watch(watch);
+               unpin_and_kill(watch, how);
        }
 
        /* free this handle: the put matching the get in inotify_init() */
@@ -719,7 +852,9 @@ void inotify_evict_watch(struct inotify_watch *watch)
 int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
 {
        struct inotify_watch *watch;
+       struct super_block *sb;
        struct inode *inode;
+       int how;
 
        mutex_lock(&ih->mutex);
        watch = idr_find(&ih->idr, wd);
@@ -727,9 +862,12 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
                mutex_unlock(&ih->mutex);
                return -EINVAL;
        }
-       get_inotify_watch(watch);
+       sb = watch->inode->i_sb;
+       how = pin_to_kill(ih, watch);
+       if (!how)
+               return 0;
+
        inode = watch->inode;
-       mutex_unlock(&ih->mutex);
 
        mutex_lock(&inode->inotify_mutex);
        mutex_lock(&ih->mutex);
@@ -740,7 +878,7 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
 
        mutex_unlock(&ih->mutex);
        mutex_unlock(&inode->inotify_mutex);
-       put_inotify_watch(watch);
+       unpin_and_kill(watch, how);
 
        return 0;
 }
index 09ce58e49e72bb000004851a1ea23e958b0b917d..d34e0f9681c6557d83852cf04646afbf9e670d98 100644 (file)
@@ -1378,7 +1378,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
        if (IS_APPEND(dir))
                return -EPERM;
        if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
-           IS_IMMUTABLE(victim->d_inode))
+           IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
                return -EPERM;
        if (isdir) {
                if (!S_ISDIR(victim->d_inode->i_mode))
index cce46702d33c98f6d9e1669ac10f4d6c23be82c2..65b3dc844c879c059c004425487672eff21b5682 100644 (file)
@@ -1815,8 +1815,8 @@ static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts)
                while (!list_empty(&graveyard)) {
                        m = list_first_entry(&graveyard, struct vfsmount,
                                                mnt_expire);
-                       touch_mnt_namespace(mnt->mnt_ns);
-                       umount_tree(mnt, 1, umounts);
+                       touch_mnt_namespace(m->mnt_ns);
+                       umount_tree(m, 1, umounts);
                }
        }
 }
index 633f7a0ebb2cdfb28207cbb9ec14128ede23f59b..6d5b213b8a9b4b6e834ca9be99ae6c15a3dc0d13 100644 (file)
@@ -348,8 +348,8 @@ static ssize_t whole_disk_show(struct device *dev,
 static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
                   whole_disk_show, NULL);
 
-int add_partition(struct gendisk *disk, int partno,
-                 sector_t start, sector_t len, int flags)
+struct hd_struct *add_partition(struct gendisk *disk, int partno,
+                               sector_t start, sector_t len, int flags)
 {
        struct hd_struct *p;
        dev_t devt = MKDEV(0, 0);
@@ -361,15 +361,15 @@ int add_partition(struct gendisk *disk, int partno,
 
        err = disk_expand_part_tbl(disk, partno);
        if (err)
-               return err;
+               return ERR_PTR(err);
        ptbl = disk->part_tbl;
 
        if (ptbl->part[partno])
-               return -EBUSY;
+               return ERR_PTR(-EBUSY);
 
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
-               return -ENOMEM;
+               return ERR_PTR(-EBUSY);
 
        if (!init_part_stats(p)) {
                err = -ENOMEM;
@@ -395,7 +395,7 @@ int add_partition(struct gendisk *disk, int partno,
 
        err = blk_alloc_devt(p, &devt);
        if (err)
-               goto out_free;
+               goto out_free_stats;
        pdev->devt = devt;
 
        /* delay uevent until 'holders' subdir is created */
@@ -424,18 +424,20 @@ int add_partition(struct gendisk *disk, int partno,
        if (!ddev->uevent_suppress)
                kobject_uevent(&pdev->kobj, KOBJ_ADD);
 
-       return 0;
+       return p;
 
+out_free_stats:
+       free_part_stats(p);
 out_free:
        kfree(p);
-       return err;
+       return ERR_PTR(err);
 out_del:
        kobject_put(p->holder_dir);
        device_del(pdev);
 out_put:
        put_device(pdev);
        blk_free_devt(devt);
-       return err;
+       return ERR_PTR(err);
 }
 
 /* Not exported, helper to add_disk(). */
@@ -566,15 +568,16 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
                               disk->disk_name, p, (unsigned long long) size);
                        size = get_capacity(disk) - from;
                }
-               res = add_partition(disk, p, from, size, state->parts[p].flags);
-               if (res) {
-                       printk(KERN_ERR " %s: p%d could not be added: %d\n",
-                               disk->disk_name, p, -res);
+               part = add_partition(disk, p, from, size,
+                                    state->parts[p].flags);
+               if (IS_ERR(part)) {
+                       printk(KERN_ERR " %s: p%d could not be added: %ld\n",
+                              disk->disk_name, p, -PTR_ERR(part));
                        continue;
                }
 #ifdef CONFIG_BLK_DEV_MD
                if (state->parts[p].flags & ADDPART_FLAG_RAID)
-                       md_autodetect_dev(bdev->bd_dev+p);
+                       md_autodetect_dev(part_to_dev(part)->devt);
 #endif
        }
        kfree(state);
index 94fcfff6863a5976965b8d4253ff3ad1ac45386b..06ed10b7da9ee17e9dae1d63ec2b09435aefa551 100644 (file)
@@ -31,6 +31,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
        inode->i_mode = table->mode;
+       inode->i_uid = inode->i_gid = 0;
        if (!table->child) {
                inode->i_mode |= S_IFREG;
                inode->i_op = &proc_sys_inode_operations;
diff --git a/include/linux/c2port.h b/include/linux/c2port.h
new file mode 100644 (file)
index 0000000..7b5a238
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  Silicon Labs C2 port Linux support
+ *
+ *  Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it>
+ *  Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * 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/device.h>
+
+#define C2PORT_NAME_LEN                        32
+
+/*
+ * C2 port basic structs
+ */
+
+/* Main struct */
+struct c2port_ops;
+struct c2port_device {
+       unsigned int access:1;
+       unsigned int flash_access:1;
+
+       int id;
+       char name[C2PORT_NAME_LEN];
+       struct c2port_ops *ops;
+       struct mutex mutex;             /* prevent races during read/write */
+
+       struct device *dev;
+
+       void *private_data;
+};
+
+/* Basic operations */
+struct c2port_ops {
+       /* Flash layout */
+       unsigned short block_size;      /* flash block size in bytes */
+       unsigned short blocks_num;      /* flash blocks number */
+
+       /* Enable or disable the access to C2 port */
+       void (*access)(struct c2port_device *dev, int status);
+
+       /* Set C2D data line as input/output */
+       void (*c2d_dir)(struct c2port_device *dev, int dir);
+
+       /* Read/write C2D data line */
+       int (*c2d_get)(struct c2port_device *dev);
+       void (*c2d_set)(struct c2port_device *dev, int status);
+
+       /* Write C2CK clock line */
+       void (*c2ck_set)(struct c2port_device *dev, int status);
+};
+
+/*
+ * Exported functions
+ */
+
+#define to_class_dev(obj) container_of((obj), struct class_device, kobj)
+#define to_c2port_device(obj) container_of((obj), struct c2port_device, class)
+
+extern struct c2port_device *c2port_device_register(char *name,
+                                       struct c2port_ops *ops, void *devdata);
+extern void c2port_device_unregister(struct c2port_device *dev);
index 2691926fb50641305219b74db1a96f94a143c4f7..8e540d32c9feab60f34e4e6f739d0f1ac85ad7fe 100644 (file)
@@ -74,8 +74,6 @@ static inline int cpuset_do_slab_mem_spread(void)
        return current->flags & PF_SPREAD_SLAB;
 }
 
-extern void cpuset_track_online_nodes(void);
-
 extern int current_cpuset_is_being_rebound(void);
 
 extern void rebuild_sched_domains(void);
@@ -151,8 +149,6 @@ static inline int cpuset_do_slab_mem_spread(void)
        return 0;
 }
 
-static inline void cpuset_track_online_nodes(void) {}
-
 static inline int current_cpuset_is_being_rebound(void)
 {
        return 0;
index e439e6aed832f3fc98b3a7944521f108e5740fbb..3df7742ce2469e4bdc3673ec904b77e9e4eab6f7 100644 (file)
@@ -522,7 +522,9 @@ extern char *disk_name (struct gendisk *hd, int partno, char *buf);
 
 extern int disk_expand_part_tbl(struct gendisk *disk, int target);
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
-extern int __must_check add_partition(struct gendisk *, int, sector_t, sector_t, int);
+extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
+                                                    int partno, sector_t start,
+                                                    sector_t len, int flags);
 extern void delete_partition(struct gendisk *, int);
 extern void printk_all_partitions(void);
 
index 07e510a3b00a89e78c2f48b591208b19dac6ef4e..3eba43878dcb2da2e6d4ad6a8b029ed13e3f8e6a 100644 (file)
@@ -46,9 +46,6 @@ enum hrtimer_restart {
  * hrtimer callback modes:
  *
  *     HRTIMER_CB_SOFTIRQ:             Callback must run in softirq context
- *     HRTIMER_CB_IRQSAFE:             Callback may run in hardirq context
- *     HRTIMER_CB_IRQSAFE_NO_RESTART:  Callback may run in hardirq context and
- *                                     does not restart the timer
  *     HRTIMER_CB_IRQSAFE_PERCPU:      Callback must run in hardirq context
  *                                     Special mode for tick emulation and
  *                                     scheduler timer. Such timers are per
@@ -61,8 +58,6 @@ enum hrtimer_restart {
  */
 enum hrtimer_cb_mode {
        HRTIMER_CB_SOFTIRQ,
-       HRTIMER_CB_IRQSAFE,
-       HRTIMER_CB_IRQSAFE_NO_RESTART,
        HRTIMER_CB_IRQSAFE_PERCPU,
        HRTIMER_CB_IRQSAFE_UNLOCKED,
 };
index bd578578a8b98408844e272fc65dc9f694692d0f..37ea2894b3c0ff870a79f014fb370894b3709e44 100644 (file)
@@ -134,6 +134,8 @@ extern void inotify_remove_watch_locked(struct inotify_handle *,
                                        struct inotify_watch *);
 extern void get_inotify_watch(struct inotify_watch *);
 extern void put_inotify_watch(struct inotify_watch *);
+extern int pin_inotify_watch(struct inotify_watch *);
+extern void unpin_inotify_watch(struct inotify_watch *);
 
 #else
 
@@ -228,6 +230,15 @@ static inline void put_inotify_watch(struct inotify_watch *watch)
 {
 }
 
+extern inline int pin_inotify_watch(struct inotify_watch *watch)
+{
+       return 0;
+}
+
+extern inline void unpin_inotify_watch(struct inotify_watch *watch)
+{
+}
+
 #endif /* CONFIG_INOTIFY */
 
 #endif /* __KERNEL __ */
index b86fb5581ce602f5978ff2a06ddc05eb67f19a07..5341e8251f8cb451243cd526f8dd34232052e055 100644 (file)
@@ -238,6 +238,7 @@ struct input_absinfo {
 #define KEY_KPEQUAL            117
 #define KEY_KPPLUSMINUS                118
 #define KEY_PAUSE              119
+#define KEY_SCALE              120     /* AL Compiz Scale (Expose) */
 
 #define KEY_KPCOMMA            121
 #define KEY_HANGEUL            122
@@ -322,6 +323,7 @@ struct input_absinfo {
 #define KEY_PAUSECD            201
 #define KEY_PROG3              202
 #define KEY_PROG4              203
+#define KEY_DASHBOARD          204     /* AL Dashboard */
 #define KEY_SUSPEND            205
 #define KEY_CLOSE              206     /* AC Close */
 #define KEY_PLAY               207
index fba141d3ca0783303c661f39fb2c503ba418dc56..dc7e0d0a6474448aba71b4c32d2045afc44e240e 100644 (file)
@@ -318,32 +318,36 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
        return buf;
 }
 
-#define pr_emerg(fmt, arg...) \
-       printk(KERN_EMERG fmt, ##arg)
-#define pr_alert(fmt, arg...) \
-       printk(KERN_ALERT fmt, ##arg)
-#define pr_crit(fmt, arg...) \
-       printk(KERN_CRIT fmt, ##arg)
-#define pr_err(fmt, arg...) \
-       printk(KERN_ERR fmt, ##arg)
-#define pr_warning(fmt, arg...) \
-       printk(KERN_WARNING fmt, ##arg)
-#define pr_notice(fmt, arg...) \
-       printk(KERN_NOTICE fmt, ##arg)
-#define pr_info(fmt, arg...) \
-       printk(KERN_INFO fmt, ##arg)
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+
+#define pr_emerg(fmt, ...) \
+        printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_alert(fmt, ...) \
+        printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_crit(fmt, ...) \
+        printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_err(fmt, ...) \
+        printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warning(fmt, ...) \
+        printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_notice(fmt, ...) \
+        printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info(fmt, ...) \
+        printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
 
 /* If you are writing a driver, please use dev_dbg instead */
 #if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
 #define pr_debug(fmt, ...) do { \
-       dynamic_pr_debug(fmt, ##__VA_ARGS__); \
+       dynamic_pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
        } while (0)
 #elif defined(DEBUG)
-#define pr_debug(fmt, arg...) \
-       printk(KERN_DEBUG fmt, ##arg)
+#define pr_debug(fmt, ...) \
+       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
 #else
-#define pr_debug(fmt, arg...) \
-       ({ if (0) printk(KERN_DEBUG fmt, ##arg); 0; })
+#define pr_debug(fmt, ...) \
+       ({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
 #endif
 
 /*
index 331e5f1c2d8ec4439bc69294337dc1b00345f3d8..29aec6e100203da5e8b0f40ab726360ca08b8e72 100644 (file)
@@ -331,10 +331,11 @@ static inline void lockdep_on(void)
 # define lock_set_subclass(l, s, i)            do { } while (0)
 # define lockdep_init()                                do { } while (0)
 # define lockdep_info()                                do { } while (0)
-# define lockdep_init_map(lock, name, key, sub)        do { (void)(key); } while (0)
+# define lockdep_init_map(lock, name, key, sub) \
+               do { (void)(name); (void)(key); } while (0)
 # define lockdep_set_class(lock, key)          do { (void)(key); } while (0)
 # define lockdep_set_class_and_name(lock, key, name) \
-               do { (void)(key); } while (0)
+               do { (void)(key); (void)(name); } while (0)
 #define lockdep_set_class_and_subclass(lock, key, sub) \
                do { (void)(key); } while (0)
 #define lockdep_set_subclass(lock, sub)                do { } while (0)
index dfda69e9f4409ca973385dc1cb7d1123fb21194c..24add2bef6c9240a30023e82766059bc8b31f81d 100644 (file)
 
 struct wm8350_rtc {
        struct platform_device *pdev;
+       struct rtc_device *rtc;
+       int alarm_enabled;      /* used over suspend/resume */
 };
 
 #endif
index 6dc14a240042eab5685fddfb0f357eaae9eecd9d..4515efae4c392bf1c33441159163a04ba80a3ff6 100644 (file)
@@ -40,7 +40,7 @@
 #define SYS_GETSOCKOPT 15              /* sys_getsockopt(2)            */
 #define SYS_SENDMSG    16              /* sys_sendmsg(2)               */
 #define SYS_RECVMSG    17              /* sys_recvmsg(2)               */
-#define SYS_PACCEPT    18              /* sys_paccept(2)               */
+#define SYS_ACCEPT4    18              /* sys_accept4(2)               */
 
 typedef enum {
        SS_FREE = 0,                    /* not allocated                */
@@ -100,7 +100,7 @@ enum sock_type {
  * remaining bits are used as flags. */
 #define SOCK_TYPE_MASK 0xf
 
-/* Flags for socket, socketpair, paccept */
+/* Flags for socket, socketpair, accept4 */
 #define SOCK_CLOEXEC   O_CLOEXEC
 #ifndef SOCK_NONBLOCK
 #define SOCK_NONBLOCK  O_NONBLOCK
@@ -223,8 +223,6 @@ extern int       sock_map_fd(struct socket *sock, int flags);
 extern struct socket *sockfd_lookup(int fd, int *err);
 #define                     sockfd_put(sock) fput(sock->file)
 extern int          net_ratelimit(void);
-extern long         do_accept(int fd, struct sockaddr __user *upeer_sockaddr,
-                              int __user *upeer_addrlen, int flags);
 
 #define net_random()           random32()
 #define net_srandom(seed)      srandom32((__force u32)seed)
index 18a5b9ba9d40180b53273d75556bb529eafb8dd0..00044b856453f45bf886ddc3b237ac3744323ac3 100644 (file)
@@ -17,11 +17,4 @@ struct ratelimit_state {
                struct ratelimit_state name = {interval, burst,}
 
 extern int __ratelimit(struct ratelimit_state *rs);
-
-static inline int ratelimit(void)
-{
-       static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
-                                       DEFAULT_RATELIMIT_BURST);
-       return __ratelimit(&rs);
-}
 #endif
index 536b0ca46a038d4b9c34df6206616a432db42936..e097c2e6b6dcaa212f26bf6b08b66e4c9021cb21 100644 (file)
@@ -120,6 +120,9 @@ unsigned long ring_buffer_overruns(struct ring_buffer *buffer);
 u64 ring_buffer_time_stamp(int cpu);
 void ring_buffer_normalize_time_stamp(int cpu, u64 *ts);
 
+void tracing_on(void);
+void tracing_off(void);
+
 enum ring_buffer_flags {
        RB_FL_OVERWRITE         = 1 << 0,
 };
index e27f216361fc1511f6fc6b52d7570536af95a9e6..4e4f1277f3bf487517faf1d2dd4f275a6ddbad7f 100644 (file)
 
 #define PORT_SC26XX    82
 
+/* SH-SCI */
+#define PORT_SCIFA     83
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
index ba965c84ae0695b175da712a0951b6c3e0530b5c..000da12b5cf03650ad90db9be142d803930fb62e 100644 (file)
 #define SLAB_CACHE_DMA         0x00004000UL    /* Use GFP_DMA memory */
 #define SLAB_STORE_USER                0x00010000UL    /* DEBUG: Store the last owner for bug hunting */
 #define SLAB_PANIC             0x00040000UL    /* Panic if kmem_cache_create() fails */
+/*
+ * SLAB_DESTROY_BY_RCU - **WARNING** READ THIS!
+ *
+ * This delays freeing the SLAB page by a grace period, it does _NOT_
+ * delay object freeing. This means that if you do kmem_cache_free()
+ * that memory location is free to be reused at any time. Thus it may
+ * be possible to see another object there in the same RCU grace period.
+ *
+ * This feature only ensures the memory location backing the object
+ * stays valid, the trick to using this is relying on an independent
+ * object validation pass. Something like:
+ *
+ *  rcu_read_lock()
+ * again:
+ *  obj = lockless_lookup(key);
+ *  if (obj) {
+ *    if (!try_get_ref(obj)) // might fail for free objects
+ *      goto again;
+ *
+ *    if (obj->key != key) { // not the object we expected
+ *      put_ref(obj);
+ *      goto again;
+ *    }
+ *  }
+ *  rcu_read_unlock();
+ *
+ * See also the comment on struct slab_rcu in mm/slab.c.
+ */
 #define SLAB_DESTROY_BY_RCU    0x00080000UL    /* Defer freeing slabs to RCU */
 #define SLAB_MEM_SPREAD                0x00100000UL    /* Spread some memory over cpuset */
 #define SLAB_TRACE             0x00200000UL    /* Trace allocations and frees */
index d6ff145919ca3d3db7a01cf53c93ff628b0d29a6..04fb47bfb920d317c4b5217ebfbb1602e7606d90 100644 (file)
@@ -410,8 +410,7 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname,
 asmlinkage long sys_bind(int, struct sockaddr __user *, int);
 asmlinkage long sys_connect(int, struct sockaddr __user *, int);
 asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *);
-asmlinkage long sys_paccept(int, struct sockaddr __user *, int __user *,
-                           const __user sigset_t *, size_t, int);
+asmlinkage long sys_accept4(int, struct sockaddr __user *, int __user *, int);
 asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *);
 asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *);
 asmlinkage long sys_send(int, void __user *, size_t, unsigned);
index 8fa973bede5e1930d8b96317b9fbc99305a4d66b..f72aa51f7bcdc3fdb3d728c452cdd12f2d3d9baf 100644 (file)
@@ -108,6 +108,7 @@ enum usb_interface_condition {
  *     (in probe()), bound to a driver, or unbinding (in disconnect())
  * @is_active: flag set when the interface is bound and not suspended.
  * @sysfs_files_created: sysfs attributes exist
+ * @unregistering: flag set when the interface is being unregistered
  * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
  *     capability during autosuspend.
  * @needs_altsetting0: flag set when a set-interface request for altsetting 0
@@ -163,6 +164,7 @@ struct usb_interface {
        enum usb_interface_condition condition;         /* state of binding */
        unsigned is_active:1;           /* the interface is not suspended */
        unsigned sysfs_files_created:1; /* the sysfs attributes exist */
+       unsigned unregistering:1;       /* unregistration is in progress */
        unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
        unsigned needs_altsetting0:1;   /* switch to altsetting 0 is pending */
        unsigned needs_binding:1;       /* needs delayed unbind/rebind */
index c04f9e18ea22033d22cfd9bf5e4ba1a74a29addd..2f47107f6d0f8f018feaba3a75eeff4dd64d14ec 100644 (file)
@@ -815,7 +815,7 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
  */
 #define sock_lock_init_class_and_name(sk, sname, skey, name, key)      \
 do {                                                                   \
-       sk->sk_lock.owned = 0;                                  \
+       sk->sk_lock.owned = 0;                                          \
        init_waitqueue_head(&sk->sk_lock.wq);                           \
        spin_lock_init(&(sk)->sk_lock.slock);                           \
        debug_check_no_locks_freed((void *)&(sk)->sk_lock,              \
index 6ad87f48599284c809371c533f287b748268097f..0c864db1a4662a5e1c89f902830e5cf4a7f91efc 100644 (file)
@@ -38,7 +38,7 @@ struct atmel_lcdfb_info {
        spinlock_t              lock;
        struct fb_info          *info;
        void __iomem            *mmio;
-       unsigned long           irq_base;
+       int                     irq_base;
        struct work_struct      task;
 
        unsigned int            guard_time;
index 86b00c53fadeb833d054fab64d13fb9a0e8d6fde..f763762d544a135a0a06f67f36701b9f0d331140 100644 (file)
@@ -354,7 +354,7 @@ config RT_GROUP_SCHED
          setting below. If enabled, it will also make it impossible to
          schedule realtime tasks for non-root users until you allocate
          realtime bandwidth for them.
-         See Documentation/sched-rt-group.txt for more information.
+         See Documentation/scheduler/sched-rt-group.txt for more information.
 
 choice
        depends on GROUP_SCHED
@@ -771,8 +771,7 @@ config SLAB
        help
          The regular slab allocator that is established and known to work
          well in all environments. It organizes cache hot objects in
-         per cpu and per node queues. SLAB is the default choice for
-         a slab allocator.
+         per cpu and per node queues.
 
 config SLUB
        bool "SLUB (Unqueued Allocator)"
@@ -781,7 +780,8 @@ config SLUB
           instead of managing queues of cached objects (SLAB approach).
           Per cpu caching is realized using slabs of objects instead
           of queues of objects. SLUB can use memory efficiently
-          and has enhanced diagnostics.
+          and has enhanced diagnostics. SLUB is the default choice for
+          a slab allocator.
 
 config SLOB
        depends on EMBEDDED
index 49b3ea615dc5fa991d921667f44172da02331a55..361fd1c96fcf31b92475882803dc927f281a8718 100644 (file)
@@ -266,9 +266,17 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
        if (ids->in_use >= size)
                return -ENOSPC;
 
+       spin_lock_init(&new->lock);
+       new->deleted = 0;
+       rcu_read_lock();
+       spin_lock(&new->lock);
+
        err = idr_get_new(&ids->ipcs_idr, new, &id);
-       if (err)
+       if (err) {
+               spin_unlock(&new->lock);
+               rcu_read_unlock();
                return err;
+       }
 
        ids->in_use++;
 
@@ -280,10 +288,6 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
                ids->seq = 0;
 
        new->id = ipc_buildid(id, new->seq);
-       spin_lock_init(&new->lock);
-       new->deleted = 0;
-       rcu_read_lock();
-       spin_lock(&new->lock);
        return id;
 }
 
index 9a3ec66a9d841c961e51bfac872462d051098a18..19fad003b19d6ac0752597f5a23e18341d1d579a 100644 (file)
@@ -11,8 +11,6 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
            hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
            notifier.o ksysfs.o pm_qos_params.o sched_clock.o
 
-CFLAGS_REMOVE_sched.o = -mno-spe
-
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
 CFLAGS_REMOVE_lockdep.o = -pg
@@ -21,7 +19,7 @@ CFLAGS_REMOVE_mutex-debug.o = -pg
 CFLAGS_REMOVE_rtmutex-debug.o = -pg
 CFLAGS_REMOVE_cgroup-debug.o = -pg
 CFLAGS_REMOVE_sched_clock.o = -pg
-CFLAGS_REMOVE_sched.o = -mno-spe -pg
+CFLAGS_REMOVE_sched.o = -pg
 endif
 
 obj-$(CONFIG_FREEZER) += freezer.o
index 8ba0e0d934f23137762f74525f6757e27a129056..8b509441f49a2f740a2d709c66cecc73d9896f1c 100644 (file)
@@ -24,6 +24,7 @@ struct audit_chunk {
        struct list_head trees;         /* with root here */
        int dead;
        int count;
+       atomic_long_t refs;
        struct rcu_head head;
        struct node {
                struct list_head list;
@@ -56,7 +57,8 @@ static LIST_HEAD(prune_list);
  * tree is refcounted; one reference for "some rules on rules_list refer to
  * it", one for each chunk with pointer to it.
  *
- * chunk is refcounted by embedded inotify_watch.
+ * chunk is refcounted by embedded inotify_watch + .refs (non-zero refcount
+ * of watch contributes 1 to .refs).
  *
  * node.index allows to get from node.list to containing chunk.
  * MSB of that sucker is stolen to mark taggings that we might have to
@@ -121,6 +123,7 @@ static struct audit_chunk *alloc_chunk(int count)
        INIT_LIST_HEAD(&chunk->hash);
        INIT_LIST_HEAD(&chunk->trees);
        chunk->count = count;
+       atomic_long_set(&chunk->refs, 1);
        for (i = 0; i < count; i++) {
                INIT_LIST_HEAD(&chunk->owners[i].list);
                chunk->owners[i].index = i;
@@ -129,9 +132,8 @@ static struct audit_chunk *alloc_chunk(int count)
        return chunk;
 }
 
-static void __free_chunk(struct rcu_head *rcu)
+static void free_chunk(struct audit_chunk *chunk)
 {
-       struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
        int i;
 
        for (i = 0; i < chunk->count; i++) {
@@ -141,14 +143,16 @@ static void __free_chunk(struct rcu_head *rcu)
        kfree(chunk);
 }
 
-static inline void free_chunk(struct audit_chunk *chunk)
+void audit_put_chunk(struct audit_chunk *chunk)
 {
-       call_rcu(&chunk->head, __free_chunk);
+       if (atomic_long_dec_and_test(&chunk->refs))
+               free_chunk(chunk);
 }
 
-void audit_put_chunk(struct audit_chunk *chunk)
+static void __put_chunk(struct rcu_head *rcu)
 {
-       put_inotify_watch(&chunk->watch);
+       struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
+       audit_put_chunk(chunk);
 }
 
 enum {HASH_SIZE = 128};
@@ -176,7 +180,7 @@ struct audit_chunk *audit_tree_lookup(const struct inode *inode)
 
        list_for_each_entry_rcu(p, list, hash) {
                if (p->watch.inode == inode) {
-                       get_inotify_watch(&p->watch);
+                       atomic_long_inc(&p->refs);
                        return p;
                }
        }
@@ -194,17 +198,49 @@ int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
 
 /* tagging and untagging inodes with trees */
 
-static void untag_chunk(struct audit_chunk *chunk, struct node *p)
+static struct audit_chunk *find_chunk(struct node *p)
+{
+       int index = p->index & ~(1U<<31);
+       p -= index;
+       return container_of(p, struct audit_chunk, owners[0]);
+}
+
+static void untag_chunk(struct node *p)
 {
+       struct audit_chunk *chunk = find_chunk(p);
        struct audit_chunk *new;
        struct audit_tree *owner;
        int size = chunk->count - 1;
        int i, j;
 
+       if (!pin_inotify_watch(&chunk->watch)) {
+               /*
+                * Filesystem is shutting down; all watches are getting
+                * evicted, just take it off the node list for this
+                * tree and let the eviction logics take care of the
+                * rest.
+                */
+               owner = p->owner;
+               if (owner->root == chunk) {
+                       list_del_init(&owner->same_root);
+                       owner->root = NULL;
+               }
+               list_del_init(&p->list);
+               p->owner = NULL;
+               put_tree(owner);
+               return;
+       }
+
+       spin_unlock(&hash_lock);
+
+       /*
+        * pin_inotify_watch() succeeded, so the watch won't go away
+        * from under us.
+        */
        mutex_lock(&chunk->watch.inode->inotify_mutex);
        if (chunk->dead) {
                mutex_unlock(&chunk->watch.inode->inotify_mutex);
-               return;
+               goto out;
        }
 
        owner = p->owner;
@@ -221,7 +257,7 @@ static void untag_chunk(struct audit_chunk *chunk, struct node *p)
                inotify_evict_watch(&chunk->watch);
                mutex_unlock(&chunk->watch.inode->inotify_mutex);
                put_inotify_watch(&chunk->watch);
-               return;
+               goto out;
        }
 
        new = alloc_chunk(size);
@@ -263,7 +299,7 @@ static void untag_chunk(struct audit_chunk *chunk, struct node *p)
        inotify_evict_watch(&chunk->watch);
        mutex_unlock(&chunk->watch.inode->inotify_mutex);
        put_inotify_watch(&chunk->watch);
-       return;
+       goto out;
 
 Fallback:
        // do the best we can
@@ -277,6 +313,9 @@ Fallback:
        put_tree(owner);
        spin_unlock(&hash_lock);
        mutex_unlock(&chunk->watch.inode->inotify_mutex);
+out:
+       unpin_inotify_watch(&chunk->watch);
+       spin_lock(&hash_lock);
 }
 
 static int create_chunk(struct inode *inode, struct audit_tree *tree)
@@ -387,13 +426,6 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
        return 0;
 }
 
-static struct audit_chunk *find_chunk(struct node *p)
-{
-       int index = p->index & ~(1U<<31);
-       p -= index;
-       return container_of(p, struct audit_chunk, owners[0]);
-}
-
 static void kill_rules(struct audit_tree *tree)
 {
        struct audit_krule *rule, *next;
@@ -431,17 +463,10 @@ static void prune_one(struct audit_tree *victim)
        spin_lock(&hash_lock);
        while (!list_empty(&victim->chunks)) {
                struct node *p;
-               struct audit_chunk *chunk;
 
                p = list_entry(victim->chunks.next, struct node, list);
-               chunk = find_chunk(p);
-               get_inotify_watch(&chunk->watch);
-               spin_unlock(&hash_lock);
-
-               untag_chunk(chunk, p);
 
-               put_inotify_watch(&chunk->watch);
-               spin_lock(&hash_lock);
+               untag_chunk(p);
        }
        spin_unlock(&hash_lock);
        put_tree(victim);
@@ -469,7 +494,6 @@ static void trim_marked(struct audit_tree *tree)
 
        while (!list_empty(&tree->chunks)) {
                struct node *node;
-               struct audit_chunk *chunk;
 
                node = list_entry(tree->chunks.next, struct node, list);
 
@@ -477,14 +501,7 @@ static void trim_marked(struct audit_tree *tree)
                if (!(node->index & (1U<<31)))
                        break;
 
-               chunk = find_chunk(node);
-               get_inotify_watch(&chunk->watch);
-               spin_unlock(&hash_lock);
-
-               untag_chunk(chunk, node);
-
-               put_inotify_watch(&chunk->watch);
-               spin_lock(&hash_lock);
+               untag_chunk(node);
        }
        if (!tree->root && !tree->goner) {
                tree->goner = 1;
@@ -878,7 +895,7 @@ static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
 static void destroy_watch(struct inotify_watch *watch)
 {
        struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
-       free_chunk(chunk);
+       call_rcu(&chunk->head, __put_chunk);
 }
 
 static const struct inotify_operations rtree_inotify_ops = {
index b7d354e2b0ef35d618f7a69fee70d301078faa02..9fd85a4640a096eab72312d33a090e417e013548 100644 (file)
@@ -1094,8 +1094,8 @@ static void audit_inotify_unregister(struct list_head *in_list)
        list_for_each_entry_safe(p, n, in_list, ilist) {
                list_del(&p->ilist);
                inotify_rm_watch(audit_ih, &p->wdata);
-               /* the put matching the get in audit_do_del_rule() */
-               put_inotify_watch(&p->wdata);
+               /* the unpin matching the pin in audit_do_del_rule() */
+               unpin_inotify_watch(&p->wdata);
        }
 }
 
@@ -1389,9 +1389,13 @@ static inline int audit_del_rule(struct audit_entry *entry,
                                /* Put parent on the inotify un-registration
                                 * list.  Grab a reference before releasing
                                 * audit_filter_mutex, to be released in
-                                * audit_inotify_unregister(). */
-                               list_add(&parent->ilist, &inotify_list);
-                               get_inotify_watch(&parent->wdata);
+                                * audit_inotify_unregister().
+                                * If filesystem is going away, just leave
+                                * the sucker alone, eviction will take
+                                * care of it.
+                                */
+                               if (pin_inotify_watch(&parent->wdata))
+                                       list_add(&parent->ilist, &inotify_list);
                        }
                }
        }
index 358e77564e6f8b0b4c3964a36da48cc3051d6e73..fe00b3b983a86387332234703217abb1d28ca202 100644 (file)
@@ -2039,10 +2039,13 @@ int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry)
        struct cgroup *cgrp;
        struct cgroup_iter it;
        struct task_struct *tsk;
+
        /*
-        * Validate dentry by checking the superblock operations
+        * Validate dentry by checking the superblock operations,
+        * and make sure it's a directory.
         */
-       if (dentry->d_sb->s_op != &cgroup_ops)
+       if (dentry->d_sb->s_op != &cgroup_ops ||
+           !S_ISDIR(dentry->d_inode->i_mode))
                 goto err;
 
        ret = 0;
@@ -2472,10 +2475,7 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
                mutex_unlock(&cgroup_mutex);
                return -EBUSY;
        }
-
-       parent = cgrp->parent;
-       root = cgrp->root;
-       sb = root->sb;
+       mutex_unlock(&cgroup_mutex);
 
        /*
         * Call pre_destroy handlers of subsys. Notify subsystems
@@ -2483,7 +2483,14 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
         */
        cgroup_call_pre_destroy(cgrp);
 
-       if (cgroup_has_css_refs(cgrp)) {
+       mutex_lock(&cgroup_mutex);
+       parent = cgrp->parent;
+       root = cgrp->root;
+       sb = root->sb;
+
+       if (atomic_read(&cgrp->count)
+           || !list_empty(&cgrp->children)
+           || cgroup_has_css_refs(cgrp)) {
                mutex_unlock(&cgroup_mutex);
                return -EBUSY;
        }
index 7fa476f01d05568ac42541391f935b23b4145c80..fb249e2bcada880a19105488c7fdde33e9483126 100644 (file)
@@ -184,9 +184,20 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
 {
        struct freezer *freezer;
 
-       task_lock(task);
+       /*
+        * No lock is needed, since the task isn't on tasklist yet,
+        * so it can't be moved to another cgroup, which means the
+        * freezer won't be removed and will be valid during this
+        * function call.
+        */
        freezer = task_freezer(task);
-       task_unlock(task);
+
+       /*
+        * The root cgroup is non-freezable, so we can skip the
+        * following check.
+        */
+       if (!freezer->css.cgroup->parent)
+               return;
 
        spin_lock_irq(&freezer->lock);
        BUG_ON(freezer->state == CGROUP_FROZEN);
@@ -331,7 +342,7 @@ static int freezer_write(struct cgroup *cgroup,
        else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0)
                goal_state = CGROUP_FROZEN;
        else
-               return -EIO;
+               return -EINVAL;
 
        if (!cgroup_lock_live_group(cgroup))
                return -ENODEV;
@@ -350,6 +361,8 @@ static struct cftype files[] = {
 
 static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup)
 {
+       if (!cgroup->parent)
+               return 0;
        return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files));
 }
 
index 3e00526f52ec14d56eb89ee1ab5c1a40fbed1331..da7ff6137f375d44d7bf33dc8e10bd0e1751f89f 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/list.h>
 #include <linux/mempolicy.h>
 #include <linux/mm.h>
+#include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -587,7 +588,6 @@ static int generate_sched_domains(cpumask_t **domains,
        int ndoms;              /* number of sched domains in result */
        int nslot;              /* next empty doms[] cpumask_t slot */
 
-       ndoms = 0;
        doms = NULL;
        dattr = NULL;
        csa = NULL;
@@ -674,10 +674,8 @@ restart:
         * Convert <csn, csa> to <ndoms, doms> and populate cpu masks.
         */
        doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL);
-       if (!doms) {
-               ndoms = 0;
+       if (!doms)
                goto done;
-       }
 
        /*
         * The rest of the code, including the scheduler, can deal with
@@ -732,6 +730,13 @@ restart:
 done:
        kfree(csa);
 
+       /*
+        * Fallback to the default domain if kmalloc() failed.
+        * See comments in partition_sched_domains().
+        */
+       if (doms == NULL)
+               ndoms = 1;
+
        *domains    = doms;
        *attributes = dattr;
        return ndoms;
@@ -2011,12 +2016,23 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
  * Call this routine anytime after node_states[N_HIGH_MEMORY] changes.
  * See also the previous routine cpuset_track_online_cpus().
  */
-void cpuset_track_online_nodes(void)
+static int cpuset_track_online_nodes(struct notifier_block *self,
+                               unsigned long action, void *arg)
 {
        cgroup_lock();
-       top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-       scan_for_empty_cpusets(&top_cpuset);
+       switch (action) {
+       case MEM_ONLINE:
+               top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
+               break;
+       case MEM_OFFLINE:
+               top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
+               scan_for_empty_cpusets(&top_cpuset);
+               break;
+       default:
+               break;
+       }
        cgroup_unlock();
+       return NOTIFY_OK;
 }
 #endif
 
@@ -2032,6 +2048,7 @@ void __init cpuset_init_smp(void)
        top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 
        hotcpu_notifier(cpuset_track_online_cpus, 0);
+       hotplug_memory_notifier(cpuset_track_online_nodes, 10);
 }
 
 /**
index ae2b92be5faec1efa73beefb63304a22d030fc16..2d8be7ebb0f73499f894a1828fd827f0217290f1 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/cn_proc.h>
 #include <linux/mutex.h>
 #include <linux/futex.h>
-#include <linux/compat.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/audit.h> /* for audit_free() */
 #include <linux/resource.h>
@@ -1059,14 +1058,6 @@ NORET_TYPE void do_exit(long code)
                exit_itimers(tsk->signal);
        }
        acct_collect(code, group_dead);
-#ifdef CONFIG_FUTEX
-       if (unlikely(tsk->robust_list))
-               exit_robust_list(tsk);
-#ifdef CONFIG_COMPAT
-       if (unlikely(tsk->compat_robust_list))
-               compat_exit_robust_list(tsk);
-#endif
-#endif
        if (group_dead)
                tty_audit_exit();
        if (unlikely(tsk->audit_context))
index f6083561dfe0a9f8d2a13138f7332bc358a51653..2a372a0e206fa2de99dbfdd594f86f6eb927bf40 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/jiffies.h>
 #include <linux/tracehook.h>
 #include <linux/futex.h>
+#include <linux/compat.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/rcupdate.h>
 #include <linux/ptrace.h>
@@ -519,6 +520,16 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
 {
        struct completion *vfork_done = tsk->vfork_done;
 
+       /* Get rid of any futexes when releasing the mm */
+#ifdef CONFIG_FUTEX
+       if (unlikely(tsk->robust_list))
+               exit_robust_list(tsk);
+#ifdef CONFIG_COMPAT
+       if (unlikely(tsk->compat_robust_list))
+               compat_exit_robust_list(tsk);
+#endif
+#endif
+
        /* Get rid of any cached register state */
        deactivate_mm(tsk, mm);
 
index 95d3949f2ae51135b181906f632b8de7f5e3f8e7..47e63349d1b2d262be2d8be568af8d3d93de3333 100644 (file)
@@ -664,14 +664,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
 
                /* Timer is expired, act upon the callback mode */
                switch(timer->cb_mode) {
-               case HRTIMER_CB_IRQSAFE_NO_RESTART:
-                       debug_hrtimer_deactivate(timer);
-                       /*
-                        * We can call the callback from here. No restart
-                        * happens, so no danger of recursion
-                        */
-                       BUG_ON(timer->function(timer) != HRTIMER_NORESTART);
-                       return 1;
                case HRTIMER_CB_IRQSAFE_PERCPU:
                case HRTIMER_CB_IRQSAFE_UNLOCKED:
                        /*
@@ -683,7 +675,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
                         */
                        debug_hrtimer_deactivate(timer);
                        return 1;
-               case HRTIMER_CB_IRQSAFE:
                case HRTIMER_CB_SOFTIRQ:
                        /*
                         * Move everything else into the softirq pending list !
index 5072cf1685a27ca9fc78986e3438ab53baa882a4..7b8b0f21a5b119356d4609e97b96b1e920be8a1a 100644 (file)
@@ -304,17 +304,24 @@ int sprint_symbol(char *buffer, unsigned long address)
        char *modname;
        const char *name;
        unsigned long offset, size;
-       char namebuf[KSYM_NAME_LEN];
+       int len;
 
-       name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
+       name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
        if (!name)
                return sprintf(buffer, "0x%lx", address);
 
+       if (name != buffer)
+               strcpy(buffer, name);
+       len = strlen(buffer);
+       buffer += len;
+
        if (modname)
-               return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
-                               size, modname);
+               len += sprintf(buffer, "+%#lx/%#lx [%s]",
+                                               offset, size, modname);
        else
-               return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+               len += sprintf(buffer, "+%#lx/%#lx", offset, size);
+
+       return len;
 }
 
 /* Look up a kernel symbol and print it to the kernel messages. */
index 8b57a2597f21fda9c9602e27028753f1f7325234..9f8a3f25259a9da4c8535bab07014b07da79a643 100644 (file)
@@ -72,7 +72,7 @@ static bool kprobe_enabled;
 DEFINE_MUTEX(kprobe_mutex);            /* Protects kprobe_table */
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
 static struct {
-       spinlock_t lock ____cacheline_aligned;
+       spinlock_t lock ____cacheline_aligned_in_smp;
 } kretprobe_table_locks[KPROBE_TABLE_SIZE];
 
 static spinlock_t *kretprobe_table_lock_ptr(unsigned long hash)
@@ -613,30 +613,37 @@ static int __kprobes __register_kprobe(struct kprobe *p,
                return -EINVAL;
        p->addr = addr;
 
-       if (!kernel_text_address((unsigned long) p->addr) ||
-           in_kprobes_functions((unsigned long) p->addr))
+       preempt_disable();
+       if (!__kernel_text_address((unsigned long) p->addr) ||
+           in_kprobes_functions((unsigned long) p->addr)) {
+               preempt_enable();
                return -EINVAL;
+       }
 
        p->mod_refcounted = 0;
 
        /*
         * Check if are we probing a module.
         */
-       probed_mod = module_text_address((unsigned long) p->addr);
+       probed_mod = __module_text_address((unsigned long) p->addr);
        if (probed_mod) {
-               struct module *calling_mod = module_text_address(called_from);
+               struct module *calling_mod;
+               calling_mod = __module_text_address(called_from);
                /*
                 * We must allow modules to probe themself and in this case
                 * avoid incrementing the module refcount, so as to allow
                 * unloading of self probing modules.
                 */
                if (calling_mod && calling_mod != probed_mod) {
-                       if (unlikely(!try_module_get(probed_mod)))
+                       if (unlikely(!try_module_get(probed_mod))) {
+                               preempt_enable();
                                return -EINVAL;
+                       }
                        p->mod_refcounted = 1;
                } else
                        probed_mod = NULL;
        }
+       preempt_enable();
 
        p->nmissed = 0;
        INIT_LIST_HEAD(&p->list);
@@ -718,6 +725,10 @@ static void __kprobes __unregister_kprobe_bottom(struct kprobe *p)
        struct kprobe *old_p;
 
        if (p->mod_refcounted) {
+               /*
+                * Since we've already incremented refcount,
+                * we don't need to disable preemption.
+                */
                mod = module_text_address((unsigned long)p->addr);
                if (mod)
                        module_put(mod);
index 153dcb2639c3df614c7862041a9d485b7dbe6614..895337b16a24e7b9df95e8a9306b224bbe000971 100644 (file)
@@ -1308,9 +1308,10 @@ static inline int task_cputime_expired(const struct task_cputime *sample,
  */
 static inline int fastpath_timer_check(struct task_struct *tsk)
 {
-       struct signal_struct *sig = tsk->signal;
+       struct signal_struct *sig;
 
-       if (unlikely(!sig))
+       /* tsk == current, ensure it is safe to use ->signal/sighand */
+       if (unlikely(tsk->exit_state))
                return 0;
 
        if (!task_cputime_zero(&tsk->cputime_expires)) {
@@ -1323,6 +1324,8 @@ static inline int fastpath_timer_check(struct task_struct *tsk)
                if (task_cputime_expired(&task_sample, &tsk->cputime_expires))
                        return 1;
        }
+
+       sig = tsk->signal;
        if (!task_cputime_zero(&sig->cputime_expires)) {
                struct task_cputime group_sample;
 
index 19122cf6d827d13d03e8a7520d0120d5adf92bbc..b8f7ce9473e8412099e476dd54a27a1a21bf8ea6 100644 (file)
@@ -174,7 +174,7 @@ static void suspend_test_finish(const char *label)
         * has some performance issues.  The stack dump of a WARN_ON
         * is more likely to get the right attention than a printk...
         */
-       WARN_ON(msec > (TEST_SUSPEND_SECONDS * 1000));
+       WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label);
 }
 
 #else
index 9830a037d8db1543215f02c01918af3fd980bb10..5b7d1ac7124c97e884d25c57bbf770f9f858d26f 100644 (file)
@@ -544,7 +544,7 @@ static const struct file_operations proc_profile_operations = {
 };
 
 #ifdef CONFIG_SMP
-static void __init profile_nop(void *unused)
+static inline void profile_nop(void *unused)
 {
 }
 
index 8d13a7855c0808858c20fd01d6decebc08c8eeaa..32b0befdcb6a6cba585cb555d9db4a87246d9468 100644 (file)
@@ -400,7 +400,7 @@ void relay_reset(struct rchan *chan)
        }
 
        mutex_lock(&relay_channels_mutex);
-       for_each_online_cpu(i)
+       for_each_possible_cpu(i)
                if (chan->buf[i])
                        __relay_reset(chan->buf[i], 0);
        mutex_unlock(&relay_channels_mutex);
@@ -611,10 +611,9 @@ struct rchan *relay_open(const char *base_filename,
        return chan;
 
 free_bufs:
-       for_each_online_cpu(i) {
-               if (!chan->buf[i])
-                       break;
-               relay_close_buf(chan->buf[i]);
+       for_each_possible_cpu(i) {
+               if (chan->buf[i])
+                       relay_close_buf(chan->buf[i]);
        }
 
        kref_put(&chan->kref, relay_destroy_channel);
index 50a21f964679ec42eee299cab7f7f86edc26a408..9b1e79371c207b37c1617d3f7c0460709a3cc39b 100644 (file)
@@ -1456,6 +1456,8 @@ static unsigned long cpu_avg_load_per_task(int cpu)
 
        if (rq->nr_running)
                rq->avg_load_per_task = rq->load.weight / rq->nr_running;
+       else
+               rq->avg_load_per_task = 0;
 
        return rq->avg_load_per_task;
 }
@@ -5868,6 +5870,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        struct rq *rq = cpu_rq(cpu);
        unsigned long flags;
 
+       spin_lock_irqsave(&rq->lock, flags);
+
        __sched_fork(idle);
        idle->se.exec_start = sched_clock();
 
@@ -5875,7 +5879,6 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        idle->cpus_allowed = cpumask_of_cpu(cpu);
        __set_task_cpu(idle, cpu);
 
-       spin_lock_irqsave(&rq->lock, flags);
        rq->curr = rq->idle = idle;
 #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
        idle->oncpu = 1;
@@ -7786,13 +7789,14 @@ static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur,
  *
  * The passed in 'doms_new' should be kmalloc'd. This routine takes
  * ownership of it and will kfree it when done with it. If the caller
- * failed the kmalloc call, then it can pass in doms_new == NULL,
- * and partition_sched_domains() will fallback to the single partition
- * 'fallback_doms', it also forces the domains to be rebuilt.
+ * failed the kmalloc call, then it can pass in doms_new == NULL &&
+ * ndoms_new == 1, and partition_sched_domains() will fallback to
+ * the single partition 'fallback_doms', it also forces the domains
+ * to be rebuilt.
  *
- * If doms_new==NULL it will be replaced with cpu_online_map.
- * ndoms_new==0 is a special case for destroying existing domains.
- * It will not create the default domain.
+ * If doms_new == NULL it will be replaced with cpu_online_map.
+ * ndoms_new == 0 is a special case for destroying existing domains,
+ * and it will not create the default domain.
  *
  * Call with hotplug lock held
  */
index 48ecc51e77019c9a54c6a565b5c3dafbf9b85be2..26ed8e3d1c1536a542b96b9262aa6dada54d9985 100644 (file)
@@ -423,10 +423,11 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 #undef __P
 
        {
+               unsigned int this_cpu = raw_smp_processor_id();
                u64 t0, t1;
 
-               t0 = sched_clock();
-               t1 = sched_clock();
+               t0 = cpu_clock(this_cpu);
+               t1 = cpu_clock(this_cpu);
                SEQ_printf(m, "%-35s:%21Ld\n",
                           "clock-delta", (long long)(t1-t0));
        }
index ee71bec1da66a9dcb64d93a0e9934c15a155905b..7dbf72a2b02cf16f256af7655eb9b28c7f3ef856 100644 (file)
@@ -298,9 +298,11 @@ static inline void account_group_user_time(struct task_struct *tsk,
 {
        struct signal_struct *sig;
 
-       sig = tsk->signal;
-       if (unlikely(!sig))
+       /* tsk == current, ensure it is safe to use ->signal */
+       if (unlikely(tsk->exit_state))
                return;
+
+       sig = tsk->signal;
        if (sig->cputime.totals) {
                struct task_cputime *times;
 
@@ -325,9 +327,11 @@ static inline void account_group_system_time(struct task_struct *tsk,
 {
        struct signal_struct *sig;
 
-       sig = tsk->signal;
-       if (unlikely(!sig))
+       /* tsk == current, ensure it is safe to use ->signal */
+       if (unlikely(tsk->exit_state))
                return;
+
+       sig = tsk->signal;
        if (sig->cputime.totals) {
                struct task_cputime *times;
 
@@ -353,8 +357,11 @@ static inline void account_group_exec_runtime(struct task_struct *tsk,
        struct signal_struct *sig;
 
        sig = tsk->signal;
+       /* see __exit_signal()->task_rq_unlock_wait() */
+       barrier();
        if (unlikely(!sig))
                return;
+
        if (sig->cputime.totals) {
                struct task_cputime *times;
 
index 9bc4c00872c927a1033013a31ab19630ba9dc170..24e8ceacc388cd14e9ff4ae87fcc47d6f8d96b2b 100644 (file)
@@ -112,7 +112,7 @@ static int chill(void *unused)
 int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
 {
        struct work_struct *sm_work;
-       int i;
+       int i, ret;
 
        /* Set up initial state. */
        mutex_lock(&lock);
@@ -137,8 +137,9 @@ int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
        /* This will release the thread on our CPU. */
        put_cpu();
        flush_workqueue(stop_machine_wq);
+       ret = active.fnret;
        mutex_unlock(&lock);
-       return active.fnret;
+       return ret;
 }
 
 int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus)
index a77b27b11b048fee528e0628798f9fe8774ebbf9..e14a23281707610c6d52338af9e091116e29b987 100644 (file)
@@ -31,7 +31,7 @@ cond_syscall(sys_socketpair);
 cond_syscall(sys_bind);
 cond_syscall(sys_listen);
 cond_syscall(sys_accept);
-cond_syscall(sys_paccept);
+cond_syscall(sys_accept4);
 cond_syscall(sys_connect);
 cond_syscall(sys_getsockname);
 cond_syscall(sys_getpeername);
index 4a39d24568c82ffddbcbfed2a6dcb5d2b9eb7f22..e60205722d0c6abff35b05a033fe895a606d0551 100644 (file)
@@ -185,7 +185,6 @@ enum {
 };
 
 static int ftrace_filtered;
-static int tracing_on;
 
 static LIST_HEAD(ftrace_new_addrs);
 
@@ -506,13 +505,10 @@ static int __ftrace_modify_code(void *data)
 {
        int *command = data;
 
-       if (*command & FTRACE_ENABLE_CALLS) {
+       if (*command & FTRACE_ENABLE_CALLS)
                ftrace_replace_code(1);
-               tracing_on = 1;
-       } else if (*command & FTRACE_DISABLE_CALLS) {
+       else if (*command & FTRACE_DISABLE_CALLS)
                ftrace_replace_code(0);
-               tracing_on = 0;
-       }
 
        if (*command & FTRACE_UPDATE_TRACE_FUNC)
                ftrace_update_ftrace_func(ftrace_trace_function);
@@ -677,7 +673,7 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
 
        cnt = num_to_init / ENTRIES_PER_PAGE;
        pr_info("ftrace: allocating %ld entries in %d pages\n",
-               num_to_init, cnt);
+               num_to_init, cnt + 1);
 
        for (i = 0; i < cnt; i++) {
                pg->next = (void *)get_zeroed_page(GFP_KERNEL);
@@ -757,13 +753,11 @@ static void *t_start(struct seq_file *m, loff_t *pos)
        void *p = NULL;
        loff_t l = -1;
 
-       if (*pos != iter->pos) {
-               for (p = t_next(m, p, &l); p && l < *pos; p = t_next(m, p, &l))
-                       ;
-       } else {
-               l = *pos;
-               p = t_next(m, p, &l);
-       }
+       if (*pos > iter->pos)
+               *pos = iter->pos;
+
+       l = *pos;
+       p = t_next(m, p, &l);
 
        return p;
 }
@@ -774,15 +768,21 @@ static void t_stop(struct seq_file *m, void *p)
 
 static int t_show(struct seq_file *m, void *v)
 {
+       struct ftrace_iterator *iter = m->private;
        struct dyn_ftrace *rec = v;
        char str[KSYM_SYMBOL_LEN];
+       int ret = 0;
 
        if (!rec)
                return 0;
 
        kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
 
-       seq_printf(m, "%s\n", str);
+       ret = seq_printf(m, "%s\n", str);
+       if (ret < 0) {
+               iter->pos--;
+               iter->idx--;
+       }
 
        return 0;
 }
@@ -808,7 +808,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
                return -ENOMEM;
 
        iter->pg = ftrace_pages_start;
-       iter->pos = -1;
+       iter->pos = 0;
 
        ret = seq_open(file, &show_ftrace_seq_ops);
        if (!ret) {
@@ -895,7 +895,7 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable)
 
        if (file->f_mode & FMODE_READ) {
                iter->pg = ftrace_pages_start;
-               iter->pos = -1;
+               iter->pos = 0;
                iter->flags = enable ? FTRACE_ITER_FILTER :
                        FTRACE_ITER_NOTRACE;
 
index 2f76193c34894e094f6374d725fd8477c4b0af72..036456cbb4f7e1ceecf929e37ed6de581866abda 100644 (file)
 #include <linux/list.h>
 #include <linux/fs.h>
 
+#include "trace.h"
+
+/* Global flag to disable all recording to ring buffers */
+static int ring_buffers_off __read_mostly;
+
+/**
+ * tracing_on - enable all tracing buffers
+ *
+ * This function enables all tracing buffers that may have been
+ * disabled with tracing_off.
+ */
+void tracing_on(void)
+{
+       ring_buffers_off = 0;
+}
+
+/**
+ * tracing_off - turn off all tracing buffers
+ *
+ * This function stops all tracing buffers from recording data.
+ * It does not disable any overhead the tracers themselves may
+ * be causing. This function simply causes all recording to
+ * the ring buffers to fail.
+ */
+void tracing_off(void)
+{
+       ring_buffers_off = 1;
+}
+
 /* Up this if you want to test the TIME_EXTENTS and normalization */
 #define DEBUG_SHIFT 0
 
 /* FIXME!!! */
 u64 ring_buffer_time_stamp(int cpu)
 {
+       u64 time;
+
+       preempt_disable_notrace();
        /* shift to debug/test normalization and TIME_EXTENTS */
-       return sched_clock() << DEBUG_SHIFT;
+       time = sched_clock() << DEBUG_SHIFT;
+       preempt_enable_notrace();
+
+       return time;
 }
 
 void ring_buffer_normalize_time_stamp(int cpu, u64 *ts)
@@ -503,6 +538,12 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
        LIST_HEAD(pages);
        int i, cpu;
 
+       /*
+        * Always succeed at resizing a non-existent buffer:
+        */
+       if (!buffer)
+               return size;
+
        size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
        size *= BUF_PAGE_SIZE;
        buffer_size = buffer->pages * BUF_PAGE_SIZE;
@@ -1133,6 +1174,9 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer,
        struct ring_buffer_event *event;
        int cpu, resched;
 
+       if (ring_buffers_off)
+               return NULL;
+
        if (atomic_read(&buffer->record_disabled))
                return NULL;
 
@@ -1249,6 +1293,9 @@ int ring_buffer_write(struct ring_buffer *buffer,
        int ret = -EBUSY;
        int cpu, resched;
 
+       if (ring_buffers_off)
+               return -EBUSY;
+
        if (atomic_read(&buffer->record_disabled))
                return -EBUSY;
 
@@ -2070,3 +2117,69 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
        return 0;
 }
 
+static ssize_t
+rb_simple_read(struct file *filp, char __user *ubuf,
+              size_t cnt, loff_t *ppos)
+{
+       int *p = filp->private_data;
+       char buf[64];
+       int r;
+
+       /* !ring_buffers_off == tracing_on */
+       r = sprintf(buf, "%d\n", !*p);
+
+       return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t
+rb_simple_write(struct file *filp, const char __user *ubuf,
+               size_t cnt, loff_t *ppos)
+{
+       int *p = filp->private_data;
+       char buf[64];
+       long val;
+       int ret;
+
+       if (cnt >= sizeof(buf))
+               return -EINVAL;
+
+       if (copy_from_user(&buf, ubuf, cnt))
+               return -EFAULT;
+
+       buf[cnt] = 0;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       /* !ring_buffers_off == tracing_on */
+       *p = !val;
+
+       (*ppos)++;
+
+       return cnt;
+}
+
+static struct file_operations rb_simple_fops = {
+       .open           = tracing_open_generic,
+       .read           = rb_simple_read,
+       .write          = rb_simple_write,
+};
+
+
+static __init int rb_init_debugfs(void)
+{
+       struct dentry *d_tracer;
+       struct dentry *entry;
+
+       d_tracer = tracing_init_dentry();
+
+       entry = debugfs_create_file("tracing_on", 0644, d_tracer,
+                                   &ring_buffers_off, &rb_simple_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs 'tracing_on' entry\n");
+
+       return 0;
+}
+
+fs_initcall(rb_init_debugfs);
index 8d2688ff1352e7ca9c20c6ac28292216fb8640ac..b7b449dafbe5abb59fe06982e337cb31c6a7eaeb 100644 (file)
@@ -395,7 +395,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
                        WARN_ON(!irqs_disabled());
                        kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ);
                } else
-                       kunmap(miter->addr);
+                       kunmap(miter->page);
 
                miter->page = NULL;
                miter->addr = NULL;
index 78330c37a61bd1682768a61148be00a9a083003a..5f6c629a924d8da3a5e126b6fa76e12e562fe768 100644 (file)
@@ -467,9 +467,13 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
        dma_addr_t dev_addr;
        void *ret;
        int order = get_order(size);
+       u64 dma_mask = DMA_32BIT_MASK;
+
+       if (hwdev && hwdev->coherent_dma_mask)
+               dma_mask = hwdev->coherent_dma_mask;
 
        ret = (void *)__get_free_pages(flags, order);
-       if (ret && address_needs_mapping(hwdev, virt_to_bus(ret), size)) {
+       if (ret && !is_buffer_dma_capable(dma_mask, virt_to_bus(ret), size)) {
                /*
                 * The allocated memory isn't reachable by the device.
                 * Fall back on swiotlb_map_single().
@@ -493,9 +497,9 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
        dev_addr = virt_to_bus(ret);
 
        /* Confirm address can be DMA'd by device */
-       if (address_needs_mapping(hwdev, dev_addr, size)) {
+       if (!is_buffer_dma_capable(dma_mask, dev_addr, size)) {
                printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
-                      (unsigned long long)*hwdev->dma_mask,
+                      (unsigned long long)dma_mask,
                       (unsigned long long)dev_addr);
 
                /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
index d143ab67be444119b6240c5f8461a72fe2fc9647..6058b53dcb8905bc33bc25371083b47167de7596 100644 (file)
@@ -1796,6 +1796,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
                                struct page *page, unsigned long address)
 {
+       struct hstate *h = hstate_vma(vma);
        struct vm_area_struct *iter_vma;
        struct address_space *mapping;
        struct prio_tree_iter iter;
@@ -1805,7 +1806,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
         * vm_pgoff is in PAGE_SIZE units, hence the different calculation
         * from page cache lookup which is in HPAGE_SIZE units.
         */
-       address = address & huge_page_mask(hstate_vma(vma));
+       address = address & huge_page_mask(h);
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT)
                + (vma->vm_pgoff >> PAGE_SHIFT);
        mapping = (struct address_space *)page_private(page);
@@ -1824,7 +1825,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
                 */
                if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER))
                        unmap_hugepage_range(iter_vma,
-                               address, address + HPAGE_SIZE,
+                               address, address + huge_page_size(h),
                                page);
        }
 
index 6837a1014372556c7dd78d66d9ba9ea9cb931832..b5b2b15085a85383b1d8d14d8eff9ed2bf397611 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/highmem.h>
 #include <linux/vmalloc.h>
 #include <linux/ioport.h>
-#include <linux/cpuset.h>
 #include <linux/delay.h>
 #include <linux/migrate.h>
 #include <linux/page-isolation.h>
@@ -498,8 +497,6 @@ int add_memory(int nid, u64 start, u64 size)
        /* we online node here. we can't roll back from here. */
        node_set_online(nid);
 
-       cpuset_track_online_nodes();
-
        if (new_pgdat) {
                ret = register_one_node(nid);
                /*
index 385db89f0c33e48a421b8adf63e63b60b0e4881e..1e0d6b237f4418c2f8b8ca50e88d85a787adc0a7 100644 (file)
@@ -522,15 +522,12 @@ static int writeout(struct address_space *mapping, struct page *page)
        remove_migration_ptes(page, page);
 
        rc = mapping->a_ops->writepage(page, &wbc);
-       if (rc < 0)
-               /* I/O Error writing */
-               return -EIO;
 
        if (rc != AOP_WRITEPAGE_ACTIVATE)
                /* unlocked. Relock */
                lock_page(page);
 
-       return -EAGAIN;
+       return (rc < 0) ? -EIO : -EAGAIN;
 }
 
 /*
index 008ea70b7afa9a2baed56cdc9b6b43ef0b05a6ff..1ada366570cb535e4a281f7d526829c708f320f3 100644 (file)
@@ -66,14 +66,10 @@ void __clear_page_mlock(struct page *page)
                putback_lru_page(page);
        } else {
                /*
-                * Page not on the LRU yet.  Flush all pagevecs and retry.
+                * We lost the race. the page already moved to evictable list.
                 */
-               lru_add_drain_all();
-               if (!isolate_lru_page(page))
-                       putback_lru_page(page);
-               else if (PageUnevictable(page))
+               if (PageUnevictable(page))
                        count_vm_event(UNEVICTABLE_PGSTRANDED);
-
        }
 }
 
@@ -166,7 +162,7 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
        unsigned long addr = start;
        struct page *pages[16]; /* 16 gives a reasonable batch */
        int nr_pages = (end - start) / PAGE_SIZE;
-       int ret;
+       int ret = 0;
        int gup_flags = 0;
 
        VM_BUG_ON(start & ~PAGE_MASK);
@@ -187,8 +183,6 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
        if (vma->vm_flags & VM_WRITE)
                gup_flags |= GUP_FLAGS_WRITE;
 
-       lru_add_drain_all();    /* push cached pages to LRU */
-
        while (nr_pages > 0) {
                int i;
 
@@ -251,8 +245,6 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
                ret = 0;
        }
 
-       lru_add_drain_all();    /* to update stats */
-
        return ret;     /* count entire vma as locked_vm */
 }
 
@@ -546,6 +538,8 @@ asmlinkage long sys_mlock(unsigned long start, size_t len)
        if (!can_do_mlock())
                return -EPERM;
 
+       lru_add_drain_all();    /* flush pagevec */
+
        down_write(&current->mm->mmap_sem);
        len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
        start &= PAGE_MASK;
@@ -612,6 +606,8 @@ asmlinkage long sys_mlockall(int flags)
        if (!can_do_mlock())
                goto out;
 
+       lru_add_drain_all();    /* flush pagevec */
+
        down_write(&current->mm->mmap_sem);
 
        lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
index 54069e64e3a8a4b0c9a0450aba08b7f0fa21c5f9..d8ac01474563954fed58a1f87e2249c99827c430 100644 (file)
@@ -1561,6 +1561,10 @@ nofail_alloc:
 
        /* We now go into synchronous reclaim */
        cpuset_memory_pressure_bump();
+       /*
+        * The task's cpuset might have expanded its set of allowable nodes
+        */
+       cpuset_update_task_memory_state();
        p->flags |= PF_MEMALLOC;
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
index f59d797dc5a9b28ddcb3eae0f0aeeb4bc6e6daad..1223d927904d196d652911e222bc4a50140c627b 100644 (file)
@@ -165,7 +165,7 @@ int online_page_cgroup(unsigned long start_pfn,
        unsigned long start, end, pfn;
        int fail = 0;
 
-       start = start_pfn & (PAGES_PER_SECTION - 1);
+       start = start_pfn & ~(PAGES_PER_SECTION - 1);
        end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
 
        for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) {
@@ -188,7 +188,7 @@ int offline_page_cgroup(unsigned long start_pfn,
 {
        unsigned long start, end, pfn;
 
-       start = start_pfn & (PAGES_PER_SECTION - 1);
+       start = start_pfn & ~(PAGES_PER_SECTION - 1);
        end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
 
        for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION)
index ba6b0f5f7fac6dcce7a9e8a7c71f00e0e691d193..30f826d484f0b935af18a793f7fe49b65903025e 100644 (file)
@@ -324,14 +324,14 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
 
        BUG_ON(size & ~PAGE_MASK);
 
-       addr = ALIGN(vstart, align);
-
        va = kmalloc_node(sizeof(struct vmap_area),
                        gfp_mask & GFP_RECLAIM_MASK, node);
        if (unlikely(!va))
                return ERR_PTR(-ENOMEM);
 
 retry:
+       addr = ALIGN(vstart, align);
+
        spin_lock(&vmap_area_lock);
        /* XXX: could have a last_hole cache */
        n = vmap_area_root.rb_node;
@@ -362,7 +362,7 @@ retry:
                                goto found;
                }
 
-               while (addr + size >= first->va_start && addr + size <= vend) {
+               while (addr + size > first->va_start && addr + size <= vend) {
                        addr = ALIGN(first->va_end + PAGE_SIZE, align);
 
                        n = rb_next(&first->rb_node);
@@ -521,6 +521,17 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end,
        spin_unlock(&purge_lock);
 }
 
+/*
+ * Kick off a purge of the outstanding lazy areas. Don't bother if somebody
+ * is already purging.
+ */
+static void try_purge_vmap_area_lazy(void)
+{
+       unsigned long start = ULONG_MAX, end = 0;
+
+       __purge_vmap_area_lazy(&start, &end, 0, 0);
+}
+
 /*
  * Kick off a purge of the outstanding lazy areas.
  */
@@ -528,7 +539,7 @@ static void purge_vmap_area_lazy(void)
 {
        unsigned long start = ULONG_MAX, end = 0;
 
-       __purge_vmap_area_lazy(&start, &end, 0, 0);
+       __purge_vmap_area_lazy(&start, &end, 1, 0);
 }
 
 /*
@@ -539,7 +550,7 @@ static void free_unmap_vmap_area(struct vmap_area *va)
        va->flags |= VM_LAZY_FREE;
        atomic_add((va->va_end - va->va_start) >> PAGE_SHIFT, &vmap_lazy_nr);
        if (unlikely(atomic_read(&vmap_lazy_nr) > lazy_max_pages()))
-               purge_vmap_area_lazy();
+               try_purge_vmap_area_lazy();
 }
 
 static struct vmap_area *find_vmap_area(unsigned long addr)
index 3b5860294bb6654a7b6765a327cef83a9952a29d..7ea1440b53db23350112cb1a46c592542807e4ac 100644 (file)
@@ -623,6 +623,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                 * Try to allocate it some swap space here.
                 */
                if (PageAnon(page) && !PageSwapCache(page)) {
+                       if (!(sc->gfp_mask & __GFP_IO))
+                               goto keep_locked;
                        switch (try_to_munlock(page)) {
                        case SWAP_FAIL:         /* shouldn't happen */
                        case SWAP_AGAIN:
@@ -634,6 +636,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        }
                        if (!add_to_swap(page, GFP_ATOMIC))
                                goto activate_locked;
+                       may_enter_fs = 1;
                }
 #endif /* CONFIG_SWAP */
 
@@ -1386,9 +1389,9 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
        file_prio = 200 - sc->swappiness;
 
        /*
-        *                  anon       recent_rotated[0]
-        * %anon = 100 * ----------- / ----------------- * IO cost
-        *               anon + file      rotate_sum
+        * The amount of pressure on anon vs file pages is inversely
+        * proportional to the fraction of recently scanned pages on
+        * each list that were recently referenced and in active use.
         */
        ap = (anon_prio + 1) * (zone->recent_scanned[0] + 1);
        ap /= zone->recent_rotated[0] + 1;
@@ -2368,39 +2371,6 @@ int page_evictable(struct page *page, struct vm_area_struct *vma)
        return 1;
 }
 
-static void show_page_path(struct page *page)
-{
-       char buf[256];
-       if (page_is_file_cache(page)) {
-               struct address_space *mapping = page->mapping;
-               struct dentry *dentry;
-               pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
-
-               spin_lock(&mapping->i_mmap_lock);
-               dentry = d_find_alias(mapping->host);
-               printk(KERN_INFO "rescued: %s %lu\n",
-                      dentry_path(dentry, buf, 256), pgoff);
-               spin_unlock(&mapping->i_mmap_lock);
-       } else {
-#if defined(CONFIG_MM_OWNER) && defined(CONFIG_MMU)
-               struct anon_vma *anon_vma;
-               struct vm_area_struct *vma;
-
-               anon_vma = page_lock_anon_vma(page);
-               if (!anon_vma)
-                       return;
-
-               list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
-                       printk(KERN_INFO "rescued: anon %s\n",
-                              vma->vm_mm->owner->comm);
-                       break;
-               }
-               page_unlock_anon_vma(anon_vma);
-#endif
-       }
-}
-
-
 /**
  * check_move_unevictable_page - check page for evictability and move to appropriate zone lru list
  * @page: page to check evictability and move to appropriate lru list
@@ -2421,8 +2391,6 @@ retry:
        if (page_evictable(page, NULL)) {
                enum lru_list l = LRU_INACTIVE_ANON + page_is_file_cache(page);
 
-               show_page_path(page);
-
                __dec_zone_state(zone, NR_UNEVICTABLE);
                list_move(&page->lru, &zone->lru[l].list);
                __inc_zone_state(zone, NR_INACTIVE_ANON + l);
index c42c0c400bf9a36176ceedcac6a94083016e5b8d..0663f99e977a8af81e1c149d3b193b6b94acb520 100644 (file)
@@ -13,22 +13,24 @@ menuconfig NET_9P
 
          If unsure, say N.
 
+if NET_9P
+
 config NET_9P_VIRTIO
-       depends on NET_9P && EXPERIMENTAL && VIRTIO
+       depends on EXPERIMENTAL && VIRTIO
        tristate "9P Virtio Transport (Experimental)"
        help
          This builds support for a transports between
          guest partitions and a host partition.
 
 config NET_9P_RDMA
-       depends on NET_9P && INFINIBAND && EXPERIMENTAL
+       depends on INET && INFINIBAND && EXPERIMENTAL
        tristate "9P RDMA Transport (Experimental)"
        help
-         This builds support for a RDMA transport.
+         This builds support for an RDMA transport.
 
 config NET_9P_DEBUG
        bool "Debug information"
-       depends on NET_9P
        help
          Say Y if you want the 9P subsystem to log debug information.
 
+endif
index 67fb6a3834a3a538221b347c309842cda1816521..a3a2ba0fac08ca49259c94806b23b12acc1a78e9 100644 (file)
@@ -226,14 +226,14 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
                return 0; /* XXX: return error? check spec. */
        }
 
-       if (level == SOL_SOCKET && type == SO_TIMESTAMP) {
+       if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
                struct timeval *tv = (struct timeval *)data;
                ctv.tv_sec = tv->tv_sec;
                ctv.tv_usec = tv->tv_usec;
                data = &ctv;
                len = sizeof(ctv);
        }
-       if (level == SOL_SOCKET && type == SO_TIMESTAMPNS) {
+       if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS) {
                struct timespec *ts = (struct timespec *)data;
                cts.tv_sec = ts->tv_sec;
                cts.tv_nsec = ts->tv_nsec;
@@ -725,7 +725,7 @@ EXPORT_SYMBOL(compat_mc_getsockopt);
 static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
                                AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
                                AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
-                               AL(6)};
+                               AL(4)};
 #undef AL
 
 asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -738,52 +738,13 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
        return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
-asmlinkage long compat_sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
-                                  int __user *upeer_addrlen,
-                                  const compat_sigset_t __user *sigmask,
-                                  compat_size_t sigsetsize, int flags)
-{
-       compat_sigset_t ss32;
-       sigset_t ksigmask, sigsaved;
-       int ret;
-
-       if (sigmask) {
-               if (sigsetsize != sizeof(compat_sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
-                       return -EFAULT;
-               sigset_from_compat(&ksigmask, &ss32);
-
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-       }
-
-       ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
-
-       if (ret == -ERESTARTNOHAND) {
-               /*
-                * Don't restore the signal mask yet. Let do_signal() deliver
-                * the signal on the way back to userspace, before the signal
-                * mask is restored.
-                */
-               if (sigmask) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                              sizeof(sigsaved));
-                       set_restore_sigmask();
-               }
-       } else if (sigmask)
-               sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-
-       return ret;
-}
-
 asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
 {
        int ret;
        u32 a[6];
        u32 a0, a1;
 
-       if (call < SYS_SOCKET || call > SYS_PACCEPT)
+       if (call < SYS_SOCKET || call > SYS_ACCEPT4)
                return -EINVAL;
        if (copy_from_user(a, args, nas[call]))
                return -EFAULT;
@@ -804,7 +765,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
                ret = sys_listen(a0, a1);
                break;
        case SYS_ACCEPT:
-               ret = do_accept(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
+               ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
                break;
        case SYS_GETSOCKNAME:
                ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
@@ -844,9 +805,8 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
        case SYS_RECVMSG:
                ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
                break;
-       case SYS_PACCEPT:
-               ret = compat_sys_paccept(a0, compat_ptr(a1), compat_ptr(a[2]),
-                                        compat_ptr(a[3]), a[4], a[5]);
+       case SYS_ACCEPT4:
+               ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
                break;
        default:
                ret = -EINVAL;
index 31f29d2989fd207b65229cb562bc6105b79a6ca1..4dfb6b4d4559c9e52addf1c247028061af0bbdd5 100644 (file)
@@ -878,7 +878,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                if (ifm->ifi_change)
                        flags = (flags & ifm->ifi_change) |
                                (dev->flags & ~ifm->ifi_change);
-               dev_change_flags(dev, flags);
+               err = dev_change_flags(dev, flags);
+               if (err < 0)
+                       goto errout;
        }
 
        if (tb[IFLA_TXQLEN])
index ab242cc1accaae7673b76784aa5838a76d9b10c4..b12303dd39d9c68df84271963c2b9132fab7b035 100644 (file)
@@ -75,7 +75,6 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
                if (!fpl)
                        return -ENOMEM;
                *fplp = fpl;
-               INIT_LIST_HEAD(&fpl->list);
                fpl->count = 0;
        }
        fpp = &fpl->fp[fpl->count];
@@ -301,7 +300,6 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
 
        new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL);
        if (new_fpl) {
-               INIT_LIST_HEAD(&new_fpl->list);
                for (i=fpl->count-1; i>=0; i--)
                        get_file(fpl->fp[i]);
                memcpy(new_fpl, fpl, sizeof(*fpl));
index 5e2a3132a8c934d5aae50f8b359ebf28c6b65d8c..341e39456952abc106b9b7c9ec5eaa04e8de208f 100644 (file)
 static struct lock_class_key af_family_keys[AF_MAX];
 static struct lock_class_key af_family_slock_keys[AF_MAX];
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
 /*
  * Make lock validator output more readable. (we pre-construct these
  * strings build-time, so that runtime initialization of socket
@@ -187,7 +186,6 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
   "clock-AF_MAX"
 };
-#endif
 
 /*
  * sk_callback_lock locking rules are per-address-family,
index 861978a4f1a8b2f92a79baf34318beb808589a64..cfb38ac9d698b933cc64a5cd5dbb42298ba07056 100644 (file)
@@ -209,9 +209,17 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
 
                hash = protocol & (MAX_INET_PROTOS - 1);
                ipprot = rcu_dereference(inet_protos[hash]);
-               if (ipprot != NULL && (net == &init_net || ipprot->netns_ok)) {
+               if (ipprot != NULL) {
                        int ret;
 
+                       if (!net_eq(net, &init_net) && !ipprot->netns_ok) {
+                               if (net_ratelimit())
+                                       printk("%s: proto %d isn't netns-ready\n",
+                                               __func__, protocol);
+                               kfree_skb(skb);
+                               goto out;
+                       }
+
                        if (!ipprot->no_policy) {
                                if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                                        kfree_skb(skb);
index af99776146ffc14a4f85cb08ceaaea619d7b8a90..937549b8a9212fa6289964bde303367e2f462d74 100644 (file)
@@ -69,9 +69,12 @@ static u32 htcp_cwnd_undo(struct sock *sk)
        const struct tcp_sock *tp = tcp_sk(sk);
        struct htcp *ca = inet_csk_ca(sk);
 
-       ca->last_cong = ca->undo_last_cong;
-       ca->maxRTT = ca->undo_maxRTT;
-       ca->old_maxB = ca->undo_old_maxB;
+       if (ca->undo_last_cong) {
+               ca->last_cong = ca->undo_last_cong;
+               ca->maxRTT = ca->undo_maxRTT;
+               ca->old_maxB = ca->undo_old_maxB;
+               ca->undo_last_cong = 0;
+       }
 
        return max(tp->snd_cwnd, (tp->snd_ssthresh << 7) / ca->beta);
 }
@@ -268,7 +271,10 @@ static void htcp_state(struct sock *sk, u8 new_state)
        case TCP_CA_Open:
                {
                        struct htcp *ca = inet_csk_ca(sk);
-                       ca->last_cong = jiffies;
+                       if (ca->undo_last_cong) {
+                               ca->last_cong = jiffies;
+                               ca->undo_last_cong = 0;
+                       }
                }
                break;
        case TCP_CA_CWR:
index 410046a8cc915f5ea2f56a4c7b6c105f58d1903d..e44deb8d4df28c54cfd90392c63647fc88b591fc 100644 (file)
@@ -661,6 +661,11 @@ int datagram_send_ctl(struct net *net,
                        switch (rthdr->type) {
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
                        case IPV6_SRCRT_TYPE_2:
+                               if (rthdr->hdrlen != 2 ||
+                                   rthdr->segments_left != 1) {
+                                       err = -EINVAL;
+                                       goto exit_f;
+                               }
                                break;
 #endif
                        default:
index 4e5eac301f91835a9bebb5b77a1c5a48c8cd9023..2aa294be0c790043bbc148a71ce030e4e5fbcc4c 100644 (file)
@@ -366,11 +366,16 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                }
 
                /* routing header option needs extra check */
+               retv = -EINVAL;
                if (optname == IPV6_RTHDR && opt && opt->srcrt) {
                        struct ipv6_rt_hdr *rthdr = opt->srcrt;
                        switch (rthdr->type) {
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
                        case IPV6_SRCRT_TYPE_2:
+                               if (rthdr->hdrlen != 2 ||
+                                   rthdr->segments_left != 1)
+                                       goto sticky_done;
+
                                break;
 #endif
                        default:
index 87665d7bb4f9aa0bad666295914edca3dfefa701..14d165f0df75ff90e1ec9648b4454245cdbcd153 100644 (file)
@@ -2570,14 +2570,14 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
 
        switch (notif_type) {
        case IEEE80211_NOTIFY_RE_ASSOC:
-               rcu_read_lock();
-               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               rtnl_lock();
+               list_for_each_entry(sdata, &local->interfaces, list) {
                        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                                continue;
 
                        ieee80211_sta_req_auth(sdata, &sdata->u.sta);
                }
-               rcu_read_unlock();
+               rtnl_unlock();
                break;
        }
 }
index defeb7a0d502ab92dcc7253f0f97e10ae341209e..7ab30f668b5a8226a6342118c96322e33f04a0c4 100644 (file)
@@ -144,8 +144,8 @@ static int pn_send(struct sk_buff *skb, struct net_device *dev,
        struct phonethdr *ph;
        int err;
 
-       if (skb->len + 2 > 0xffff) {
-               /* Phonet length field would overflow */
+       if (skb->len + 2 > 0xffff /* Phonet length field limit */ ||
+           skb->len + sizeof(struct phonethdr) > dev->mtu) {
                err = -EMSGSIZE;
                goto drop;
        }
index 57550c3bcabec28ab7ee82030e6d1d4cb36192a0..92764d836891833e1cb7f8255a38edacad1f3b7f 100644 (file)
@@ -1426,8 +1426,8 @@ asmlinkage long sys_listen(int fd, int backlog)
  *     clean when we restucture accept also.
  */
 
-long do_accept(int fd, struct sockaddr __user *upeer_sockaddr,
-              int __user *upeer_addrlen, int flags)
+asmlinkage long sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
+                           int __user *upeer_addrlen, int flags)
 {
        struct socket *sock, *newsock;
        struct file *newfile;
@@ -1510,66 +1510,10 @@ out_fd:
        goto out_put;
 }
 
-#if 0
-#ifdef HAVE_SET_RESTORE_SIGMASK
-asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
-                           int __user *upeer_addrlen,
-                           const sigset_t __user *sigmask,
-                           size_t sigsetsize, int flags)
-{
-       sigset_t ksigmask, sigsaved;
-       int ret;
-
-       if (sigmask) {
-               /* XXX: Don't preclude handling different sized sigset_t's.  */
-               if (sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
-                       return -EFAULT;
-
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-        }
-
-       ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
-
-       if (ret < 0 && signal_pending(current)) {
-               /*
-                * Don't restore the signal mask yet. Let do_signal() deliver
-                * the signal on the way back to userspace, before the signal
-                * mask is restored.
-                */
-               if (sigmask) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                              sizeof(sigsaved));
-                       set_restore_sigmask();
-               }
-       } else if (sigmask)
-               sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-
-       return ret;
-}
-#else
-asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
-                           int __user *upeer_addrlen,
-                           const sigset_t __user *sigmask,
-                           size_t sigsetsize, int flags)
-{
-       /* The platform does not support restoring the signal mask in the
-        * return path.  So we do not allow using paccept() with a signal
-        * mask.  */
-       if (sigmask)
-               return -EINVAL;
-
-       return do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
-}
-#endif
-#endif
-
 asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
                           int __user *upeer_addrlen)
 {
-       return do_accept(fd, upeer_sockaddr, upeer_addrlen, 0);
+       return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0);
 }
 
 /*
@@ -2096,7 +2040,7 @@ static const unsigned char nargs[19]={
        AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
        AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
        AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
-       AL(6)
+       AL(4)
 };
 
 #undef AL
@@ -2115,7 +2059,7 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
        unsigned long a0, a1;
        int err;
 
-       if (call < 1 || call > SYS_PACCEPT)
+       if (call < 1 || call > SYS_ACCEPT4)
                return -EINVAL;
 
        /* copy_from_user should be SMP safe. */
@@ -2143,9 +2087,8 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
                err = sys_listen(a0, a1);
                break;
        case SYS_ACCEPT:
-               err =
-                   do_accept(a0, (struct sockaddr __user *)a1,
-                             (int __user *)a[2], 0);
+               err = sys_accept4(a0, (struct sockaddr __user *)a1,
+                                 (int __user *)a[2], 0);
                break;
        case SYS_GETSOCKNAME:
                err =
@@ -2192,12 +2135,9 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
        case SYS_RECVMSG:
                err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
                break;
-       case SYS_PACCEPT:
-               err =
-                   sys_paccept(a0, (struct sockaddr __user *)a1,
-                               (int __user *)a[2],
-                               (const sigset_t __user *) a[3],
-                               a[4], a[5]);
+       case SYS_ACCEPT4:
+               err = sys_accept4(a0, (struct sockaddr __user *)a1,
+                                 (int __user *)a[2], a[3]);
                break;
        default:
                err = -EINVAL;
index 9b77b3e0fa98dadceaba640c4e185a2e496a0cc9..3ecd7e797deecbbb9fbf5bbfa9ea3c02c00fdaee 100644 (file)
@@ -37,6 +37,9 @@ static void snd_hda_generate_beep(struct work_struct *work)
                container_of(work, struct hda_beep, beep_work);
        struct hda_codec *codec = beep->codec;
 
+       if (!beep->enabled)
+               return;
+
        /* generate tone */
        snd_hda_codec_write_cache(codec, beep->nid, 0,
                        AC_VERB_SET_BEEP_CONTROL, beep->tone);
@@ -85,6 +88,10 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        snprintf(beep->phys, sizeof(beep->phys),
                "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
        input_dev = input_allocate_device();
+       if (!input_dev) {
+               kfree(beep);
+               return -ENOMEM;
+       }
 
        /* setup digital beep device */
        input_dev->name = "HDA Digital PCBeep";
@@ -115,6 +122,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        beep->nid = nid;
        beep->dev = input_dev;
        beep->codec = codec;
+       beep->enabled = 1;
        codec->beep = beep;
 
        INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
index de4036e6e710feb014caf71095e6c93f8a6270f1..b9679f081cae9006a3a81b784f5e1e4927f567f5 100644 (file)
@@ -31,6 +31,7 @@ struct hda_beep {
        char phys[32];
        int tone;
        int nid;
+       int enabled;
        struct work_struct beep_work; /* scheduled task for beep event */
 };
 
index 4300a679cd8639a0bd1e5a89c22d630a50125def..9563b5bbb272f41dda83997ceaf97bba7484af22 100644 (file)
 #include "hda_beep.h"
 
 #define NUM_CONTROL_ALLOC      32
+
+#define STAC_VREF_EVENT                0x00
+#define STAC_INSERT_EVENT      0x10
 #define STAC_PWR_EVENT         0x20
 #define STAC_HP_EVENT          0x30
-#define STAC_VREF_EVENT                0x40
 
 enum {
        STAC_REF,
@@ -1686,6 +1688,10 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
+                     "HP dv5", STAC_HP_M4),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
+                     "HP dv7", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
                                "unknown HP", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
@@ -2587,8 +2593,10 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
 };
 
 /* add dynamic controls */
-static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
-               int idx, const char *name, unsigned long val)
+static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
+                                    struct snd_kcontrol_new *ktemp,
+                                    int idx, const char *name,
+                                    unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
@@ -2607,20 +2615,29 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
        }
 
        knew = &spec->kctl_alloc[spec->num_kctl_used];
-       *knew = stac92xx_control_templates[type];
+       *knew = *ktemp;
        knew->index = idx;
        knew->name = kstrdup(name, GFP_KERNEL);
-       if (! knew->name)
+       if (!knew->name)
                return -ENOMEM;
        knew->private_value = val;
        spec->num_kctl_used++;
        return 0;
 }
 
+static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
+                                          int type, int idx, const char *name,
+                                          unsigned long val)
+{
+       return stac92xx_add_control_temp(spec,
+                                        &stac92xx_control_templates[type],
+                                        idx, name, val);
+}
+
 
 /* add dynamic controls */
-static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
-               const char *name, unsigned long val)
+static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
+                                      const char *name, unsigned long val)
 {
        return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
@@ -3062,6 +3079,43 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
        return 0;
 }
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
+
+static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = codec->beep->enabled;
+       return 0;
+}
+
+static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int enabled = !!ucontrol->value.integer.value[0];
+       if (codec->beep->enabled != enabled) {
+               codec->beep->enabled = enabled;
+               return 1;
+       }
+       return 0;
+}
+
+static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = stac92xx_dig_beep_switch_info,
+       .get = stac92xx_dig_beep_switch_get,
+       .put = stac92xx_dig_beep_switch_put,
+};
+
+static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
+{
+       return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
+                                        0, "PC Beep Playback Switch", 0);
+}
+#endif
+
 static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -3368,6 +3422,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
        if (spec->digbeep_nid > 0) {
                hda_nid_t nid = spec->digbeep_nid;
+               unsigned int caps;
 
                err = stac92xx_auto_create_beep_ctls(codec, nid);
                if (err < 0)
@@ -3375,6 +3430,14 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                err = snd_hda_attach_beep_device(codec, nid);
                if (err < 0)
                        return err;
+               /* if no beep switch is available, make its own one */
+               caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+               if (codec->beep &&
+                   !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
+                       err = stac92xx_beep_switch_ctl(codec);
+                       if (err < 0)
+                               return err;
+               }
        }
 #endif
 
@@ -4419,6 +4482,13 @@ again:
                stac92xx_set_config_regs(codec);
        }
 
+       if (spec->board_config > STAC_92HD71BXX_REF) {
+               /* GPIO0 = EAPD */
+               spec->gpio_mask = 0x01;
+               spec->gpio_dir = 0x01;
+               spec->gpio_data = 0x01;
+       }
+
        switch (codec->vendor_id) {
        case 0x111d76b6: /* 4 Port without Analog Mixer */
        case 0x111d76b7:
@@ -4429,10 +4499,10 @@ again:
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                break;
        case 0x111d7608: /* 5 Port with Analog Mixer */
-               switch (codec->subsystem_id) {
-               case 0x103c361a:
+               switch (spec->board_config) {
+               case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
-                       snd_hda_codec_write(codec, codec->afg, 0,
+                       snd_hda_codec_write_cache(codec, codec->afg, 0,
                                AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
                        snd_hda_codec_write_cache(codec, codec->afg, 0,
                                        AC_VERB_SET_UNSOLICITED_ENABLE,
@@ -4478,13 +4548,6 @@ again:
        spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
 
-       if (spec->board_config > STAC_92HD71BXX_REF) {
-               /* GPIO0 = EAPD */
-               spec->gpio_mask = 0x01;
-               spec->gpio_dir = 0x01;
-               spec->gpio_data = 0x01;
-       }
-
        spec->powerdown_adcs = 1;
        spec->digbeep_nid = 0x26;
        spec->mux_nids = stac92hd71bxx_mux_nids;
@@ -4832,7 +4895,7 @@ static int patch_stac9205(struct hda_codec *codec)
                stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
 
                /* Enable unsol response for GPIO4/Dock HP connection */
-               snd_hda_codec_write(codec, codec->afg, 0,
+               snd_hda_codec_write_cache(codec, codec->afg, 0,
                        AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
                snd_hda_codec_write_cache(codec, codec->afg, 0,
                                          AC_VERB_SET_UNSOLICITED_ENABLE,
index 0e06c6c9fcc01d1406e3ba61921aece7bef9196f..73de6e989b3d4ab78069d8b24240637890fd3131 100644 (file)
@@ -1229,8 +1229,11 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
                return -ENOMEM;
        }
 
-       if (snd_BUG_ON(pci_id->driver_data >= PCI_ID_LAST))
+       if (snd_BUG_ON(pci_id->driver_data >= PCI_ID_LAST)) {
+               kfree(mgr);
+               pci_disable_device(pci);
                return -ENODEV;
+       }
        card_name = pcxhr_board_params[pci_id->driver_data].board_name;
        mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips;
        mgr->capture_chips  = pcxhr_board_params[pci_id->driver_data].capture_chips;